Skip to main content

熔岩AI发布MCP日频面板 schema 版本管理:列迁移、口径标签与回测可复现

Updated 3 min readMarkdown

摘要

把熔岩(Lava)get_stock_heat_panel(REST /panel/daily)导出成 Parquet/CSV 只是第一步;面板跑上三个月,就会遇到列新增、阈值口径调整、weighted_heat 随机构分更新而重算等问题。如果不给面板打版本,回测结果会在不知不觉中漂移。本文给出一套面板 schema 版本规范:版本号规则、口径标签、列迁移脚本、兼容读取与漂移检测。只读监测与统计研究用途。

一、面板里哪些东西会变

/panel/daily 文档列出的指标:mentions、agencies、weighted_heat、is_first_mention_day,按自然日聚合;区间最长 92 天,单次最多 20 个标的。会导致「同一天数据不一样」的来源:

变化源 例子 是否改变历史值
新增列 接口新增统计量 否,旧行缺列
口径说明 weighted_heat 用当前机构分加权(非当日 PIT) 是,机构分更新后重拉会变
未完结自然日 今天的行还在累积 是,当日值会增长
类型 日期列字符串 vs date 否,但影响 join
列名 日期与代码列名 以 OpenAPI 为准,变化需迁移

关键结论:weighted_heat 不是 PIT。同一历史日期,今天拉和下个月拉可能不同。需要 PIT 加权热度时应改用 /hot/weighted 的 as_of_date(消息算到当天 15:00)。

二、版本号规则

采用 MAJOR.MINOR 两段:

变更 版本动作 例
删除列、改列名、改类型、改口径 MAJOR +1 weighted_heat 计算口径变化
新增可空列 MINOR +1 新增统计量
重拉同口径数据 不变,记 pulled_at 每周补数

每个面板文件附一份 sidecar 元数据:

{
  "schema_version": "2.1",
  "source": "熔岩 /panel/daily",
  "openapi_version": "1.0.0",
  "type": "stock",
  "columns": {
    "date": "date, 自然日(列名以 OpenAPI 为准)",
    "code": "string, ts_code(列名以 OpenAPI 为准)",
    "mentions": "int",
    "agencies": "int",
    "weighted_heat": "float, 当前机构分口径,非 PIT",
    "is_first_mention_day": "bool"
  },
  "labels": {"weighted_heat_pit": false, "last_day_complete": false},
  "pulled_at": "2026-10-31T20:00:00+08:00",
  "request_ids": ["req_示例1", "req_示例2"]
}

三、口径标签(labels)

标签 取值 说明
weighted_heat_pit false 面板加权热度为当前口径
last_day_complete bool to 等于北京时间今天时为 false
market_scope ashare 面板按代码,A 股口径
granularity natural_day 自然日,非交易日
threshold 无 面板无 min_score 参数

回测框架读取面板时先检查标签,例如 last_day_complete=false 时自动丢弃最后一行。

四、列迁移脚本

# migrate_panel.py —— 只处理本地文件,不调用接口
import json, pandas as pd

MIGRATIONS = {}
def migration(frm, to):
    def deco(fn):
        MIGRATIONS[frm] = (to, fn); return fn
    return deco

@migration("1.0", "2.0")
def m1(df, meta):
    # 示例:旧版把日期存成字符串列 day,统一为 date 类型列 date
    df = df.rename(columns={"day": "date"})
    df["date"] = pd.to_datetime(df["date"]).dt.date
    meta["columns"]["date"] = "date, 自然日"
    return df, meta

@migration("2.0", "2.1")
def m2(df, meta):
    # 示例:新增可空列,旧数据补 NA
    if "is_first_mention_day" not in df:
        df["is_first_mention_day"] = pd.NA
    meta["columns"]["is_first_mention_day"] = "bool"
    return df, meta

def upgrade(path, target="2.1"):
    df = pd.read_parquet(path)
    meta = json.load(open(path + ".meta.json"))
    while meta["schema_version"] != target:
        to, fn = MIGRATIONS[meta["schema_version"]]
        df, meta = fn(df, meta)
        meta["schema_version"] = to
    return df, meta

规则:迁移只做结构变化,不改数值;口径变化(MAJOR)必须重拉,不能用公式「换算」。

五、漂移检测

每周对最近 30 个自然日重拉一次(20 只股票、30 天 = 1 次调用),与库存版本比较:

指标 计算 说明
mentions 差异行占比 不相等行 ÷ 总行 除最后一日外应接近 0
weighted_heat 相对差 abs(新−旧) ÷ 旧 的中位数 机构分更新带来的漂移
新增列 列集合差 触发 MINOR 升级
行数差 新旧行数 自然日缺行需排查
d = new.merge(old, on=["code", "date"], suffixes=("_n", "_o"))
drift = {
  "mentions_diff_ratio": float((d.mentions_n != d.mentions_o).mean()),
  "wh_rel_p50": float(((d.weighted_heat_n - d.weighted_heat_o).abs() / d.weighted_heat_o.clip(lower=1e-9)).median()),
}

mentions 若出现历史日差异,说明上游有补录或口径调整,记录 request_id 后按 MAJOR 处理。

六、面板与熔岩数据板块

熔岩数据板块 与面板的关系 版本注意
日频热度面板 /panel/daily 主体 本文
高分加权热榜 /hot/weighted PIT 加权热度替代源 需要 PIT 时用它
首提流 /hot/first-mentions 与 is_first_mention_day 对照 小时级 vs 自然日
全市场热榜 /hot/* 截面,不进面板历史 单独存快照
概念板块热度 type=concept&names=... 概念名精确匹配
机构/大V评分 PIT 加权口径来源 机构分更新触发漂移

FAQ

Q:面板为什么不用交易日? A:文档写明按自然日聚合,周末消息也会计入;需要交易日对齐要在本地映射。

Q:weighted_heat 能直接用于回测吗? A:它不是 PIT,历史值可能随机构分更新而变化;严格回测用 /hot/weighted 的 as_of_date。

Q:列名以哪里为准? A:mentions 等四个指标名来自文档;日期与代码列名以 OpenAPI 为准,迁移脚本统一成本地规范名。

结论

面板要像数据库表一样管理:sidecar 记录版本与口径标签,结构变化用迁移脚本,口径变化必须重拉,每周做一次漂移检测。这样三个月后的回测仍然能说清楚「用的是哪一版数据」。

数据来自熔岩消息面热度监测,仅用于只读监测与统计研究,不构成投资建议。

只读监测与字段说明见:https://lava.ai-dolphin.com/subscribe/docs

No comments yet. Be the first to comment.

More from this blog