Click here to Skip to main content
16,022,296 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Python
  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  # Import your Elliott Wave algorithms & Fibonacci Levels
  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  # Print statements to ensure algorithms and Fibonacci levels are imported
 15  print("Imported Elliott Wave algorithms and Fibonacci level functions.")
 16  
 17  # Load historical data
 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  # 1% of total equity per trade
 33          self.symbols = ['BTC-USD', 'ETH-USD']  # List of symbols to trade
 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)  # Get last 100 data points
 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  # The dataframe is already available as a property
 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          # Print the identified peaks and valleys
 70          print(f"Peaks for {asset.symbol}: {peaks}")
 71          print(f"Valleys for {asset.symbol}: {valleys}")
 72  
 73          # Get results from the wave algorithms
 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          # Print the results for debugging
 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          # Check if the results are not None before proceeding
 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          # Additional information you might find useful
 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          # Correction Inverse Logic
 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          # Correction Logic
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          # Impulse Inverse Logic
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          # Impulse Logic
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  # Read the data from the CSV files
140  assets = ['ETH-USD', 'BTC-USD']
141  pandas_data = {}
142  earliest_date = None
143  latest_date = None
144  
145  # Assuming quote asset type should be 'forex' in this context
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  # Use the full date range from the data
160  backtesting_start = earliest_date
161  backtesting_end = latest_date
162  
163  print(f"Backtesting from {backtesting_start} to {backtesting_end}")
164  
165  # Run the backtesting
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  #quote_asset (Asset (crypto)) – An Asset object for the crypto currency that will get used as a valuation asset for measuring overall portfolio values. Usually USDT, USD, USDC.


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'
Posted
Updated 16-Jul-24 1:25am
v4
Comments
Richard Deeming 16-Jul-24 7:12am    
Dumping 174 lines of unformatted, unexplained code, and expecting someone to "solve it" for you, when you haven't even bothered to tell us what the problem is, which line it occurs on, etc. does not make this a question.

The quality of solutions you get directly depend on the effort you put into asking your question.
Montell Greef 16-Jul-24 7:16am    
Good day Richard, this is the first time im making use of this platform, I will provide a terminal output since I see that I can update the question, I will try to format and fix the the provided code

1 solution

Based on the trace, the error comes from the lumibot _strategy.py file. It's calling self.broker.quote_assets, but self.broker is not initialized.

At a guess, I would try reordering the lines in your file so that you set the broker before you construct the strategy:
Python
# strategy = ElliottWaveStrategy() # <- Move this line...
trader.set_broker(broker)
strategy = ElliottWaveStrategy()   # <- to here.
trader.add_strategy(strategy)
If that doesn't work, then you'll need to check the documentation for the package you're using to see if you've missed something.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900