mirror of
https://ghfast.top/https://github.com/aeroxw/tick-stock-panel.git
synced 2026-09-12 17:54:15 +08:00
fix: 修复 4 个 P1 issue (#224/#232/#223/#215)
- #224 screener 自定义 SQL 的内存连接关闭 enable_external_access, 注入的 read_parquet/COPY 文件读写直接报错 (安全) - #232 指数展示缓存百分数口径在消费边界显式 /100: pipeline._bench_rt_pct_of 与 abnormal_moves._bench_rt_pct 两处, 修复 3/10/30 日偏离值被放大两个数量级 - #223 盘后管道按同日 daily/enriched 行数比较检测实时合并提前 创建的部分分区, 删除后由增量重算全市场补齐 - #215 _basic_filter_for_asset 扩展中和股票专属键 (price_min/max/boards), 并应用到回测/挖掘/策略扫描三个运行期入口, 修复 ETF 静默零信号
This commit is contained in:
@@ -497,20 +497,32 @@ _TURNOVER_FILTER_KEYS = (
|
||||
"turnover_max",
|
||||
)
|
||||
|
||||
# 股票专属的价格界与板块过滤对非股票资产同样不可满足 (#215):
|
||||
# ETF 单价普遍 0.5~7 元, 会被 price_min=3 整列误杀; boards 按股票代码
|
||||
# 前缀匹配, ETF 代码不属于任何板块 → 掩码全 False, 静默零信号。
|
||||
_STOCK_ONLY_FILTER_KEYS = (
|
||||
*_SHARE_CAP_FILTER_KEYS,
|
||||
*_TURNOVER_FILTER_KEYS,
|
||||
"price_min",
|
||||
"price_max",
|
||||
"boards",
|
||||
)
|
||||
|
||||
|
||||
def _basic_filter_for_asset(basic_filter: dict, asset_type: str) -> dict:
|
||||
"""非股票资产没有股本数据 (etf/index 维表只有 symbol/name), 市值、流通
|
||||
市值与换手率界对它们既无意义也不可满足: 依赖解析前先置 None, 避免解析出
|
||||
total_shares/float_shares/turnover_rate 字段需求导致矩阵加载直接失败。
|
||||
市值与换手率界对它们既无意义也不可满足: 依赖解析与运行期过滤前先置
|
||||
None。价格界 (price_min/max) 与板块过滤 (boards) 是股票专属口径, 对
|
||||
ETF 同样不可满足, 一并中和, 否则入场候选在运行期被静默清零 (#215)。
|
||||
|
||||
运行期过滤无需同步修改 —— polars 侧有列守卫 (engine._basic_filter_expr),
|
||||
矩阵侧 _optional_field 对缺失字段返回全 NaN 且 _apply_bound 跳过全 NaN
|
||||
界, 二者对缺失股本/换手率列本就降级为 no-op。
|
||||
置 None 后: 依赖解析不再产出 total_shares/float_shares/turnover_rate
|
||||
需求; polars 侧有列守卫 (engine._basic_filter_expr), 矩阵侧
|
||||
_optional_field 对缺失字段返回全 NaN 且 _apply_bound 跳过全 NaN 界。
|
||||
"""
|
||||
if asset_type == "stock" or not basic_filter:
|
||||
return basic_filter
|
||||
sanitized = dict(basic_filter)
|
||||
for key in (*_SHARE_CAP_FILTER_KEYS, *_TURNOVER_FILTER_KEYS):
|
||||
for key in _STOCK_ONLY_FILTER_KEYS:
|
||||
sanitized[key] = None
|
||||
return sanitized
|
||||
|
||||
@@ -844,7 +856,11 @@ class StrategyBacktestService:
|
||||
)
|
||||
|
||||
overrides = first.overrides or {}
|
||||
basic_filter = self._effective_basic_filter(strategy, overrides)
|
||||
# 运行期过滤用的也是同一份 basic_filter: 在入口处按资产类型中和,
|
||||
# 否则 boards/price_min 会在掩码阶段静默清零 ETF 候选 (#215)
|
||||
basic_filter = _basic_filter_for_asset(
|
||||
self._effective_basic_filter(strategy, overrides), first.asset_type
|
||||
)
|
||||
entry_signals = self._effective_signals(overrides, "entry_signals", strategy.entry_signals)
|
||||
exit_signals = self._effective_signals(overrides, "exit_signals", strategy.exit_signals)
|
||||
resolver = StrategyDependencyResolver()
|
||||
@@ -1021,7 +1037,10 @@ class StrategyBacktestService:
|
||||
|
||||
params = self._normalize_params(config.params or {}, s)
|
||||
overrides = config.overrides or {}
|
||||
basic_filter = self._effective_basic_filter(s, overrides)
|
||||
# 同回测 run 路径: 挖掘运行期也要按资产类型中和股票专属过滤键 (#215)
|
||||
basic_filter = _basic_filter_for_asset(
|
||||
self._effective_basic_filter(s, overrides), config.asset_type
|
||||
)
|
||||
entry_signals = self._effective_signals(overrides, "entry_signals", s.entry_signals)
|
||||
exit_signals = self._effective_signals(overrides, "exit_signals", s.exit_signals)
|
||||
if config.exit_fill == "signal_next_minute":
|
||||
|
||||
Reference in New Issue
Block a user