Reputation: 11
Here is the part of the code that is specifying the backtest. I already have a 'Signal' column in another dataframe 'data', but that isnt the problem here.
temp = yf.download(
symb,
interval=interval,
period=period
)
temp.reset_index(inplace=True)
print(temp.columns)
class MyStrategy(Strategy):
stop_factor = 0.02 # stop loss factor
take_profit_factor = 0.04 # take profit factor for 1:2 risk-reward ratio
def init(self):
# Set up signals
self.signal = self.data['signals']
def next(self):
# If the signal is a buy, we want to buy
if self.signal == 1:
self.buy(size=1, stop=self.data.close[-1] * (1 - self.stop_factor), takeprofit=self.data.close[-1] * (1 + self.take_profit_factor))
# If the signal is a sell, we want to sell
elif self.signal == -1:
self.sell(size=1, stop=self.data.close[-1] * (1 + self.stop_factor), takeprofit=self.data.close[-1] * (1 - self.take_profit_factor))
# Backtest setup
bt = Backtest(temp, MyStrategy, cash=10000, commission=0.002)
stats = bt.run()
# Print the backtest results
print(stats)
I have tried to change the index to a new 'Candle_No' column and tried to reset the index but nothing has worked.
This is the error that actually shows up:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/usr/local/lib/python3.10/dist-packages/pandas/core/indexes/multi.py in _convert_can_do_setop(self, other)
3853 try:
-> 3854 other = MultiIndex.from_tuples(other, names=self.names)
3855 except (ValueError, TypeError) as err:
8 frames
ValueError: Length of names must match number of levels in MultiIndex.
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
/usr/local/lib/python3.10/dist-packages/pandas/core/indexes/multi.py in _convert_can_do_setop(self, other)
3856 # ValueError raised by tuples_to_object_array if we
3857 # have non-object dtype
-> 3858 raise TypeError(msg) from err
3859 else:
3860 result_names = get_unanimous_names(self, other)
TypeError: other must be a MultiIndex or a list of tuples
Upvotes: 1
Views: 149
Reputation: 11504
The data that you collect from yfinance
has MultiIndex
columns, especially when downloading data with specific intervals. You need to deal with that. To test a solution, I needed to add data (As was mentioned to you in the comments, your question needs to be elaborated and sample data needs to be shared, particularily the data
containing the signal
variable. So, adapt the following to your needs:
import pandas as pd
import yfinance as yf
from backtesting import Backtest, Strategy
import numpy as np
symb = "AAPL"
interval = "1d"
period = "1y"
temp = yf.download(
symb,
interval=interval,
period=period
)
temp.reset_index(inplace=True)
temp['signals'] = np.random.choice([-1, 0, 1], size=len(temp))
if isinstance(temp.columns, pd.MultiIndex):
temp.columns = ['_'.join(col).strip() if isinstance(col, tuple) else col for col in temp.columns]
temp.rename(columns={'Open': 'Open', 'High': 'High', 'Low': 'Low', 'Close': 'Close'}, inplace=True)
class MyStrategy(Strategy):
stop_factor = 0.02
take_profit_factor = 0.04
def init(self):
self.signal = self.data['signals']
def next(self):
if self.signal[-1] == 1:
self.buy(size=1, sl=self.data.Close[-1] * (1 - self.stop_factor),
tp=self.data.Close[-1] * (1 + self.take_profit_factor))
elif self.signal[-1] == -1:
self.sell(size=1, sl=self.data.Close[-1] * (1 + self.stop_factor),
tp=self.data.Close[-1] * (1 - self.take_profit_factor))
bt = Backtest(temp, MyStrategy, cash=10000, commission=0.002)
stats = bt.run()
print(stats)
which returns
[*********************100%%**********************] 1 of 1 completed
Start 0.0
End 251.0
Duration 251.0
Exposure Time [%] 0.0
Equity Final [$] 10000.0
Equity Peak [$] 10000.0
Return [%] 0.0
Buy & Hold Return [%] 25.001282
Return (Ann.) [%] 0.0
Volatility (Ann.) [%] NaN
Sharpe Ratio NaN
Sortino Ratio NaN
Calmar Ratio NaN
Max. Drawdown [%] -0.0
Avg. Drawdown [%] NaN
Max. Drawdown Duration NaN
Avg. Drawdown Duration NaN
# Trades 0.0
Win Rate [%] NaN
Best Trade [%] NaN
Worst Trade [%] NaN
Avg. Trade [%] NaN
Max. Trade Duration NaN
Avg. Trade Duration NaN
Profit Factor NaN
...
_equity_curve Equity Dr...
_trades Empty DataFrame
...
dtype: object
Upvotes: 1