1 import pandas as pd
2 from scipy.signal import find_peaks
3 from lumibot.backtesting import PandasDataBacktesting, BacktestingBroker
4 from lumibot.entities import Asset, Data
5 from lumibot.strategies import Strategy
6 from lumibot.traders import Trader
7
8
9 from Trends.correction_inverse import correction_inverse, calculate_fibonacci_levels as fib_ci, calculate_extension_levels as ext_ci
10 from Trends.correction import correction, calculate_fibonacci_levels as fib_c, calculate_extension_levels as ext_c
11 from Trends.impulse_inverse import downtrend, calculate_fibonacci_levels as fib_di
12 from Trends.impulse import uptrend, calculate_fibonacci_levels as fib_u
13
14
15 print("Imported Elliott Wave algorithms and Fibonacci level functions.")
16
17
18 def load_data(file_path):
19 df = pd.read_csv(file_path, parse_dates=['Datetime'], index_col='Datetime')
20 if df.index.tzinfo is None:
21 df.index = df.index.tz_localize('UTC')
22 else:
23 df.index = df.index.tz_convert('UTC')
24 print(f"Loaded data from {file_path}:")
25 print(f"Shape: {df.shape}")
26 print(f"Date range: {df.index.min()} to {df.index.max()}")
27 print(df.head())
28 return df
29
30 class ElliottWaveStrategy(Strategy):
31 def initialize(self):
32 self.position_size = 0.01
33 self.symbols = ['BTC-USD', 'ETH-USD']
34
35 def on_trading_iteration(self):
36 for symbol in self.symbols:
37 asset = Asset(symbol, asset_type='crypto')
38 self.process_data(asset)
39
40 def process_data(self, asset):
41 print(f"Processing data for {asset.symbol}")
42 bars = self.get_historical_prices(asset, 100)
43
44 if bars is None or len(bars.df) == 0:
45 print(f"No data for {asset.symbol}")
46 return
47
48 data = bars.df
49
50 print(f"Data for {asset.symbol}:")
51 print(f"Shape: {data.shape}")
52 print(f"Date range: {data.index.min()} to {data.index.max()}")
53 print(data.head())
54
55 if len(data) < 20:
56 print(f"Insufficient data for {asset.symbol}")
57 return
58
59 close_prices = data['Close']
60 peaks, _ = find_peaks(data['High'], prominence=1)
61 valleys, _ = find_peaks(-data['Low'], prominence=1)
62
63 mean_price = close_prices.rolling(window=20).mean()
64 upper_band = mean_price + 2 * close_prices.rolling(window=20).std()
65 lower_band = mean_price - 2 * close_prices.rolling(window=20).std()
66 above_mean = close_prices > mean_price
67 below_mean = close_prices < mean_price
68
69
70 print(f"Peaks for {asset.symbol}: {peaks}")
71 print(f"Valleys for {asset.symbol}: {valleys}")
72
73
74 correction_inv_results = correction_inverse(close_prices, peaks, valleys)
75 correction_results = correction(close_prices, peaks, valleys)
76 impulse_inv_results = downtrend(close_prices, mean_price, upper_band, below_mean, peaks, valleys)
77 impulse_results = uptrend(close_prices, mean_price, lower_band, above_mean, peaks, valleys)
78
79
80 print(f"Correction Inverse Results: {correction_inv_results}")
81 print(f"Correction Results: {correction_results}")
82 print(f"Impulse Inverse Results: {impulse_inv_results}")
83 print(f"Impulse Results: {impulse_results}")
84
85
86 if all(result is not None for result in [correction_inv_results, correction_results, impulse_inv_results, impulse_results]):
87 self.execute_trades(asset, correction_inv_results, correction_results, impulse_inv_results, impulse_results)
88 else:
89 print(f"Warning: One of the results for {asset.symbol} is None.")
90
91
92 print(f"Last price for {asset.symbol}: {bars.get_last_price()}")
93 print(f"Total volume for {asset.symbol}: {bars.get_total_volume()}")
94 momentum = bars.get_momentum()
95 print(f"Momentum for {asset.symbol}: {momentum}")
96
97 def execute_trades(self, asset, correction_inv, correction, impulse_inv, impulse):
98
99 if correction_inv.get('Wave B'):
100 self.sell_positions(asset, 3)
101 if correction_inv.get('Wave C'):
102 self.take_profit(asset, 3)
103
104
105 if correction.get('Wave B'):
106 self.buy_positions(asset, 3)
107 if correction.get('Wave C'):
108 self.take_profit(asset, 3)
109
110
111 if impulse_inv:
112 self.sell_positions(asset, 3)
113 self.take_profit(asset, 3)
114 self.sell_positions(asset, 2)
115 self.take_profit(asset, 2)
116
117
118 if impulse:
119 self.buy_positions(asset, 3)
120 self.take_profit(asset, 3)
121 self.buy_positions(asset, 2)
122 self.take_profit(asset, 2)
123
124 def buy_positions(self, asset, num_positions):
125 position_size = self.portfolio_value * self.position_size * num_positions
126 order = self.create_order(asset, position_size, "buy")
127 self.submit_order(order)
128
129 def sell_positions(self, asset, num_positions):
130 position_size = self.portfolio_value * self.position_size * num_positions
131 order = self.create_order(asset, position_size, "sell")
132 self.submit_order(order)
133
134 def take_profit(self, asset, num_positions):
135 position_size = self.portfolio_value * self.position_size * num_positions
136 order = self.create_order(asset, position_size, "sell")
137 self.submit_order(order)
138
139
140 assets = ['ETH-USD', 'BTC-USD']
141 pandas_data = {}
142 earliest_date = None
143 latest_date = None
144
145
146 quote_asset = Asset(symbol='USD', asset_type='forex')
147
148 for symbol in assets:
149 df = load_data(f"{symbol}_5minute_data.csv")
150
151 if earliest_date is None or df.index.min() < earliest_date:
152 earliest_date = df.index.min()
153 if latest_date is None or df.index.max() > latest_date:
154 latest_date = df.index.max()
155
156 base_asset = Asset(symbol=symbol, asset_type='crypto')
157 pandas_data[base_asset] = Data(asset=base_asset, df=df, timestep="minute", quote=quote_asset)
158
159
160 backtesting_start = earliest_date
161 backtesting_end = latest_date
162
163 print(f"Backtesting from {backtesting_start} to {backtesting_end}")
164
165
166 trader = Trader(backtest=True)
167 data_source = PandasDataBacktesting(pandas_data=pandas_data, datetime_start=backtesting_start, datetime_end=backtesting_end)
168 broker = BacktestingBroker(data_source)
169 strategy = ElliottWaveStrategy()
170 trader.set_broker(broker)
171 trader.add_strategy(strategy)
172 trader.run_all(show_plot=True, show_tearsheet=True)
173
174 print("Backtest completed.")
175
176
What I have tried:
I tried using chatgpt and stackoverflow. I will be reviewing the code by again and im leaving this up incase someone solves it before me.
below is my terminal output for the script:
(.venv) (base) montellgreef@Nathaniels-MacBook-Air algostack % /Users/montellgreef/Desktop/algostack/.venv/bin/python /Users/montellgreef/Desktop/al
gostack/backtest.py
Imported Elliott Wave algorithms and Fibonacci level functions.
Loaded data from ETH-USD_5minute_data.csv:
Shape: (17256, 6)
Date range: 2024-05-10 19:05:00+00:00 to 2024-07-09 17:00:00+00:00
Open High Low Close Adj Close Volume
Datetime
2024-05-10 19:05:00+00:00 2912.727295 2912.727295 2911.097168 2911.254150 2911.254150 0
2024-05-10 19:10:00+00:00 2911.173340 2911.173340 2905.322266 2906.032959 2906.032959 9549824
2024-05-10 19:15:00+00:00 2906.769775 2906.926270 2906.105957 2906.105957 2906.105957 404480
2024-05-10 19:20:00+00:00 2906.297363 2906.297363 2902.526611 2902.526611 2902.526611 7694336
2024-05-10 19:25:00+00:00 2902.547852 2904.846436 2902.526855 2902.526855 2902.526855 4087808
Loaded data from BTC-USD_5minute_data.csv:
Shape: (17256, 6)
Date range: 2024-05-10 19:05:00+00:00 to 2024-07-09 17:00:00+00:00
Open High Low Close Adj Close Volume
Datetime
2024-05-10 19:05:00+00:00 60807.664062 60807.664062 60758.941406 60780.312500 60780.312500 0
2024-05-10 19:10:00+00:00 60792.988281 60792.988281 60692.152344 60707.042969 60707.042969 25731072
2024-05-10 19:15:00+00:00 60717.902344 60717.902344 60674.304688 60674.304688 60674.304688 9680896
2024-05-10 19:20:00+00:00 60676.972656 60676.972656 60625.015625 60625.015625 60625.015625 770048
2024-05-10 19:25:00+00:00 60580.074219 60623.589844 60558.226562 60558.226562 60558.226562 0
Backtesting from 2024-05-10 19:05:00+00:00 to 2024-07-09 17:00:00+00:00
Traceback (most recent call last):
File "/Users/montellgreef/Desktop/algostack/backtest.py", line 169, in <module>
strategy = ElliottWaveStrategy()
File "/Users/montellgreef/Desktop/algostack/.venv/lib/python3.10/site-packages/lumibot/strategies/_strategy.py", line 198, in __init__
self.broker.quote_assets.add(self._quote_asset)
AttributeError: 'NoneType' object has no attribute 'quote_assets'