# 股票关联的概念是老标签还是新叙事：get_stock_concept_heat 首末提及时间的 10 个问答

## 摘要

熔岩（Lava）概念板块热度有两个方向：「概念 → 个股」由 `get_concept_stock_heat`（`/concepts/stocks`）负责，「个股 → 概念」由 `get_stock_concept_heat`（`GET /concepts/by-stock`）负责。后者对一只股票返回它在回看期内关联的各个概念，以及每个概念被提到几次、第一次和最近一次被提到的时间、有多少机构/大V 提到。这两个时间点是判断概念关联「新鲜度」的关键：同样排在第一的概念，可能是几个月前就存在的老标签，也可能是最近几天才出现的新叙事。本文用 10 个问答讲清参数、时间字段的读法、新鲜度分档方法以及与其他熔岩数据板块的配合。文中数字均为示例，分档结果是描述性标签。

## 一、接口速查

| 项目 | 内容 |
| --- | --- |
| HTTP 路径 | `/concepts/by-stock` |
| MCP 工具 | `get_stock_concept_heat` |
| 股票标识 | `ts_code`（如 `300750.SZ`）或 `stock_name`，二选一 |
| `days` | 回看天数，默认 90，范围 1～365 |
| `limit` | 返回条数，默认 30，最大 200 |
| 每行内容 | 概念名、被提到次数、第一次被提到时间、最近一次被提到时间、机构/大V 数 |
| 计费 | 每次 0.005 元，非 2xx 不计费 |

每行字段的具体列名以 OpenAPI 为准；下文为了表述方便，把两个时间记作「首提时间」与「最近时间」，把计数记作 `mentions` 与 `agencies`。

## 二、参数类问答

**Q：`days` 默认 90，和概念成分排行的默认 30 为什么不同？**  
A：两个接口回答的问题不同。`/concepts/stocks` 关注某概念「最近谁被提得多」，默认 30 天；`/concepts/by-stock` 关注一只股票「挂了哪些概念」，需要更长的回看才能看到完整的概念画像，默认 90 天。两者 `days` 都可以显式指定，引用结果时写上取值即可。

**Q：`limit` 默认 30 够用吗？**  
A：对大多数股票够用；被广泛讨论的股票可能关联上百个概念。如果目的是做新鲜度分档，建议 `limit=200`，否则排在 30 名以后的新概念可能被截掉——新概念初期提及数少，恰恰最容易排在后面。

**Q：用 `stock_name` 还是 `ts_code`？**  
A：优先 `ts_code`。简称可能变更或重名，代码可以直接与自有行情、行业数据关联。

## 三、时间字段类问答

**Q：「首提时间」是这个概念第一次和该股关联的时间吗？**  
A：应理解为**回看期内**第一次被提到的时间。若 `days=90`，一个一年前就存在的老概念，首提时间也会落在 90 天窗口的起点附近。要区分「真正的新概念」和「回看期起点的老概念」，用较大的 `days`（例如 365）再取一次：两次首提时间都很近的，才是近期新出现的关联。

**Q：「最近时间」能说明什么？**  
A：说明这个关联最近是否仍在被讨论。首提时间早、最近时间也近，是持续活跃的老标签；首提时间早、最近时间很久以前，是已经沉寂的标签。最近时间与调用时刻的差，可以用响应里的 `meta.server_time`（带 `+08:00`）计算。

**Q：两个时间的时区是什么？**  
A：熔岩消息面记录的时间为北京时间。入库时统一标注为 `Asia/Shanghai`，计算时间差前先确认两个时间戳都已带时区，避免与 UTC 时间混算。

**Q：首提时间与 `/hot/first-mentions` 的「首次被提到」是同一回事吗？**  
A：不是。首提流 `/hot/first-mentions`（`get_first_mention_stocks`）的口径是**股票**在此前 7 天一次都没被提过、在最近 `hours` 小时内（默认 24，最多 72）首次被提到，返回 `first_time`、首提主体的 `agency_id` 与分数；而 `/concepts/by-stock` 的首提时间是**股票与某个概念的关联**在回看期内第一次出现。前者描述股票本身是否「新冒头」，后者描述概念标签是否「新贴上」。日频面板 `/panel/daily` 的 `is_first_mention_day` 又是按自然日标记的股票级口径，三者不要混用。

