轮动交易
轮动交易涉及购买表现最好的资产,同时出售表现不佳的资产。你可能已经猜到了,PyBroker 是回测此类策略的极佳工具。那么,让我们深入了解,并开始测试我们的轮动交易策略!
[1]:
import pybroker as pyb
from pybroker import ExecContext, Strategy, StrategyConfig, YFinance
我们的策略将涉及对 价格涨幅(ROC) 最高的股票进行排名和购买。首先,我们将使用 TA-Lib 定义一个 20 天的 ROC 指标:
[2]:
import talib as ta
roc_20 = pyb.indicator(
'roc_20', lambda data: ta.ROC(data.adj_close, timeperiod=20))
接下来,让我们定义策略的规则:
购买 20 天涨幅(ROC)最高的两只股票。
将我们的资本的 50% 分配给每只股票。
如果其中一只股票不再位于前五名的 20 天涨幅(ROC)中,则我们将清盘该股票。
每天交易这些规则。
为了实现上述规则,让我们设置配置和一些参数:
[3]:
config = StrategyConfig(max_long_positions=2)
pyb.param('target_size', 1 / config.max_long_positions)
pyb.param('rank_threshold', 5)
[3]:
5
为了继续我们的策略,我们将实现一个排名函数,根据每只股票的 20 天涨幅(ROC)降序 排列
,从最高到最低。
[4]:
def rank(ctxs: dict[str, ExecContext]):
scores = {
symbol: ctx.indicator('roc_20')[-1]
for symbol, ctx in ctxs.items()
}
sorted_scores = sorted(
scores.items(),
key=lambda score: score[1],
reverse=True
)
threshold = pyb.param('rank_threshold')
top_scores = sorted_scores[:threshold]
top_symbols = [score[0] for score in top_scores]
pyb.param('top_symbols', top_symbols)
top_symbols
全局参数包含了 20 天涨幅(ROC)最高的前五名股票的符号。
现在我们已经有了一个根据 ROC 对股票进行排名的方法,我们可以继续实现一个 轮动
函数来管理轮动交易。
[5]:
def rotate(ctx: ExecContext):
if ctx.long_pos():
if ctx.symbol not in pyb.param('top_symbols'):
ctx.sell_all_shares()
else:
target_size = pyb.param('target_size')
ctx.buy_shares = ctx.calc_target_shares(target_size)
ctx.score = ctx.indicator('roc_20')[-1]
如果目前持有的股票不再位于前五名的 20 天涨幅(ROC)中,我们将清盘该股票。否则,我们将根据它们的 20 天涨幅(ROC)对所有股票进行排名,并购买排名最高的前两名。有关在下达买入订单时的排名信息,请参阅 排名和仓位文档。
我们将使用 set_before_exec 方法在运行 轮动
函数之前使用 rank
执行我们的排名。对于这次回测,我们将使用 10 只股票组成的股票池:
[6]:
strategy = Strategy(
YFinance(),
start_date='1/1/2018',
end_date='1/1/2023',
config=config
)
strategy.set_before_exec(rank)
strategy.add_execution(rotate, [
'TSLA',
'NFLX',
'AAPL',
'NVDA',
'AMZN',
'MSFT',
'GOOG',
'AMD',
'INTC',
'META'
], indicators=roc_20)
result = strategy.backtest(warmup=20)
Backtesting: 2018-01-01 00:00:00 to 2023-01-01 00:00:00
Loading bar data...
[*********************100%***********************] 10 of 10 completed
Loaded bar data: 0:00:03
Computing indicators...
100% (10 of 10) |########################| Elapsed Time: 0:00:00 Time: 0:00:00
Test split: 2018-01-02 00:00:00 to 2022-12-30 00:00:00
100% (1259 of 1259) |####################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:06
[7]:
result.orders
[7]:
type | symbol | date | shares | limit_price | fill_price | fees | |
---|---|---|---|---|---|---|---|
id | |||||||
1 | buy | NFLX | 2018-02-01 | 184 | NaN | 267.67 | 0.0 |
2 | buy | AMD | 2018-02-01 | 3639 | NaN | 13.53 | 0.0 |
3 | sell | AMD | 2018-02-05 | 3639 | NaN | 11.56 | 0.0 |
4 | buy | AMZN | 2018-02-05 | 627 | NaN | 69.49 | 0.0 |
5 | sell | AMZN | 2018-04-03 | 627 | NaN | 69.23 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... |
256 | buy | AMD | 2022-11-21 | 3589 | NaN | 72.28 | 0.0 |
257 | sell | AMD | 2022-12-14 | 3589 | NaN | 70.16 | 0.0 |
258 | buy | NFLX | 2022-12-14 | 881 | NaN | 319.57 | 0.0 |
259 | sell | NVDA | 2022-12-28 | 1491 | NaN | 140.73 | 0.0 |
260 | buy | META | 2022-12-28 | 1869 | NaN | 116.83 | 0.0 |
260 rows × 7 columns