From 0033d433c41128a11e343c538719d3a21bfbbc58 Mon Sep 17 00:00:00 2001 From: "Bobby (aider)" Date: Fri, 14 Feb 2025 00:32:03 -0800 Subject: [PATCH] feat: Add new technical indicators to backtesting strategy --- src/pages/backtesting/backtesting_page.py | 120 ++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/pages/backtesting/backtesting_page.py b/src/pages/backtesting/backtesting_page.py index 4f6d5dc..15603e2 100644 --- a/src/pages/backtesting/backtesting_page.py +++ b/src/pages/backtesting/backtesting_page.py @@ -97,6 +97,76 @@ class DynamicStrategy(Strategy): self.indicators[f"{ind_name}_middle"] = bb_vals[1] self.indicators[f"{ind_name}_lower"] = bb_vals[2] + elif ind_config['type'] == 'WMA': + def wma_calc(x): + series = pd.Series(x) + result = ta.wma(series, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(wma_calc, self.data.Close) + + elif ind_config['type'] == 'DEMA': + def dema_calc(x): + series = pd.Series(x) + result = ta.dema(series, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(dema_calc, self.data.Close) + + elif ind_config['type'] == 'TEMA': + def tema_calc(x): + series = pd.Series(x) + result = ta.tema(series, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(tema_calc, self.data.Close) + + elif ind_config['type'] == 'HMA': + def hma_calc(x): + series = pd.Series(x) + result = ta.hma(series, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(hma_calc, self.data.Close) + + elif ind_config['type'] == 'VWAP': + def vwap_calc(high, low, close, volume): + result = ta.vwap(high, low, close, volume, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(vwap_calc, self.data.High, self.data.Low, self.data.Close, self.data.Volume) + + elif ind_config['type'] == 'Stochastic': + def stoch_calc(high, low, close): + result = ta.stoch(high, low, close, + k=int(ind_config['params']['k']), + d=int(ind_config['params']['d']), + smooth_k=int(ind_config['params']['smooth_k'])) + return (result['STOCHk_14_3_3'].fillna(method='ffill').fillna(0).values, + result['STOCHd_14_3_3'].fillna(method='ffill').fillna(0).values) + stoch_vals = self.I(stoch_calc, self.data.High, self.data.Low, self.data.Close) + self.indicators[f"{ind_name}_k"] = stoch_vals[0] + self.indicators[f"{ind_name}_d"] = stoch_vals[1] + + elif ind_config['type'] == 'ADX': + def adx_calc(high, low, close): + result = ta.adx(high, low, close, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(adx_calc, self.data.High, self.data.Low, self.data.Close) + + elif ind_config['type'] == 'CCI': + def cci_calc(high, low, close): + result = ta.cci(high, low, close, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(cci_calc, self.data.High, self.data.Low, self.data.Close) + + elif ind_config['type'] == 'MFI': + def mfi_calc(high, low, close, volume): + result = ta.mfi(high, low, close, volume, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(mfi_calc, self.data.High, self.data.Low, self.data.Close, self.data.Volume) + + elif ind_config['type'] == 'Williams%R': + def willr_calc(high, low, close): + result = ta.willr(high, low, close, length=int(ind_config['params']['length'])) + return result.fillna(method='ffill').fillna(0).values + self.indicators[ind_name] = self.I(willr_calc, self.data.High, self.data.Low, self.data.Close) + def next(self): price = self.data.Close[-1] @@ -192,6 +262,56 @@ def get_available_indicators() -> Dict: 'params': ['length', 'std'], 'defaults': {'length': 20, 'std': 2.0}, 'ranges': {'length': (10, 50), 'std': (1.5, 3.0)} + }, + 'WMA': { + 'params': ['length'], + 'defaults': {'length': 20}, + 'ranges': {'length': (5, 200)} + }, + 'DEMA': { + 'params': ['length'], + 'defaults': {'length': 20}, + 'ranges': {'length': (5, 200)} + }, + 'TEMA': { + 'params': ['length'], + 'defaults': {'length': 20}, + 'ranges': {'length': (5, 200)} + }, + 'HMA': { + 'params': ['length'], + 'defaults': {'length': 20}, + 'ranges': {'length': (5, 200)} + }, + 'VWAP': { + 'params': ['length'], + 'defaults': {'length': 14}, + 'ranges': {'length': (1, 30)} + }, + 'Stochastic': { + 'params': ['k', 'd', 'smooth_k'], + 'defaults': {'k': 14, 'd': 3, 'smooth_k': 3}, + 'ranges': {'k': (5, 30), 'd': (2, 10), 'smooth_k': (2, 10)} + }, + 'ADX': { + 'params': ['length'], + 'defaults': {'length': 14}, + 'ranges': {'length': (5, 30)} + }, + 'CCI': { + 'params': ['length'], + 'defaults': {'length': 20}, + 'ranges': {'length': (10, 50)} + }, + 'MFI': { + 'params': ['length'], + 'defaults': {'length': 14}, + 'ranges': {'length': (5, 30)} + }, + 'Williams%R': { + 'params': ['length'], + 'defaults': {'length': 14}, + 'ranges': {'length': (5, 30)} } }