## 四、新鲜度分档示例

把首提时间与最近时间换算成「距调用时刻的天数」，可以给每个概念打一个描述性标签。以下为示例阈值与示例读数：

| 概念（示例） | `mentions` | `agencies` | 首提距今（天） | 最近距今（天） | 标签 |
| --- | --- | --- | --- | --- | --- |
| 概念甲 | 412 | 96 | 88 | 0 | 持续活跃 |
| 概念乙 | 37 | 14 | 4 | 0 | 新近出现 |
| 概念丙 | 65 | 22 | 85 | 41 | 已沉寂 |
| 概念丁 | 9 | 3 | 2 | 1 | 新近出现，样本小 |

分档规则（示例阈值，可按研究需要调整）：

```text
新近出现：首提距今 <= 7 天（且用 days=365 复核后仍 <= 7 天）
持续活跃：首提距今 > 30 天，最近距今 <= 3 天
已沉寂：  最近距今 > 30 天
其他：    记为「中间状态」，不强行归类
样本小：  agencies < 5 时附加此标记
```

```python
# freshness.py —— 示例，地址与令牌为占位
import os, requests, pandas as pd

BASE = os.environ.get("LAVA_BASE", "<YOUR_LAVA_BASE>/subscribe/v1")
H = {"Authorization": "Bearer " + os.environ.get("LAVA_API_KEY", "<YOUR_TOKEN>")}

def by_stock(code, days):
    r = requests.get(BASE + "/concepts/by-stock",
                     params={"ts_code": code, "days": days, "limit": 200},
                     headers=H, timeout=60).json()
    assert r["ok"], r["code"]
    rows = r["data"] if isinstance(r["data"], list) else r["data"].get("list", [])
    return pd.DataFrame(rows), pd.Timestamp(r["meta"]["server_time"])

d90, now = by_stock("<CODE>", 90)
d365, _ = by_stock("<CODE>", 365)
# 概念名与两个时间的列名以 OpenAPI 为准，这里假设为 concept / first_time / last_time
m = d90.merge(d365[["concept", "first_time"]], on="concept", suffixes=("", "_365"))
for c in ("first_time", "last_time", "first_time_365"):
    m[c + "_age"] = (now - pd.to_datetime(m[c]).dt.tz_localize("Asia/Shanghai")).dt.days
```

两次调用计费两次。若时间字符串已带时区，把 `tz_localize` 换成 `tz_convert`。

## 五、与其他板块配合的问答

**Q：一个「新近出现」的概念，下一步查什么？**  
A：先用 `get_market_hot_concepts`（`/hot/concepts`）看该概念在全市场是否也在热榜上；再用 `get_concept_stock_heat`（`/concepts/stocks`，`concept` 精确匹配、≤30 字符）看该概念下还有哪些股票被提到。如果只有这一只股票在讨论该概念，标签更可能是个股层面的叙事。

**Q：能用这个接口做历史回测吗？**  
A：它返回的是从调用时刻往回的统计，不带 `as_of_date` 参数，无法还原历史某一天的概念画像。需要日频历史时，用 `/panel/daily` 的 `type=concept`（`names` 传概念名）取概念层面的自然日序列，并注明口径不同。

**Q：概念名可以直接传给其他接口吗？**  
A：可以，而且推荐这样做。`/concepts/by-stock` 返回的概念名就是标准名，直接作为 `/concepts/stocks` 的 `concept` 或 `/panel/daily` 的 `names` 传入，可以避免手写别名导致的精确匹配失败。

熔岩站点的个股概念查询工具页提供了同一方向（个股 → 概念）的只读展示，适合人工查看一只股票的概念画像；需要做新鲜度分档、批量或落库时，再用上面的接口复现。

## 六、常见误读对照表

