群益API 即時 K 線怎麼接上歷史 K?K 棒接縫與凍結偵測
程式啟動,先抓歷史 K 線,再接上即時的成交明細,自己組出盤中的 K 棒。畫面看起來很完整,但最後一兩根 K 棒的成交量偏大,像是算了兩次。
兩條資料來源在時間上會重疊,而重疊的那一段只能算一次。 這就是群益API 即時 K 線銜接的核心問題。
先說清楚本文的定位:官方文件告訴你歷史 K 什麼時候送完、成交明細怎麼送來,但沒有說明兩者要怎麼接起來。以下是通用的設計原則,不是官方規格。

目錄
群益API 即時 K 線從哪裡來?兩條來源、一條時間軸
先說明本文的「即時 K 線」指的是什麼:用即時成交明細自己組出來的 K 棒。V2.13.59 起官方另有一個「即時分 K」,那是另一個功能,本文最後會提一句。
要畫一條從過去連到現在的 K 線,資料來自兩條路:
- 歷史 K:〈群益API 歷史 K 線怎麼取〉講的兩個請求函式,送完以
OnKLineComplete通知。 - 即時 Tick:〈群益API Tick 回補是什麼〉講的成交明細,自己聚合成 K 棒。
兩條路在時間上會重疊:歷史 K 的最後一根,跟即時 Tick 的前幾筆,可能落在同一分鐘。兩邊都算進去,那一分鐘的成交量就算了兩次。
所以第一條原則是:每一分鐘只能有一個來源。 歷史 K 涵蓋的分鐘以歷史為準,歷史之後的分鐘才用 Tick 聚合。
什麼時候可以開始用 Tick 組 K 棒?等 OnKLineComplete
接縫的規則有三步:
- 歷史 K 還沒送完之前,接縫還沒確定。 這段時間收到的 Tick 先收著,不聚合成 K 棒。否則會先用 Tick 畫出幾根,等歷史送到又被蓋掉。
OnKLineComplete到了,接縫就確定了:歷史的最後一根是哪一分鐘。官方對這個事件的說明是「收完歷史KLine,等收到此事件通知後表示回補完成。」- 晚於那一分鐘的 Tick 才聚合;落在那一分鐘或更早的 Tick 丟掉,因為歷史已經涵蓋了。
先前收著的 Tick,在接縫確定之後交給同一道規則處理。
分 K 的時間標籤,代表那一分鐘的起點還是終點?
這是接縫最關鍵、也是本文給不出確定答案的地方之一。
歷史最後一根標著 09:04,它涵蓋的是 09:03–09:04,還是 09:04–09:05?官方沒有說明,我們也還沒有校正。 V2.13.59 即時分 K 的官方時間欄位說明是「成交時間HHmm (Ex: 904,代表09點04分)」,同樣沒有說明是起點還是終點。
好消息是,上面的接縫規則不依賴是哪一種語意。只要「一筆 Tick 屬於哪一分鐘」跟「歷史 K 的時間標籤」用同一套語意,接縫就不會重複也不會漏。請用實際資料對一次,確認你的標籤語意。
歷史的最後一根,是已經收完的分鐘嗎?
規則第 3 步還有一個前提:歷史的最後一根,是一個已經收完的完整分鐘。
如果在盤中 09:04:30 送出請求,而歷史的最後一根就是還在進行中的 09:04,照規則,09:04:30 之後落在 09:04 的 Tick 會全部被丟掉,09:04 那根就只有前半段。「接縫那一分鐘的 K 棒少了一段」,可能就是因為這個前提不成立。
歷史 K 會不會包含還在進行中的那一分鐘,官方沒有寫,我們也沒有紀錄。請跟標籤語意一起,用實際資料確認。
如果你不想依賴這個前提,有一個設計選項:把歷史最後一根當成可能不完整,接縫設在它之前,最後一根那一分鐘改用 Tick 重組。這個做法可行的條件,是那一分鐘的 Tick 都拿得到:如果這是當天第一次訂閱這檔商品,回補會送來當天稍早的成交,可以補上那一分鐘的前段;不是第一次訂閱時,回補會不會再送,官方沒有寫(見〈群益API Tick 回補是什麼〉)。這是設計選項,我們沒有實作過。
回補的 Tick 落在接縫上怎麼辦?
第一次訂閱時,當天稍早的成交會從回補事件送進來。回補的 Tick 裡,凡是落在歷史 K 已涵蓋分鐘內的,照接縫規則丟掉;晚於接縫的則照常聚合。
這裡有兩道獨立的過濾,不要合成一條規則:
- 〈群益API Tick 回補是什麼〉的「回補不觸發策略」,管的是要不要拿去做即時判斷。
- 本文的接縫,管的是要不要算進 K 棒。
兩者都要做,但判斷依據不同。
群益API 即時 K 線不動了?兩個會卡住的地方
K 棒停在某一根不動、程式卻沒有報錯。從資料流來看,有兩個地方會卡:
- 歷史 K 送到一半就沒了:
OnKLineComplete一直沒來。照接縫規則,接縫永遠不確定,Tick 永遠收著不聚合,K 棒就停在歷史的某一根。 - 即時 Tick 不再進來:這就是〈群益API 報價停止更新怎麼辦〉講的停格。K 棒會停在最後一筆 Tick 所在的那一分鐘。
所以 K 棒不動,不一定是報價停了,也可能是歷史 K 沒送完。
K 棒凍結怎麼偵測?
思路跟報價停格的看門狗一樣:
- 記一個「最後一次有實質進展的時間」:收到歷史 K 的一列、收到
OnKLineComplete、有 Tick 聚合進 K 棒,都算進展。 - 初始值設成開始的那一刻,不要設成「還沒開始」——這樣「從來沒收到任何資料」也能被逾時抓到。
- 發出歷史請求時,把這個時間重設一次,避免請求剛送出就被判定卡住。
- 逾時之後,重新請求歷史 K,或重新訂閱 Tick。逾時多長、重試幾次,本文不給數字;一定要有退避與次數上限。
這裡記的是「K 棒序列」這一條流的進展,跟報價流的健康時間是兩個獨立的時間戳,不要共用。 一個時間戳只代表一條流。
還有哪些工具?GetTickLONG 與即時分 K
SKQuoteLib_GetTickLONG:官方說明可依nPtr取回指定第幾筆成交明細(nPtr的說明見〈群益API Tick 回補是什麼〉)。也就是說,元件內部保存著已經送來的成交明細,可以回頭讀;官方在RequestLiveTick的備註提到,用那個函式訂閱時,GetTickLONG只查得到訂閱之後的資料。要重建某一段 K 棒時,這是一個選項,不必重新向伺服器請求。注意官方備註要求不要在成交明細的事件裡呼叫它。- V2.13.59 的即時分 K(
OnNotifyLiveKLineData):官方說明包含當日分 K 的回補,只涵蓋當日,不能取代跨多日的歷史 K 線。它跟本文用 Tick 自組的即時 K 棒是兩回事,本文不展開。
群益API 即時 K 線銜接的 7 條原則+程式碼
- 每一分鐘只能有一個來源:歷史涵蓋的分鐘以歷史為準,之後才用 Tick 聚合。
OnKLineComplete還沒到之前,Tick 先收著、不聚合;接縫確定後,晚於歷史最後一根的 Tick 才聚合。- 「Tick 屬於哪一分鐘」與「歷史 K 的時間標籤」用同一套語意;這個語意官方沒寫,請用實際資料確認。歷史最後一根是否完整,也一起確認。
- 回補的 Tick 同樣要過接縫這一關;它跟「回補不觸發策略」是兩道獨立的過濾。
- 凍結偵測記「最後一次實質進展的時間」,初始值設成開始的那一刻,發出歷史請求時重設。
- K 棒序列的進展時間,跟報價流的健康時間分開記。
- 逾時後重新請求或重新訂閱,要有退避與上限。
DateTime _lastProgressAt = DateTime.Now; // 初始值=開始的那一刻,不是「還沒開始」
bool _historyDone = false; // OnKLineComplete 到了沒
int _lastHistoryMinute = -1; // 歷史最後一根的分鐘(例如 hhmm)
List<Tick> _pending = new List<Tick>();
void OnNotifyKLineData(string bstrStockNo, string bstrData)
{
// 解析歷史列(E1),寫入 K 棒;取最大值,不依賴歷史列的送達順序
_lastHistoryMinute = Math.Max(_lastHistoryMinute, ParseAndStore(bstrData));
_lastProgressAt = DateTime.Now; // 有實質進展
}
void OnKLineComplete(string bstrEndString)
{
_historyDone = true; // 接縫確定
foreach (var t in _pending) AddToBar(t); // 先前收著的 Tick,交給同一道接縫過濾
_pending.Clear();
_lastProgressAt = DateTime.Now;
}
void AddToBar(Tick t)
{
if (!_historyDone) { _pending.Add(t); return; } // 接縫還沒確定:先收著
if (MinuteOf(t) <= _lastHistoryMinute) return; // 歷史已涵蓋:丟掉,避免重複
AggregateIntoBar(t); // 接縫之後:聚合
_lastProgressAt = DateTime.Now;
}幾點補充:
- 片段裡有兩處要你自己確認:
MinuteOf(t)的語意必須跟歷史 K 標籤一致;以及AddToBar裡「歷史已涵蓋就丟掉」那一行背後的前提——歷史最後一根是否完整。 - 分鐘用
hhmm比較只是示意。跨日、跨夜盤要用日期加時間——全盤 K 線包含前一晚的夜盤,片段沒有寫這部分。 - 事件在元件自己的執行緒上觸發,這幾個欄位實際使用時要做同步,見〈群益API 事件回呼跑在哪個執行緒〉。
常見問題
接上歷史 K 之後,最後幾根 K 棒的成交量偏大,是什麼原因?
歷史 K 的最後一根和即時 Tick 的前幾筆可能落在同一分鐘,兩邊都算進去就重複了。每一分鐘只能有一個來源:歷史涵蓋的分鐘以歷史為準,之後的分鐘才用 Tick 聚合。
一訂閱就可以開始用 Tick 組群益API 即時 K 線嗎?
不建議。歷史 K 還沒送完之前,接縫還沒確定。Tick 先收著,等 OnKLineComplete 到了,再把晚於歷史最後一根的 Tick 聚合進去。
分 K 的時間標籤代表那一分鐘的開始還是結束?
官方沒有說明,我們也還沒有校正,請用實際資料確認。接縫規則本身不依賴是哪一種,只要 Tick 的歸屬分鐘跟歷史 K 標籤用同一套語意即可。
K 棒不動了,就是報價停了嗎?
不一定。也可能是歷史 K 沒送完、OnKLineComplete 一直沒來,接縫永遠沒確定,Tick 就一直收著沒有聚合。
風險揭露
期貨與選擇權屬高槓桿商品,價格波動可能造成超過原始保證金的損失,交易人須自負交易責任。本文為程式開發技術教學,說明歷史 K 線與即時成交明細的銜接設計,不構成投資建議,也不保證任何交易結果。程式化交易並不降低市場風險,K 棒重複計算、缺段或凍結而程式未察覺,都可能讓程式依據錯誤的資料運作。
投資人教育資源
| 機構 | 資源 |
|---|---|
| 臺灣期貨交易所(TAIFEX) | 期貨及選擇權數位學習網 |
| 證券暨期貨市場發展基金會 | 證券期貨市場教育推廣 |
| 金融智慧網 | 金管會金融知識平台 |
| 中華民國期貨業商業同業公會 | 期貨業法規與宣導 |
| 證券投資人及期貨交易人保護中心 | 投資人保護與申訴 |
延伸閱讀
- 〈群益API 歷史 K 線怎麼取〉——歷史 K 的兩個請求函式、
OnKLineComplete、全盤包含前一晚。 - 〈群益API Tick 回補是什麼〉——回補與即時的分流、
nPtr去重。 - 〈群益API 報價停止更新怎麼辦〉——看門狗、從未收過的盲區、退避與上限。
- 〈群益API 事件回呼跑在哪個執行緒〉——事件執行緒與同步。
參考資料
OnKLineComplete、OnNotifyKLineData、SKQuoteLib_GetTickLONG的說明,依群益官方元件說明文件「國內報價」章節;即時分 K 與時間欄位說明,依 V2.13.59 主手冊。官方文件沒有說明歷史 K 與即時成交明細怎麼銜接。- 接縫規則、凍結偵測與設計選項:通用設計原則,非官方文件記載。
免責聲明
本文章僅作為群益API實作經驗分享,不構成投資建議,且策略及程式皆應自行撰寫。期貨及衍生性金融商品交易屬高風險投資,請謹慎評估自身風險承擔能力。







