回测数据与分析方案
数据格式
文件命名:
- BTC:
YYYY-MM-DD.jsonl(保留旧命名,向后兼容历史数据) - 其他币种:
YYYY-MM-DD-{sym}.jsonl(如2026-04-26-eth.jsonl、2026-04-26-sol.jsonl)
每行一条 JSON:
{"type":"tick","ts":1775195098289,"symbol":"btc","windowStart":1775194800,"diff":51.16,"upPct":100,"rem":2}
| 字段 | 含义 |
|---|---|
| ts | 时间戳(毫秒) |
| symbol | 币种(btc/eth/sol)。老数据无此字段时默认 btc |
| windowStart | 所属5分钟窗口的起始时间(秒) |
| diff | 参考价 - (priceToBeat - 偏移),正值=涨,负值=跌 |
| upPct | Polymarket 涨概率(0-100整数) |
| rem | 窗口剩余秒数 |
采样频率:每秒1条,每天约86400条,约4MB。
分析目标
找到 diff 和 upPct 之间的历史映射关系,当实际概率偏离历史均值时入场。
分析步骤
1. 建立 diff → 合理概率 映射
将 diff 按区间分桶(如每5一档:-60~-55, -55~-50, ..., 55~60),统计每个桶内 upPct 的中位数,得到"在某个 diff 水平下,市场通常给出的概率"。
import json, glob
import pandas as pd
ticks = []
for f in sorted(glob.glob('*.jsonl')):
for line in open(f):
row = json.loads(line)
if row.get('type') == 'tick':
ticks.append(row)
df = pd.DataFrame(ticks)
# 按 diff 分桶,rem 分段
df['diff_bin'] = (df['diff'] / 5).round() * 5
df['rem_bin'] = pd.cut(df['rem'], bins=[0, 30, 60, 120, 180, 300], labels=['0-30','30-60','60-120','120-180','180-300'])
# 每个 (diff_bin, rem_bin) 的概率中位数
mapping = df.groupby(['diff_bin', 'rem_bin'])['upPct'].agg(['median', 'mean', 'std', 'count'])
2. 计算偏差
# 对每条 tick,查找对应的合理概率
fair_prob = mapping.loc[(diff_bin, rem_bin), 'median']
bias = fair_prob - actual_upPct
# bias > 0:市场低估涨(买涨机会)
# bias < 0:市场高估涨(买跌机会)
3. 确定入场阈值
统计不同 bias 阈值下的入场次数和后续概率走势:
# 找出 bias > N 的时刻,看之后概率是否向合理概率回归
for threshold in [5, 8, 10, 12, 15]:
entries = df[df['bias'] > threshold]
# 看入场后 10s/30s/60s 概率变化
# 如果概率确实向 fair_prob 回归 → 该阈值可用
4. 考虑波动率
用 diff 序列的标准差衡量波动率:
# 每个窗口内 diff 的标准差
vol = df.groupby('windowStart')['diff'].std()
# 高波动 vs 低波动时,同样 diff 对应的概率分布是否不同
# 如果不同,映射关系需要加入波动率维度
5. 输出
- diff → 合理概率 的映射表(按 rem 分段)
- 最优入场偏差阈值
- 波动率是否需要作为额外维度
- 模拟入场后的概率回归速度和幅度
注意事项
- 数据至少收集 2-3 天再分析(需要覆盖不同时段和市场状态)
- diff 极端值(>80 或 <-80)样本可能很少,映射不可靠
- rem 对映射有影响:窗口早期(rem>180)概率波动大,晚期(rem<30)概率趋于收敛
- 分析脚本在 backtest-data/ 目录下运行