Commit Graph

218 Commits

Author SHA1 Message Date
2c1689089d revert(execution): 恢复动态权重仓位分配逻辑
- 恢复原逻辑: 按实际持仓数量等权分配
- 选出2只时每只权重50%,选出1只时权重100%
- 收益计算恢复为 np.mean(returns)
- 交易成本恢复为 swapped/len(old)
- 固定仓位逻辑记录在 docs/experiments/仓位分配逻辑修改分析.md
2026-05-16 00:34:12 +08:00
e0d6f81ea1 docs: 仓位分配逻辑修改分析文档
- 记录动态权重vs固定仓位逻辑对比
- 分析收益下降原因(4479%→1678%)
- 说明固定仓位设计意义与改进方向
2026-05-16 00:31:14 +08:00
444dc0e751 refactor(execution): 改为固定仓位分配逻辑
- 原逻辑: 按实际持仓数量等权(选出2只时权重50%)
- 新逻辑: 按select_num固定等权(选出2只时权重33.3%+现金33.3%)
- 缺失仓位用现金替代,收益为0
- 交易成本按固定仓位比例计算
- 目的: 保持稳定风险敞口,避免仓位不足时波动放大
2026-05-16 00:18:19 +08:00
07463f68e1 fix(strategy): 消除pandas pct_change弃用警告
- 添加 fill_method=None 参数避免 FutureWarning
- pandas 未来版本将移除默认 fill_method='pad' 行为
2026-05-15 23:38:45 +08:00
80c7fe0ba8 refactor(log): 优化回测日志输出格式
- strategy.py: 在数据获取前打印回测配置区间说明
- flask_api_source.py: 使用API返回的实际数据范围(date_range)
- 原问题: 日志显示请求参数的start_date,而非实际数据范围
- 修改后: 各标的显示实际数据时间周期(如创业板2010年开始)
2026-05-15 23:34:52 +08:00
cbd60894b9 fix(strategy): 修复债券指数OHLCV数据处理逻辑
- 问题: 债券指数(931862.CSI)只有close数据,open/high/low全是None
- 原代码: 检查列存在后整行dropna → 数据变成0条
- 修复: 检查列存在 + 检查数据是否有效(不全为None)
- 如果OHLCV无效 → 使用close列单独dropna
- 结果: 30年国债4330条数据正常参与回测
- 收益影响: 累计收益+258%, Sharpe+0.04
2026-05-15 23:26:54 +08:00
85c20b4626 refactor(strategy): 取消数据不足标的剔除逻辑,保留所有标的以暴露策略问题
- compute_factors: 不剔除数据不足/缺失率高的标的
- 改为警告并保留,因子值NaN时信号生成自动跳过
- 目的:暴露策略自身问题,后续支持更多大类资产
- 回测配置改为start_date=2000-01-01以测试更长历史
2026-05-15 23:18:44 +08:00
763713213c refactor(config): 有色金属标的改用COMEX铜期货替代上期所
- CU.SHF -> HG=F: COMEX铜期货(2000年至今)
- 原因:上期所主力合约数据仅2018年后,COMEX铜数据更长
- ETF保持不变(159980.SZ 有色金属ETF)
- 配合之前替换:AU.SHF->GC=F, CL.NYM->CL=F
2026-05-15 22:21:55 +08:00
4f1207dc4d refactor(config): 商品标的改用COMEX/WTI期货替代上期所
- AU.SHF -> GC=F: COMEX黄金期货(2000年至今)
- CL.NYM -> CL=F: WTI原油期货(2000年至今)
- 原因:上期所主力合约数据仅2018年后,COMEX/WTI数据更长
- ETF保持不变(518880.SH 黄金ETF, 160723.SZ 原油ETF)
2026-05-15 21:57:32 +08:00
18ef2a1704 feat(datasource): 加密货币数据支持分钟级时间精度
- flask_server.py: dataframe_to_json 增加 asset_type 参数,crypto 使用 '%Y-%m-%d %H:%M:%S' 格式
- ccxt_source.py: 移除 normalize() 调用,保留完整时间精度
- ETF/指数数据保持天级精度 '%Y-%m-%d' 不变
2026-05-15 21:25:08 +08:00
a49002f622 fix(datasource): 溢价率计算改用同一天市价与净值
问题:之前用 ffill 将前一天净值填充到当天,导致溢价率偏差过大
例如:5月13日市价 4.048 vs 5月12日净值 3.946 → 溢价率 2.58%

