土耳其股票 API 技術接入指南:BIST 即時行情與歷史數據深度解析

引言:為什麼土耳其市場值得技術開發者關注?
土耳其作為橫跨歐亞大陸的關鍵新興市場,其資本市場近年吸引越來越多國際投資者的目光。伊斯坦堡證券交易所(Borsa Istanbul,簡稱 BIST)是該國唯一的交易所,擁有超過 400 家上市公司,總市值超過 2000 億美元,涵蓋金融、工業、消費品、能源等多樣化產業。
對技術開發者及量化團隊而言,土耳其股票市場具有獨特的技術挑戰與機遇:
1. 新興市場的數據接入難題:與歐美成熟市場不同,土耳其股票數據的標準化程度較低,免費公共介面普遍存在 15 分鐘以上的延遲,無法滿足即時交易需求;歷史數據往往只有 1-2 年,不足以支撐長期策略回測;文件品質參差不齊,股票代碼格式混亂導致接入困難。
2. 歐亞樞紐的策略地位:土耳其位處歐亞交界,其資本市場與歐洲、中東、中亞市場存在較強的聯動性,為跨區域套利策略提供獨特機會。同時,土耳其里拉(TRY)的匯率波動也為量化策略增添多元化的 alpha 來源。
3. 優質藍籌股的投資價值:從銀行巨頭 İş Bankası(ISCTR)、Garanti BBVA(GARAN),到工業龍頭 Koç Holding(KCHOL),從鋼鐵巨頭 Ereğli Demir ve Çelik(EREGL),到全球航線網絡最廣的土耳其航空(THYAO),BIST 市場為投資者提供豐富的行業選擇。
4. 高波動性的交易機會:土耳其里拉匯率波動及宏觀經濟環境變化,令 BIST 市場呈現較高波動性,為短線交易者及量化策略創造更多機會。
本文將從技術開發者的角度,深度解析如何使用 iTick API 構建穩定、高效的土耳其股票數據接入模組。iTick 官方文件顯示,平台已全面支援土耳其市場(Turkey),開發者可透過統一 API 介面獲取 BIST 交易所全部股票的即時行情、歷史 K 線及盤口數據。
一、iTick 土耳其市場數據能力一覽
根據 iTick 官方文件,平台針對土耳其市場提供以下核心數據服務:
| 數據類型 | REST 介面 | WebSocket 推送 | 典型應用場景 |
|---|---|---|---|
| 即時報價 | /stock/quote | 支援 | 即時行情展示、價格監控 |
| 歷史 K 線 | /stock/kline | 支援 | 策略回測、技術分析 |
| 盤口深度 | /stock/depth | 支援 | 流動性分析、訂單簿監控 |
| 逐筆成交 | /stock/tick | 支援 | 高頻交易、市場微觀結構分析 |
| 公司資訊 | /stock/info | 不支援 | 基本面分析、選股策略 |
技術特點:
- 低延遲:WebSocket 推送延遲<50ms,滿足高頻交易需求
- 多週期 K 線:支援分鐘線(1、5、15、30、60 分鐘)、日線、週線、月線
- 多檔盤口:支援買賣雙方多檔掛單數據
- 統一認證:透過 API Token 在 headers 中鑑權
- 免費套餐:基礎行情無限呼叫,個人開發者友好
二、土耳其市場核心數據速查
主流土耳其股票代碼參考
| 公司名稱 | 股票代碼 | 所屬板塊 | 業務簡介 |
|---|---|---|---|
| Koç Holding (科奇控股) | KCHOL | 工業集團 | 土耳其最大工業集團,業務涵蓋能源、汽車、消費品等領域 |
| Garanti BBVA | GARAN | 金融 | 西班牙 BBVA 控股的土耳其領先銀行 |
| Ereğli Demir ve Çelik (埃雷利鋼鐵) | EREGL | 鋼鐵 | 土耳其最大鋼鐵生產商 |
| Turkish Airlines (土耳其航空) | THYAO | 航空 | 全球航線網絡最廣的航空公司之一 |
| Turkcell (土耳其電信) | TCELL | 電信 | 土耳其領先移動通訊營運商 |
| Arçelik (阿奇立克) | ARCLK | 家電 | 歐洲知名家電品牌 |
| Koza Altın (科扎黃金) | KOZAL | 礦業 | 土耳其領先黃金礦業公司 |
市場技術參數
| 項目 | 說明 |
|---|---|
| 市場代碼 | region=TR(REST)或 $TR(WebSocket) |
| 交易所 | Borsa Istanbul (BIST) |
| 指數代碼 | XU100(BIST 100 指數) |
| 交易時間 | 伊斯坦堡時間 10:00-18:00(夏令時)/ 11:00-19:00(冬令時) |
| 對應北京時間 | 15:00-23:00(夏令時)/ 16:00-00:00(冬令時) |
| 貨幣單位 | 土耳其里拉(TRY) |
三、REST API 實戰:歷史數據獲取與回測支援
3.1 基礎配置與鑑權
所有 iTick REST API 請求都需要在 headers 中攜帶 API Token,基址為https://api.itick.org:
import requests
API_TOKEN = "your_token_here" # 從iTick官網獲取
BASE_URL = "https://api.itick.org"
def get_headers():
return {
"accept": "application/json",
"token": API_TOKEN
}
3.2 即時行情獲取
獲取土耳其航空(THYAO)即時報價:
def get_turkey_quote(symbol):
"""獲取土耳其股票即時報價"""
url = f"{BASE_URL}/stock/quote"
params = {"region": "TR", "code": symbol}
resp = requests.get(url, params=params, headers=get_headers(), timeout=5)
data = resp.json()
if data.get("code") == 0:
quote = data["data"]
print(f"📊 {quote.get('n')} ({quote.get('s')})")
print(f"最新價: {quote.get('ld')} TRY")
print(f"漲跌幅: {quote.get('chp')}%")
print(f"成交量: {quote.get('v')}")
return quote
else:
print(f"API錯誤: {data.get('msg')}")
# 測試
get_turkey_quote("THYAO")
回應欄位說明:
ld:最新價chp:漲跌幅(百分比)v:成交量o:開盤價h:最高價l:最低價t:時間戳(毫秒)
3.3 歷史 K 線數據
歷史數據是量化回測的基礎。iTick 提供超 30 年的 K 線數據,支援多種週期:
def get_turkey_kline(symbol, ktype=8, limit=100):
"""
獲取土耳其股票歷史K線數據
ktype參數說明:
1: 1分鐘線
2: 5分鐘線
3: 15分鐘線
4: 30分鐘線
5: 60分鐘線
8: 日線
9: 週線
10: 月線
"""
url = f"{BASE_URL}/stock/kline"
params = {
"region": "TR",
"code": symbol,
"kType": ktype,
"limit": str(limit) # 注意:limit需要傳字串
}
resp = requests.get(url, params=params, headers=get_headers())
data = resp.json()
if data.get("code") == 0:
klines = data.get("data", [])
period_map = {1:"1分鐘",2:"5分鐘",3:"15分鐘",4:"30分鐘",5:"60分鐘",8:"日線",9:"週線",10:"月線"}
print(f"✅ 獲取到 {len(klines)} 條{period_map.get(ktype, '')}數據")
# 轉換為OHLCV格式
for k in klines[-5:]: # 顯示最近5條
print(f"時間:{k['t']} 開:{k['o']} 高:{k['h']} 低:{k['l']} 收:{k['c']} 量:{k['v']}")
return klines
else:
print(f"錯誤: {data.get('msg')}")
# 測試:獲取KCHOL日線數據
get_turkey_kline("KCHOL", ktype=8, limit=30)
# 測試:獲取EREGL週線數據
get_turkey_kline("EREGL", ktype=9, limit=20)
# 測試:獲取GARAN60分鐘線
get_turkey_kline("GARAN", ktype=5, limit=50)
3.4 盤口深度數據
盤口數據對於分析市場流動性、辨識支撐阻力位至關重要:
def get_turkey_depth(symbol):
"""獲取土耳其股票即時盤口數據"""
url = f"{BASE_URL}/stock/depth"
params = {"region": "TR", "code": symbol}
resp = requests.get(url, params=params, headers=get_headers())
data = resp.json()
if data.get("code") == 0:
depth = data.get("data", {})
print(f"📊 {symbol} 盤口深度")
print(f"--- 賣盤 (Ask) ---")
for ask in depth.get('a', [])[:5]: # 顯示前5檔
print(f"檔位{ask.get('po')}: {ask.get('p')} TRY | 數量: {ask.get('v')}")
print(f"--- 買盤 (Bid) ---")
for bid in depth.get('b', [])[:5]:
print(f"檔位{bid.get('po')}: {bid.get('p')} TRY | 數量: {bid.get('v')}")
return depth
else:
print(f"錯誤: {data.get('msg')}")
# 測試
get_turkey_depth("KCHOL")
3.5 公司基本面數據
def get_turkey_company_info(symbol):
"""獲取土耳其公司基本資訊"""
url = f"{BASE_URL}/stock/info"
params = {"region": "TR", "code": symbol}
resp = requests.get(url, params=params, headers=get_headers())
data = resp.json()
if data.get("code") == 0:
company = data.get("data", {})
print(f"🏢 {company.get('n')} ({symbol})")
print(f"行業: {company.get('i')}")
print(f"板塊: {company.get('s')}")
print(f"簡介: {company.get('bd')[:100]}...")
print(f"總市值: {company.get('mcb')}")
print(f"市盈率: {company.get('pet')}")
return company
else:
print(f"錯誤: {data.get('msg')}")
get_turkey_company_info("KCHOL")
四、WebSocket 即時推送:構建低延遲數據流
對於量化交易系統,WebSocket 是實現即時行情監控的首選方案。iTick WebSocket 支援quote(報價)、tick(逐筆成交)、depth(盤口深度)三種數據類型。
4.1 生產級 WebSocket 客戶端
以下實現包含自動重連、心跳保活、多標的訂閱等生產級特性:
import websocket
import json
import threading
import time
from typing import List, Callable
class TurkeyWebSocketClient:
"""土耳其股票WebSocket即時行情客戶端(支援自動重連)"""
def __init__(self, token: str, symbols: List[str], callback: Callable, types: str = "quote"):
self.token = token
self.symbols = [f"{s}$TR" for s in symbols] # 格式:代碼$TR
self.callback = callback
self.types = types
self.ws = None
self.running = False
self.reconnect_interval = 5
self.ws_url = "wss://api.itick.org/stock"
def start(self):
self.running = True
self._connect()
def _connect(self):
headers = {"token": self.token}
self.ws = websocket.WebSocketApp(
self.ws_url,
header=headers,
on_open=self._on_open,
on_message=self._on_message,
on_error=self._on_error,
on_close=self._on_close
)
# 在獨立執行緒運行
wst = threading.Thread(target=self.ws.run_forever, daemon=True)
wst.start()
def _on_open(self, ws):
print("✅ WebSocket連接成功,開始訂閱...")
subscribe_msg = {
"ac": "subscribe",
"params": ",".join(self.symbols),
"types": self.types # quote/tick/depth
}
ws.send(json.dumps(subscribe_msg))
print(f"📤 訂閱請求: {subscribe_msg['params']}")
# 啟動心跳
self._start_heartbeat()
def _start_heartbeat(self):
def heartbeat():
while self.running:
time.sleep(30)
if self.ws and self.ws.sock and self.ws.sock.connected:
ping = {"ac": "ping", "params": str(int(time.time()*1000))}
self.ws.send(json.dumps(ping))
print("💓 心跳已發送")
threading.Thread(target=heartbeat, daemon=True).start()
def _on_message(self, ws, message):
try:
data = json.loads(message)
if "data" in data:
self.callback(data["data"])
except Exception as e:
print(f"訊息解析錯誤: {e}")
def _on_error(self, ws, error):
print(f"❌ WebSocket錯誤: {error}")
def _on_close(self, ws, close_status, close_msg):
print(f"🔌 連接關閉: {close_msg}")
if self.running:
print(f"⏱️ {self.reconnect_interval}秒後重連...")
time.sleep(self.reconnect_interval)
self._connect()
def stop(self):
self.running = False
if self.ws:
self.ws.close()
# 使用範例
def handle_market_data(data):
"""自訂數據處理函數"""
data_type = data.get("type")
symbol = data.get("s")
if data_type == "quote":
print(f"[{symbol}] 最新:{data.get('ld')} TRY | 漲跌:{data.get('chp')}% | 量:{data.get('v')}")
elif data_type == "tick":
print(f"[{symbol}] 成交:{data.get('ld')} TRY | 時間:{data.get('t')}")
elif data_type == "depth":
bids = data.get("b", [])[:3]
asks = data.get("a", [])[:3]
print(f"[{symbol}] 買盤:{bids} | 賣盤:{asks}")
# 訂閱土耳其主流股票
client = TurkeyWebSocketClient(
token="your_token_here",
symbols=["KCHOL", "EREGL", "THYAO", "GARAN"],
types="quote,tick,depth",
callback=handle_market_data
)
client.start()
# 保持主執行緒運行
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
client.stop()
4.2 WebSocket 回應範例
報價(quote)回應:
{
"code": 1,
"data": {
"s": "KCHOL",
"r": "TR",
"ld": 164.5,
"chp": 1.23,
"v": 12456700,
"o": 162.8,
"h": 165.2,
"l": 162.5,
"t": 1741680000000,
"type": "quote"
}
}
盤口(depth)回應:
{
"code": 1,
"data": {
"s": "KCHOL",
"r": "TR",
"a": [
{ "po": 1, "p": 164.6, "v": 15000 },
{ "po": 2, "p": 164.7, "v": 23000 }
],
"b": [
{ "po": 1, "p": 164.4, "v": 12000 },
{ "po": 2, "p": 164.3, "v": 18000 }
],
"type": "depth"
}
}
五、高級應用:量化策略整合
5.1 將 K 線數據轉換為 DataFrame
import pandas as pd
def kline_to_dataframe(klines):
"""將K線數據轉換為Pandas DataFrame"""
df = pd.DataFrame(klines)
df['timestamp'] = pd.to_datetime(df['t'], unit='ms')
df.set_index('timestamp', 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])
return df
# 獲取數據並轉換為DataFrame
klines = get_turkey_kline("KCHOL", ktype=8, limit=100)
if klines:
df = kline_to_dataframe(klines)
print(df.head())
5.2 計算技術指標
def calculate_technical_indicators(df):
"""計算常用技術指標"""
# 移動平均線
df['MA20'] = df['close'].rolling(window=20).mean()
df['MA50'] = df['close'].rolling(window=50).mean()
# RSI
delta = df['close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
rs = gain / loss
df['RSI'] = 100 - (100 / (1 + rs))
# MACD
exp12 = df['close'].ewm(span=12, adjust=False).mean()
exp26 = df['close'].ewm(span=26, adjust=False).mean()
df['MACD'] = exp12 - exp26
df['Signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
return df
# 計算指標
df_with_indicators = calculate_technical_indicators(df)
print(df_with_indicators[['close', 'MA20', 'RSI', 'MACD']].tail())
六、生產環境最佳實務
6.1 限流與重試策略
為避免觸發 API 限制,建議在程式碼中加入限流和重試邏輯:
import time
from functools import wraps
def rate_limit(max_calls_per_second=2):
"""限流裝飾器"""
def decorator(func):
last_called = [0.0]
@wraps(func)
def wrapper(*args, **kwargs):
elapsed = time.time() - last_called[0]
left_to_wait = 1.0/max_calls_per_second - elapsed
if left_to_wait > 0:
time.sleep(left_to_wait)
ret = func(*args, **kwargs)
last_called[0] = time.time()
return ret
return wrapper
return decorator
@rate_limit(max_calls_per_second=2)
def rate_limited_api_call(symbol):
return get_turkey_quote(symbol)
6.2 錯誤碼處理
| 錯誤碼 | 含義 | 解決方案 |
|---|---|---|
| 401 | 無效 API Key | 檢查 Token 是否正確,重新生成 |
| 404 | 數據不存在 | 確認 region=TR,股票代碼正確 |
| 429 | 請求過頻 | 降低請求頻率,或升級套餐 |
6.3 數據對齊與快取策略
class TurkeyDataCache:
"""簡單的本地快取,減少API呼叫"""
def __init__(self, ttl_seconds=60):
self.cache = {}
self.ttl = ttl_seconds
def get(self, key):
if key in self.cache:
data, timestamp = self.cache[key]
if time.time() - timestamp < self.ttl:
return data
return None
def set(self, key, data):
self.cache[key] = (data, time.time())
# 使用範例
cache = TurkeyDataCache(ttl_seconds=30)
def get_cached_quote(symbol):
cached = cache.get(f"quote_{symbol}")
if cached:
print("使用快取數據")
return cached
print("呼叫API獲取")
data = get_turkey_quote(symbol)
if data:
cache.set(f"quote_{symbol}", data)
return data
七、總結:構建專業級土耳其股票數據模組
透過本文的深度解析,您已經掌握了使用 iTick API 構建土耳其股票數據模組的核心技術:
- REST API:適用於歷史數據獲取、批量查詢、基本面分析,支援多種 K 線週期
- WebSocket:實現低延遲即時行情推送,支援自動重連和心跳保活
- 技術分析整合:將 K 線數據轉化為量化策略可用的技術指標
- 生產級優化:限流、重試、快取、錯誤處理等最佳實務
iTick 為土耳其市場提供完整的數據覆蓋,免費套餐即可滿足個人開發者需求,付費套餐適合專業量化團隊。平台支援透過 Telegram(iticksupport)和 WhatsApp 聯絡客服獲取技術支援。
立即前往 iTick 官網 註冊,獲取您的 API Key,開啟土耳其股市量化之旅!
延伸閱讀: