新加坡股票 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)的全部流程:
- REST 即時報價 — 簡單快速,適合批次查詢與定時任務
- 歷史 K 線數據 — 多週期支援,適合策略回測與技術分析
- WebSocket 即時推送 — 低於 50ms 延遲,適用高頻與即時監控策略
- 逐筆成交數據 — 滿足市場微結構與執行品質分析需求
iTick 在新加坡市場的核心優勢:
- 完整覆蓋 SGX 所有上市公司
- 毫秒級低延遲串流
- 開發者友善的 Python 介面
- 免費方案實用,付費方案性價比高
立即前往 iTick 官網 註冊帳號,開始您的 Singapore 股市數據應用之旅!
延伸閱讀: