群益API 報價價格的整數編碼與 sDecimal 換算示意圖

群益API 報價價格為什麼是整數?4 種數字不對的狀況與換算方式

訂閱終於通了,報價開始進來——然後你看到群益API 報價價格欄位裡,台積電是 108500,台指期是 2295000

這一種查五分鐘就會知道原因。真正麻煩的是另外三種:除以 100 之後還是不對、時間欄位丟進解析函式就爆掉、同一支程式對 K 線和快照的行為不一致。

群益API 報價價格的整數編碼與 sDecimal 換算示意圖

群益API 報價價格為什麼是整數?

SKSTOCKLONG 結構裡的價格欄位——最高、開盤、最低、成交——型別都是 LONG沒有小數點

群益API 報價價格的小數點資訊沒有消失,它放在同一個結構的另一個欄位裡:

SHORT sDecimal;   // 小數位數

所以換算方式是:

^^實際價格 = 整數值 ÷ 10^sDecimal^^

官方在另一處也有「價格欄位一般除以 100.0 顯示」這樣的說法。這兩件事不衝突——多數商品的 sDecimal 就是 2,除以 100 剛好對。

問題出在「多數」不是「全部」。

「除以 100」什麼時候會錯?官方自己舉了例子

在說明 K 線舊版輸出格式時,官方文件給了兩個範例:

舊版輸出函式中所取回的價格都未經過小數點處理,例如1101 價格為「36.50」,則函式所傳回的價格為「3650」

特別注意舊版輸出格式中的期匯率商品(TypeNo=209)小位數有四位須特別再處理,例如RH1704價格為「6.8712」,則函式所傳回的價格為「68712」

把這兩個例子放在一起看,就是群益API 報價價格這個主題真正的難處:

同一支寫死 /100 的程式,在 1101 上完全正確;在 RH1704 上會得到 687.12。

一個大了 100 倍的價格——而且它不會觸發任何錯誤,你拿到的是一個看起來很像價格的數字

寫死除以 100 不是會不會錯的問題,是什麼時候錯的問題。

(上面兩段引文的脈絡是 K 線的舊版輸出格式說明。至於「期匯率商品有四位小數」,那是商品本身的性質,不限於 K 線。)

比寫死更難查的版本:把 sDecimal 快取起來

知道群益API 報價價格要讀 sDecimal 之後,還有一個更隱蔽的寫法會出事。

sDecimal 是每一檔商品各自的,跟著那一檔的結構一起送過來。但很自然會寫出來的第一版是——讀一次存成常數或設定值,之後所有商品共用

在一個只看台股、只看台指期的程式裡,這樣寫永遠不會出事,因為大家的 sDecimal 都是 2。等到有一天加進一檔期匯率商品,那個快取的 2 就會套到一個四位小數的商品上。

這比寫死 100 更難查,因為程式碼看起來「有在讀 sDecimal」——只是讀錯了時機。

sDecimal 要從當下那一檔的結構讀,不要快取成全域設定。

K 線的新舊輸出,換算規則不一樣

群益API 報價價格還有一個容易混淆的地方,它是「同一支程式在不同地方行為不一致」那種症狀的成因。

依官方說明:K 線舊版輸出格式的價格未經小數處理,新版輸出(sOutType=1)則已經處理過,由 K 線主機提供。

所以會出現這個狀況:你走快照拿到的價格要自己換算,走新版 K 線拿到的價格已經是處理好的——如果你對兩邊套用同一套換算,K 線那邊就會被多除一次

這不是資料髒,是兩條路的約定不同。 寫程式前先確認自己走的是哪一種輸出格式,比事後對著數字猜有效率得多。

時間與日期也是整數,而且不只一種格式

這是另一個獨立的坑:它跟價格無關,但處理群益API 報價價格時幾乎一定會一起遇到——SKCOM 的時間與日期欄位全部是整數編碼,不是時間型別。

欄位格式範例
日期yyyyMMdd20260916
時間hhmmss134530
毫秒/微秒六位數另有獨立欄位

134530 丟給泛用的日期時間解析函式,不會得到下午一點四十五分——你會拿到例外,或是一個 1970 年的時間戳。這些數字要自己拆位數再組。

群益API 報價價格的換算函式該怎麼寫?

重點只有一個:位數從結構讀,不要寫死、也不要快取。

// 價格是整數,小數位數由結構自己帶:實際價格 = 整數 / 10^sDecimal
static decimal ToPrice(long raw, short sDecimal)
{
    decimal factor = 1m;
    for (int i = 0; i < sDecimal; i++) factor *= 10m;
    return raw / factor;
}

// 時間與日期是整數編碼,要自己拆
// nDate = 20260916、nTime = 134530
static DateTime ToDateTime(int nDate, int nTime)
{
    int y = nDate / 10000, m = nDate / 100 % 100, d = nDate % 100;
    int hh = nTime / 10000, mm = nTime / 100 % 100, ss = nTime % 100;
    return new DateTime(y, m, d, hh, mm, ss);
}

⚠️ 上面的 ToDateTime 刻意沒有做範圍檢查,實務上要補。 盤後或異常狀態下可能拿到不合理的值,直接組 DateTime 會丟例外——而那個例外會從資料層一路冒上來,出現在一個跟時間毫無關係的地方。值不合理就當作沒有資料,不要讓例外離開這一層。

為什麼建議用 decimal 而不是 double?

如果這套群益API 報價價格的換算只用來顯示double 其實沒有問題。

但實務上有一個很自然的發展:同一套換算工具,後來會被送單那一端共用。 而下單那邊對價格的要求嚴格得多——差一檔就可能被退單,二進位浮點的誤差在那裡是會出事的。

所以建議是條件式的:如果你預期這套換算之後會被送單端共用,就從一開始用 decimal 一開始選對,比之後回來改一輪省事。

(下單端價格為什麼有那麼嚴格的要求,是另一篇的主題,這裡不展開。)

常見問題

群益API 報價價格為什麼要除以 100?

嚴格說不是除以 100,是除以 10^sDecimal。多數商品的 sDecimal 是 2,所以除以 100 剛好對;但官方自己就舉了一個四位小數的期匯率商品範例,那一檔除以 100 會大 100 倍。

群益API 報價價格我已經有讀 sDecimal 了,為什麼還是會錯?

檢查是不是讀一次就快取起來了。sDecimal 是每一檔商品各自的,要從當下那一檔的結構讀,不能存成全域設定給所有商品共用。

K 線的價格也要除嗎?

看輸出格式。依官方說明,舊版輸出未經小數處理,新版輸出(sOutType=1)已經處理過——對新版再除一次就錯了。

時間欄位可以直接丟給日期解析函式嗎?

不行。那是 yyyyMMdd/hhmmss 的整數編碼,不是時間戳。要自己拆位數再組,而且組之前先驗範圍。

換算一定要用 decimal 嗎?

只用來顯示的話 double 沒問題。但如果這套換算之後會被送單那邊共用,建議一開始就用 decimal——下單端對價格精度的要求嚴格得多。

風險揭露

期貨與選擇權屬高槓桿商品,價格波動可能造成超過原始保證金的損失,交易人須自負交易責任。本文為程式開發技術教學,說明報價欄位的編碼方式與換算,不構成投資建議,也不保證任何交易結果。程式化交易並不降低市場風險,反而可能因程式錯誤造成非預期的委託行為——價格換算錯誤正是這類錯誤的來源之一。

投資人教育資源

機構資源
臺灣期貨交易所(TAIFEX)期貨及選擇權數位學習網
證券暨期貨市場發展基金會證券期貨市場教育推廣
金融智慧網金管會金融知識平台
中華民國期貨業商業同業公會期貨業法規與宣導
證券投資人及期貨交易人保護中心投資人保護與申訴

延伸閱讀

參考資料

  • SKSTOCKLONG 結構定義(價格欄位為 LONGsDecimal 為小數位數)、K 線新舊輸出格式的差異、兩則價格範例(1101 與 RH1704),均依群益官方元件說明文件的國內報價章節。
  • 兩則價格範例的原文脈絡為 K 線舊版輸出格式的說明。
  • 時間與日期為整數編碼:實測歸納。
  • DateTime 前先驗範圍:實務建議,非官方規定。

免責聲明

本文章僅作為群益API實作經驗分享,不構成投資建議,且策略及程式皆應自行撰寫。期貨及衍生性金融商品交易屬高風險投資,請謹慎評估自身風險承擔能力。

延伸閱讀|相關文章

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *