de04a8904b
三策略(聚宽py2→BulletTrade 0.9.2,BrokerFacade注入跨版本兼容): - momentum_timing 动量择时(牛熊分界+行业RPS+均线,切回10中证行业指数) - value_selection 价值精选(6条基本面过滤,切回沪深300) - small_cap 小市值(去IC对冲,切回000985中证全指) 框架: - runner_backtest 加 --strategy 分发(原硬编码all_weather) - provider 加 get_value_metrics(价值精选6条基本面,NOTICE_DATE治前视偏差) - 72单测全过(21+27+24) 修8个回测实测发现的真bug: - 01第⑥条EPS绝对值0.08~0.5与①大盘矛盾→6条交集恒空致全程空仓,按注释本意改净利润同比8~50% - 03原帖calRPS取数区间错(get_price start=end只取1天)→涨跌幅恒0 RPS失效;date.today()取真实今天非回测日 - 02 universe 000985不在constituent_unified→候选池空 VPS实测(短区间验证逻辑,非长期表现): 01价值+23%/03行业轮动+48%/02选出20只小盘 数据缺口(详见docs/research/joinquant_strategies/SUMMARY.md + data_gaps_fix_plan.md): - 三表"1/3损坏"误报已撤回(全扫5530文件/表0损坏,沪深95%+健康,仅北交所920xxx空,不做北交所) - 真实缺口: 行业成份股(G1已补)/000985(G2已补)/IC期货(02对冲去掉)/provider批量接口(G5待做,解锁长回测)
55 lines
2.2 KiB
Python
55 lines
2.2 KiB
Python
"""sanguo_portfolio:聚宽全天候轮动策略搬到 BulletTrade 框架。
|
|
|
|
子模块:
|
|
- ``factors`` 纯函数估值/ROIC 因子(无外部依赖)
|
|
- ``filters`` ST/停牌/科创北交/次新/涨跌停 过滤(无外部依赖)
|
|
- ``providers`` BaostockProvider(Mac/回测,历史成分股+TTM) /
|
|
SanguoMiniQmtProvider(VPS 实盘,继承 bullet-trade MiniQMTProvider)
|
|
- ``strategies`` AllWeatherStrategy(聚宽 post48819 翻译)
|
|
|
|
ENV GUARD(bullet-trade 0.9.2 坑):
|
|
- ``import bullet_trade`` 时 default provider 是 jqdata,会强制 ``import jqdatasdk``,
|
|
本地/服务器都没装(用户铁律不用 jqdata 付费)。
|
|
- 在任何 ``import bullet_trade`` **之前**设 ``DEFAULT_DATA_PROVIDER``,
|
|
default provider 切到非 jqdata provider,跳过 jqdatasdk。
|
|
- 实际数据走 ``set_data_provider(...)`` 覆盖。
|
|
"""
|
|
import os
|
|
import sys as _sys
|
|
from unittest.mock import MagicMock as _MagicMock
|
|
|
|
# ENV + mock 必须早于任何 bullet_trade import(providers 子模块会触发 bullet_trade):
|
|
# miniqmt → import xtquant(周六休市 miniQMT 客户端不响应→卡死)
|
|
# jqdata → import jqdatasdk(用户铁律不装→ModuleNotFoundError)
|
|
# 方案: ENV 设 jqdata + 预插 mock jqdatasdk(@jq.utils.assert_auth 装饰器 passthrough),
|
|
# 让 bullet_trade import 走 jqdata 分支拿 mock 不崩不卡;真实 provider 由
|
|
# set_data_provider 运行时注入覆盖(local/baostock/miniqmt)。
|
|
# 必须在包 __init__ 顶部(providers import 触发 bullet_trade 之前),runner_backtest 顶部太晚。
|
|
os.environ.setdefault("DEFAULT_DATA_PROVIDER", "jqdata")
|
|
if "jqdatasdk" not in _sys.modules:
|
|
_m = _MagicMock()
|
|
_m.utils.assert_auth = lambda func: func # jqdata.py 用 @jq.utils.assert_auth 装饰器
|
|
_sys.modules["jqdatasdk"] = _m
|
|
|
|
from . import factors, filters
|
|
from .providers import BaostockProvider, SanguoMiniQmtProvider
|
|
from .strategies import (
|
|
AllWeatherConfig,
|
|
AllWeatherStrategy,
|
|
BrokerFacade,
|
|
MomentumTimingConfig,
|
|
MomentumTimingStrategy,
|
|
)
|
|
|
|
__all__ = [
|
|
"factors",
|
|
"filters",
|
|
"BaostockProvider",
|
|
"SanguoMiniQmtProvider",
|
|
"AllWeatherStrategy",
|
|
"AllWeatherConfig",
|
|
"BrokerFacade",
|
|
"MomentumTimingStrategy",
|
|
"MomentumTimingConfig",
|
|
]
|