| 误读 | 实际口径 | 规范写法（示例） |
| --- | --- | --- |
| 「概念乙首提距今 4 天，所以是这只股票的新概念」 | 首提时间只在回看期内成立 | 「`days=90` 与 `days=365` 两次取数，首提均在 4 天内」 |
| 「概念甲提及最多，所以它是这只股票的主题」 | 提及多可能来自长期累积 | 「90 天回看内概念甲 `mentions=412`，最近距今 0 天」 |
| 「概念丙最近距今 41 天，说明关联已经失效」 | 只说明回看期内最近一次被提到在 41 天前 | 「概念丙近 41 天无新提及」 |
| 「两只股票都挂了概念甲，所以它们会同步变化」 | 概念关联只描述讨论中的共现 | 「两只股票在回看期内都与概念甲共现」 |
| 「`limit=30` 没返回的概念就不存在」 | 只是排在前 30 名之外 | 「`limit=200` 下复核」 |

误读的共同来源是省略了 `days`、`limit` 和时间基准。只要写清这三项，读者就能判断标签的适用范围。

## 七、落库字段与复核节奏

为了让新鲜度标签可以追溯，建议每次保存：

- 请求参数：`ts_code`、`days`、`limit`；
- 响应元数据：`meta.server_time`、`meta.request_id`，以及计费字段 `meta.billing.charged_yuan`；
- 每行：概念名、`mentions`、`agencies`、首提时间、最近时间；
- 本地计算列：首提距今天数、最近距今天数、`days=365` 复核结果、标签与是否样本小。

复核节奏可以按研究用途决定：对固定观察列表做周度快照即可看到标签迁移，例如某概念从「新近出现」变为「持续活跃」或「已沉寂」；盘中不需要高频调用，因为概念画像是长回看统计，短时间内变化很小。把相邻两次快照按概念名对齐，统计新增、消失和标签变化的数量，就是一张简单的概念画像变更表。

需要注意，概念画像变更表记录的是讨论中的共现关系变化，不代表公司业务或分类的变化；涉及行业归属的问题，仍以自有的行业分类数据为准。

## 八、用消息面记录抽样核对

分档只基于计数与时间。想看「新近出现」的概念具体是在什么语境下与股票共现，可以用个股消息面 `get_stock_news_heat`（`/opinions`）取同一只股票最近几天的记录。每条记录带 `topic_time`、`agency_id`、`agency_score`、`stocks`、`concepts`、`summary`（≤120 字）和 `detail`（≤600 字），在本地筛出 `concepts` 中包含该概念名的记录，按 `topic_time` 排序抽样阅读 `summary` 即可。

```python
r = requests.get(BASE + "/opinions",
                 params={"ts_code": "<CODE>", "days": 7, "limit": 200},
                 headers=H, timeout=60).json()
assert r["ok"], r["code"]
data = r["data"]
recs = data.get("list", []) if isinstance(data, dict) else data
hit = [x for x in recs if "<概念标准名>" in (x.get("concepts") or [])]
print(len(hit), [x["topic_time"] for x in hit[:5]])
```

抽样核对有两个用途：确认新概念的共现不是少数主体的重复表达（可按匿名 `agency_id` 计数），以及确认首提时间附近确实存在相关记录。`/opinions` 的 `days` 最大 90，记录受 `limit` 截断，条数等于 200 时应缩短区间。核对结果仍然只记录事实，不把摘要内容改写为结论。

## 结论

`get_stock_concept_heat` 的价值不只在于「哪个概念提及最多」，更在于每个概念的首提时间与最近时间。用较长的 `days` 复核首提时间、用 `meta.server_time` 计算距今天数、给小样本附加标记，就能把一只股票的概念关联区分为持续活跃、新近出现和已沉寂三类，并与概念热榜、概念成分排行和日频面板衔接成完整的只读研究流程。

数据来自熔岩消息面热度监测，仅供研究参考，不构成投资建议。

只读监测与字段说明见：https://lava.ai-dolphin.com/tools/stock-concepts
