使用 Bootstrap 指标评估

自助法指标可以帮助我们更全面地评估交易策略,正如我们将在本文档中看到的那样。

在上一篇文档中,我们实现了一个交易策略并对其进行了回测。这是再次实现:

[1]:
import pybroker
from pybroker import Strategy, StrategyConfig, YFinance

pybroker.enable_data_source_cache('my_strategy')

def buy_low(ctx):
    if ctx.long_pos():
        return
    if ctx.bars >= 2 and ctx.close[-1] < ctx.low[-2]:
        ctx.buy_shares = ctx.calc_target_shares(0.25)
        ctx.buy_limit_price = ctx.close[-1] - 0.01
        ctx.hold_bars = 3

def short_high(ctx):
    if ctx.short_pos():
        return
    if ctx.bars >= 2 and ctx.close[-1] > ctx.high[-2]:
        ctx.sell_shares = 100
        ctx.hold_bars = 2

与之前一样,我们使用给定的配置创建一个新的 Strategy 实例:

[2]:
config = StrategyConfig(initial_cash=500_000, bootstrap_sample_size=100)
strategy = Strategy(YFinance(), '3/1/2017', '3/1/2022', config)
strategy.add_execution(buy_low, ['AAPL', 'MSFT'])
strategy.add_execution(short_high, ['TSLA'])

这次,由于使用了较少的历史数据,Strategy 配置了 bootstrap_sample_size100。接下来,我们运行启用自助法指标的回测:

[3]:
result = strategy.backtest(calc_bootstrap=True)
result.metrics_df
Backtesting: 2017-03-01 00:00:00 to 2022-03-01 00:00:00

Loaded cached bar data.

Test split: 2017-03-01 00:00:00 to 2022-02-28 00:00:00
100% (1259 of 1259) |####################| Elapsed Time: 0:00:00 Time:  0:00:00

Calculating bootstrap metrics: sample_size=100, samples=10000...
Calculated bootstrap metrics: 0:00:03

Finished backtest: 0:00:05
[3]:
name value
0 trade_count 388.000000
1 initial_market_value 500000.000000
2 end_market_value 655753.670000
3 total_pnl 156575.000000
4 unrealized_pnl -821.330000
5 total_return_pct 31.315000
6 total_profit 383032.400000
7 total_loss -226457.400000
8 total_fees 0.000000
9 max_drawdown -30181.580000
10 max_drawdown_pct -4.554816
11 win_rate 52.577320
12 loss_rate 47.422680
13 winning_trades 204.000000
14 losing_trades 184.000000
15 avg_pnl 403.543814
16 avg_return_pct 0.279639
17 avg_trade_bars 2.414948
18 avg_profit 1877.609804
19 avg_profit_pct 3.168775
20 avg_winning_trade_bars 2.465686
21 avg_loss -1230.746739
22 avg_loss_pct -2.923533
23 avg_losing_trade_bars 2.358696
24 largest_win 20797.970000
25 largest_win_pct 14.490000
26 largest_win_bars 3.000000
27 largest_loss -10831.630000
28 largest_loss_pct -6.490000
29 largest_loss_bars 3.000000
30 max_wins 7.000000
31 max_losses 7.000000
32 sharpe 0.054488
33 sortino 0.061320
34 profit_factor 1.312935
35 ulcer_index 0.627821
36 upi 0.035531
37 equity_r2 0.893202
38 std_error 63596.828230

当我们查看上面的 total_pnl 指标时,似乎我们在第一次尝试时就拥有了一个盈利的交易策略。然而,我们不能完全确定这些结果是可重复的,而不仅仅是偶然的。为了对我们的结果更有信心,我们可以使用 自助法 来计算指标。

自助法通过在从回测收益率抽取的随机样本上反复计算指标来工作。然后,在每个随机样本上计算指标,并取平均值。通过在数千个随机样本上进行这样的操作,我们可以获得更稳健、更准确的指标估计。

置信区间

PyBroker 使用自助法计算两个绩效指标( 利润因子夏普比率)的 置信区间

[4]:
result.bootstrap.conf_intervals
[4]:
lower upper
name conf
Profit Factor 97.5% 0.594243 4.400753
95% 0.719539 3.715684
90% 0.877060 3.153457
Sharpe Ratio 97.5% -0.136541 0.243573
95% -0.100146 0.220099
90% -0.060583 0.193326

PyBroker 使用 偏差校正和加速(BCa)自助法 计算这些指标的置信区间。收益率是按每根 K 线进行抽样的,而不是按每笔交易进行抽样,以便在指标中捕捉更多信息。

生成的表格显示了给定置信水平下置信区间的下限。这为策略的表现提供了一个更保守的估计。例如,我们可以 97.5% 的把握认为夏普比率在给定值 x 或更高。

在这个例子中,夏普比率的下界为负,利润因子的下界小于 1,这表明策略是不可靠的。

最大回撤

在本节中,我们使用自助法检查策略的最大回撤。不超过某些值的回撤概率(用现金和投资组合权益百分比表示)如下所示:

[5]:
result.bootstrap.drawdown_conf
[5]:
amount percent
conf
99.9% -66401.25 -10.462527
99% -50062.49 -7.963632
95% -35794.82 -5.848482
90% -29931.10 -4.912087

这些置信水平是根据回测的样本外结果中的每根 K 线收益率获得的,类似于计算利润因子和夏普比率的方法。

我们可以观察到,99.9% 置信水平下的自助法最大回撤为 -10.56%,这比我们原始结果中看到的 -4.71% 更糟。这突显了使用随机测试评估交易策略绩效的重要性。

在下一篇文章中,我们将讨论如何在交易策略中结合排名和头寸规模