跳轉到

價量支撐壓力(high_volume_support_resistance)Integration Guide — Frontend

Backend branch: feat/chip-high-volume-support-resistance → cortex/dev Endpoints:GET /api/agent/chip/{ticker}、GET /api/signals/stock/{ticker}(chip 段) 生效時間:merge 後 cortex-api --reload 立即生效(顯示名/新 index 欄位);每日 15:30 cortex-scheduler 重啟後,新寫入的籌碼快照才會帶 high_volume_support_resistance 區塊,之前的快照回 {}。無 migration。

Consumer:讀這兩支端點籌碼段的前端(個股頁籌碼區塊)。本次盤點 docs/integration/ 只有前端 consumer 紀錄;若有未登記的 consumer,請補一份對應檔案。

相容性:純新增。既有欄位 indexes.support_resistance 內容不變;既有 signal/event/story 代碼都不變,只有顯示名改了(見 §2),前端若以 name 字串比對會壞,以 *_code 比對不受影響。


1. 欄位 diff 表

兩支端點的籌碼 indexes 物件各新增兩個 key;其餘欄位不變。

endpoint 欄位 型別 變動 語意
兩支 indexes.high_volume_support_resistance HighVolumeSupportResistance \| {} \| null 新增 價量支撐壓力區塊,原樣回傳快照 evidence 的頂層同名區塊。本功能上線前寫入的快照為 {};/api/agent/chip 在 analysis_status = "pending_source"(籌碼來源未到齊)時為 null(與 support_resistance 同)
兩支 indexes.institutional_support_resistance 同 support_resistance 新增(別名) 法人支撐壓力,與既有 indexes.support_resistance 同一個物件;兩個 key 都保留
兩支 indexes.support_resistance — 不變 —
兩支 signals[]/events[]/stories[] — 新增代碼+改顯示名 見 §2

HighVolumeSupportResistance 欄位(status 不是 available 時,thresholds 為 {}、所有 level 為 null、reason 有值):

欄位 型別 說明
status "available" \| "insufficient_data" \| "compute_failed" 只有 available 才有 level
reason string \| null 非 available 的原因(例 rows=50 < 61、RuntimeError: …)
basis "raw" 原始價
stages number[] [60, 120, 240],三階視窗(含當日)
stddev_multiplier string "2":大量日=量 ≥ 視窗平均+2×樣本標準差
thresholds { [stage: string]: { mean, stddev, volume } } 只含實際用到的階(兩側都在 60 根內找滿就只有 "60";不可假設三個 key 都在);volume 為門檻(股數)
window_start / window_end string(YYYY-MM-DD) \| null 實際搜尋的最大視窗起訖
closing_price number \| null 當日收盤(快照存值)
support / support2 Level \| null 第一/第二支撐(低於現價的大量日收盤,依與現價距離近→遠)
resistance / resistance2 Level \| null 第一/第二壓力(高於現價)
previous_support / previous_resistance { date, close, as_of } \| null 以前一交易日當「今天」重算的第一支撐/壓力(跌破/突破事件的比較基準)

Level = { date: string, close: number, volume: number(股), z_score: number, stage: 60|120|240, distance_pct: number };distance_pct 恆為正:支撐=現價高於支撐的百分比((close/support − 1)×100),壓力=現價低於壓力的百分比((resistance − close)/resistance×100)。

2. 行為改變對照表

項目 代碼(不變) 修前顯示名 修後顯示名
signal chip_support_resistance 籌碼支撐壓力 法人支撐壓力
event chip_support_nearby 籌碼支撐接近 法人支撐接近
event chip_resistance_nearby 籌碼壓力接近 法人壓力接近
event chip_support_break 籌碼支撐跌破 法人支撐跌破
story cost_defense 成本防守 法人成本防守
項目 新代碼 顯示名 direction 成立條件
signal chip_high_volume_support_resistance 價量支撐壓力 state ∈ support/risk/bullish/neutral 顯示 state 優先序:支撐跌破 risk > 壓力突破 bullish > 壓力接近 risk > 支撐接近 support
event chip_high_volume_support_nearby 支撐接近 support 收盤在第一支撐上方 3% 以內(含)
event chip_high_volume_support_break 支撐跌破 risk 收盤 < 前一日第一支撐(嚴格)
event chip_high_volume_resistance_nearby 壓力接近 risk 收盤在第一壓力下方 3% 以內(含)
event chip_high_volume_resistance_break 壓力突破 bullish 收盤 > 前一日第一壓力(嚴格)
story high_volume_cost_defense 成本防守 support 支撐接近成立且支撐跌破不成立(priority 301,排在 cost_defense 300 之後)