修复:
- 不使用 ffill,只计算有净值日期的溢价率
- 使用 price_df 和 nav_df 的交集日期计算
- 溢价率 = (当天市价 - 当天净值) / 当天净值
- 5月12日市价 3.94 vs 净值 3.946 → 溢价率 ~0%

注意:净值 T+1 公布,最新一天溢价率可能无法计算
2026-05-14 01:31:39 +08:00
2789713637 fix(report): 修复 generate_legacy_report 重复日期导致的 reindex 失败
问题:nav_series 或 backtest_result.index 存在重复日期时,
reindex() 抛出 'cannot reindex on an axis with duplicate labels'

修复:
- 先检查并去除 nav_series 的重复日期
- 同时检查并去除 backtest_result.index 的重复日期
- 使用 duplicated(keep='last') 保留最后一条记录
2026-05-14 01:21:07 +08:00
6a5d4dacd4 fix(datasource): 修复溢价率计算重复日期导致的 reindex 失败
问题:长时间范围 ETF 数据获取时,出现 'cannot reindex on an axis with duplicate labels' 错误

修复:
- 在 _calculate_premium_series 中先检测并去除重复日期
- price_df 和 nav_df 的索引都使用 duplicated(keep='last') 去重
- 确保 reindex 操作正常执行
2026-05-14 01:15:03 +08:00
7121e78e70 fix(report): 修复 generate_legacy_report 数据类型处理
- benchmark_data 可能是 Series 或 DataFrame,添加类型判断
- etf_nav_data 现在是字典格式 {etf_code: DataFrame},修正解析逻辑
- 正确从 DataFrame.attrs 中提取净值和溢价率数据
2026-05-14 01:10:12 +08:00
72e980e956 refactor(rotation): 利用 Flask API 内联的 ETF 净值和溢价率数据
- 移除单独的 fetch_etf_nav 调用
- 从 ETF OHLCV DataFrame.attrs 中提取净值和溢价率
- 新增 etf_premium_data 字段存储溢价率详情
- 减少一次 API 请求,提高数据获取效率
2026-05-14 01:03:31 +08:00
d62763b0bd feat(flask): OHLCV 端点自动附加 ETF 净值和溢价率
flask_server.py:
- 当 asset_type 为 china_etf 时,自动调用 fetch_etf_with_nav
- 响应中添加 nav、premium_series、latest_premium、premium_stats

flask_api_source.py:
- 解析 ETF 数据中的净值和溢价率信息
- 将 nav_df、premium_series、premium_stats 存入 DataFrame.attrs
2026-05-14 00:57:37 +08:00
d4047d4cf4 fix(flask_api_source): 修复 fetch_etf_nav zstd 解压与溢价率解析
- 处理 zstd 响应的 JSON 解析问题
- 正确解析 Flask server 返回的净值数据结构
- 添加 premium_series、latest_premium、premium_stats 到 DataFrame attrs
2026-05-14 00:51:23 +08:00
4fe21a7cd4 fix(datasource): 修复 zstd 响应 JSON 解析问题
- flask_api_source.py: 添加 requests.exceptions.JSONDecodeError 捕获
- flask_server.py: 启用 flask-compress gzip 压缩
- requirements.txt: 添加 flask-compress>=1.14
- strategy.py: 修复 flask_api 配置读取方式

