量化回测净值曲线与最大回撤的计算思路

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}%)")
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。