3.3 数据统一与质检


3.3 数据统一与质检

本节摘要:多源数据的默认状态是「互相看不懂」:同一时刻在不同源里差着时区、同一价格差着精度、同一交易对差着写法。本节先做三重归一:时区(对内一律 UTC 存储,展示层再本地化)、精度(价格与数量按品种规则取整,浮点比较禁用等号)、符号(建立规范名到各源方言的映射表);再处理缺口:用时间步进扫描检测缺口,用 REST 回填历史区间,回填不了的要留「已知缺口」标记而不是假装连续;然后给出一张十项质检清单作为数据放行的验收标准;最后用一个可运行的缺口扫描脚本把检测落地。本节是数据层的出口:从这里走出去的数据,才被允许进入第 4 章的指标与第 5 章的策略。

学习目标

  • 落地三重归一约定:UTC 存储、精度规则、符号映射表。
  • 用步进扫描脚本检测任意 K 线序列的缺口。
  • 说明回填与「已知缺口」标记的处理边界。
  • 用十项清单对一份数据做放行验收。

一、三重归一

维度 不统一的样子 归一约定
时区 源 A 给 UTC 时间戳,源 B 给带偏移的本地时间,源 C 给字符串 对内一律 UTC(毫秒时间戳或等价形式);展示层再转本地时区
精度 同一价格 42000.5 与 42000.50000;浮点累加出 0.30000000000000004 按品种规则统一小数位;比较用容差或整数化最小变动单位
符号 BTC-USDT、BTC/USDT、BTCUSDT 并存 建立规范名(自选一种)到各源方言的映射表,落库只用规范名
# symbol_map.py —— 符号与精度归一示意(教学示意,映射表以实际数据源为准) CANONICAL = "BTC/USDT" # 规范名:自选一种,全库唯一 DIALECTS = { "exchange_a": "BTC-USDT", "exchange_b": "BTCUSDT", "exchange_c": "btc/usdt", } TO_CANONICAL = {v.lower(): CANONICAL for v in DIALECTS.values()} TICK_SIZE = 0.5 # 最小变动单位(示意值) def to_canonical(raw: str) -> str: key = raw.strip().lower().replace("_", "-").replace("/", "-") return TO_CANONICAL.get(key, TO_CANONICAL.get(raw.strip().lower(), raw)) def round_price(price: float) -> float: return round(round(price / TICK_SIZE) * TICK_SIZE, 2) if __name__ == "__main__": print(to_canonical("BTCUSDT")) # BTC/USDT print(round_price(42000.37)) # 42000.5(按示意最小变动单位取整) ​

时区是三重里最容易埋雷的:一次「差八小时」能让两套策略回测结果天差地别。约定要硬:入库前转换、库内无本地时间、出库展示时才本地化——三处任何一处走捷径,前面两处就白做。

二、缺口检测与回填

缺口来自断流、维护窗口、上线晚于回测起点。检测思路是步进扫描:相邻两根 K 线的时间差超过一个步长,中间就缺了若干根。

# gap_scan.py —— K 线缺口检测(教学示意,可独立运行) from datetime import datetime, timedelta def scan_gaps(bars, step_minutes): """bars: [(datetime, close), ...] 升序;返回缺口描述列表""" step = timedelta(minutes=step_minutes) gaps = [] for prev, curr in zip(bars, bars[1:]): if curr[0] - prev[0] > step: missing = int((curr[0] - prev[0]) / step) - 1 gaps.append({"after": prev[0], "until": curr[0], "missing": missing}) return gaps if __name__ == "__main__": demo = [(datetime(2026, 1, 1, 0, 0), 100.0), (datetime(2026, 1, 1, 0, 5), 100.2), (datetime(2026, 1, 1, 0, 30), 101.0)] for g in scan_gaps(demo, step_minutes=5): print(g["after"], "→", g["until"], "缺", g["missing"], "根") # 期望输出:缺 4 根(00:05 与 00:30 之间) ​

回填的边界要认清:能补的用 REST 补(按 3.1 节的通道接力),补不了的必须显式标记「已知缺口」,让下游指标与回测自行决定跳过或告警——绝不允许用插值悄悄抹平缺口,那等于伪造历史。补回来的数据还要过一遍「与既有邻接数据无矛盾」的检查(闭合价衔接、量纲一致)。

三、十项质检清单

序 检查项 达标标准
1 时区统一 全库时间戳可追溯到 UTC 口径
2 符号规范 无方言符号入库,映射表覆盖在用数据源
3 精度一致 价格、数量符合品种规则,无浮点尾影
4 网格完整 步进扫描无未标记缺口
5 缺口处置 已回填或已标记,无插值抹平
6 值域合理 价格大于零、量非负、无穿越上下限的异常值
7 重复检测 同键(符号+时间戳)无重复行
8 闭合价衔接 相邻 K 线开收价符合市场可解释关系
9 源间抽核 多源重合区间抽样对比,偏差在容差内
10 新鲜度 最新数据时间距当前在预期延迟内

清单用法:新接入一个数据源、一次大范围回填、一次异常重启之后,各跑一遍;把结果留档。第 10 项的新鲜度阈值按数据类型设定(K 线分钟级、宏观按发布节奏)。

四、数据层的出口纪律

多源数据 ──▶ 三重归一 ──▶ 落库 ──▶ 十项清单 ──▶ 放行 │ │ └── 不合格:修复或标记缺口,绝不放行带病数据 ──┘ ​

这套流程的精神与《量化投资方法论》第 15 章《批判性思维与研究纪律》一脉相承:对数据的每一次纵容,都会在回测报告里连本带利地还回来。质检不是数据层的收尾杂务,而是研究可信度的地基——第 6 章的每一个绩效数字,可信度上限都在这里被决定。

本节要点回顾

  • 三重归一:UTC 存储(三处不留捷径)、精度按品种规则、符号映射表落库。
  • 缺口处理边界:REST 能补则补,补不了则显式标记,插值抹平是伪造历史。
  • 步进扫描十行代码即可检测缺口,重复与值域检查同样便宜且必要。
  • 十项清单是放行标准,三类触发点(新源、回填、异常重启)各跑一遍。
  • 数据质量决定回测可信度上限,这是数据层给全书的交代。

数据层至此闭环。接下来让合格的数据开口说话——第 4 章把行情翻译成指标:overlay 叠加线、marker 事件点、band 区间带,三种形态覆盖你见过的绝大多数技术指标。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U