規則:支撐側(跌破>接近)與壓力側(突破>接近)各自只出一個事件,兩側可同日並存(例:2603 同日「支撐接近」+「壓力突破」)。法人那組事件與 story 的規則不變,只改名;margin_call_capitulation/margin_call_risk 仍只參考法人支撐跌破。

情境 修前 修後
快照已帶區塊 無此 key indexes.high_volume_support_resistance = 區塊(§4-1)
快照是本功能上線前寫的 無此 key {}(§4-3)
日 K 不足 61 根/最後一根不是當日/收盤與快照存值不符 — status = "insufficient_data"(§4-2)
計算例外 — status = "compute_failed",其他區塊照常(§4-5)
analysis_status = "pending_source"(只有 /api/agent/chip 有此形狀) support_resistance: null 兩個新 key 也是 null(§4-4)
story 顯示上限 每域 top-3(既有 ses_display.story_top_n_per_domain) #2114 起改為全部回傳:這兩支端點的 stories 不再每域 top-3 修剪。high_volume_cost_defense 排在 priority 301,同檔若已有 ≥3 個更前面的 story(例 1219:foreign_entry/institutional_accumulation/cost_defense),它排第 4 以後但仍會出現;前端預設顯示前 3 個、展開看完整(見 §4-7 與 docs/integration/stock-stories-full-list-frontend.md)。列表端點 GET /api/signals/latest 仍為 top-N

3. TypeScript type diff

// 新增
export type HighVolumeLevel = {
  date: string;            // YYYY-MM-DD
  close: number;
  volume: number;          // 股
  z_score: number;         // (volume − mean) / stddev,2 位小數
  stage: 60 | 120 | 240;
  distance_pct: number;    // 恆為正,見 §1
};

export type HighVolumePreviousLevel = { date: string; close: number; as_of: string };

export type HighVolumeSupportResistance = {
  status: "available" | "insufficient_data" | "compute_failed";
  reason: string | null;
  basis: "raw";
  stages: number[];                       // [60, 120, 240]
  stddev_multiplier: string;              // "2"
  thresholds: Record<string, { mean: number; stddev: number; volume: number }>; // 只含實際用到的階,可能是 {}
  window_start: string | null;
  window_end: string | null;
  closing_price: number | null;
  support: HighVolumeLevel | null;
  support2: HighVolumeLevel | null;
  resistance: HighVolumeLevel | null;
  resistance2: HighVolumeLevel | null;
  previous_support: HighVolumePreviousLevel | null;
  previous_resistance: HighVolumePreviousLevel | null;
};

// 兩支端點的籌碼 indexes
export type ChipIndexes = {
  // ...既有欄位不變
  support_resistance: ChipSupportResistance | Record<string, never> | null;          // 不變
+ institutional_support_resistance: ChipSupportResistance | Record<string, never> | null; // === support_resistance
+ high_volume_support_resistance: HighVolumeSupportResistance | Record<string, never> | null;
};

// 判斷方式
export const isHighVolumeBlock = (v: unknown): v is HighVolumeSupportResistance =>
  !!v && typeof v === "object" && "status" in (v as object);   // {} 與 null 都不是

event/story 代碼 union 各加:"chip_high_volume_support_nearby" | "chip_high_volume_support_break" | "chip_high_volume_resistance_nearby" | "chip_high_volume_resistance_break"、"high_volume_cost_defense";signal 代碼加 "chip_high_volume_support_resistance"。

4. 真實 response(拋棄式 parity DB,13 檔 live 輸入唯讀匯出,交易日 2026-10-30)

4-1 有資料(3105.TWO,GET /api/agent/chip/3105.TWO)

indexes.high_volume_support_resistance:

