这是指定回测的代码部分。我在另一个数据框“数据”中已经有一个“信号”列,但这不是这里的问题。
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)
我尝试将索引更改为新的“Candle_No”列,并尝试重置索引,但没有任何效果。
这是实际显示的错误:
---------------------------------------------------------------------------
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
您从
yfinance
收集的数据有 MultiIndex
列,特别是在以特定间隔下载数据时。你需要处理这个问题。为了测试解决方案,我需要添加数据(正如在评论中向您提到的,需要详细说明您的问题并且需要共享示例数据,特别是包含 data
变量的 signal
。因此,调整根据您的需求:
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)
返回
[*********************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