新加坡股票 API 接入指南:新交所(SGX)即時報價與歷史數據獲取

  1. iTick
  2. 教程
新加坡股票 API 接入指南:新交所(SGX)即時報價與歷史數據獲取 - iTick
新加坡股票 API 接入指南:新交所(SGX)即時報價與歷史數據獲取

新加坡作為亞洲頂尖的金融中心,其股市匯聚了眾多東南亞龍頭企業。從星展集團控股到新加坡電信,從揚子江船業到凱德集團,新加坡交易所(SGX)上市公司橫跨銀行金融、電信、房地產、海事與離岸等多個核心產業,是全球投資人布局東南亞市場的重要門戶。

本指南將詳細說明如何透過 iTick API 完整接入新加坡股市,涵蓋即時 Level-1 報價、歷史 OHLCV K 線、深度盤口快照與逐筆成交紀錄,並附上可直接投入生產的 Python 範例程式碼,協助您快速建構高效的新加坡股市數據與分析系統。

一、為什麼選擇 iTick 接入 SGX 市場?

在眾多市場數據供應商中,iTick 對開發者特別友善,尤其適合需要同時覆蓋多個亞洲與全球市場(包含新加坡)的量化團隊。

全面市場覆蓋
單一 API 金鑰即可接入新加坡(SGX)、美國、香港、台灣、日本、印度、馬來西亞、泰國等多個交易所。

靈活的傳輸協議

  • RESTful API — 適合單次查詢與批次輪詢
  • WebSocket — 超低延遲即時推送
  • FIX API — 機構級高頻交易專用通道

優異的開發者體驗
註冊後立即享有免費額度(無需信用卡);文件清晰,並提供 Python、Java、Go 等多語言官方範例。

專業級數據品質
毫秒級延遲;完整涵蓋最新成交(tick)、Level-1 報價、Level-2 盤口快照,滿足從自由裁量分析到高頻與量化策略的各種需求。

二、環境準備

開始接入前,請完成以下準備:

1. 註冊 iTick 帳號並取得 API Token

前往 iTick 官方網站 註冊帳號(約 30 秒完成,無需信用卡)。註冊完成後立即可在控制台取得您的專屬 API Token。

2. 安裝 Python 依賴套件

      pip install requests websocket-client pandas matplotlib

    

三、新加坡股票即時行情接入(REST API)

對於不需要即時推送的場景,REST API 是最簡單直接的方式。以下程式碼示範同時獲取三檔新加坡代表性藍籌股的即時報價:

  • 星展集團控股(D05) — 東南亞資產規模最大銀行
  • 華僑銀行(O39) — 新加坡主要金融機構
  • 新加坡電信(Z74 / Singtel) — 區域領先電信營運商
      import requests
import datetime

# 請替換為您實際的 API Token
API_TOKEN = "your_api_token_here"
BASE_URL = "https://api.itick.org"

def get_singapore_stock_quote(symbol):
    """
    獲取新加坡上市證券的即時 Level-1 報價
    :param symbol: SGX 股票代碼,例如 "D05"(星展)
    """
    url = f"{BASE_URL}/stock/quote"
    params = {
        "region": "SG",      # 新加坡市場代碼
        "code": symbol
    }
    headers = {
        "accept": "application/json",
        "token": API_TOKEN
    }

    try:
        response = requests.get(url, params=params, headers=headers, timeout=5)
        response.raise_for_status()
        result = response.json()

        if result.get("code") == 0:
            data = result.get("data", {})
            print(f"📊 證券名稱: {data.get('n', 'N/A')}")
            print(f"股票代碼: {data.get('s', 'N/A')}")
            print(f"最新成交價: {data.get('ld', 'N/A')} SGD")
            print(f"開盤價: {data.get('o', 'N/A')} SGD")
            print(f"日內最高: {data.get('h', 'N/A')} SGD")
            print(f"日內最低: {data.get('l', 'N/A')} SGD")
            print(f"成交量: {data.get('v', 'N/A')} 股")
            print(f"漲跌幅: {data.get('chp', 'N/A')}%")

            # 轉換時間戳(毫秒 → datetime)
            ts = data.get('t', 0) / 1000
            if ts > 0:
                dt = datetime.datetime.fromtimestamp(ts)
                print(f"數據時間: {dt.strftime('%Y-%m-%d %H:%M:%S')} (新加坡時間)")
            return data
        else:
            print(f"❌ API 錯誤: {result.get('msg', '未知錯誤')}")
            return None

    except Exception as e:
        print(f"❌ 請求異常: {str(e)}")
        return None