问题原因:Traefik Ingress 使用 zstd 压缩响应,
requests.response.json() 解析失败,但 json.loads(response.text) 成功
2026-05-14 00:27:30 +08:00
020e90aa2b feat(rotation): 添加 Flask API 配置
- 新增 flask_api 配置块
- url: https://k3s.tokenpluse.xyz
- enabled: true
- 支持策略通过远程 API 获取数据
2026-05-13 23:55:26 +08:00
0a9795febb feat(strategy): rotation策略支持Flask API数据获取
- 新增 flask_api_source.py: Flask API远程数据源模块
- 修改 strategy.py: get_data() 支持通过Flask API获取数据

使用方式:
strategy.get_data(use_flask_api=True)  # 通过部署服务获取
strategy.get_data(use_flask_api=False) # 本地HybridDataSource

配置项:
flask_api_url: 可在config.yaml中指定API地址
2026-05-13 23:49:26 +08:00
416f708d53 feat(datasource): 实现加密货币数据获取功能
- 新增 ccxt_source.py: CCXT + OKX 加密货币数据源
- 新增 socks2http.py: SOCKS5 转 HTTP 代理转换器
- 修改 universal_fetcher.py: 添加 _fetch_crypto 方法,支持 timeframe 参数
- 修改 flask_server.py: API 支持 timeframe 参数,加密货币不缓存

支持的 timeframe: 1d, 1h, 4h, 15m, 1m
测试验证: BTC 数据获取成功
2026-05-13 23:30:32 +08:00
105af19690 feat(strategy): 新增纯美股动量轮动策略
新增美股轮动策略模块:
- strategies/us_rotation/config.yaml: 47只美股标的池,动量窗口250天,Top5选股
- strategies/us_rotation/strategy.py: USRotationStrategy实现
- run_us_rotation.py: 回测入口脚本

回测结果 (2016-2026, 约10年):
- 总收益: 7675% (年化52.49%)
- 基准NDX收益: 540% (年化19.72%)
- 超额年化收益: 32.78%
- 夏普比率: 1.33 (基准0.80)
- 最大回撤: 42.15%
- 卡玛比率: 1.25
- 胜率: 56.1%
- 平均持仓: 2.7天

年度最佳: 2020年+221% (超额176%)
年度防守: 2022年-10.5% (基准-33.7%, 超额+23.3%)

持仓Top5: NVDA(35.8%), AMD(30.1%), SHOP(26%), AVGO(23.9%), FICO(23.3%)
2026-05-13 01:27:09 +08:00
a712bc0f03 fix(datasource): 支持US_STOCK和HK_STOCK类型数据获取
- universal_fetcher.py: 添加 _fetch_us_stock 和 _fetch_hk_stock 方法
- flask_server.py: SSH_HOST 修正为正确的IP地址 8.218.167.69
- 测试 META 获取成功,info 字段在最外层返回179个属性
2026-05-13 00:38:01 +08:00
ecd8d6539f feat(datasource): 股票info字段放到API响应最外层
- yfinance_source.py: stock_info 存储在 df.attrs['info'] 中
- flask_server.py: dataframe_to_json 从 df.attrs 提取 info 放到最外层
- flask_server.py: 缓存切片函数保留 info 字段
- Dockerfile: 启用 Flask 服务作为默认 CMD(端口80)

响应结构示例:
{
  "data": [{"date": "2024-01-01", "code": "AAPL", ...}],
  "info": {"sector": "Technology", "industry": "...", ...}
}
2026-05-13 00:26:19 +08:00
7c48e4ab21 chore: Dockerfile注释Flask服务CMD,恢复默认调度器
修改内容:
- Flask服务CMD改为注释状态
- 定时调度器CMD恢复为默认启动

说明:
- 默认启动定时任务调度器(保持向后兼容)
- 如需使用Flask服务,取消Flask CMD注释并注释调度器CMD
2026-05-12 23:59:59 +08:00
c5ec9cfe04 docs: Dockerfile添加Flask服务启动命令注释
修改内容:
- 将Flask服务启动命令作为主CMD(取消注释)
- 将定时任务调度器作为备选(注释掉)
- 添加注释说明如何切换

当前默认启动Flask服务:
CMD ["python", "datasource/flask_server.py", "--host", "0.0.0.0"]

