from examples.astock.strategy.model.Signal import SignalType
def backtest(signals, initial_balance=100000):
"""
根据信号列表进行回测,计算收益率和最大回撤
:param signals: 信号列表(按时间排序)
:param initial_balance: 初始资金
:return: 最终资金、最大回撤、资金曲线
"""
balance = initial_balance # 初始资金
max_balance = initial_balance # 资金曲线的最大值
min_balance = initial_balance # 资金曲线的最小值
position = 0 # 当前持仓数量
entry_price = 0 # 持仓的买入价格
equity_curve = [initial_balance] # 资金曲线
for signal in signals:
signal_time = signal.trigger_time
signal_price = signal.trigger_price
signal_type = signal.signal_type
sl_price = signal.sl_price
tp_price = signal.tp_price
if signal_type == SignalType.BUY:
if position == 0: # 如果当前没有持仓
position = 1 # 开仓
entry_price = signal_price # 记录买入价格
print(f"买入: 时间={signal_time}, 价格={signal_price}")
elif signal_type == SignalType.SELL:
if position == 1: # 如果当前有持仓
profit = (signal_price - entry_price) * position # 计算盈亏
balance += profit # 更新账户余额
position = 0 # 清空持仓
print(f"卖出: 时间={signal_time}, 价格={signal_price}, 盈亏={profit}")
# 检查止盈止损
if position == 1: # 如果当前有持仓
if sl_price and signal_price <= sl_price: # 触发止损
loss = (sl_price - entry_price) * position
balance += loss
position = 0
print(f"止损: 时间={signal_time}, 价格={sl_price}, 损失={loss}")
elif tp_price and signal_price >= tp_price: # 触发止盈
profit = (tp_price - entry_price) * position
balance += profit
position = 0
print(f"止盈: 时间={signal_time}, 价格={tp_price}, 盈利={profit}")
# 更新资金曲线
equity_curve.append(balance)
max_balance = max(max_balance, balance)
min_balance = min(min_balance, balance)
# 计算最大回撤
max_drawdown = (max_balance - min_balance) / max_balance
return balance, max_drawdown, equity_curve
这段代码的思路:
1、计算净值曲线就是每个遍历都要记录净值的数值,方便后续绘制资金曲线
2、但是最大回撤设计的逻辑有问题,真实的做法应该是类似于下面的代码思路:
def calculate_max_drawdown(equity_curve):
peak = equity_curve[0] # 初始峰值
max_drawdown = 0 # 最大回撤初始化为 0
for equity in equity_curve:
peak = max(peak, equity) # 更新历史峰值
drawdown = (peak - equity) / peak # 当前回撤
max_drawdown = max(max_drawdown, drawdown) # 更新最大回撤
return max_drawdown
# 测试
equity_curve = [100, 80, 150, 140]
max_drawdown = calculate_max_drawdown(equity_curve)
print(f"最大回撤: {max_drawdown:.4f} ({max_drawdown * 100:.2f}%)")