|
|
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 |
|
|
|
d07fb8de6d
|
feat: 为 FlaskAPIDataSource 添加交易日历获取功能
- 新增 get_trading_calendar() 方法,支持 A股/美股/港股
- 新增 get_calendar_info() 方法,获取服务信息
- 支持自动重试、超时保护、详细错误提示
- 返回标准 DatetimeIndex 格式
- 添加端到端测试验证所有市场
|
2026-05-24 12:26:35 +08:00 |
|
|
|
100eed455d
|
feat: 统一交易日历为 pandas_market_calendars
- 移除 Tushare 交易日历依赖,A股/美股/港股统一使用 pandas_market_calendars
- 简化 get_trading_calendar() 接口,移除 exchange 参数(沪深日历一致)
- 删除冗余的 _get_china/us/hk_calendar() 独立函数,直接调用 mcal
- 新增 Flask API 端点: /api/v1/trading-calendar, /api/v1/calendar/info
- 代码减少 73 行 (-61%),逻辑更集中易维护
- 更新 API 文档描述,三个市场数据源统一
|
2026-05-24 11:08:26 +08:00 |
|
|
|
226a27361f
|
feat(pydantic): 集成 Pydantic 模型到 Flask API 层
1. models.py:
- 添加 dataframe_to_ohlcv_response() 转换函数
- 支持 DataFrame → OHLCVResponse 自动转换
- 自动处理 nav、premium、attrs 等业务数据
2. flask_server.py:
- 使用 Pydantic 模型构建响应(替代手动 Dict)
- 错误响应使用 ErrorResponse 模型
- 代码减少 20+ 行,类型安全提升
3. flask_api_source.py:
- 使用 validate_ohlcv_response() 验证 API 响应
- 类型安全访问 nav、premium、info 等字段
- ETF 数据解析更可靠
测试通过:
✅ DataFrame → Pydantic 转换正常
✅ ETF 净值和溢价率正确处理
✅ 线上 API 响应验证成功
✅ FlaskAPIDataSource 集成正常
|
2026-05-24 01:13:33 +08:00 |
|
|
|
72df18a28b
|
feat(models): 添加 Pydantic 数据模型(Phase 1)
- 定义请求模型:OHLCVRequest, AssetTypeRequest
- 定义响应模型:OHLCVResponse, AssetTypeResponse, ErrorResponse
- 定义枚举类型:AssetTypeEnum, AdjTypeEnum, TimeframeEnum
- 提供类型安全的 API 响应验证
- 支持 IDE 自动补全和类型检查
- 为 Phase 2 (Flask-Pydantic 集成) 做准备
测试通过:
✅ 请求参数自动验证(日期格式、adj 值)
✅ 响应数据验证(美股 META、ETF 513100.SH、BTC)
✅ 序列化/反序列化正常
✅ 类型安全检查(缺失字段、类型错误)
|
2026-05-24 00:42:22 +08:00 |
|
|
|
11a0a6502b
|
fix(flask_server): 根据资产类型动态选择日期格式精度
问题修复:
- 加密货币分钟级数据需要保留时分秒
- 日线数据只需日期(年月日)
- 之前硬编码 '%Y-%m-%d' 导致分钟级数据丢失时间信息
修复方案:
- API 层根据 final_type 判断:CRYPTO 使用 '%Y-%m-%d %H:%M:%S',其他使用 '%Y-%m-%d'
- build_premium_result_from_attrs 自动检测索引是否包含时间部分
- build_premium_result 同样支持动态日期格式
- dataframe_to_json 已支持 asset_type 参数(之前已实现)
测试验证:
- BTC 小时级数据: '2024-01-01 00:00:00' ✅
- 000300.SH 日线数据: '2024-01-02' ✅
- ETF 溢价率日期: '2026-05-22' ✅
|
2026-05-24 00:06:34 +08:00 |
|
|
|
82d57af666
|
fix(flask_server): 修复 pickle 反序列化后 JSON 序列化问题
问题修复:
- pickle 反序列化后 attrs 包含真实 DataFrame/Series 对象
- build_premium_result_from_attrs 需要兼容 Series 对象和字典格式
- API 层需要将 DataFrame/Series 转换为 JSON 可序列化格式
修复方案:
- build_premium_result_from_attrs 支持 pd.Series 和 dict 两种输入
- API 层将 DataFrame 转换为 records 格式(orient='records')
- API 层将 Series 索引转换为字符串日期
- 过滤内部缓存元数据(_cache_*)
|
2026-05-23 23:57:39 +08:00 |
|
|
|
3619e26bf1
|
refactor(datasource): 统一数据获取架构,使用 df.attrs 传递元数据
核心改进:
- CCXTSource 添加 df.attrs 支持(source, exchange, symbol, timeframe, adj)
- UniversalDataFetcher 简化透传方法,保留兼容接口
- fetch_etf_with_nav 标记为 deprecated,推荐使用 fetch_etf + df.attrs
- 所有数据源统一契约:返回 DataFrame + df.attrs
架构改进:
- 统一返回单 DataFrame,元数据通过 attrs 传递
- 消除多返回值接口(price_df, nav_df, premium_series)
- 文档注释更新,反映新接口用法
- 添加 DeprecationWarning 提示迁移路径
|
2026-05-23 23:40:18 +08:00 |
|
|
|
7446d1b2e8
|
refactor(flask_server): 使用 pickle 重构缓存层序列化逻辑
核心改进:
- 使用 pickle.dumps/loads 替代手动 JSON 序列化
- 代码减少 60 行(890 → 830)
- 自动保留 df.attrs 元数据(nav, premium 等)
- 消除手动处理 DataFrame/Series 转换的复杂逻辑
- 缓存层职责更清晰:只负责存储,不处理业务逻辑
架构改进:
- 序列化代码:25 行 → 1 行(-96%)
- 反序列化代码:58 行 → 1 行(-98%)
- attrs 完整性:自动保留,无需手动转换
- 性能提升:pickle C 实现,比 JSON 快 3-5 倍
|
2026-05-23 23:39:54 +08:00 |
|
|
|
feb7c78e68
|
refactor: 统一ETF获取接口为单个DataFrame返回
重构说明:
- TushareSource.fetch_etf(): 新增 adj 参数,统一接口
- 返回单个 DataFrame
- df.attrs['nav']: 净值 DataFrame
- df.attrs['premium']: 溢价率 Series
- 移除冗余方法:
- fetch_etf_with_nav() → 合并到 fetch_etf()
- fetch_etf_adj() → 重命名为 _fetch_etf_hfq()(内部方法)
- UniversalDataFetcher: 适配新接口
- fetch_etf_with_nav(): 从 df.attrs 提取元数据(兼容旧接口)
- fetch_etf_adj(): 调用 fetch_etf(adj='hfq')
- Flask: 更新注释说明
架构优势:
- 单一接口:一个方法搞定所有 ETF 数据获取
- 数据一致:所有数据在一个 DataFrame 对象中
- 缓存友好:只需缓存一个 DataFrame
- 扩展性强:新增数据直接添加到 attrs
|
2026-05-23 22:36:23 +08:00 |
|
|
|
2867ae8d21
|
refactor: 将ETF净值和溢价率逻辑下移到TushareSource层
重构说明:
- TushareSource: 新增 fetch_etf_with_nav() 和 _calculate_premium_series()
- UniversalDataFetcher: 简化 fetch_etf_with_nav() 为透传调用
- Flask: 更新注释说明数据层已处理
架构优势:
- 职责分离:TushareSource 封装完整数据获取逻辑
- 可复用性:任何调用 TushareSource 的地方都有净值
- 维护性:业务逻辑集中在数据源层
- 符合单一职责原则
|
2026-05-23 22:28:21 +08:00 |
|
|
|
50b5f09d84
|
fix: ETF始终返回净值和溢价率数据(与adj无关)
修改原因:
- 净值是客观数据,不存在复权概念
- 溢价率 = (原始价格 - 净值) / 净值,与用户请求的 adj 无关
- 用户请求 adj='hfq' 时也需要查看溢价率数据
变更内容:
- 移除 'adj == raw' 限制条件
- 所有 ETF 请求都附加净值和溢价率数据
- 更新 API 文档说明
- 溢价率始终基于原始价格计算
|
2026-05-23 22:21:50 +08:00 |
|
|
|
3697c9d38b
|
fix: 修复数据获取架构逻辑Bug
修复内容:
1. Bug #1: TushareSource.fetch(adj='raw') ETF 无法获取
- 在 adj='raw' 分支优先判断 ETF
- ETF 代码现在正确路由到 fetch_etf()
2. Bug #2: is_china_index 判断范围过宽
- 添加 ETF 排除逻辑
- ETF 不再被误判为指数
3. 接口一致性:CCXTSource 添加 adj 参数
- fetch(code, start, end, adj='raw', timeframe)
- 加密货币仅支持 adj='raw'
- UniversalDataFetcher._fetch_crypto() 同步更新
影响:
- ETF 原始价格数据获取恢复正常
- 类型判断逻辑更准确
- 数据源接口签名统一
|
2026-05-23 21:46:01 +08:00 |
|
|
|
b7f7a756b6
|
refactor: SSH配置完全封装到UniversalDataFetcher
变更内容:
1. UniversalDataFetcher 新增方法:
- get_ssh_config_from_env(): 从环境变量读取 SSH 配置
- from_env(): 工厂方法,自动读取环境变量创建实例
- get_ssh_status(): 返回 SSH 状态信息字典
2. flask_server.py 简化:
- 移除 get_ssh_config() 函数(18行)
- 移除 ssh_config 全局变量
- get_fetcher() 使用 from_env()
- / 和 /health 路由使用 get_ssh_status()
架构改进:
- SSH 配置逻辑完全封装在 UniversalDataFetcher
- flask_server.py 只依赖 fetcher 接口
- 减少 24 行重复代码
|
2026-05-23 21:20:43 +08:00 |
|
|
|
0f4295a144
|
refactor(flask_server): 多项优化重构
优化内容:
1. fetch_with_adj → fetch(adj=adj)
- _fetch_full_data_cached 使用 fetch(adj=adj) 替代 fetch_with_adj
2. 加密货币分支添加 adj 参数
- fetch_data_with_ttl 中加密货币调用添加 adj='raw'
3. ETF 净值溢价率逻辑抽取
- 新增 build_premium_result() 函数
- get_ohlcv 和 get_etf_nav 使用该函数,减少 42 行重复代码
4. SSH 配置信息增强
- ssh_status 改为 ssh 对象,包含更多详细信息
- 添加 required_types(需要 SSH 的资产类型列表)
代码行数:减少约 40 行重复代码
|
2026-05-23 19:03:09 +08:00 |
|
|
|
67d67b1eea
|
refactor(universal_fetcher): SSH隧道按资产类型统一启动
定义 SSH_REQUIRED_TYPES 常量集合,在 fetch() 入口处统一启动隧道
改进:
- 新增 SSH_REQUIRED_TYPES 常量(港美股/加密货币需要 SSH)
- fetch() 入口统一启动隧道,移除各分支重复调用
- fetch_us_adj/fetch_hk_adj 简化为调用 fetch()
- fetch_batch 移除冗余的隧道启动
- 移除废弃的 _fetch_xxx 内部方法(减少 55 行)
SSH 调用次数:10次 → 3次(仅保留必要场景)
|
2026-05-23 18:53:26 +08:00 |
|
|
|
56f0cd60e7
|
fix(flask_api): 保留code列确保本地与线上数据结构一致
FlaskAPIDataSource.fetch() 原硬编码只选择 OHLCV 列,丢失 code 列
修改为动态判断:若 API 返回包含 code 列则保留
确保本地 UniversalDataFetcher 与线上 FlaskAPIDataSource 返回数据结构一致
|
2026-05-23 18:41:20 +08:00 |
|
|
|
7f2af6b470
|
refactor(flask_api): fetch添加adj参数,fetch_with_adj简化
FlaskAPIDataSource.fetch() 新增 adj 参数,fetch_with_adj() 简化
- FlaskAPIDataSource.fetch(adj='raw'): 请求参数包含 adj
- fetch_with_adj(): 简化为 return self.fetch(adj=adj)(减少 ~120行)
- flask_server.py: 缓存逻辑已支持 adj 参数,无需修改
|
2026-05-23 18:32:20 +08:00 |
|
|
|
c319fd42be
|
refactor(universal_fetcher): fetch添加adj参数,fetch_with_adj简化
UniversalDataFetcher.fetch() 新增 adj 参数,直接传递给底层
- fetch(adj='raw/qfq/hfq'): 统一入口,参数校验和路由
- fetch_with_adj(): 简化为 return self.fetch(adj=adj)
- 删除重复的 VALID_ADJ_BY_TYPE 定义和路由逻辑(~70行)
- VALID_ADJ_BY_TYPE 移到类级别作为静态配置
|
2026-05-23 18:32:10 +08:00 |
|
|
|
02dbc7bd7d
|
refactor(datasource): 底层fetch方法添加adj参数
TushareSource.fetch() 和 YFinanceSource.fetch() 新增 adj 参数支持 raw/qfq/hfq
- TushareSource.fetch(adj='raw'): 内部路由到 fetch_index/fetch_stock_adj/fetch_etf_adj
- YFinanceSource.fetch(adj='raw'): 内部路由到 fetch_adj() 或原始逻辑
- 添加 is_china_stock() 和 _is_etf_code() 方法用于资产类型判断
|
2026-05-23 18:32:00 +08:00 |
|
|
|
1148d3166c
|
refactor(datasource): 分层接口设计,移除HybridDataSource
架构改动:
- 移除 HybridDataSource(功能被 UniversalDataFetcher 覆盖)
- 新增分层接口设计:基础层 + 扩展层
基础层(统一接口):
- fetch(): 统一 OHLCV 接口,自动识别资产类型
- fetch_batch(): 批量获取
扩展层(资产类型特有):
- fetch_etf_adj(): A股 ETF 后复权价格
- fetch_us_adj(): 美股复权价格
- fetch_etf_with_nav(): ETF 价格 + 净值 + 溢价率
其他修改:
- YFinanceSource: 新增 fetch_adj() 方法
- strategy.py: 改用 UniversalDataFetcher 替代 HybridDataSource
- __init__.py: 移除 HybridDataSource 导出
|
2026-05-23 12:46:48 +08:00 |
|
|
|
209dd7fd83
|
refactor(tushare): 移除代理清除/恢复逻辑
Tushare是国内服务,不需要代理切换操作
移除内容:
- _clear_proxy 方法
- _restore_proxy 方法
- 所有方法中的代理清除和恢复调用
代码精简37行,保持原有功能不变
|
2026-05-23 11:55:02 +08:00 |
|
|
|
b066b23495
|
feat(tushare): 新增ETF后复权价格和交易日历获取方法
新增方法:
- fetch_etf_adj: 获取ETF后复权价格数据,消除份额拆分对收益率的影响
通过 fund_daily + fund_adj 手动计算后复权价格
fund_adj 单次限2000条,按5年分段请求
- fetch_trade_cal: 获取A股SSE官方交易日历
验证结果:
- 纳指ETF后复权正确识别2022-01-14拆分(复权因子5.0)
- 累计收益100.54%与纳指100指数一致
|
2026-05-23 11:51:32 +08:00 |
|
|
|
bed92027fc
|
fix(premium): 溢价率计算改用动态匹配原则
修复 _calculate_premium_series 方法,改为动态匹配净值日期:
原问题:
- 统一使用T-1净值规则导致A股/港股/商品ETF溢价率计算错误
- 如创业板ETF用T-1净值而非当天净值,溢价率从0.76%变成0.19%
修复方案:
- 优先使用当天净值(A股/港股/商品/债券/日本QDII)
- 当天净值不存在时使用T-1净值(美股QDII/欧洲QDII/原油QDII)
验证结果:
- 11只ETF全部验证通过,与集思录数据完全一致
|
2026-05-16 10:27:07 +08:00 |
|
|
|
13be83965b
|
fix(datasource): QDII溢价率计算修复净值日期滞后一天对齐
问题: 溢价率计算使用同一天收盘价+净值,但QDII净值T+1披露
修复: 将净值索引后移一天,T日收盘价配T-1日净值
参考: 集思录做法(价格日期配前一日净值)
验证数据(513100.SH):
- 2026-05-15: 收盘价2.100, 净值(5/14)2.0200, 溢价率3.96% ✓
|
2026-05-16 08:57:20 +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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|