{
  "basis": "raw",
  "reason": null,
  "stages": [
    60,
    120,
    240
  ],
  "status": "available",
  "support": {
    "date": "2026-09-01",
    "close": 492.0,
    "stage": 60,
    "volume": 55247000,
    "z_score": 2.37,
    "distance_pct": 17.48
  },
  "support2": {
    "date": "2026-08-31",
    "close": 447.5,
    "stage": 60,
    "volume": 50920000,
    "z_score": 2.02,
    "distance_pct": 29.16
  },
  "resistance": {
    "date": "2026-10-29",
    "close": 594.0,
    "stage": 60,
    "volume": 56374000,
    "z_score": 2.46,
    "distance_pct": 2.69
  },
  "thresholds": {
    "60": {
      "mean": 26388800.0,
      "stddev": 12165761.95695199,
      "volume": 50720323.91390398
    },
    "120": {
      "mean": 25479941.666666668,
      "stddev": 10736803.439842435,
      "volume": 46953548.54635154
    },
    "240": {
      "mean": 26185370.833333332,
      "stddev": 12991282.47362846,
      "volume": 52167935.78059025
    }
  },
  "window_end": "2026-10-30",
  "resistance2": {
    "date": "2026-04-21",
    "close": 617.0,
    "stage": 240,
    "volume": 53504000,
    "z_score": 2.1,
    "distance_pct": 6.32
  },
  "window_start": "2025-11-03",
  "closing_price": 578.0,
  "previous_support": {
    "date": "2026-09-01",
    "as_of": "2026-10-29",
    "close": 492.0
  },
  "stddev_multiplier": "2",
  "previous_resistance": {
    "date": "2026-04-21",
    "as_of": "2026-10-29",
    "close": 617.0
  }
}
同一回應的 S/R 相關 signal/event/story(節錄;壓力接近成立:594 高於 578 僅 2.69%;法人支撐跌破照舊):
{
  "signals": [
    {
      "signal_code": "chip_support_resistance",
      "state": "risk",
      "direction": "risk/support",
      "score": 0.7,
      "name": "法人支撐壓力"
    },
    {
      "signal_code": "chip_high_volume_support_resistance",
      "state": "risk",
      "direction": "bullish/risk/support",
      "score": 0.7,
      "name": "價量支撐壓力"
    }
  ],
  "events": [
    {
      "event_code": "chip_support_break",
      "signal_code": "chip_support_resistance",
      "state": "active",
      "direction": "risk",
      "score": 0.7,
      "name": "法人支撐跌破"
    },
    {
      "event_code": "chip_high_volume_resistance_nearby",
      "signal_code": "chip_high_volume_support_resistance",
      "state": "active",
      "direction": "risk",
      "score": 0.7,
      "name": "壓力接近"
    }
  ],
  "stories": [
    {
      "story_code": "institutional_distribution",
      "state": "active",
      "direction": "bearish",
      "score": 0.38695,
      "name": "法人派發",
      "suppressed_by": null
    },
    {
      "story_code": "ownership_accumulation",
      "state": "active",
      "direction": "support",
      "score": 0.58,
      "name": "籌碼集中",
      "suppressed_by": null
    }
  ]
}

4-2 日 K 不足(6488.TWO,只剩 50 根)— insufficient_data

{
  "basis": "raw",
  "reason": "rows=50 < 61",
  "stages": [
    60,
    120,
    240
  ],
  "status": "insufficient_data",
  "support": null,
  "support2": null,
  "resistance": null,
  "thresholds": {},
  "window_end": null,
  "resistance2": null,
  "window_start": null,
  "closing_price": 756.0,
  "previous_support": null,
  "stddev_multiplier": "2",
  "previous_resistance": null
}

4-3 本功能上線前寫入的快照(2412.TW)— {}

{}

4-4 籌碼來源未到齊(1301.TW,當日融資餘額未到)— pending_source,兩個新 key 為 null

{
  "ticker": "1301.TW",
  "trading_date": "2026-10-30",
  "analysis_status": "pending_source",
  "indexes": {
    "raw_chip_summary": "…",
    "institutional_flow": "…",
    "margin": "…",
    "short": "…",
    "ownership": "…",
    "cost_zones": null,
    "support_resistance": null,
    "institutional_support_resistance": null,
    "high_volume_support_resistance": null
  }
}

4-5 計算例外(2382.TW,計算函式被強制丟出例外)— compute_failed,其他區塊照常

