排名做多和做空信号
在本文档中,你将学习如何对各股票代码的多头和空头信号进行排名。
[1]:
import pybroker
from pybroker import Strategy, YFinance
pybroker.enable_data_source_cache("ranking")
[1]:
<pybroker.cache._L1Cache at 0x7f5f881bb290>
多头信号
让我们从一个示例开始,说明如何在下买单时根据成交量对股票代码进行排名:
[2]:
def buy_highest_volume(ctx):
# If there are no long positions across all tickers being traded:
if not ctx.has_long_positions():
ctx.buy_shares = ctx.calc_target_shares(1)
ctx.long_score = ctx.volume[-1]
ctx.hold_bars = 2
buy_highest_volume 函数分配 100% 的投资组合并持有 2 个 Bar。它将 ctx.long_score 设置为 ctx.volume[-1],因此 PyBroker 会根据成交量对买入信号进行排名。
[3]:
strategy = Strategy(YFinance(), "6/1/2021", "6/1/2022")
strategy.add_execution(buy_highest_volume, ["T", "F", "GM", "PFE"])
strategy.set_max_long_positions(1)
要将同一时间可持有的多头仓位数量限制为 1,我们调用 set_max_long_positions。这实际上会买入成交量最高的股票代码。
[4]:
result = strategy.backtest()
result.trades
Backtesting: 2021-06-01 00:00:00 to 2022-06-01 00:00:00
Loading bar data...
[*********************100%***********************] 4 of 4 completed
Loaded bar data: 0:00:01
Test split: 2021-06-01 00:00:00 to 2022-05-31 00:00:00
100% (253 of 253) |######################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:01
[4]:
| type | symbol | entry_date | exit_date | entry | exit | shares | pnl | return_pct | agg_pnl | bars | pnl_per_bar | stop | mae | mfe | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||
| 1 | long | F | 2021-06-02 | 2021-06-04 | 14.85 | 16.13 | 6734 | 8619.52 | 8.62 | 8619.52 | 2 | 4309.76 | bar | -0.17 | 1.28 |
| 2 | long | F | 2021-06-07 | 2021-06-09 | 15.93 | 15.51 | 6801 | -2856.42 | -2.64 | 5763.10 | 2 | -1428.21 | bar | -0.60 | 0.27 |
| 3 | long | F | 2021-06-10 | 2021-06-14 | 15.43 | 15.06 | 6832 | -2527.84 | -2.40 | 3235.26 | 2 | -1263.92 | bar | -0.37 | 0.35 |
| 4 | long | F | 2021-06-15 | 2021-06-17 | 14.96 | 14.99 | 6900 | 207.00 | 0.20 | 3442.26 | 2 | 103.50 | bar | -0.20 | 0.33 |
| 5 | long | F | 2021-06-18 | 2021-06-22 | 14.61 | 14.96 | 7003 | 2451.05 | 2.40 | 5893.31 | 2 | 1225.53 | bar | -0.17 | 0.35 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 80 | long | F | 2022-05-10 | 2022-05-12 | 13.43 | 12.47 | 7258 | -6967.68 | -7.15 | -9482.76 | 2 | -3483.84 | bar | -0.96 | 0.41 |
| 81 | long | F | 2022-05-13 | 2022-05-17 | 13.25 | 13.34 | 6831 | 614.79 | 0.68 | -8867.97 | 2 | 307.40 | bar | -0.38 | 0.38 |
| 82 | long | F | 2022-05-18 | 2022-05-20 | 13.03 | 12.59 | 6735 | -2963.40 | -3.38 | -11831.37 | 2 | -1481.70 | bar | -0.44 | 0.33 |
| 83 | long | F | 2022-05-23 | 2022-05-25 | 12.72 | 12.57 | 6931 | -1039.65 | -1.18 | -12871.02 | 2 | -519.83 | bar | -0.45 | 0.23 |
| 84 | long | F | 2022-05-26 | 2022-05-31 | 12.99 | 13.59 | 6707 | 4024.20 | 4.62 | -8846.82 | 2 | 2012.10 | bar | -0.20 | 0.64 |
84 rows × 15 columns
空头信号
PyBroker 还可以使用 short_score 对空头信号进行排名,空头订单会下给 short_score 值最高的股票代码。以下示例买入 5 日变化率(ROC)最高的股票代码,同时卖空 5 日 ROC 最负的股票代码:
[5]:
def long_high_short_low(ctx):
# Wait for 6 bars of data and skip symbols with an open position:
if ctx.bars < 6 or ctx.long_pos() or ctx.short_pos():
return
# Calculate the 5-day rate of change (ROC):
roc = (ctx.close[-1] - ctx.close[-6]) / ctx.close[-6]
if roc > 0 and not ctx.has_long_positions():
ctx.buy_shares = ctx.calc_target_shares(0.5)
# Hold the long position for 2 bars
ctx.hold_bars = 2
ctx.long_score = roc
elif roc < 0 and not ctx.has_short_positions():
ctx.sell_shares = ctx.calc_target_shares(0.5)
# Hold the short position for 2 bars
ctx.hold_bars = 2
ctx.short_score = -roc
strategy = Strategy(YFinance(), "1/1/2025", "1/1/2026")
strategy.add_execution(long_high_short_low, ["T", "F", "GM", "PFE"])
strategy.set_max_long_positions(1)
strategy.set_max_short_positions(1)
result = strategy.backtest()
result.trades
Backtesting: 2025-01-01 00:00:00 to 2026-01-01 00:00:00
Loading bar data...
[*********************100%***********************] 4 of 4 completed
Loaded bar data: 0:00:00
Test split: 2025-01-02 00:00:00 to 2025-12-31 00:00:00
100% (250 of 250) |######################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:00
[5]:
| type | symbol | entry_date | exit_date | entry | exit | shares | pnl | return_pct | agg_pnl | bars | pnl_per_bar | stop | mae | mfe | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||
| 1 | long | PFE | 2025-01-13 | 2025-01-15 | 26.59 | 26.43 | 1871 | -299.36 | -0.60 | -299.36 | 2 | -149.68 | bar | -0.32 | 0.28 |
| 2 | short | T | 2025-01-13 | 2025-01-15 | 21.54 | 21.98 | 2305 | -1014.20 | -2.00 | -1313.56 | 2 | -507.10 | bar | -0.44 | 0.16 |
| 3 | long | F | 2025-01-16 | 2025-01-21 | 9.98 | 10.34 | 4939 | 1778.04 | 3.61 | 464.48 | 2 | 889.02 | bar | -0.09 | 0.36 |
| 4 | short | PFE | 2025-01-16 | 2025-01-21 | 26.26 | 26.51 | 1881 | -470.25 | -0.94 | -5.77 | 2 | -235.13 | bar | -0.31 | 0.30 |
| 5 | long | GM | 2025-01-22 | 2025-01-24 | 52.94 | 54.15 | 927 | 1121.67 | 2.29 | 1115.90 | 2 | 560.84 | bar | -0.51 | 1.41 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 142 | short | PFE | 2025-12-18 | 2025-12-22 | 25.10 | 25.26 | 1650 | -264.00 | -0.63 | -17237.70 | 2 | -132.00 | bar | -0.42 | 0.12 |
| 143 | long | GM | 2025-12-19 | 2025-12-23 | 81.89 | 83.05 | 508 | 589.28 | 1.42 | -16648.42 | 2 | 294.64 | bar | -0.80 | 1.79 |
| 144 | short | PFE | 2025-12-23 | 2025-12-26 | 25.09 | 25.02 | 1652 | 115.64 | 0.28 | -16532.78 | 2 | 57.82 | bar | -0.25 | 0.26 |
| 145 | long | T | 2025-12-24 | 2025-12-29 | 24.54 | 24.81 | 1703 | 459.81 | 1.10 | -16072.97 | 2 | 229.91 | bar | -0.17 | 0.27 |
| 146 | short | F | 2025-12-29 | 2025-12-31 | 13.28 | 13.17 | 3142 | 345.62 | 0.84 | -15727.35 | 2 | 172.81 | bar | -0.03 | 0.11 |
146 rows × 15 columns