feat(sync): 优化日志格式和进度记录逻辑
This commit is contained in:
+10
@@ -7,6 +7,16 @@
|
|||||||
**历史可复现分析**:给定一个历史交易日,在当前目标股票池范围内重建该日的行情与估值状态;价格采用数据库中当前最新修订的前复权行情,不要求还原某次同步时的价格版本。
|
**历史可复现分析**:给定一个历史交易日,在当前目标股票池范围内重建该日的行情与估值状态;价格采用数据库中当前最新修订的前复权行情,不要求还原某次同步时的价格版本。
|
||||||
_Avoid_: 用当前市值回填历史、把当前目标股票池当作无幸存者偏差的长期回测宇宙
|
_Avoid_: 用当前市值回填历史、把当前目标股票池当作无幸存者偏差的长期回测宇宙
|
||||||
|
|
||||||
|
**选股策略**:一组针对明确目标交易日、依赖该日之前历史行情的选股规则;它产出可解释的选股信号,不等同于交易执行指令或收益承诺。
|
||||||
|
|
||||||
|
**知行 B1**:当前迁移中的知行选股策略名称;它按知行公式语义评估目标交易日,并包含七种可以独立命中的子信号。
|
||||||
|
|
||||||
|
**子信号**:选股公式中具有独立业务含义的命中分支;同一只股票在同一交易日可以同时命中多个子信号,不能因为存在合并条件而丢失分类信息。
|
||||||
|
|
||||||
|
**公式语义**:公式原文及已确认业务调整所表达的规则意图;当旧代码与公式意图冲突时,公式语义是迁移后的判断依据,旧代码只作为实现参考和差异证据。
|
||||||
|
|
||||||
|
**历史样本验证**:使用固定的历史行情样本和固定期望结果验证策略规则;它用于发现规则迁移偏差,不等同于回测收益评价。
|
||||||
|
|
||||||
## 市场数据
|
## 市场数据
|
||||||
|
|
||||||
**股票主数据**:描述证券标识及其在市场中的基础状态,例如代码、名称、交易所和上市状态。
|
**股票主数据**:描述证券标识及其在市场中的基础状态,例如代码、名称、交易所和上市状态。
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
status: accepted
|
||||||
|
---
|
||||||
|
|
||||||
|
# 选股策略以公式语义为准并独立保留子信号
|
||||||
|
|
||||||
|
知行选股策略迁移时,以通达信公式原文和已确认的业务调整作为规则语义来源,
|
||||||
|
旧项目 Python 实现只作为迁移参考与差异证据。原因是旧实现存在无法历史重放的
|
||||||
|
数据行为,也会在多个 XG 条件同时命中时只保留第一个分类;直接追求旧输出兼容
|
||||||
|
会把实现缺陷固化到新系统。
|
||||||
|
|
||||||
|
新策略使用 `zhixing_b1` 作为业务标识,并把七种子信号作为独立分类。同一股票、
|
||||||
|
同一交易日可以产生多条不同分类的信号;每条信号的稳定身份由股票、交易日、
|
||||||
|
策略标识和子信号分类共同确定。
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
- **完全兼容旧 Python 输出**:迁移成本较低,但会保留旧的首个分类截断和历史
|
||||||
|
数据前视风险。
|
||||||
|
- **只按公式返回一条合并信号**:实现简单,但会丢失子信号的解释性和后续统计
|
||||||
|
维度。
|
||||||
|
- **按公式语义计算并独立返回全部子信号**:需要增加分类结果和差异测试,但能
|
||||||
|
保持规则意图、解释能力和历史重放边界。
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- golden 验证需要同时记录命中分类集合和有意的旧实现差异。
|
||||||
|
- 后续信号持久化可以使用 `(ts_code, trade_date, strategy, category)` 作为唯一
|
||||||
|
键,但本 ADR 不决定具体数据库表或 HTTP 契约。
|
||||||
|
- 其他策略迁移时仍需逐一确认其公式来源与历史依赖,不能自动套用旧策略的输出
|
||||||
|
兼容规则。
|
||||||
@@ -425,8 +425,7 @@ class SyncMarketData:
|
|||||||
failure = self._failure("daily_basic", key, exc)
|
failure = self._failure("daily_basic", key, exc)
|
||||||
failures.append(failure)
|
failures.append(failure)
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"market_data_sync_item_failed batch_id=%s stage=daily_basic item=%s "
|
"market_data_sync_item_failed batch_id=%s stage=daily_basic item=%s error_type=%s",
|
||||||
"error_type=%s",
|
|
||||||
batch_id,
|
batch_id,
|
||||||
key,
|
key,
|
||||||
failure.error_type,
|
failure.error_type,
|
||||||
@@ -520,10 +519,16 @@ class SyncMarketData:
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Log bounded, secret-free progress for a batch stage."""
|
"""Log bounded, secret-free progress for a batch stage."""
|
||||||
|
|
||||||
if not force and total > _PROGRESS_LOG_INTERVAL and current not in {
|
if (
|
||||||
1,
|
not force
|
||||||
total,
|
and total > _PROGRESS_LOG_INTERVAL
|
||||||
} and current % _PROGRESS_LOG_INTERVAL != 0:
|
and current
|
||||||
|
not in {
|
||||||
|
1,
|
||||||
|
total,
|
||||||
|
}
|
||||||
|
and current % _PROGRESS_LOG_INTERVAL != 0
|
||||||
|
):
|
||||||
return
|
return
|
||||||
logger.info(
|
logger.info(
|
||||||
"market_data_sync_progress batch_id=%s stage=%s progress=%d/%d item=%s "
|
"market_data_sync_progress batch_id=%s stage=%s progress=%d/%d item=%s "
|
||||||
|
|||||||
@@ -190,8 +190,7 @@ def test_sync_logs_progress_for_initialize_and_daily_update(
|
|||||||
assert initialize.status == "success"
|
assert initialize.status == "success"
|
||||||
assert any("stage=daily_basic" in message for message in initialize_messages)
|
assert any("stage=daily_basic" in message for message in initialize_messages)
|
||||||
assert any(
|
assert any(
|
||||||
"stage=bar" in message and "progress=1/1" in message
|
"stage=bar" in message and "progress=1/1" in message for message in initialize_messages
|
||||||
for message in initialize_messages
|
|
||||||
)
|
)
|
||||||
|
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
|
|||||||
Reference in New Issue
Block a user