{
  "basis": "raw",
  "reason": "RuntimeError: sample: forced high-volume compute failure",
  "stages": [
    60,
    120,
    240
  ],
  "status": "compute_failed",
  "support": null,
  "support2": null,
  "resistance": null,
  "thresholds": {},
  "window_end": null,
  "resistance2": null,
  "window_start": null,
  "closing_price": null,
  "previous_support": null,
  "stddev_multiplier": "2",
  "previous_resistance": null
}

4-6 story「成本防守」(2454.TW,GET /api/signals/stock/2454.TW?qryDate=2026-10-30 的 chip 段節錄)

{
  "indexes.high_volume_support_resistance.support": {
    "date": "2026-08-04",
    "close": 3865.0,
    "stage": 60,
    "volume": 17318591,
    "z_score": 2.26,
    "distance_pct": 1.29
  },
  "closing_price": 3915.0,
  "events": [
    {
      "event_code": "chip_high_volume_support_nearby",
      "name": "支撐接近",
      "direction": "support"
    }
  ],
  "stories": [
    {
      "story_code": "high_volume_cost_defense",
      "name": "成本防守",
      "direction": "support",
      "score": 0.7999999999999999,
      "source_event_codes": [
        "chip_high_volume_support_nearby",
        "consensus_buy",
        "institutional_dominant"
      ]
    }
  ]
}

4-7 同檔同時有「法人成本防守」與「成本防守」(1219.TW):ledger 兩列都在,端點也全部回(#2114 起)

ledger(taiwan.ses_story_daily,2026-10-30):

story_code | direction | score | suppressed_by
cost_defense | support | 0.8 | -
foreign_entry | bullish | 0.56045 | -
high_volume_cost_defense | support | 0.8 | -
institutional_accumulation | bullish | 0.68545 | foreign_entry
ownership_accumulation | support | 0.072 | foreign_entry
依上方 ledger(#2115 撰寫時的資料;2026-11-03 dev 該日 ledger 只有 4 列、尚無 high_volume_cost_defense,dev 實測見 stock-stories-full-list-frontend.md §4),GET /api/agent/chip/1219.TW 的 stories 自 #2114 起依引擎排序(priority 優先,同 priority 再比 score)回全部 5 個:foreign_entry、institutional_accumulation、cost_defense、high_volume_cost_defense、ownership_accumulation(priority 280/290/300/301/310,見 investment-agent/backend/config/replacement_story_definitions.py)。#2114 之前只回下列前 3 個;前端預設顯示 3 個時,high_volume_cost_defense 落在展開區:
[
  {
    "story_code": "foreign_entry",
    "name": "外資成本區進場",
    "direction": "bullish",
    "score": 0.56045,
    "suppressed_by": null
  },
  {
    "story_code": "institutional_accumulation",
    "name": "法人吸籌",
    "direction": "bullish",
    "score": 0.68545,
    "suppressed_by": "foreign_entry"
  },
  {
    "story_code": "cost_defense",
    "name": "法人成本防守",
    "direction": "support",
    "score": 0.7999999999999999,
    "suppressed_by": null
  }
]

5. 前端遷移 checklist

  • [ ] 以 *_code 比對 signal/event/story,不要用 name:五個顯示名改了(§2),代碼沒變
  • [ ] 讀 indexes.high_volume_support_resistance 前先 isHighVolumeBlock():{}(舊快照)、null(pending_source)、status !== "available"(insufficient_data/compute_failed)三種都沒有 level,各給對應文案
  • [ ] thresholds 只含實際用到的階,不可假設 "60"/"120"/"240" 都在
  • [ ] 每側最多兩個 level(support/support2、resistance/resistance2),任一可為 null
  • [ ] volume 是股數;顯示張數請 ÷1000
  • [ ] 若要區分「法人」與「價量」支撐壓力:法人讀 institutional_support_resistance(=support_resistance),價量讀 high_volume_support_resistance
  • [ ] 四個新事件與新 story 加進代碼 union/文案表;壓力接近(risk)與壓力突破(bullish)方向不同
  • [ ] 知悉 story 顯示:#2114 起這兩支端點回全部 story,前端預設顯示前 3 個、提供展開看完整;high_volume_cost_defense 可能排在第 4 以後(§4-7)

6. 參考