def get_multiple_quotes(symbols):
    """批次獲取多檔股票即時報價"""
    for symbol in symbols:
        print(f"\n{'='*50}")
        print(f"正在獲取 {symbol} 即時行情...")
        get_singapore_stock_quote(symbol)

# 單檔範例
print("🔍 獲取星展集團 (D05) 即時報價:")
get_singapore_stock_quote("D05")

# 批次範例
singapore_stocks = ["D05", "O39", "Z74"]
get_multiple_quotes(singapore_stocks)

    

四、獲取歷史 K 線數據(策略回測必備)

歷史數據是量化策略回測的基礎。以下範例獲取新加坡電信(Z74)的日線數據,並進行簡單視覺化展示:

      import requests
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime, timedelta

def get_singapore_stock_kline(symbol, ktype=8, limit=100):
    """
    獲取新加坡股票歷史 K 線數據
    :param symbol: 股票代碼,例如 "Z74"(新加坡電信)
    :param ktype: K 線類型 (1:1分鐘, 2:5分鐘, ..., 8:日線, 9:週線, 10:月線)
    :param limit: 獲取的 K 線條數
    """
    url = f"{BASE_URL}/stock/kline"
    params = {
        "region": "SG",
        "code": symbol,
        "kType": ktype,
        "limit": limit
    }
    headers = {
        "accept": "application/json",
        "token": API_TOKEN
    }

    try:
        response = requests.get(url, params=params, headers=headers)
        result = response.json()

        if result.get("code") == 0:
            kline_data = result.get("data", [])

            if not kline_data:
                print(f"❌ 未獲取到 {symbol} 的數據")
                return None

            df = pd.DataFrame(kline_data)
            df['datetime'] = pd.to_datetime(df['t'], unit='ms')
            df['datetime'] = df['datetime'].dt.tz_localize('UTC').dt.tz_convert('Asia/Singapore')
            df.set_index('datetime', inplace=True)

            df.rename(columns={
                'o': 'open', 'h': 'high', 'l': 'low',
                'c': 'close', 'v': 'volume'
            }, inplace=True)

            for col in ['open', 'high', 'low', 'close', 'volume']:
                df[col] = pd.to_numeric(df[col], errors='coerce')

            print(f"✅ 成功獲取 {len(df)} 條 K 線")
            print(f"數據範圍:{df.index[0]}{df.index[-1]}")

            print("\n📊 最近 5 條 K 線:")
            print(df[['open', 'high', 'low', 'close', 'volume']].tail())

            return df
        else:
            print(f"❌ API 錯誤: {result.get('msg', '未知錯誤')}")
            return None

    except Exception as e:
        print(f"❌ 請求異常: {str(e)}")
        return None

def plot_stock_data(df, symbol):
    """繪製收盤價走勢圖與 20 日均線"""
    if df is None or df.empty:
        return

    plt.figure(figsize=(14, 7))
    plt.plot(df.index, df['close'], 'b-', linewidth=1.5, label='收盤價')
    plt.title(f'{symbol} 收盤價走勢圖(新加坡市場)', fontsize=16)
    plt.xlabel('日期')
    plt.ylabel('價格 (SGD)')
    plt.grid(True, alpha=0.3)
    plt.legend()

    df['MA20'] = df['close'].rolling(window=20).mean()
    plt.plot(df.index, df['MA20'], 'r--', linewidth=1, label='20日均線')
    plt.legend()

    plt.gcf().autofmt_xdate()
    plt.tight_layout()
    plt.show()

# 範例:獲取新加坡電信最近 100 個交易日數據
print("\n🔍 正在獲取新加坡電信 (Z74) 歷史數據...")
singtel_df = get_singapore_stock_kline("Z74", ktype=8, limit=100)

