279 lines
7.3 KiB
Plaintext
279 lines
7.3 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# 阿尔法策略回测 — 完整示例\n",
|
|
"\n",
|
|
"本 Notebook 演示如何使用 `quanxiel.alpha` 模块进行:\n",
|
|
"1. 因子计算与 IC 分析\n",
|
|
"2. 策略信号生成\n",
|
|
"3. 事件驱动回测\n",
|
|
"4. 绩效评估"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import sys\n",
|
|
"sys.path.insert(0, '..')\n",
|
|
"\n",
|
|
"import numpy as np\n",
|
|
"import pandas as pd\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"\n",
|
|
"from alpha.config import AlphaConfig\n",
|
|
"from alpha.factors import FactorRegistry, FactorAnalyzer\n",
|
|
"from alpha.strategy import Strategy, QuantileSignal, EqualWeightAllocator\n",
|
|
"from alpha.backtest import BacktestEngine\n",
|
|
"from alpha.evaluation import PerformanceEvaluator, ReportGenerator\n",
|
|
"\n",
|
|
"%matplotlib inline\n",
|
|
"plt.rcParams['font.sans-serif'] = ['SimHei']\n",
|
|
"plt.rcParams['axes.unicode_minus'] = False"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 1. 准备数据\n",
|
|
"\n",
|
|
"从本地数据库或 Tushare 获取量价数据与财务数据。这里用随机数据演示流程。"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# ---- 生成示例数据 -------\n",
|
|
"np.random.seed(42)\n",
|
|
"dates = pd.date_range('2022-01-01', '2024-12-31', freq='B')\n",
|
|
"stocks = [f'{i:06d}.SH' for i in range(600000, 600050)]\n",
|
|
"\n",
|
|
"# 价格数据\n",
|
|
"price_data = pd.DataFrame(\n",
|
|
" np.cumprod(1 + np.random.randn(len(dates), len(stocks)) * 0.02, axis=0),\n",
|
|
" index=dates, columns=stocks\n",
|
|
")\n",
|
|
"\n",
|
|
"# 因子数据(模拟技术面因子值)\n",
|
|
"factor_df = pd.DataFrame(\n",
|
|
" np.random.randn(len(dates), len(stocks)),\n",
|
|
" index=dates, columns=stocks\n",
|
|
")\n",
|
|
"\n",
|
|
"print(f'价格数据: {price_data.shape}')\n",
|
|
"print(f'因子数据: {factor_df.shape}')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 2. 因子 IC 分析"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# 计算未来 1 期收益率\n",
|
|
"fwd_returns = price_data.pct_change().shift(-1).stack()\n",
|
|
"factor_stacked = factor_df.stack()\n",
|
|
"\n",
|
|
"analyzer = FactorAnalyzer(factor_stacked, fwd_returns)\n",
|
|
"\n",
|
|
"# Rank IC\n",
|
|
"ic = analyzer.compute_ic(method='rank')\n",
|
|
"print('IC 汇总:')\n",
|
|
"for k, v in analyzer.ic_summary().items():\n",
|
|
" print(f' {k}: {v:.4f}')\n",
|
|
"\n",
|
|
"# IC 曲线\n",
|
|
"ic.plot(figsize=(12, 3), title='Rank IC 时间序列')\n",
|
|
"plt.axhline(y=0, color='r', linestyle='--')\n",
|
|
"plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 3. 分层回测"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"quantile_ret = analyzer.quantile_returns(n_quantiles=5)\n",
|
|
"print('各分位组平均收益:')\n",
|
|
"print(quantile_ret)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 4. 构建策略 & 回测"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# 配置\n",
|
|
"config = AlphaConfig(\n",
|
|
" initial_cash=1_000_000,\n",
|
|
" commission_rate=0.0003,\n",
|
|
" slippage=0.001,\n",
|
|
" stamp_tax=0.001,\n",
|
|
")\n",
|
|
"\n",
|
|
"# 策略组合\n",
|
|
"strategy = Strategy(\n",
|
|
" name='技术因子-分位数策略',\n",
|
|
" factors=[],\n",
|
|
" signal_generator=QuantileSignal(n_quantiles=5, long_quantile=5, short_quantile=1),\n",
|
|
" weight_allocator=EqualWeightAllocator(max_positions=20),\n",
|
|
" description='买入因子值最高的分位组,等权持仓'\n",
|
|
")\n",
|
|
"\n",
|
|
"# 回测引擎\n",
|
|
"engine = BacktestEngine(config)\n",
|
|
"equity_curve = engine.run(\n",
|
|
" strategy=strategy,\n",
|
|
" price_data=price_data,\n",
|
|
" factor_data={'technical': factor_df},\n",
|
|
" rebalance_freq='M', # 月频调仓\n",
|
|
")\n",
|
|
"\n",
|
|
"print(f'回测完成, 共 {len(equity_curve)} 个交易日')\n",
|
|
"print(f'累计收益率: {(equity_curve[\"nav\"].iloc[-1] - 1) * 100:.2f}%')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 5. 净值曲线"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"fig, axes = plt.subplots(2, 1, figsize=(14, 8))\n",
|
|
"\n",
|
|
"# 净值曲线\n",
|
|
"axes[0].plot(equity_curve.index, equity_curve['nav'], label='策略净值', color='steelblue')\n",
|
|
"axes[0].axhline(y=1.0, color='gray', linestyle='--')\n",
|
|
"axes[0].set_title('策略净值曲线')\n",
|
|
"axes[0].legend()\n",
|
|
"axes[0].grid(True, alpha=0.3)\n",
|
|
"\n",
|
|
"# 回撤曲线\n",
|
|
"nav = equity_curve['nav']\n",
|
|
"running_max = nav.cummax()\n",
|
|
"drawdown = (nav - running_max) / running_max\n",
|
|
"axes[1].fill_between(equity_curve.index, 0, drawdown, color='red', alpha=0.3)\n",
|
|
"axes[1].set_title('回撤曲线')\n",
|
|
"axes[1].grid(True, alpha=0.3)\n",
|
|
"\n",
|
|
"plt.tight_layout()\n",
|
|
"plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 6. 绩效评估"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"evaluator = PerformanceEvaluator(equity_curve, risk_free_rate=0.03)\n",
|
|
"print(evaluator.summary())\n",
|
|
"\n",
|
|
"# 导出报告 DataFrame\n",
|
|
"report_df = evaluator.full_report()\n",
|
|
"pd.DataFrame(list(report_df.items()), columns=['指标', '数值']).set_index('指标')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 7. 交易记录分析"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"trades = engine.portfolio.trades\n",
|
|
"if trades:\n",
|
|
" trade_df = pd.DataFrame([\n",
|
|
" {'日期': t.date, '股票': t.stock, '方向': t.side,\n",
|
|
" '数量': t.quantity, '价格': t.price, '佣金': t.commission}\n",
|
|
" for t in trades\n",
|
|
" ])\n",
|
|
" print(f'总交易数: {len(trade_df)}')\n",
|
|
" print(f'买入: {(trade_df[\"方向\"]==\"buy\").sum()}, 卖出: {(trade_df[\"方向\"]==\"sell\").sum()}')\n",
|
|
" display(trade_df.head(20))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n",
|
|
"## 使用真实数据\n",
|
|
"\n",
|
|
"将以上模拟数据替换为从 `quanxiel.quantitative_data` 模块加载的真实行情:\n",
|
|
"\n",
|
|
"```python\n",
|
|
"from quantitative_data.importer import DataImporter\n",
|
|
"\n",
|
|
"importer = DataImporter()\n",
|
|
"price_data = importer.load_daily_prices('2020-01-01', '2024-12-31')\n",
|
|
"```"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"name": "python",
|
|
"version": "3.10.0"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
} |