土耳其股票API技术接入指南:BIST实时行情与历史数据深度解析

  1. iTick
  2. 教程
土耳其股票API技术接入指南:BIST实时行情与历史数据深度解析 - iTick
土耳其股票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 BBVAGARAN金融西班牙 BBVA 控股的土耳其领先银行
Ereğli Demir ve Çelik (埃雷利钢铁)EREGL钢铁土耳其最大钢铁生产商
Turkish Airlines (土耳其航空)THYAO航空全球航线网络最广的航空公司之一
Turkcell (土耳其电信)TCELL电信土耳其领先移动通信运营商
Arçelik (阿奇立克)ARCLK家电欧洲知名家电品牌
Koza Altin (科扎黄金)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 构建土耳其股票数据模块的核心技术:

  1. REST API:适用于历史数据获取、批量查询、基本面分析,支持多种 K 线周期
  2. WebSocket:实现低延迟实时行情推送,支持自动重连和心跳保活
  3. 技术分析集成:将 K 线数据转化为量化策略可用的技术指标
  4. 生产级优化:限流、重试、缓存、错误处理等最佳实践

iTick 为土耳其市场提供完整的数据覆盖,免费套餐即可满足个人开发者需求,付费套餐适合专业量化团队。平台支持通过 Telegram(iticksupport)和 WhatsApp 联系客服获取技术支持。

立即访问 iTick 官网 注册,获取您的 API Key,开启土耳其股市量化之旅!


延伸阅读: