多品种模型
到目前为止,模型训练都是为每个股票代码单独训练一个实例。而现在,也可以在行为相似的品种(例如同一行业的股票)之间训练一个共享模型。
PyBroker v2 支持在传递给 Strategy.add_execution 的所有品种上训练同一个模型,本文档将对此进行演示。
[1]:
import pybroker
from pybroker import Strategy, YFinance
from sklearn.linear_model import LinearRegression
pybroker.enable_data_source_cache("multi_symbol_models")
[1]:
<pybroker.cache._L1Cache at 0x7f0d105fee40>
在多个品种上训练一个模型
本文档复用了 训练模型 中的线性回归示例。下面将使用 close_minus_ma 指标,在四只芯片股上训练一个共享的 LinearRegression 模型:
[2]:
from pybroker.indicator import close_minus_ma
cmma_20 = close_minus_ma("cmma_20", lookback=20, atr_length=14)
def train_slr(symbols, train_data, test_data):
# Shift within symbols so returns never cross a symbol boundary.
next_close = train_data.groupby("symbol")["close"].shift(-1)
train_data["target"] = next_close / train_data["close"] - 1
train_data = train_data.dropna()
model = LinearRegression()
model.fit(train_data[["cmma_20"]], train_data["target"])
return model, ["cmma_20"]
model_slr = pybroker.model("slr", train_slr, indicators=[cmma_20], pooled=True)
SYMBOLS = ["MU", "TXN", "ADI", "AMAT"]
以 pooled=True 注册模型后,该模型在每次执行中只会训练一次。这会用一个 symbols 元组替换训练函数原本单一的 symbol 参数,并传入这些品种合并后的训练集和测试集划分。
在回测过程中,已训练的模型会在该执行中的所有品种之间共享:
[3]:
POS_SIZE = 1 / len(SYMBOLS)
def hold_long(ctx):
pred = ctx.preds("slr")[-1]
if not ctx.long_pos():
if pred > 0:
ctx.buy_shares = ctx.calc_target_shares(POS_SIZE)
elif pred < 0:
ctx.sell_all_shares()
strategy = Strategy(YFinance(), start_date="1/1/2021", end_date="1/1/2026")
strategy.add_execution(hold_long, SYMBOLS, models=model_slr)
result = strategy.walkforward(
warmup=20, windows=3, train_size=0.5, lookahead=1
)
result.metrics_df.head(20)
Backtesting: 2021-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
Computing indicators...
100% (4 of 4) |##########################| Elapsed Time: 0:00:00 Time: 0:00:00
Train split: 2021-01-07 00:00:00 to 2022-04-04 00:00:00
Finished training models: 0:00:00
Test split: 2022-04-05 00:00:00 to 2023-07-05 00:00:00
100% (313 of 313) |######################| Elapsed Time: 0:00:00 Time: 0:00:00
Train split: 2022-04-05 00:00:00 to 2023-07-05 00:00:00
Finished training models: 0:00:00
Test split: 2023-07-06 00:00:00 to 2024-10-01 00:00:00
100% (313 of 313) |######################| Elapsed Time: 0:00:00 Time: 0:00:00
Train split: 2023-07-06 00:00:00 to 2024-10-01 00:00:00
Finished training models: 0:00:00
Test split: 2024-10-02 00:00:00 to 2025-12-31 00:00:00
100% (313 of 313) |######################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:01
[3]:
| name | value | |
|---|---|---|
| 0 | trade_count | 170 |
| 1 | initial_market_value | 100000.0 |
| 2 | end_market_value | 173448.08 |
| 3 | total_pnl | 76163.08 |
| 4 | unrealized_pnl | -2715.0 |
| 5 | total_return_pct | 76.16308 |
| 6 | total_profit | 150256.55 |
| 7 | total_loss | -74093.47 |
| 8 | total_fees | 0.0 |
| 9 | max_drawdown | -41802.76 |
| 10 | max_drawdown_pct | -28.604164 |
| 11 | max_drawdown_date | 2025-04-08 00:00:00 |
| 12 | win_rate | 70.0 |
| 13 | loss_rate | 30.0 |
| 14 | winning_trades | 119 |
| 15 | losing_trades | 51 |
| 16 | avg_pnl | 448.018118 |
| 17 | avg_return_pct | 1.465824 |
| 18 | avg_trade_bars | 14.005882 |
| 19 | avg_profit | 1262.660084 |