如需切换回调度器:
1. 注释掉Flask服务的CMD
2. 取消注释定时调度器的CMD
2026-05-12 23:58:53 +08:00
d226916131 fix: Flask服务默认端口改为80,简化Dockerfile CMD
修改内容:
- flask_server.py: 默认端口从5000改为80
- Dockerfile: CMD简化,无需指定--port参数

最终Dockerfile:
FROM index-base:latest
WORKDIR /app
...
EXPOSE 80
CMD ["python", "datasource/flask_server.py", "--host", "0.0.0.0"]
2026-05-12 23:53:23 +08:00
cf48c4418f fix: asset_type参数改为强制覆盖而非验证
问题:
- 原设计要求asset_type与自动检测结果一致
- 如果自动检测逻辑有问题,用户无法覆盖

修改:
- 指定asset_type后直接使用,不再验证
- 用户指定的类型强制覆盖自动检测结果
- 返回type_override字段提示覆盖情况

返回示例(覆盖时):
{
  "asset_type": "us_index",  // 用户指定
  "type_override": {
    "detected": "hk_index",  // 自动检测结果
    "specified": "us_index", // 用户指定
    "hint": "用户强制覆盖了自动检测结果"
  }
}
2026-05-12 23:34:36 +08:00
95c7a091f5 feat: Flask API增加asset_type参数支持类型验证
新功能:
- /api/v1/ohlcv 接口新增可选 asset_type 参数
- 用于验证code与指定类型是否匹配
- 类型不匹配时返回400错误并说明

API文档更新:
- endpoints 添加 asset_type 参数说明
- 新增 asset_types 字段说明各类型含义

使用示例:
- /api/v1/ohlcv?code=000300.SH (自动检测)
- /api/v1/ohlcv?code=000300.SH&asset_type=china_index (验证类型)
- /api/v1/ohlcv?code=513100.SH&asset_type=us_index (类型不匹配报错)
2026-05-12 23:32:08 +08:00
fb755fc31e refactor: 加密货币默认不缓存,简化分层缓存策略
问题:
- 加密货币分钟级数据量大,不适合全量缓存
- 原分层策略过于复杂

优化方案:
- 日级别数据(股票/指数/ETF/期货): 缓存全量数据,切片返回
- 加密货币: 每次实时下载,不缓存

代码简化:
- 删除 CRYPTO_CACHE_DAYS 配置
- 删除 _get_crypto_cache_start 函数
- _fetch_full_data_cached: 加密货币直接返回None
- fetch_data_with_ttl: 加密货币分支直接下载

优势:
- 日级别数据:减少重复下载
- 加密货币:避免内存爆炸,实时获取最新价格
2026-05-12 23:27:44 +08:00
1d3483bc02 feat: DEFAULT_START_DATE改为1980-01-01支持最长历史数据
数据历史深度调研:
- YFinance 标普500: 1980-01-02 (45年, 11685条)
- YFinance 日经225: 1980-01-04 (45年, 11396条)
- YFinance 纳斯达克100: 1985-10-01 (40年, 10232条)
- YFinance 恒生指数: 1986-12-31 (38年, 9712条)
- Tushare 沪深300: 2005-01-04 (21年, 5183条)

修改:
- DEFAULT_START_DATE: '2015-01-01' -> '1980-01-01'
- 支持最长45年的历史数据下载
- A股数据会在数据源端自动截取有效范围
2026-05-12 23:03:37 +08:00
4cee249823 feat: 优化缓存策略 - 全量数据缓存 + 按日期切片
缓存策略改进:
- Key改为(code, today_date):每天缓存一次全量数据
- 下载全量数据:从DEFAULT_START_DATE(2015-01-01)到今天
- 返回时切片:从缓存数据中按start-end范围切片返回

新增功能:
- DEFAULT_START_DATE配置项(可通过环境变量覆盖)
- _fetch_full_data_cached:缓存全量数据
- _slice_data_from_cache:从缓存切片指定日期范围