if singtel_df is not None:
    plot_stock_data(singtel_df, "Z74 (新加坡電信)")

    print("\n📈 統計指標:")
    print(f"最新收盤價: {singtel_df['close'].iloc[-1]:.3f} SGD")
    print(f"期間最高價: {singtel_df['high'].max():.3f} SGD")
    print(f"期間最低價: {singtel_df['low'].min():.3f} SGD")
    print(f"平均日成交量: {singtel_df['volume'].mean():,.0f} 股")
    print(f"期間漲跌幅: {((singtel_df['close'].iloc[-1] / singtel_df['close'].iloc[0] - 1) * 100):.2f}%")

    

五、WebSocket 即時行情訂閱(低延遲策略適用)

對於高頻或需要極低延遲的策略,WebSocket 是最佳選擇。以下範例展示如何訂閱新加坡股票的即時報價、成交與盤口更新:

      import websocket
import json
import threading
import time

WS_URL = "wss://api.itick.org/stock"
API_TOKEN = "your_api_token_here"  # ← 請替換成您的實際 Token

def on_message(ws, message):
    """處理接收到的訊息"""
    data = json.loads(message)

    if data.get("code") == 1 and data.get("msg") == "Connected Successfully":
        print("✅ WebSocket 連線成功,等待認證...")

    elif data.get("resAc") == "auth":
        if data.get("code") == 1:
            print("✅ 認證成功,開始訂閱...")
            subscribe(ws)
        else:
            print("❌ 認證失敗")
            ws.close()

    elif data.get("resAc") == "subscribe":
        if data.get("code") == 1:
            print("✅ 訂閱成功")
        else:
            print(f"❌ 訂閱失敗: {data.get('msg')}")

    elif data.get("data"):
        market_data = data["data"]
        data_type = market_data.get("type")
        symbol = market_data.get("s")

        if data_type == "quote":
            print(f"[{symbol}] 最新價: {market_data.get('ld')} SGD | "
                  f"漲跌幅: {market_data.get('chp')}% | "
                  f"成交量: {market_data.get('v')}")
        elif data_type == "tick":
            print(f"[{symbol}] 成交: {market_data.get('ld')} SGD | "
                  f"時間: {time.strftime('%H:%M:%S', time.localtime(market_data.get('t')/1000))}")
        elif data_type == "depth":
            bids = market_data.get("b", [])[:3]  # 買三檔
            asks = market_data.get("a", [])[:3]  # 賣三檔
            print(f"[{symbol}] 買盤: {bids} | 賣盤: {asks}")

def on_error(ws, error):
    print(f"❌ WebSocket 錯誤: {error}")

def on_close(ws, close_status_code, close_msg):
    print(f"🔌 WebSocket 連線關閉: {close_msg}")

def on_open(ws):
    print("🌐 WebSocket 連線已開啟")

def subscribe(ws):
    """訂閱新加坡股票即時數據"""
    subscribe_msg = {
        "ac": "subscribe",
        "params": "D05$SG,O39$SG,Z74$SG",
        "types": "tick,quote,depth"
    }
    ws.send(json.dumps(subscribe_msg))
    print(f"📤 已發送訂閱請求: {subscribe_msg['params']}")

def send_ping(ws):
    """每 30 秒發送心跳維持連線"""
    while True:
        time.sleep(30)
        ping_msg = {
            "ac": "ping",
            "params": str(int(time.time() * 1000))
        }
        ws.send(json.dumps(ping_msg))
        print("💓 心跳已發送")

if __name__ == "__main__":
    ws = websocket.WebSocketApp(
        WS_URL,
        header={"token": API_TOKEN},
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close
    )

    ping_thread = threading.Thread(target=send_ping, args=(ws,))
    ping_thread.daemon = True
    ping_thread.start()

    print("🚀 啟動 WebSocket 連線...")
    ws.run_forever()

    

六、獲取逐筆成交(Tick)數據

