多品种模型

到目前为止,模型训练都是为每个股票代码单独训练一个实例。而现在,也可以在行为相似的品种(例如同一行业的股票)之间训练一个共享模型。

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