1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
| """ Qlib量化策略完整实战脚本 运行方式: python qlib_strategy.py """
import qlib from qlib.data import D from qlib.data.dataset import DatasetH from qlib.contrib.model.gbdt import LGBModel from qlib.contrib.strategy import TopkDropoutStrategy from qlib.backtest import backtest, executor from qlib.contrib.evaluate import risk_analysis from qlib.workflow import R import pandas as pd import matplotlib.pyplot as plt
CONFIG = { "market": "csi300", "benchmark": "SH000300", "train_period": ("2010-01-01", "2018-12-31"), "valid_period": ("2019-01-01", "2020-12-31"), "test_period": ("2021-01-01", "2023-12-31"), "initial_capital": 10000000, "topk": 30, "n_drop": 3, }
def main(): print("=" * 60) print("Qlib量化策略实战") print("=" * 60)
print("\n[1/6] 初始化Qlib...") qlib.init(provider_uri="~/.qlib/qlib_data/cn_data")
print("\n[2/6] 准备数据集...") dataset = DatasetH( handler={ "class": "Alpha158", "module_path": "qlib.contrib.data.handler", "kwargs": { "start_time": CONFIG["train_period"][0], "end_time": CONFIG["test_period"][1], "fit_start_time": CONFIG["train_period"][0], "fit_end_time": CONFIG["train_period"][1], "instruments": CONFIG["market"], }, }, segments={ "train": CONFIG["train_period"], "valid": CONFIG["valid_period"], "test": CONFIG["test_period"], }, )
print("\n[3/6] 训练LightGBM模型...") model = LGBModel( loss="mse", colsample_bytree=0.8, learning_rate=0.05, subsample=0.8, max_depth=6, num_leaves=50, )
with R.start(experiment_name="qlib_strategy"): model.fit(dataset) R.save_objects(trained_model=model) recorder_id = R.get_recorder().id
print("\n[4/6] 生成预测信号...") predictions = model.predict(dataset) print(f"预测样本数: {len(predictions)}")
print("\n[5/6] 执行回测...") strategy = TopkDropoutStrategy( topk=CONFIG["topk"], n_drop=CONFIG["n_drop"], signal=predictions, )
executor_obj = executor.SimulatorExecutor( time_per_step="day", generate_portfolio_metrics=True, )
portfolio_dict, _ = backtest( executor=executor_obj, strategy=strategy, start_time=CONFIG["test_period"][0], end_time=CONFIG["test_period"][1], account=CONFIG["initial_capital"], benchmark=CONFIG["benchmark"], exchange_kwargs={ "freq": "day", "limit_threshold": 0.095, "deal_price": "vwap", "open_cost": 0.0003, "close_cost": 0.0013, "min_cost": 5, }, )
report, positions = portfolio_dict.get("day")
print("\n[6/6] 分析回测结果...") print_results(report)
plot_results(report)
print("\n" + "=" * 60) print("策略运行完成!") print("=" * 60)
def print_results(report): """打印关键指标""" strategy_analysis = risk_analysis(report["return"], freq="day") bench_analysis = risk_analysis(report["bench"], freq="day") excess_analysis = risk_analysis( report["return"] - report["bench"] - report["cost"], freq="day" )
print("\n" + "-" * 50) print(f"{'指标':<20} {'策略':<15} {'基准':<15} {'超额':<15}") print("-" * 50) print(f"{'年化收益率':<20} {strategy_analysis['annualized_return']:<15.4f} " f"{bench_analysis['annualized_return']:<15.4f} " f"{excess_analysis['annualized_return']:<15.4f}") print(f"{'夏普比率':<20} {strategy_analysis['sharpe_ratio']:<15.4f} " f"{bench_analysis['sharpe_ratio']:<15.4f} " f"{excess_analysis['sharpe_ratio']:<15.4f}") print(f"{'最大回撤':<20} {strategy_analysis['max_drawdown']:<15.4f} " f"{bench_analysis['max_drawdown']:<15.4f} " f"{excess_analysis['max_drawdown']:<15.4f}") print("-" * 50)
def plot_results(report): """可视化回测结果""" fig, axes = plt.subplots(2, 1, figsize=(14, 8))
cum_return = (1 + report["return"]).cumprod() cum_bench = (1 + report["bench"]).cumprod()
axes[0].plot(cum_return.index, cum_return, label="策略", linewidth=2) axes[0].plot(cum_bench.index, cum_bench, label="沪深300", linewidth=2) axes[0].set_title("累计收益对比", fontsize=14) axes[0].legend() axes[0].grid(True, alpha=0.3)
cummax = cum_return.cummax() drawdown = (cum_return - cummax) / cummax axes[1].fill_between(drawdown.index, 0, drawdown, alpha=0.3, color='red') axes[1].plot(drawdown.index, drawdown, color='red', linewidth=2) axes[1].set_title("策略回撤", fontsize=14) axes[1].grid(True, alpha=0.3)
plt.tight_layout() plt.savefig('qlib_backtest_result.png', dpi=150) print("\n图表已保存: qlib_backtest_result.png")
if __name__ == "__main__": main()
|