對於需要精細市場微結構分析的策略,逐筆成交數據是重要輸入。以下為 REST 方式獲取最新 Tick 範例:

      def get_singapore_tick_data(symbol):
    """
    獲取新加坡股票最新逐筆成交數據
    :param symbol: 股票代碼,例如 "D05"
    """
    url = f"{BASE_URL}/stock/tick"
    params = {
        "region": "SG",
        "code": symbol
    }
    headers = {
        "accept": "application/json",
        "token": API_TOKEN
    }

    try:
        response = requests.get(url, params=params, headers=headers)
        result = response.json()

        if result.get("code") == 0:
            tick_data = result.get("data", {})
            print(f"📊 股票: {tick_data.get('s', 'N/A')}")
            print(f"最新成交價: {tick_data.get('ld', 'N/A')} SGD")
            print(f"成交量: {tick_data.get('v', 'N/A')} 股")

            ts = tick_data.get('t', 0) / 1000
            if ts > 0:
                dt = datetime.datetime.fromtimestamp(ts)
                print(f"成交時間: {dt.strftime('%Y-%m-%d %H:%M:%S')} (新加坡時間)")
            return tick_data
        else:
            print(f"❌ API 錯誤: {result.get('msg', '未知錯誤')}")
            return None

    except Exception as e:
        print(f"❌ 請求異常: {str(e)}")
        return None

print("\n🔍 獲取星展銀行 (D05) 最新逐筆成交:")
get_singapore_tick_data("D05")

    

七、新加坡市場實用參考

1. 股票代碼格式

新加坡市場使用本地代碼(如 D05、O39、Z74),在 iTick API 中透過 region=SG 指定市場。WebSocket 訂閱時格式為 代碼$SG

2. 主要新加坡股票代碼參考表

公司名稱股票代碼所屬板塊業務簡介
DBS Group Holdings (星展銀行)D05金融東南亞資產規模最大銀行
OCBC Bank (華僑銀行)O39金融新加坡主要銀行
United Overseas Bank (大華銀行)U11金融新加坡主要銀行
Singapore Telecommunications (新電信)Z74電信新加坡及區域領先電信營運商
Keppel Corporation (吉寶企業)BN4綜合企業海事、房地產、基礎設施
Sembcorp Industries (勝科工業)U96能源能源、水務、城市解決方案
CapitaLand Group (凱德集團)C31房地產亞洲領先房地產投資集團
Yangzijiang Shipbuilding (揚子江船業)BS6造船中國在新加坡上市的造船企業
Wilmar International (豐益國際)F34農業全球領先棕櫚油與農產品企業

3. 新交所交易時間(新加坡時間)

  • 開盤前集合競價:08:30 – 08:59
  • 連續交易:09:00 – 12:00 / 13:00 – 17:00
  • 收盤前集合競價:17:00 – 17:16
  • 午休:12:00 – 13:00
  • 時區:SGT (UTC+8),與北京/香港無時差

4. 常見問題

Q:免費方案有哪些限制?
A:免費方案提供無限次即時報價呼叫、日/週/月 K 線歷史數據以及 WebSocket 連線,對個人學習、研究與輕量應用已足夠。

Q:如何取得更長期的歷史數據?
A:付費方案支援超過 15 年的完整歷史數據,適合專業回測與因子研究。

Q:WebSocket 連線不穩定怎麼辦?
A:範例程式已內建 30 秒心跳機制。如仍斷線,可自行實作自動重連邏輯。

Q:新加坡股票代碼是否區分大小寫?
A:不區分,但建議使用官方大寫格式(如 D05、O39、Z74)。

八、總結

透過本指南,您已掌握使用 iTick API 完整接入新加坡交易所(SGX)的全部流程:

  1. REST 即時報價 — 簡單快速,適合批次查詢與定時任務
  2. 歷史 K 線數據 — 多週期支援,適合策略回測與技術分析
  3. WebSocket 即時推送 — 低於 50ms 延遲,適用高頻與即時監控策略
  4. 逐筆成交數據 — 滿足市場微結構與執行品質分析需求

iTick 在新加坡市場的核心優勢

  • 完整覆蓋 SGX 所有上市公司
  • 毫秒級低延遲串流
  • 開發者友善的 Python 介面
  • 免費方案實用,付費方案性價比高

立即前往 iTick 官網 註冊帳號,開始您的 Singapore 股市數據應用之旅!


延伸閱讀: