使用 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_size 为 100
。接下来,我们运行启用自助法指标的回测:
[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%
更糟。这突显了使用随机测试评估交易策略绩效的重要性。