优势:
- 同一天内不同日期范围请求不会重复下载
- 第二天请求自动更新缓存(today_date变化)
- 减少对外部数据源的请求次数

修改文件:
- datasource/flask_server.py
2026-05-12 22:47:03 +08:00
2fba6d82f4 fix: SSH隧道启动前清理残留进程
问题:
- 多次运行回测后残留SSH进程干扰代理连接
- yfinance因代理冲突无法获取数据

修复:
- SSHTunnelManager添加 _cleanup_old_processes 方法
- 启动新隧道前自动清理同端口残留进程

验证:
- 清理后YFinance成功下载纳指、日经、DAX等数据
2026-05-12 22:40:35 +08:00
5c98b1cb6a refactor: SSH密钥移到根目录,删除config目录
迁移内容:
- config/hk_ecs.pem → hk_ecs.pem(根目录)
- 删除 config 目录(无其他内容)

路径更新:
- datasource/flask_server.py:默认路径改为 hk_ecs.pem
- strategies/rotation/config.yaml:SSH配置路径
- docker-compose.yml:挂载路径
- build-and-push.sh:示例命令
- README.md:项目结构说明

设计原则:敏感文件集中放在根目录
- .env:环境变量
- hk_ecs.pem:SSH密钥
2026-05-12 22:31:43 +08:00
50032d628f fix: 删除废弃的config/settings.py
删除内容:
- config/settings.py(仅被归档代码引用)
- config/__init__.py
- config/__pycache__

保留:
- config/hk_ecs.pem(SSH密钥,仍在使用)

说明:
- get_dingtalk_config/get_db_config 已归档
- DEFAULT_CODE_NAME_MAP 已迁移到策略配置
- DATA_DIR 各模块已直接使用"data"路径
2026-05-12 22:22:42 +08:00
c36044a1d6 fix: 删除废弃的config/strategies目录
删除内容:
- config/strategies/cci.yaml(相关代码已归档)

说明:
- rotation.yaml 已迁移到 strategies/rotation/config.yaml
- cci.yaml 仅被归档代码引用,无活跃使用
- config目录保留 hk_ecs.pem 和 settings.py
2026-05-12 22:18:44 +08:00
aeb95a6f4c refactor: 配置文件迁移到策略目录(模块自包含)
迁移内容:
- config/strategies/rotation.yaml → strategies/rotation/config.yaml

路径更新(核心文件):
- strategies/rotation/strategy.py(注释示例)
- scripts/generate_legacy_report.py(config_path)
- run_rotation.py(注释和默认参数)
- datasource/hybrid_source.py(from_yaml示例和fetch_rotation_data)

保留:
- config/strategies/cci.yaml(无对应策略目录,暂保留)

设计原则:策略模块自包含,配置与实现同目录,方便移植和复制

验证:策略加载成功(候选池11只,回测区间2019-01-01 ~ 2026-05-12)
2026-05-12 22:14:35 +08:00
0a8d0d9212 fix: 删除未使用的空目录data_cache
删除内容:
1. data_cache 目录(空目录,无文件)
2. config/settings.py 中的 DATA_CACHE_DIR 定义(第22-25行)

说明:
- 该目录原设计用于CSV文件缓存,但实际未使用
- 当前项目使用 data/etf_cache/daily 作为数据缓存目录
2026-05-12 22:07:54 +08:00
70515ab169 fix: SSH密钥路径从根目录迁移到config目录
修改内容:
1. datasource/flask_server.py
   - 默认路径从 'hk_ecs.pem' 改为 'config/hk_ecs.pem'

2. docker-compose.yml
   - 挂载路径从 './hk_ecs.pem:/app/hk_ecs.pem'
   - 改为 './config/hk_ecs.pem:/app/config/hk_ecs.pem'

3. build-and-push.sh
   - 示例命令中的路径同步更新

4. README.md
   - 项目结构说明中更新密钥位置

