pi-fin-prism
v0.1.0
Published
Unified, natively async financial data interface over 同花顺/万得/妙想 for pi — every answer carries source/tier/ts provenance; AI driven by verified data, not noise.
Maintainers
Readme
pi-fin-prism
由核实过的数据驱动 AI,而非噪音。 AI driven by verified data, not noise.
pi-fin-prism 是一个 pi 扩展,为 LLM 提供统一、原生异步的金融数据接口,覆盖三家中国市场数据商(同花顺 / 万得 / 妙想),以三个自定义工具、一个按需技能(skill)和两个研究子代理的形式暴露给 agent。每一个回答都携带溯源信封——source/tier/ts 永不剥离——并用 finVerify 双源对账拦截关键数据的分歧。
- 同花顺 (ths) — 最快(~0.1s)。A 股行情/财务/估值;市场情绪(涨停/连板/龙虎榜/热榜/异动);交易日历;全市场 parquet dump。
- 万得 (wind) — 最全面。港股/美股行情、分钟 K 线、技术面与风险指标、债券、资金流、EDB 宏观(含单位元数据)、公告/新闻 RAG。免费配额(1000 积分/天 ≈ 1 积分/请求),耗尽自动
Disable<exceed upper limit>。 - 妙想 (mx) — NL 优先。研报全文(评级/目标价)、一致预期、可解释选股、不受限的财务历史。慢(1.4–4.4s)但免费。
每个回答都是一个信封:{ data, source, tier, ts, unit?, magnitude?, caliber?, warnings? }。
目录
安装
pi install npm:pi-fin-prism # 全局(用户设置:~/.pi/agent/settings.json)
pi install git:github.com/v587d/[email protected] # 或 GitHub 源
pi install -l ./ # 项目级(.pi/settings.json)— 可与团队共享开发期加载(仅当前运行):
pi -e ./src/extension/index.tsAPI 密钥
密钥优先从环境变量读取,其次读全局配置文件:
export FINPRISM_THS_API_KEY=...
export FINPRISM_WIND_API_KEY=...
export FINPRISM_MX_API_KEY=...// ~/.pi/agent/fin-prism.json
{ "ths": "...", "wind": "...", "mx": "..." }密钥绝不进入项目文件或会话内容;/fin status 只显示掩码尾部。缺少密钥的 vendor 会被路由跳过并给出降级提示——不是错误。
工具
| 工具 | 用途 |
|---|---|
| finQuery | 统一查询:indicator(17 个域)+ 宽松 params。路由器按链选择数据源(默认 ths → wind → mx,按延迟排序),瞬态错误指数退避重试,自动 failover。 |
| finJob | 异步长任务(全市场 dump):start 立即返回 jobId——绝不阻塞;status/wait 轮询(含 TTL)。 |
| finVerify | 关键指标(quote/valuation/kline)的同时点双源对账。标记分歧——由 LLM 裁决,不做自动修复。 |
示例:
finQuery(indicator="valuation", params={ code: "600519.SH" })
→ { data: { securities: [{ pe: { value: 20.36, unit: "倍" }, ... }] },
source: "ths", tier: "free", ts: { iso: "2026-08-11T01:30:00Z", tz: "+08:00" },
caliber: "TTM" }技能(Skill)
fin-prism —— 先读 SKILL.md(指标字典与参数约定),再调 finQuery(/skill:fin-prism 也可按需加载):
skills/fin-prism/SKILL.md
references/indicator-dictionary.md # 指标 + 参数 + 路由表(与 router.ts ROUTES 同步)
references/vendor-quirks.md # 17 条实测 vendor 经验(429、NER 噪音、EDB 两段式、ths 开区间、EDB 新形状…)
references/envelope.md # 溯源规则、tier/caliber 语义
references/async-jobs.md # finJob 协议、TTL、完成通知子代理
| 代理 | 角色 |
|---|---|
| fin-research | 主动研究:并行 finQuery 多源挖掘、failover 穷尽、finVerify 交叉核对、每个事实带溯源、显式不确定性 → research.md |
| fin-reviewer | 对抗式质检:审计溯源完整性、caliber/时点一致性、主动双源对账并给出可接受性意见、幻觉风险 → review.md。只读,不改。 |
编排由父代理负责:研究 → 评审 → 裁决(workflowScript 自动化是未来里程碑)。
命令
/fin status— 掩码密钥尾部、vendor 可用性、已注册的 fin 工具/fin verify-contracts— 同花顺端点与 vendorllms.txt的漂移检查(需网络;对 docs 省略/api前缀的端点做别名匹配)/fin <查询>— 直接提问,转发给 agent(读取技能 → 调 finQuery/finVerify)
开发
npm test # vitest(基于录制的夹具,无实时网络)
npm run typecheck # tsc --noEmit(严格模式)
npm run record:fixtures -- --vendor ths|wind|mx # 仅开发期:录制真实响应为脱敏夹具(真实密钥,绝不进 CI)
npm run smoke -- --vendor ths|wind|mx # 三个样例标的的实机冒烟- 核心(
src/core/)为纯 TypeScript,零 pi 依赖,可独立单测。 src/extension/是唯一允许 import@earendil-works/*的地方。- 所有 vendor 调用都贯穿
AbortSignal(Esc 可中断飞行中的查询)。 - 测试绝不访问网络——vendor 响应只录制一次为脱敏夹具。
设计原则
- 溯源不变量 —
source/tier/ts永不剥离;unit/magnitude永不丢失(亿元/元、股/手的混淆是经典故障模式)。 - 只归一化原语 — 证券身份、时间(ISO-8601 + 时区标签)、数字(原值 + 单位标签)、枚举词汇。其余全部原样透传;caliber(复权/TTM/MRQ/行业分类)只打标签,绝不换算。
- 数据驱动的路由 — 默认链 ths → wind → mx(延迟序);独有能力指标钉死唯一源;vendor 可用性门控(缺密钥/配额耗尽 →
Disable<reason>,路由跳过并记录降级)。 - 长任务绝不阻塞 — dump 立即返回
jobId;完成时推送带 TTL 提示的跟进消息(URL 不进入会话上下文)。
仓库结构
src/core/ 纯 TS,零 pi 依赖
vendors/{ths,wind,mx}.ts per-vendor 适配器(鉴权、参数翻译、错误映射)
router.ts 路由表 + failover + 指数退避 + vendor 门控
vendor-state.ts 可用性门控(Disable<unset | exceed upper limit>)
jobs.ts 异步任务注册表(jobId、TTL)
envelope.ts / normalize.ts / schema.ts 信封构建、4 原语、Typebox schema
src/extension/ pi 外壳:index.ts(finQuery/finJob/finVerify)、commands.ts(/fin)、clients.ts、verify.ts
skills/fin-prism/ SKILL.md + 4 份 references
.pi/agents/ fin-research.md、fin-reviewer.md
tests/ Vitest + 夹具驱动(CI 无实时网络)许可
MIT
English
pi-fin-prism
AI driven by verified data, not noise. 由核实过的数据驱动 AI,而非噪音。
A pi extension providing a unified, natively async financial data interface over three
Chinese market-data vendors, exposed to the LLM as three custom tools, an on-demand skill,
and two research subagents. Every answer carries a provenance envelope —
source/tier/ts are never stripped — and finVerify cross-checks critical numbers
between two sources at the same time point.
- 同花顺 (ths) — fastest (~0.1s). A-share quotes/financials/valuation; market heat (涨停/连板/龙虎榜/热榜/异动); trading calendar; full-market parquet dump.
- 万得 (wind) — most comprehensive. HK/US quotes, minute K-lines, technical & risk
indicators, bonds, money flow, EDB macro with unit metadata, docs RAG. Free quota
(1000 积分/day ≈ 1/request) — auto-
Disable<exceed upper limit>when exhausted. - 妙想 (mx) — NL-first. Research reports with ratings/target prices, analyst consensus (一致预期), explainable screening, unlimited financial history. Slow (1.4–4.4s) but free.
Every answer is one envelope: { data, source, tier, ts, unit?, magnitude?, caliber?, warnings? }.
Install
pi install npm:pi-fin-prism # global (user settings: ~/.pi/agent/settings.json)
pi install git:github.com/v587d/[email protected] # or from GitHub
pi install -l ./ # project scope (.pi/settings.json) — share with your teamDev loop (current run only):
pi -e ./src/extension/index.tsAPI keys
Environment variables first, then the global config file:
export FINPRISM_THS_API_KEY=...
export FINPRISM_WIND_API_KEY=...
export FINPRISM_MX_API_KEY=...// ~/.pi/agent/fin-prism.json
{ "ths": "...", "wind": "...", "mx": "..." }Keys never enter project files or session content; /fin status shows masked tails only.
A vendor without a key is skipped by the router with a degradation note — not an error.
Tools
| Tool | Purpose |
|---|---|
| finQuery | Unified query: indicator (17 domains) + loose params. The router picks the source chain (ths → wind → mx by latency), retries transient errors with backoff, and fails over automatically. |
| finJob | Async long operations (全市场 dump): start returns a jobId immediately — never blocks; status/wait poll with TTL. |
| finVerify | Same-timepoint double-source 对账 for critical indicators (quote/valuation/kline). Flags disagreements — the LLM decides, no auto-repair. |
Example:
finQuery(indicator="valuation", params={ code: "600519.SH" })
→ { data: { securities: [{ pe: { value: 20.36, unit: "倍" }, ... }] },
source: "ths", tier: "free", ts: { iso: "2026-08-11T01:30:00Z", tz: "+08:00" },
caliber: "TTM" }Skill
fin-prism — read SKILL.md first for the indicator dictionary and parameter
conventions, then call finQuery (/skill:fin-prism also loads it on demand):
skills/fin-prism/SKILL.md
references/indicator-dictionary.md # indicator + params + routing table (mirrors router.ts ROUTES)
references/vendor-quirks.md # 17 measured vendor lessons (429, NER noise, EDB two-stage, ths ranges, …)
references/envelope.md # provenance rules, tier/caliber semantics
references/async-jobs.md # finJob protocol, TTL, completion follow-upSubagents
| Agent | Role |
|---|---|
| fin-research | Forward research: aggressive multi-source digging, parallel finQuery, failover exhaustion, finVerify cross-checks, provenance on every fact, explicit uncertainty → research.md |
| fin-reviewer | Adversarial safety net: audits provenance completeness, caliber/time-point consistency, active cross-source 对账 with acceptability opinion, hallucination risk → review.md. Read-only. |
Parent orchestrates: research → review → decide (a workflowScript loop is a future milestone).
Commands
/fin status— masked key tails, vendor availability, registered fin tools/fin verify-contracts— ths endpoint drift check vs the vendorllms.txt(needs network; alias-matches endpoints whose docs omit the/apiprefix)/fin <query>— ask fin-prism directly; forwarded to the agent (reads the skill → calls finQuery/finVerify)
Development
npm test # vitest (fixture-based, no live network)
npm run typecheck # tsc --noEmit (strict)
npm run record:fixtures -- --vendor ths|wind|mx # dev-only: record live cassettes (real keys, never CI)
npm run smoke -- --vendor ths|wind|mx # live smoke for the 3 sample symbols- Core (
src/core/) is pure TypeScript, zero pi imports, unit-testable in isolation. src/extension/is the only place allowed to import@earendil-works/*.- All vendor calls thread an
AbortSignal(Esc cancels mid-flight). - Tests never hit the network — vendor responses are recorded once as sanitized fixtures.
Design principles
- Provenance invariant —
source/tier/tsnever stripped;unit/magnitudenever dropped (亿元/元 and 股/手 mistakes are the classic failure mode). - Normalize primitives only — security identity, time (ISO-8601 + tz tag), numbers (raw + unit tag), enum vocabulary. Everything else passes through raw; caliber (复权/TTM/MRQ/行业分类) is tagged, never converted.
- Data-driven routing — default chain ths → wind → mx (latency order); unique-capability indicators pinned to their only source; vendor availability gate (missing key / quota exhaustion →
Disable<reason>, skipped with a degradation note). - Never block on long jobs — dumps return a
jobIdimmediately; completion posts a TTL-aware follow-up (the URL itself stays out of session context).
Repository map
src/core/ Pure TS, zero pi imports
vendors/{ths,wind,mx}.ts Per-vendor adapters (auth, param translation, error mapping)
router.ts Routing tables + failover + exponential backoff + vendor gate
vendor-state.ts Availability gate (Disable<unset | exceed upper limit>)
jobs.ts Async job registry (jobId, TTL)
envelope.ts / normalize.ts / schema.ts Envelope builders, 4 primitives, Typebox schemas
src/extension/ pi shell: index.ts (finQuery/finJob/finVerify), commands.ts (/fin), clients.ts, verify.ts
skills/fin-prism/ SKILL.md + 4 references
.pi/agents/ fin-research.md, fin-reviewer.md
tests/ Vitest + fixture-based (no live network in CI)License
MIT
