972bbbe706
fix(rotation): signal_date改用日历日前一天以捕获外盘假期数据
...
- 将 signal_date = trading_calendar[i-1] 改为 date - timedelta(days=1)
- 解决A股长假期间美股继续交易但动量计算丢失外盘数据的问题
- 同步修复 export_results 中的 signal_date 映射逻辑
2026-06-03 01:25:09 +08:00
524fa5f513
refactor(rotation): 移除数据缓存 + 修复空值和pct_change警告
...
- 移除CSV本地缓存(cache_dir、_cache_path、_premium_cache_path、_save_premium_cache)
- 每次运行直接从API获取数据,简化DataCache类
- 修复_get_etf_prices中open/close为None时的空值处理(中证指数API不提供OHLC)
- 修复pct_change的FutureWarning(显式传fill_method=None)
- 更新trade_cost注释
2026-06-03 00:54:48 +08:00
d1139a9ee9
fix(http): 用requests+trust_env=False修复SSL EOF问题
...
根因:Clash代理(127.0.0.1:7890)在处理TLS 1.3+后量子密钥交换时
不兼容,导致SSL EOF错误。requests默认trust_env=True会读取系统
代理配置,通过代理转发HTTPS请求时触发问题。
修复:使用requests.Session(trust_env=False)绕过系统代理,
直连目标服务器。无需降级urllib3版本。
影响文件:
- rotation/simple_rotation.py
- datasource/flask_api_source.py
2026-06-03 00:35:49 +08:00
a2b4289080
revert(http): 改回串行数据获取
...
回退并行获取逻辑,恢复简单的串行循环:
- 移除 ThreadPoolExecutor 并行代码
- 移除 concurrent.futures 导入
- 保持简单的 for 循环串行获取
2026-06-03 00:09:29 +08:00
e29f57749d
perf(http): 并行获取数据加速数据加载
...
使用 ThreadPoolExecutor 并行获取多个标的的数据:
- 信号源 (index): 11个标的并行获取
- 交易源 (ETF): 4个标的并行获取
- 溢价率数据: 4个标的并行获取
性能提升:5个标的从 ~15s 串行 → ~4.6s 并行(约 3x 加速)
修改:
- 增大 urllib3 连接池 maxsize=16 支持并行连接
- 使用 concurrent.futures.ThreadPoolExecutor
2026-06-02 22:29:59 +08:00
81045f9d85
fix(http): 用urllib3替代requests修复SSL EOF错误
...
问题根因:
- Python OpenSSL 3.5.4 + requests 2.32.4 + urllib3 2.5.0 版本不兼容
- requests 2.32.4 内部使用 urllib3 的方式与 urllib3 2.5.0 API 不兼容
- curl(SecureTransport)正常工作,但 Python requests(OpenSSL)失败
- 服务器(Caddy)使用 TLS 1.3 + X25519MLKEM768(后量子密钥交换)
修复方案:
- 用 urllib3.PoolManager 直接发起 HTTP 请求(已验证可正常工作)
- 封装 _http_get() 函数替代 requests.get()
- 替换所有 requests 相关异常类型为 urllib3 异常
修改文件:
- datasource/flask_api_source.py: 核心数据源层
- rotation/simple_rotation.py: 简单轮动策略层
2026-06-02 22:22:36 +08:00
74f0eebef0
docs(experiment): add 1-day holding deep attribution analysis (006)
...
- Rank decline: 70.3% (45/64), mostly rank=3 entry → rank=4/5 exit
- Threshold breach: 25.0% (16/64), all actual momentum drops
- 38% cases: own momentum rises but outranked by others
- N225/GDAXI highest 1-day rate (22-26%), A-shares lowest (3-6%)
- Optimization: min holding period, confidence filter, rank smoothing
2026-06-02 21:41:34 +08:00
361b82fa4a
docs(experiment): add holding duration distribution analysis (006)
...
- Analyze holding period distribution from simple_rotation_detail.json
- 391 complete holding episodes across 11 assets
- Median holding: 7 days, mean: 10.9 days
- 75% of holdings within 16 days, 16.4% are 1-day switches
- NDX has longest avg holding (17.4d), HSI shortest (6.5d)
- Insight: consider minimum holding period to reduce noise trades
2026-06-02 21:36:46 +08:00
a47af0f0eb
docs(experiment): add select_num A/B/C comparison report (005)
...
- Experiment: select_num = 1, 2, 3 comparison
- Period: 2020-01-10 ~ 2026-06-02 (1546 trading days)
- Key findings:
- Top-1: highest return (600%), highest drawdown (-25.5%)
- Top-3: best risk-adjusted return (Calmar 1.73, Sharpe 1.35)
- Top-2: balanced middle ground (Calmar 1.69)
- Add rotation/experiment_select_num.py experiment script
- Save report to docs/experiments/005_select_num_comparison.md
2026-06-02 01:32:43 +08:00
07d6f1451c
fix(rotation): raise RuntimeError on held asset data failure
...
- Add data integrity check: if any currently held asset is missing
from factors, raise RuntimeError immediately to prevent false rebalance
- Previously missing data would silently cause incorrect sell signals
- Now fails fast with clear error message identifying the missing assets
and the date of failure
2026-06-02 01:16:44 +08:00
4791d3cf40
refactor(scheduler): move daily_scheduler.py to rotation/ and add simple_rotation support
...
- Move scripts/daily_scheduler.py -> rotation/daily_scheduler.py
- Add run_simple_rotation() to execute simple_rotation.py via subprocess
- Add --strategy flag (simple/legacy/all) for flexible strategy selection
- Add --simple-config flag for custom simple rotation config path
- Update Dockerfile and docker-compose.yml path references
- Add configurable title to send_report_to_dingtalk()
2026-06-02 01:16:34 +08:00
5e11b6b690
fix(rotation): 溢价率缓存增加增量更新逻辑
...
- preload_premium: 检查缓存日期范围,不足时增量拉取
- 新增 _fetch_premium_api: 拉取并合并新溢价率数据
- 调用时传入 end_date 触发增量检查
修复前: premium CSV存在即返回旧数据,明天9点运行时拿不到最新
修复后: 检测 latest_cached < end_date 时自动拉取增量
2026-06-01 23:56:18 +08:00
19f1c63981
fix(rotation): 修复溢价率计算,改用Flask API真实premium_series数据
...
- _fetch_api: 提取premium_series并存入df.attrs和CSV缓存
- DataCache: 新增premium_data字典、preload_premium方法
- preload_premium: 无缓存时主动请求API获取全量历史溢价率
- _preload_data: 加载ETF后同步调用preload_premium
- _compute_premium(trade_code, date): 从内存缓存按日期查找真实溢价率
- 新增trade_code_to_group映射,确保BOND资产正确识别
修复前: 溢价率 = (ETF价格 - 指数点位) / 指数点位 → -99.9%
修复后: 使用API返回的(ETF价格 - NAV) / NAV → 合理范围
2026-06-01 23:31:36 +08:00
6d0b928894
fix(rotation): 消除前视偏差 + V2兼容detail导出
...
时序对齐修复:
- 信号生成改用 T-1 收盘数据(9AM信号时T日未开盘)
- entry_price_etf 改用 T 日 open(实际买入价)
- 年化收益: 52.66% → 25.12%(去除约4倍虚高)
V2兼容detail JSON:
- _generate_signals 返回 (holdings, factors, bond_momentum)
- 6个helper方法: build_meta_codes, get_index/etf_close, daily_returns, premium, day_assets
- 每日11资产×16字段完整记录(momentum/rank/holding_days/cum_return等)
- export_results 同步修复 entry_info 时序逻辑
Backtest (2020-01-10 ~ 2026-06-01, 1545天):
- 总收益 295.14%, 年化 25.12%
- 最大回撤 -14.74%, 夏普 1.33, 卡尔马 1.70
2026-06-01 23:13:43 +08:00
451ffa33d2
clean(rotation): add simple rotation strategy and remove unused files
...
New:
- rotation/simple_rotation.py: daily-iteration rotation strategy (584 lines)
- rotation/config_loader.py: standalone config loader
- rotation/config_simple.yaml: 11 assets, 7 groups
- rotation/README_SIMPLE.md: usage guide
- scripts/get_trading_calendar.py: trading calendar fetcher
Removed:
- rotation/example_usage.py, run_strategy.py (replaced by simple_rotation.py)
- rotation/results/ output files (gitignored)
- scripts/verify_*.py, calculate_returns_from_detail.py (one-off scripts)
- scripts/README_TRADING_CALENDAR.md
Backtest result (2020-01-10 ~ 2026-06-01):
- Total return: 1237.6%, Annual: 52.66%
- Max drawdown: -11.71%, Sharpe: 2.50
2026-06-01 22:28:26 +08:00
3b0208d7d3
docs(viewer): 添加 backtest_viewer.html 到 git 追踪
...
- 修改 .gitignore 添加 HTML 文件例外规则
- 将 visualization/backtest_viewer.html 纳入版本控制
- 保留回测可视化查看器供团队使用
2026-05-26 23:33:06 +08:00
ee2453f65e
fix(rotation): 修复 backtest detail 中指数和 ETF 累计收益计算 bug
...
- 问题:cum_return_idx 和 cum_return_etf 使用相同的 ETF 价格计算
- 修复:分别使用指数价格(raw)和 ETF 价格(hfq)独立计算
- 验证:72.6% 的持仓记录显示差异(0.06%~0.48%),符合预期
- 新增验证脚本:verify_cum_return_fix.py
2026-05-26 23:22:26 +08:00
6a86a27108
test(scripts): 新增ETF数据获取验证脚本
...
新增脚本:
- verify_etf_hfq_fix.py: 验证指数使用raw、ETF使用hfq
- compare_index_vs_etf_returns.py: 对比指数收益vs ETF收益的KPI指标
验证内容:
- 指数数据完整性检查
- ETF数据完整性检查
- ETF是否正确使用hfq后复权价格(抽样对比raw和hfq)
- 验证510300.SH等ETF的hfq/raw比值(应>1.0)
2026-05-26 19:55:01 +08:00
2ff48e8d56
refactor(flask_api_fetcher): 暴露adj参数,增强接口透明度和灵活性
...
改进:
- fetch_indices()添加adj参数,默认'raw',可自定义
- fetch_etf()添加adj参数,默认'hfq',可自定义
- 改进日志输出,显示实际使用的adj参数
- 保持向后兼容,默认值保持原有行为
优势:
- 透明性:调用者清楚知道使用的复权方式
- 灵活性:可按需获取raw/qfq/hfq数据
- 一致性:两个方法接口统一
- 向后兼容:不影响现有代码
2026-05-26 19:54:41 +08:00
d404ddee17
fix(rotation): 修复ETF数据获取逻辑,分别获取指数raw和ETF hfq数据
...
问题:之前统一使用fetch_indices(adj='raw')导致ETF未使用后复权价格
修复:
- 在GlobalRotationStrategy中覆盖get_data()方法
- 指数数据:调用fetch_indices(adj='raw')获取原始价格
- ETF数据:调用fetch_etf(adj='hfq')获取后复权价格
- 确保指数信号计算和ETF收益计算使用正确的数据源
影响:回测将正确反映ETF的真实收益(包含分红再投资)
2026-05-26 19:54:21 +08:00
7fc1170964
feat(v2): 修复跨市场因子对齐 + 添加当日收益率字段
...
核心修复:
- 因子对齐到 A 股交易日历(ffill 填充休市日)
- 修复美股休市日 NDX 信号丢失问题(Memorial Day)
- BOND 参与大类竞争,作为阈值过滤其他组
- 添加 index_return 和 etf_return_ctc 字段
性能提升:
- 总收益: 356% → 686% (+92.7%)
- 年化收益: 28% → 40% (+12%)
- 夏普比率: 1.61 → 2.04 (+26.7%)
- 调仓次数: 747 → 399 (-46.6%)
- 最大回撤: -14.75% → -10.66% (改善)
2026-05-26 01:04:39 +08:00
537e7ccc45
feat(v2): 将导出功能内建到策略 run() 方法
...
- 修改 StrategyBase.run() 支持 export_detail 参数
- 保存 self._data 供导出方法复用
- 简化 export_backtest_detail.py 从 441 行到 62 行
- 消除策略重复执行,提升运行效率 40%
- API 请求减少 50%(溢价率数据复用)
2026-05-26 01:04:20 +08:00
b9543f0669
chore(env): 更新 Tushare API Token
2026-05-25 23:24:08 +08:00
3d9929904b
config(rotation): 更新回测配置 - 关闭溢价过滤并使用最新数据
...
- 注释掉 end_date,使用最新数据进行回测
- 关闭溢价率过滤 (premium_control.enabled: false)
- 溢价过滤逻辑未实现 (TODO),配置无效
- 避免误导,显式关闭该功能
2026-05-25 23:22:40 +08:00
7844b1ebf0
fix(tushare): QDII基金溢价率计算修复 - ETF类型识别+反向偏移T+2+周末填充
...
实现完整QDII基金溢价率计算修复方案:
1. 新增_get_etf_type()方法:
- 使用Tushare etf_basic接口查询etf_type字段
- 自动识别境内/QDII基金类型
- 缓存机制避免重复查询
2. 修改fetch_etf()方法:
- QDII基金净值范围向前/向后扩大2天
- 确保有足够净值数据进行T+2匹配
3. 修改_calculate_premium_series()方法:
- QDII基金使用反向偏移:价格日期-2天=净值日期
- 周末/节假日填充:使用ffill填充缺失净值
- 境内ETF保持T+0匹配逻辑
验证结果:
- 纳指ETF 513100.SH 5月18日溢价率:3.84%
- 同花顺溢价率:3.84%
- 偏差:0.00% ✅ 完美对齐
修复与同花顺等主流平台一致的QDII基金溢价率计算逻辑。
2026-05-25 22:46:08 +08:00
c79cde5d7f
fix(tushare): 修复ETF复权qfq支持和溢价率获取
...
- 移除fetch()方法中ETF复权路由的qfq硬编码限制
- 修改ETF复权调用从fetch_etf_adj改为fetch_etf
- 确保qfq/hfq模式也能获取净值和溢价率数据
- 溢价率始终基于原始价格计算,不受复权影响
修复前:
- qfq返回404错误
- hfq无溢价率数据
修复后:
- raw/qfq/hfq三种模式均正常
- 所有模式都返回溢价率数据
- 本地测试全部通过
2026-05-25 20:25:29 +08:00
c0195c5bca
refactor(tushare): 合并ETF复权方法,消除冗余设计
...
- 合并 fetch_etf_adj 和 _fetch_etf_adj 为单一方法
- 删除 _fetch_etf_qfq 转发方法
- 减少~26行代码,优化代码结构(从3个方法→1个方法)
- 保持公共接口签名不变,完全向后兼容
- 全面测试通过:raw/qfq/hfq三种模式数据正确
- 更新 VALID_ADJ_BY_TYPE 配置,ETF支持前复权/后复权
2026-05-25 19:59:49 +08:00
a62cfb4cd5
fix: 修复因子前向填充不生效的 bug(清理调试代码)
...
问题根因:
- pandas reindex(method='ffill') 只填充新增行的 NaN,不填充已存在的 NaN
- 当 factor_df 中已有境外市场放假日期的 NaN 值时,reindex 无法填充
修复方案:
- 改为两步操作:reindex() 然后 ffill()
- ffill() 会填充所有 NaN,包括已存在的
验证结果:
- 2026-04-30 HSI: None → 0.2388 ✅
- 2026-04-30 GDAXI: None → 0.5647 ✅
- 2026-05-08 HSI: None → 0.1144 ✅
2026-05-25 19:16:14 +08:00
b8d433d519
fix: 修复因子前向填充不生效的 bug
...
问题根因:
- reindex(method='ffill') 不会填充已存在的 NaN 值
- 当 factor_df 中已有 NaN(境外市场放假),reindex 无法填充
修复方案:
- 改为两步操作:reindex() 然后 ffill()
- ffill() 会填充所有 NaN,包括已存在的
影响范围:
- rotation.py: positions 对齐到 A 股日历
- export_backtest_detail.py: 因子对齐到展示日历
验证结果:
- 2026-04-30 HSI: nan → 0.2388 ✅
- 2026-05-08 HSI: nan → 0.1144 ✅
2026-05-25 08:53:42 +08:00
2f6b031361
feat: 添加因子对齐调试输出
...
- 检查 factor_df 索引类型
- 检查 reindex 后 2026-04-30 的 HSI 动量值
- 待进一步分析为何 ffill 未生效
2026-05-25 02:45:27 +08:00
0ef0623538
fix: 导出脚本因子前向填充对齐到展示日历
...
- 先定义 common_dates = equity_curve.index
- 再执行 factor_df.reindex(common_dates, method='ffill')
- 修复境外市场放假时动量显示为 None 的问题
2026-05-25 02:30:58 +08:00
959a863b5e
fix: 导出脚本因子对齐到A股日历
...
- 因子在原始数据上计算(正确)
- 导出时将因子前向填充到A股交易日历
- 修复境外市场放假时动量显示为None的问题
2026-05-25 02:07:18 +08:00
b89e975aed
refactor: 删除 SimpleRotationStrategy 简化版
...
- 删除 simple.py(已被 GlobalRotationStrategy 替代)
- 删除 backtest_simple_rotation.py 回测脚本
- 删除 test_simple_rotation.py 测试脚本
- 更新 __init__.py 移除 SimpleRotationStrategy 导出
- 现在只保留 GlobalRotationStrategy 正式版
2026-05-25 01:33:23 +08:00
e8e4e9c3ac
fix: GlobalRotationStrategy select_num 未生效
...
- 修复分散化选股逻辑:每个 group 选 Top 1 后,需要再按动量排序选 Top select_num
- 之前:所有 group 的 Top 1 都标记为信号(忽略 select_num)
- 现在:先从每个 group 选 Top 1,再从中按动量选 Top select_num 个
- 影响:配置 select_num=3 时,实际持仓 3 只而不是 4 只(group 数量)
2026-05-25 01:23:00 +08:00
2be81ba00d
feat(v2): 添加回测逐日明细导出脚本
...
新增功能:
- 创建 framework_v2/scripts/export_backtest_detail.py
- 导出 GlobalRotationStrategy 回测细节到 JSON
- 输出路径: framework_v2/results/backtest_detail_v2.json
导出数据内容:
1. 元数据(meta)
- 策略版本、模式、日期范围
- 动态阈值配置
- 调仓次数、最终净值
- 标的列表(名称、ETF、分组)
2. 逐日明细(days)
- 日期、净值、日收益率
- 调仓信息(is_rebalance、added、removed)
- 持仓列表(holdings)
- 每标的详情(11 个标的 × 1539 天)
* 动量得分、排名、阈值
* 持仓状态、权重
* 入场日期、入场价格、持仓天数
* 累计收益、当日收益、收益贡献
技术特性:
- 使用 CrossMarketAligner 对齐数据
- 支持动态短债阈值
- 支持强制分散化
- 包含交易成本计算
- Pydantic Schema 验证
回测验证(2020-01-10 ~ 2026-05-22):
- 总收益:137.64%
- 年化收益:15.23%
- 调仓次数:829 次
- 交易天数:1539 天
- 文件大小:4.5 MB
用途:
- 供 HTML 回放器加载
- 策略分析和调试
- 信号可视化
- 持仓明细查询
2026-05-25 00:39:47 +08:00
6a5f50cc85
chore: 添加 FLASK_API_URL 环境变量配置
...
- 添加 FLASK_API_URL=https://k3s.tokenpluse.xyz
- 用于 framework_v2 配置加载器读取 Flask API 服务地址
- 支持 V2 策略回测自动获取数据
2026-05-25 00:30:02 +08:00
6749f8cf61
feat(v2): GlobalRotationStrategy 使用 CrossMarketAligner 进行数据对齐
...
核心改进:
- 替换手动对齐逻辑为框架标准的 CrossMarketAligner
- 修复收益率计算顺序:先对齐价格 → 再计算收益率
- 修复首日收益率 NaN 问题(填充为 0%)
- 添加 Pydantic Schema 验证(数据质量保证)
对齐逻辑变更:
修复前(错误):
1. returns = close_df.pct_change() # 在原始日历计算
2. returns = returns[returns.index.isin(trading_calendar)] # 过滤
修复后(正确):
1. aligner = CrossMarketAligner(target_calendar)
2. returns_df = aligner.align_multi_asset(close_dict)
- 内部:先 ffill 价格到 A 股日历
- 内部:再计算收益率(休市日 = 0%)
- 内部:填充首日 NaN 为 0%
- 内部:Pydantic Schema 验证
回测验证(2020-01-10 ~ 2026-05-22):
- 修复前:总收益 135.63%,年化 15.07%,夏普 1.15
- 修复后:总收益 137.88%,年化 15.25%,夏普 1.16
- 收益提升:+2.25%(修复首日 NaN 和跨日收益率问题)
关键修复:
1. 首日收益率从 NaN 改为 0%(避免收益丢失)
2. 休市日收益率正确 = 0%(价格 ffill 后不变)
3. 消除跨多日收益率被当作单日收益率的 bug
4. 统一使用框架标准组件(CrossMarketAligner)
2026-05-25 00:29:49 +08:00
798a316ad5
feat: ETF复权功能扩展至支持前复权qfq
...
核心变更:
- TushareSource: _fetch_etf_adj() 支持 qfq 和 hfq 双模式
* 后复权(hfq): close × adj_factor
* 前复权(qfq): close × adj_factor / latest_factor
- UniversalDataFetcher: VALID_ADJ_BY_TYPE 更新
* CHINA_ETF: ['raw', 'hfq'] → ['raw', 'qfq', 'hfq']
复权公式验证:
- 纳指ETF(513100.SH): HFQ / QFQ = latest_factor (5.0020) ✅
- 5/5 个交易日全部通过验证
技术实现:
- fetch_etf_adj(): 公共接口支持 adj='qfq' 或 'hfq'
- _fetch_etf_adj(): 内部实现根据 adj 参数分支计算
- 前复权使用全量最新复权因子确保准确性
2026-05-25 00:15:59 +08:00
c07974ad94
feat: 重构ETF和股票复权逻辑,抛弃pro_bar自行实现
...
核心变更:
- 放弃 Tushare pro_bar 接口(pandas 3.x 不兼容)
- A股股票: 使用 pro.daily() + pro.adj_factor() 自行计算复权
- ETF: 使用 fund_daily() + fund_adj() 分段获取复权因子
- 修复 pandas 兼容性: 使用 ffill() 替代 fillna(method='ffill')
验证结果 (4层独立验证):
1. AKShare新浪交叉验证: AKShare_raw × Tushare_factor ≈ Our_hfq, 差异 < 0.0001
2. 数学公式验证: Tushare_raw × factor = Our_hfq, 差异 < 0.0001
3. 股票复权对比: 我们的实现 vs pro_bar, 差异 < 0.00005
4. 浏览器直接验证: 东方财富官方后复权 vs Our_hfq, 差异 0.0024 (0.04%)
技术实现:
- fetch_stock_adj(): 完整重写A股股票复权逻辑
- fetch_etf_adj(): 新增ETF复权公共接口
- _fetch_etf_hfq(): 重写ETF后复权,支持分段请求(单次限2000条)
- 前复权计算使用全量最新复权因子,确保准确性
2026-05-25 00:06:37 +08:00
7fcf63d68a
docs: 添加版本对比分析脚本与配置设计文档
...
新增对比脚本:
- compare_v1_v2.py: V1 vs V2 简单版对比分析(153 行)
* 发现 V2 简单版收益虚高(981.95% vs V1 的 103.29%)
* 识别核心差异:交易成本、调仓逻辑、动态阈值、溢价控制
- compare_three_versions.py: 三版本完整对比(190 行)
* V1 原始版:103.29%(基准)
* V2 简单版:981.95%(未计入交易成本,虚高)
* V2 正式版:135.63%(已计入交易成本,真实)
* 量化分析收益下降 846% 的原因
新增文档:
- CONFIG_DESIGN.md: V2 配置系统设计文档
* 扁平化资产池设计
* signal_source/trade_source 分离机制
* group 字段策略化语义
测试脚本:
- test_api_dates.py: API 日期范围验证测试
关键发现:
1. V2 简单版未计入交易成本导致收益虚高 878%
2. V2 正式版计入 829 次调仓成本后收益降至 135.63%
3. V2 正式版 vs V1(+32.34%)差异合理,夏普比率更优(1.15 vs 0.78)
2026-05-24 22:54:50 +08:00
1807258176
feat(v2): 实现全球轮动策略正式版(GlobalRotationStrategy)
...
核心功能:
- 交易成本计算:每次调仓扣除 0.1%(829 次调仓)
- 动态短债阈值:标的动量 < 短债动量 × 1.0 → 不持有
- 强制分散化:每个 group 内竞争,只选 Top 1
- 溢价过滤:预留接口(阈值 10%)
- 调仓控制:rebalance_days + rebalance_threshold(预留接口)
- A 股交易日过滤:只保留 SSE 交易日(1539 天)
策略逻辑:
1. 计算各指数标的动量得分(加权线性回归)
2. 使用动态短债阈值过滤负动量标的
3. 每个 group 内竞争,只选 Top 1(强制分散化)
4. 溢价过滤:排除溢价率 > 阈值的 ETF
5. 调仓控制:最低持仓天数 + 调仓阈值
6. 等权分配仓位
7. 扣除交易成本(0.1%)
回测验证(2020-01-10 ~ 2026-05-22):
- 总收益:135.63%(vs V1 的 103.29%,+32.34%)
- 年化收益:15.07%(vs V1 的 12.32%,+2.75%)
- 最大回撤:-17.57%(vs V1 的 -17.72%,略好)
- 夏普比率:1.15(vs V1 的 0.78,+47%)
- 调仓次数:829 次(vs V1 的 404 次)
新增文件:
- rotation.py: GlobalRotationStrategy 正式版实现(456 行)
- __init__.py: 导出 SimpleRotationStrategy 和 GlobalRotationStrategy
- backtest_global_rotation.py: 正式版回测脚本(117 行)
2026-05-24 22:54:21 +08:00
94b9ef165b
feat(v2): 增强框架核心功能与ETF复权修复
...
- 修复 end_date=None 导致 Flask API 返回错误时间范围的 bug
* strategy.py: 自动使用今天日期作为 end_date
* 验证:回测区间从 77 天恢复到 1539 天
- ETF 收益计算从原始价格改为后复权价格
* flask_api_fetcher.py: adj='raw' → adj='hfq'
* 自动处理 ETF 份额拆分事件,确保收益率准确
- V2 简单版添加 A 股交易日过滤
* simple.py: 获取 SSE 交易日历,过滤非交易日
* 验证:1999 天 → 1539 天(与 V1 一致)
- 配置严格对齐 V1 config.yaml
* config_simple.yaml: start_date 从 2020-01-01 改为 2020-01-10
* group 字段值严格映射 V1 的 market 字段
关键验证:
- V2 简单版回测:1539 天,981.95% 收益(未计入交易成本)
- V2 正式版回测:1539 天,135.63% 收益(已计入交易成本)
- V1 旧版框架:1539 天,103.29% 收益(基准)
2026-05-24 22:53:45 +08:00
86fce7a975
fix: group 字段严格对齐 V1 market 字段值
...
修正分组命名,不再自行创造:
- CN_GROWTH/CN_VALUE → A
- US_TECH → US
- JP_BROAD → JP
- EU_BROAD → EU
- HK_BROAD/HK_TECH → HK
- FIXED_INCOME → BOND
- COMMODITY → COMMODITY (不变)
同步更新 market_overrides:
- CN_EQUITY → A
- HK_EQUITY → HK
- US_EQUITY → US
现在 group 字段完全映射 V1 的 market 字段值
2026-05-24 15:00:48 +08:00
e6657bd2cc
feat(framework_v2): 对齐 V1 配置,实现指数信号→ETF收益回测
...
配置对齐:
- config_simple.yaml 严格对齐 V1 config.yaml
* 11 个标的覆盖 7 个策略分组
* 回测区间: 2020-01-01 ~ 至今
* 选股数量: Top-3,强制分散化
* V3 动态阈值(短债动量参考)
* 溢价控制启用(HK/US 10%阈值)
策略实现:
- SimpleRotationStrategy 支持 signal_source/trade_source 分离
* get_codes() 同时获取信号和交易标的
* compute_factors() 只使用 signal_source 计算因子
* _execute_backtest() 使用 trade_source 计算收益
* 支持跨市场场景(指数信号 → ETF收益)
回测验证:
- 成功运行端到端回测
- 获取 21 个标的(11 signal + 10 trade)
- 平均仓位 84.42%
- ⚠️ 已知问题: Flask API 只返回缓存数据(2026年),需修复
修复项:
- StrategyBase.run() 兼容信号矩阵(移除 'weight' 列假设)
2026-05-24 14:58:41 +08:00
43ce8056f1
docs: 添加 982fbe2 后代码变更总结文档
...
记录 framework_v2 配置系统重构和策略框架实现的关键变更
2026-05-24 14:27:06 +08:00
5212b004dc
fix: 回测细节导出、交易日历测试和动量因子修复
...
修复项:
- export_backtest_detail.py: 统一回测导出脚本的数据源调用逻辑
- test_trading_calendar.py: 交易日历功能测试
- verify_fix_result.py: 修复结果验证
- verify_mode_b.py: 模式 B 验证
策略修复:
- momentum.py: 动量因子计算优化
- strategy.py: StrategyBase 数据获取修复(fetch_indices 返回 dict)
2026-05-24 14:26:35 +08:00
0954458114
test(framework_v2): 添加配置系统测试和策略示例
...
配置文件:
- rotation_global.yaml: 扁平化资产池配置示例,演示 group 策略分组
* 13 个标的覆盖 7 个策略分组(US_TECH, CN_GROWTH, JP_BROAD, EU_BROAD, HK_TECH, COMMODITY, FIXED_INCOME)
* signal_source/trade_source 分离配置(跨市场场景)
* 分散化选股配置示例(注释状态)
* 默认使用 Flask API 数据源
测试用例:
- test_flat_asset_pool.py: 7/7 测试通过
* 扁平配置加载验证
* 策略分组功能测试(by_group, groups, count)
* 信号/交易标的获取(get_signal_codes, get_trade_codes)
* 信号→交易映射(get_signal_to_trade_mapping)
* 分散化配置验证
* 标的配置详情验证
- test_config.py: 配置加载器测试
- test_simple_rotation.py: 简单轮动策略端到端测试
2026-05-24 14:26:09 +08:00
de988b919b
feat(framework_v2): 实现 StrategyBase 抽象基类和简单轮动策略
...
StrategyBase ABC:
- 定义标准回测流程:get_data → compute_factors → generate_signals → manage_positions → execute
- 实现通用数据获取(使用 FlaskAPIFetcher.fetch_indices)
- 提供 run() 方法执行完整回测流程
SimpleRotationStrategy:
- 实现 4 个抽象方法:get_codes, compute_factors, generate_signals, manage_positions
- 支持动量因子计算(MomentumFactor)
- 实现全局选股和等权仓位管理
- 修复 int64 → float 转换问题
框架定位:
- 通用量化回测框架,支持轮动、CTA、趋势跟踪等多种策略
- 策略只需实现 4 个抽象方法即可接入框架
2026-05-24 14:25:47 +08:00
341611c32b
feat(framework_v2): 实现通用配置系统,支持扁平化资产池和策略分组
...
- 使用 Pydantic Schema 验证配置类型安全
- 实现扁平化 AssetPool,移除预设分类(equity/commodity/fixed_income)
- 移除 MarketType 枚举,改用 group 字符串字段实现策略分组
- AssetConfig 引入 signal_source/trade_source 分离,支持跨市场场景
- ConfigLoader 支持通用 StrategyConfig,向后兼容 RotationStrategyConfig
- 新增 GroupConfig 替代 MarketGroupConfig,支持分散化选股
重构核心:
- market → group(策略分组语义,组内竞争强制分散)
- by_market → by_group
- MarketGroupConfig → GroupConfig
2026-05-24 14:25:25 +08:00
99d3584d05
docs(framework_v2): 更新 FlaskAPIFetcher 文档(API 日历集成)
...
## 使用指南更新(FLASK_API_FETCHER_GUIDE.md)
- get_trading_calendar() 方法签名更新
- 新增 start, end 参数(支持动态日期范围)
- 返回类型: pd.DatetimeIndex(准确日历)
- 使用示例更新(API 调用方式)
- 注意事项更新:交易日历准确性 ✅ 已解决
## 架构设计更新(FLASK_API_FETCHER_ARCHITECTURE.md)
- get_trading_calendar() 实现更新
- 从临时 pandas BDay → API 准确日历
- API 端点: GET /api/v1/trading-calendar
- 未来优化: 移除交易日历 TODO(已完成)
## 文档一致性
- 所有示例代码使用 API 日历
- 架构描述与实际实现一致
- 版本历史更新(2024-04-16)
2026-05-24 12:38:55 +08:00