验证:
- rotation.yaml 已使用 config/hk_ecs.pem(无需修改)
- flask_server 默认路径正确指向 config/hk_ecs.pem
- 密钥文件存在于 config/hk_ecs.pem
2026-05-12 22:02:35 +08:00
9fe779bced refactor: SSH私钥移至config目录
变更内容:
- hk_ecs.pem -> config/hk_ecs.pem
- rotation.yaml: key_path路径更新为 config/hk_ecs.pem

理由:
- 配置文件统一归档到config目录
- 便于管理和权限控制
2026-05-12 21:58:12 +08:00
16affb2368 feat: fetch_etf_with_nav 返回历史溢价率序列
修改内容:
1. universal_fetcher.py
   - fetch_etf_with_nav 返回三值:(price_df, nav_df, premium_series)
   - 新增 _calculate_premium_series 方法:计算每一天的溢价率
   - 溢价率 = (ETF收盘价 - ETF净值) / ETF净值
   - 净值用ffill对齐价格日期(处理T+1延迟)

2. flask_server.py
   - /api/v1/etf/nav 端点返回历史溢价率序列
   - 添加 premium_series 字段:[{date, premium}]
   - 添加 latest_premium: 最新溢价率
   - 添加 premium_stats: 统计数据(mean/std/min/max/median)

测试结果(513100.SH 纳指100 ETF):
- 价格数据: 8条
- 净值数据: 8条
- 溢价率序列: 8条
- 最新溢价率: 0.1500%
- 溢价率均值: 1.1433%
- 溢价率范围: 0.15% ~ 1.69%
2026-05-12 21:39:07 +08:00
4e3aac5e0e feat: Flask统一数据服务迁移(分层架构)
架构设计:
- 对外统一接口 fetch():自动识别资产类型并路由
- 对内分层实现:各资产类型独立方法,职责单一

新增文件:
- datasource/universal_fetcher.py: 统一数据获取器
  - _fetch_china_index: A股指数(Tushare)
  - _fetch_china_etf: A股ETF(含净值)
  - _fetch_us_index: 美股指数(YFinance+SSH)
  - _fetch_hk_index: 港股指数(YFinance+SSH)
  - _fetch_futures: 期货(Tushare/YFinance)
  - fetch_etf_with_nav: ETF价格+净值(计算溢价率)

- datasource/asset_type_detector.py: 资产类型检测器
  - AssetType枚举:9种资产类型
  - detect(): 自动识别资产类型
  - group_by_type(): 批量分组

- datasource/flask_server.py: Flask API服务
  - LRU + TTL 双缓存机制
  - 8个API端点:ohlcv、etf/nav、batch、cache等

更新:
- datasource/__init__.py: 导出新模块

验证:
- 模块导入成功
- 资产类型检测正确
- A股数据获取正常(沪深300: 5条)
2026-05-12 21:33:19 +08:00
c63158c99d fix: 移除溢价率高溢警告表情符号
用户要求不显示溢价率上的表情符号(⚠️),修改:
- archive/legacy_core/report.py 第259-260行
- archive/legacy_core/report.py 第298-299行
- archive/legacy_core/report.py 第562-563行
- archive/legacy_core/report.py 第597-598行

修复后溢价率显示:
- 创业板指: +0.02%(原 +3.70%⚠️)
- 日经225: +0.89%(原 +0.85%)
2026-05-12 21:14:03 +08:00
412177837f fix: 报告生成器数据对齐修复
修复内容:
1. 指数价格获取改用index_data而非index_close
   - 原问题:index_close对齐后N225最后几天的值为nan
   - 修复:从原始OHLCV获取close,用ffill填充缺失值

2. ETF净值数据对齐到回测日期
   - 原问题:etf_nav_data索引与backtest_result不对齐
   - 修复:用reindex(backtest_result.index, method='ffill')

3. ETF价格数据同样对齐到回测日期

修复后报告显示:
- 日经225指数最新价: 62713.65(原为nan)
- 创业板指溢价率: +3.70%⚠️
- 日经225溢价率: +0.85%
2026-05-12 01:50:30 +08:00
38a31357d1 feat: 新框架集成原引擎报告生成模块
新增 scripts/generate_legacy_report.py:
- 使用新框架运行回测
- 将数据格式转换为原引擎格式
- 调用原引擎 generate_performance_report 生成报告

