Files
daily_stock_analysis/docs/market-support.md
Wenyu Chiou 7715896fe4 feat(market): tw institutional-flows (三大法人) data-layer fetcher (#1829)
Implements the #1777 maintainer-greenlit Phase-2 data layer: a self-contained,
tw-only fetcher for Taiwan per-stock institutional (外資/投信/自營商) net
buy/sell. Strictly additive -- no change to the existing cn/hk/us/jp/kr flows in
data_provider/base.py, and not yet wired into the report/Web/scoring path (a
deliberate follow-up per the maintainer's scope).

- data_provider/tw_institutional_fetcher.py (NEW): TwInstitutionalFetcher
  - 上市 .TW  -> TWSE T86 legacy rwd JSON endpoint (西元 date, comma values)
  - 上櫃 .TWO -> TPEx OpenAPI tpex_3insti_daily_trading (民國 date, plain ints)
  - T86 columns are read by NAME (validated against the payload `fields` header),
    so a TWSE column rename / reorder fails open instead of silently shipping
    misaligned numbers under stale indices
  - foreign_net = 外陸資 (ex 外資自營商, T86) / dealer-excluded foreign (TPEx) so
    the breakdown matches the official 三大法人 total; total_net is the official
    figure; unit = shares, signs preserved
  - whole-market single-day cache keyed by (market, date), filtered per stock;
    ~3 req/5s throttle (own lock) for the T86 endpoint
  - fail-open: any network/rate-limit/empty/unknown-stock returns None; a missing
    or renamed column drops the row (never a fabricated 0); a row whose trading
    date cannot be attributed (TPEx 民國 unconvertible) is dropped; empty/failed
    fetches are not cached (no TTL-long blackout)
- tests/test_tw_institutional_fetcher.py (NEW): 20 offline tests with fixtures
  trimmed from real T86 (2330) / TPEx (3105) responses; pins the net breakdown +
  sign, 民國->西元 conversion, routing, caching, and fail-open -- including
  column reorder (parsed by name), column rename / missing header (fail-open),
  the missing-column-vs-genuine-zero distinction, and unconvertible TPEx dates
- docs/market-support.md + docs/CHANGELOG.md: data-source capability boundary +
  OGDL v1 license note; no new config (.env.example untouched)

Addresses the #1829 review (read T86 by field name; drop TPEx rows with an
unconvertible date; foreign_net excludes foreign-dealers).

Sources are 政府開放資料 under 政府資料開放授權條款第 1 版 (OGDL v1, commercial-safe).

Refs #1777
2026-06-28 18:49:09 +08:00

11 KiB
Raw Blame History

市场支持与边界

日本/韩国个股 suffix-only MVPIssue #1718Refs #1718

当前阶段支持手动输入日本、韩国股票的 Yahoo Finance 后缀代码进入既有个股分析、历史保存和基础报告展示链路。Web 自动补全内置一批常用日股/韩股种子索引,支持按 suffix 代码、中英文名称或常用别名搜索。

支持格式:

  • 日本:7203.T6758.T
  • 韩国 KOSPI005930.KS
  • 韩国 KOSDAQ035720.KQ

约束与边界:

  • 手动输入裸代码时会先检索本地/远程股票池;若 005930000660 等裸码命中 005930.KS000660.KS 等日韩条目,则按命中的市场提交分析;若股票池未命中,仍按既有 6 位数字代码规则默认落到 A 股语义,并保留为可追踪的跨市场歧义边界。
  • 日股/韩股 suffix 识别已集中到共享市场代码工具数据源路由、Prompt 市场识别、交易日历和股票索引裸码解析复用同一组规则,减少后续市场扩展时的规则漂移。
  • 日股/韩股日线和基础实时/近实时行情只走 YfinanceFetcher,不尝试 AkShare、Tushare、Efinance、Pytdx、Baostock 等 A 股专属数据源yfinance 报价会尽量带上 marketcurrencydata_qualitymissing_fields 等质量元数据。
  • 基本面复用既有 offshore yfinance 轻量路径A 股专属资金流、龙虎榜、板块等能力按 not_supported 降级offshore 基本面上下文也会标记 provider、as_of、data_quality 和缺失块。
  • 报告 Prompt 已增加日股/韩股市场语义,避免套用 A 股涨跌停、北向资金、龙虎榜、融资融券等概念。
  • 交易日历注册 jp: XTKS / Asia/Tokyokr: XKRX / Asia/Seoul。若本地 exchange-calendars 版本缺少对应日历,既有 fail-open/fail-closed 语义保持不变。

兼容性与回退说明(针对结构化检测命中项):

  • #1815 本次仅新增 yfinance 报价/基本面上下文中的可选字段元数据(如 marketcurrencydata_qualitymissing_fieldsprovider),未改动 LLM provider/model/base URL、配置 Schema、运行时环境变量、数据库字段、存量缓存序列化或消息协议版本。
  • 与本条 PR 相关的配置语义上,未新增或替换 provider、model、base URL未新增配置清理/迁移分支;已保存配置仍保持原样,回退方式为回退该提交。
  • 外部 API 边界仍仅限既有 yfinance fetch 路径(含 Ticker/history/fast_info)与既有兜底逻辑;没有新增或迁移 API 网关/hostYFINANCE_PRIORITY 是唯一受影响的可见参数。JP/KR 主指数与 Yahoo symbol 对应如下(可核验):
  • 兼容性与回退:MARKET_REVIEW_REGION 会保留合法逗号子集(如 cn,us)并保持 both 全量行为,非法值或空值回退到 cn,不会清空或迁移已保存配置。
  • 运行时边界JP/KR 指数按 market_review 的 fail-open 约定逐项抓取;单项失败不会阻断其余指数与其他市场;当两个市场均无可用主指数行情时返回本地可见 None/空,主流程继续可按其余市场输出或直接降级。
  • 兼容性验证依据:行情/基本面上下文在 data_provider/base.pyrealtime_types.py 中按现有 getattr/可选字段约定向下游透传,不强制读写新增字段;无配置迁移脚本,未观察到 provider/model/base URL fallback 路径变更。
  • 回退方式:若新增元数据字段在某端产生兼容问题,可先忽略这些字段并按既有市场判定+行情展示链路运行;必要时回滚本次提交或通过移除 jp/kr MarketSymbol 及路由扩展恢复旧行为。

不承诺项:

  • 不承诺实时行情Yahoo Finance 数据可能延迟或字段缺失。
  • 不承诺完整基本面、行业/板块、市场宽度或涨跌家数。JP/KR 大盘复盘 v1 仅提供主要指数、新闻线索与模板/LLM 复盘,不提供日韩市场宽度或板块排行。
  • 不承诺完整日韩全市场股票列表Web 自动补全当前仅覆盖仓内种子索引中的常用标的(已扩充至各 30 只左右的头部标的),未命中时仍可手动输入 suffix 代码。
  • 不补齐 Portfolio 的 JPY/KRW 汇率、成本、市值完整口径;相关字段仅放开市场类型以避免前后端校验拒绝。

回滚方式:移除 jp/kr 市场识别、交易日历注册、YFinance 路由扩展、Web/API 类型放行、scripts/stock_index_seeds/ 日韩种子索引,并删除本文档中的能力声明。

日本/韩国大盘复盘 v1Issue #1815 Phase 2

大盘复盘 MARKET_REVIEW_REGION 新增 jpkr,并纳入 both 的多市场顺序:cn,hk,us,jp,kr

支持范围:

说明(兼容性与验收口径):

  • 线上数据可用性来自 Yahoo Finance 指数页面与接口契约,当前实现仅覆盖 data_provider/yfinance_fetcher.py 的指数路由与降级行为;不对实时行情连通性作稳定性承诺。

  • 与该条目标相关的本地自动化验证默认使用离线回归:tests/test_yfinance_jp_kr_indices.pytests/test_yfinance_hk_indices.py(共性映射/回退)与 tests/test_trading_calendar.py(交易日过滤)。如果要补充实时可用性复核,可在联网环境直接访问上述 Yahoo Finance 页面进行一次性抽检。

  • 外部兼容性边界(当前实现默认假设):

    • 数据源:yfinance(版本下限 requirements.txt 中的 yfinance>=0.2.0
    • 长期约束:^N225^TOPX^KS11^KQ11 必须在 Yahoo Finance 端有可检索 quote 页面;无法检索视为索引级不可用,由 market_review fail-open 机制退化到已有市场输出,不中断主流程。
  • 兼容验证(可复核):

python - <<'PY'
from yfinance import Ticker
for symbol in ("^N225", "^TOPX", "^KS11", "^KQ11"):
    data = Ticker(symbol).history(period="5d")
    print(symbol, "rows", len(data))
PY

边界:

  • JP/KR 大盘复盘 v1 不提供涨跌家数、涨跌停、行业/板块排行或资金流统计;结构化 payload 中 breadth 仍只在有市场宽度数据时出现。
  • 单一 JP/KR 指数拉取失败按既有 yfinance fail-open 逻辑跳过,不拖垮其它指数或其它市场。
  • 如果 exchange-calendars 缺少对应交易所日历,继续沿用既有交易日 fail-open/fail-closed 语义。

回滚方式:从 MARKET_REVIEW_REGION 合法值、Web 设置枚举、MarketProfile/MarketStrategy、_MARKET_REVIEW_MARKETS 和本文档中移除 jp / kr

台湾个股 suffix-only MVPIssue #1772Refs #1772

当前阶段支持手动输入台湾股票的 Yahoo Finance 后缀代码进入既有个股分析、历史保存和基础报告展示链路。TWSE 上市股票使用 .TW 后缀TPEx 上柜(柜买)股票使用 .TWO 后缀,二者折叠为同一 tw 市场标签。本次覆盖市场识别detection、数据路由层、DecisionSignal/Portfolio/Intelligence 服务层与 API 市场枚举,以及 DecisionSignal/Portfolio 前端市场类型与筛选;台股股票索引/种子、Web 自动补全与告警(大盘红绿灯)市场放行仍作为后续 PR。对齐 #1718 日韩 MVP 模式。

支持格式:

  • 上市TWSE2330.TW0050.TW
  • 上柜TPEx / 柜买):6488.TWO5483.TWO
  • 代码 base 为 4-6 位数字(普通股 4 位ETF/其他至 6 位,如 00878.TW006208.TW),较日股 .T 的 4-5 位更宽。

约束与边界:

  • 严格 suffix-only:裸 233000878 等不带后缀的代码不会进入台股语义(detect_market / get_market_for_stock 仅在显式 .TW/.TWO 后缀时返回 tw)。本次不引入任何台股股票索引/种子解析,故裸码不可能经本地/远程股票池被改写为台股 suffix该索引解析与 jp/kr 同款的裸码命中行为)属后续 PR。
  • 台股日线和基础实时/近实时行情只走 YfinanceFetcher,不尝试 AkShare、Tushare、Efinance、Pytdx、Baostock 等 A 股专属数据源。
  • 基本面复用既有 offshore yfinance 轻量路径A 股专属资金流、龙虎榜、板块等能力按 not_supported 降级。
  • 报告 Prompt 已增加台股市场语义新台币、三大法人、TWSE/TPEx ±10% 涨跌停),避免套用 A 股北向资金、龙虎榜等概念。
  • 交易日历注册 tw: XTAI / Asia/Taipei。TWSE 为 09:0013:30 连续交易、无午休;收盘集合竞价暂不建模,与 jp/kr 一致。若本地 exchange-calendars 版本缺少对应日历,既有 fail-open/fail-closed 语义保持不变。
  • 主要指数提供加权指数 ^TWII 与柜买指数 ^TWOII
  • 三大法人买卖超institutional flows资料层TwInstitutionalFetcherdata_provider/tw_institutional_fetcher.py提供上市TWSE T86legacy rwd 端点)/ 上柜TPEx OpenAPI每日外资·投信·自营商·三大法人买卖超单位股数;按日期+市场做单日全市场缓存再过滤个股TPEx 民国年转西元有单测覆盖)。接口失败/限流/空响应/字段缺失一律 fail-open 返回无数据,不中断分析;仅对 .TW/.TWO 生效,不改动现有市场流程。资料来源为政府开放资料,采「政府资料开放授权条款第 1 版」(OGDL v1允许商用与再散布需标示来源)。本次仅资料层 fetcher/parser/cache/tests尚未接入报告展示、Web 展示、评分权重或 capital_flow_signal 派生。

不承诺项:

  • 不承诺实时行情Yahoo Finance 数据可能延迟或字段缺失。
  • 不承诺完整基本面、行业/板块、市场宽度、涨跌家数或台股大盘复盘。
  • 台股股票索引/种子、Web 自动补全与告警(大盘红绿灯)市场放行仍作为后续 PR告警 MarketRegion 与后端 market_light 仍为 cn/hk/us未含 tw。
  • 不补齐 Portfolio 的 TWD 汇率、成本、市值完整口径(属上述后续 PR 范围)。

回滚方式:移除 tw 市场识别、交易日历注册、YFinance 路由扩展与服务层/API 市场枚举及前端市场类型放行,并删除本文档中的能力声明。