输出文件:
- rotation_legacy_chart.png (净值曲线+回撤+持仓分布)
- rotation_legacy_metrics.json (策略指标JSON)
- rotation_legacy_nav.csv (净值曲线数据)

用法:python scripts/generate_legacy_report.py
2026-05-12 01:42:25 +08:00
76faf78a42 fix: 完整匹配原引擎剔除逻辑和因子对齐顺序
关键修复:
1. OHLCV整行dropna()剔除逻辑(匹配原引擎)
   - 国债 931862.CSI 因 open/high/low 全空被剔除
   - 原引擎: df = index_ohlcv_data[code].dropna()
   - 新框架: 同样逻辑

2. 因子计算顺序:先计算因子再对齐到A股交易日历
   - 原引擎: factor_series = rolling(n).apply(); factor_aligned = reindex(ffill)
   - 新框架: 同样顺序,避免ffill填充的重复值影响rolling窗口

对比结果:
| 指标 | 原引擎 | 新框架(修复后) |
|------|--------|---------------|
| 累计收益 | 1804% | 1999% |
| 信号匹配率 | - | 90.3% |
| 调仓次数 | 459 | ~578 |

剩余195%收益差距可能来自收益计算细节差异
2026-05-12 01:14:07 +08:00
f5d748257e fix: 关键修复-境外数据对齐到A股交易日历后计算因子
问题根因:
- 2019-02-18等日期是A股交易日但不是美股交易日(总统日假期)
- 新框架因子计算使用原始境外数据索引,导致这些日期因子值为NaN
- 原引擎使用 reindex(a_share_dates, method='ffill') 前向填充

修复:
- 因子计算前将所有标的数据对齐到A股交易日历
- 使用前向填充(ffill)处理境外市场交易日缺失

收益对比:
- 原引擎: 1804% 累计收益, 459次调仓
- 新框架(修复后): 1703% 累计收益, 578次调仓

剩余差异:
- 新框架保留国债(931862.CSI),原引擎剔除
- 信号匹配率36.5%,但收益接近说明策略逻辑有效
2026-05-12 01:01:32 +08:00
19131c41dd fix: 数据源路由修复与因子计算改进
1. 修复期货路由逻辑:NYMEX期货(.NYM)走YFinance而非Tushare
2. 添加SSH隧道路径修复(原引擎)
3. 因子计算只使用close列(处理部分指数只有收盘价的情况)
4. 添加数据不足和缺失率剔除日志

收益对比:
- 原引擎(剔除国债): 累计1804%, 调仓459次
- 新框架: 累计772%, 调仓1276次

差异原因待查:
- 国债剔除逻辑不同
- 调仓频率差异
2026-05-12 00:47:43 +08:00
a7a4a69153 fix: 修复回测日期对齐问题,优化收益率计算
- 使用对齐后的index_close数据计算日收益率
- 添加日期对齐逻辑确保信号和收益率数据一致
- 修复pivot重复索引问题,使用pivot_table
- 修复tushare期货接口调用(futures_daily -> fut_daily)

回测结果:
- 最终净值: 0.9435
- 累计收益: -5.65%
- 信号日期: 2302天
2026-05-12 00:12:46 +08:00
e56bd39400 feat: 创建数据源模块 datasource/
核心功能:
- ssh_tunnel.py: SSH隧道管理器(连接香港ECS)
- tushare_source.py: A股数据获取(指数、ETF、期货)
- yfinance_source.py: 境外数据获取(港股、美股)
- hybrid_source.py: 混合数据源(整合所有)

使用方式:
  from datasource import HybridDataSource

  source = HybridDataSource.from_yaml('config/strategies/rotation.yaml')
  result = source.fetch_all()

更新 RotationStrategy 使用新数据源模块
2026-05-12 00:03:25 +08:00