引言:量化交易的"燃料"问题
量化交易的起点从来不是策略模型,而是数据。据统计,超过 85% 的量化策略失效,其核心原因之一是行情数据的延迟或接口不稳定。对个人开发者或小型团队而言,专业数据源(如 Bloomberg Terminal)年费动辄数万美元,而免费渠道要么格式混乱、要么延迟严重、要么连接极不稳定。

那么,2026 年的个人量化交易者到底有哪些可靠且免费的 API 可用?如何在不违反使用条款的前提下搭建稳定、可扩展的数据采集系统?本文将从数据源选型 、iTick API 接入实战 、性能优化与坑点规避三个维度,给出完整的技术方案。
一、免费数据源选型:先搞清楚你的需求
在动手写代码之前,先问自己三个问题:
- 你需要什么类型的资产? A 股、美股、加密货币、外汇还是期货?不同数据源各有侧重。
- 你对实时性要求多高? 高频策略需要 tick 级实时推送(WebSocket),回测研究则接受 15 分钟延迟。
- 你能接受多大的技术投入? 有的 API 开箱即用(无需注册),有的需要申请 token、理解文档、处理各种格式陷阱。
目前市场上主流的免费量化数据源大致可分为三类:
- 开源 Python 库:如 AKShare、yfinance、Baostock。优点是完全免费且无需 API 密钥,即装即用;缺点是数据源依赖第三方网站,稳定性不可控,部分接口有延迟。
- 商业 API 免费层:如 iTick、Tushare Pro、Alpha Vantage。优点是接口规范、延迟低、有官方文档和技术支持;缺点是有请求频率限制,部分需要注册。
- 交易所直连:如 Binance WebSocket、Coinbase API。优点是实时性最好,数据源权威;缺点是仅限加密货币,需要处理原始协议。
对于大多数个人开发者,组合使用 是最佳策略:用开源库获取历史数据做回测,用商业免费 API 或交易所直连做实时行情监控。本文后续将介绍 iTick API 的接入方法,因为它同时提供了 REST 和 WebSocket 两种协议,覆盖 A 股、港股、美股、外汇、加密货币等多个市场,且免费套餐对个人开发者足够友好。
二、跨市场实时行情的免费方案
1. REST API 实战:获取实时与历史数据
以下代码示例均假设你已经安装了 requests 和 pandas 库。
1.1 基础配置
python
import requests
import pandas as pd
API_TOKEN = "你的API Token"
BASE_URL = "https://api.itick.org"
HEADERS = {"accept": "application/json", "token": API_TOKEN}
1.2 获取单只股票实时报价
python
def get_quote(region, code):
url = f"{BASE_URL}/stock/quote?region={region}&code={code}"
resp = requests.get(url, headers=HEADERS)
if resp.status_code == 200:
data = resp.json()
if data.get("code") == 0:
return data.get("data")
return None
# 示例:获取苹果公司(AAPL)实时行情
quote = get_quote("US", "AAPL")
if quote:
print(f"最新价: {quote['ld']}, 涨跌幅: {quote['chp']}%, 成交量: {quote['v']}")
参数说明:region 可选 US(美股)、SH(上交所)、SZ(深交所)、HK(港股)等。返回字段中 ld 为最新价,chp 为涨跌幅(百分比),v 为成交量。
1.3 批量获取多只股票实时报价
python
def get_batch_quotes(region, codes):
# codes 为逗号分隔的字符串,如 "AAPL,MSFT,GOOG"
url = f"{BASE_URL}/stock/quotes?region={region}&codes={codes}"
resp = requests.get(url, headers=HEADERS)
if resp.status_code == 200:
data = resp.json()
if data.get("code") == 0:
return data.get("data")
return None
quotes = get_batch_quotes("US", "AAPL,MSFT,GOOG")
if quotes:
df = pd.DataFrame(quotes).T
print(df[["ld", "chp"]].head())
1.4 获取历史 K 线数据(用于回测)
python
def get_kline(region, code, ktype=6, limit=100):
"""
ktype: 1=分钟线, 2=5分钟, 3=15分钟, 4=30分钟, 5=60分钟,
6=日线, 7=周线, 8=月线
"""
url = f"{BASE_URL}/stock/kline?region={region}&code={code}&kType={ktype}&limit={limit}"
resp = requests.get(url, headers=HEADERS)
if resp.status_code == 200:
data = resp.json()
if data.get("code") == 0:
klines = data.get("data", [])
df = pd.DataFrame(klines, columns=["timestamp", "open", "high", "low", "close", "volume"])
df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
df.set_index("timestamp", inplace=True)
return df
return None
# 获取贵州茅台日线数据(最近100个交易日)
df = get_kline("SH", "600519", ktype=6, limit=100)
print(df.tail())
iTick 支持长达 15 年的日线历史数据,通过增加 limit 参数即可获取更多。
1.5 获取外汇数据
python
def get_forex(region="GB", code="EURUSD"):
url = f"{BASE_URL}/forex/quote?region={region}&code={code}"
resp = requests.get(url, headers=HEADERS)
if resp.status_code == 200:
data = resp.json()
if data.get("code") == 0:
return data.get("data")
return None
eurusd = get_forex("GB", "EURUSD")
print(f"EURUSD 最新价: {eurusd['ld']}")
1.6 获取加密货币数据
python
def get_crypto(code="BTC-USD"):
url = f"{BASE_URL}/crypto/quote?code={code}"
resp = requests.get(url, headers=HEADERS)
if resp.status_code == 200:
data = resp.json()
if data.get("code") == 0:
return data.get("data")
return None
btc = get_crypto("BTC-USD")
print(f"比特币: ${btc['ld']}")
2. WebSocket 实时推送:适合低延迟策略
对于需要实时监控多只股票走势的策略,REST API 的轮询方式效率较低。WebSocket 采用长连接推送机制,数据实时到达,延迟可控制在 50ms 以内。
2.1 安装依赖
bash
pip install websocket-client
2.2 完整的 WebSocket 客户端示例
python
import websocket
import json
import threading
import time
API_TOKEN = "你的API Token"
WS_URL = "wss://api-free.itick.org/stock" # 免费版 WebSocket 地址
def on_message(ws, message):
data = json.loads(message)
# 处理认证结果
if 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"):
for symbol, tick in data["data"].items():
print(f"{symbol} 最新价: {tick.get('ld')}, 成交量: {tick.get('v', 0)}")
def on_error(ws, error):
print(f"WebSocket 错误: {error}")
def on_close(ws, close_status_code, close_msg):
print("WebSocket 连接已关闭")
def on_open(ws):
# 发送认证请求
auth_msg = {"ac": "auth", "token": API_TOKEN}
ws.send(json.dumps(auth_msg))
def subscribe(ws):
# 订阅 tick 数据,多个代码用逗号分隔,格式:code$region
sub_msg = {
"ac": "subscribe",
"params": "AAPL$US,MSFT$US,600519$SH",
"types": "tick"
}
ws.send(json.dumps(sub_msg))
def send_heartbeat(ws):
"""每30秒发送心跳保持连接"""
while True:
time.sleep(30)
try:
ws.send(json.dumps({"ac": "ping"}))
except:
break
if __name__ == "__main__":
ws = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message,
on_error=on_error,
on_close=on_close
)
# 启动心跳线程
threading.Thread(target=send_heartbeat, args=(ws,), daemon=True).start()
ws.run_forever()
WebSocket 支持的数据类型包括 tick(逐笔成交)、quote(报价)和 depth(盘口深度),可通过 types 参数自由组合。
三、实战案例:双均线策略回测
有了数据接口,我们来构建一个简单的量化策略------双均线交叉策略,并用 iTick 获取的历史数据进行回测。
策略逻辑:当 20 日均线上穿 60 日均线时全仓买入,当 20 日均线下穿 60 日均线时全仓卖出。
python
import numpy as np
def fetch_kline_for_backtest(symbol, region, limit=200):
"""获取日线数据用于回测"""
return get_kline(region, symbol, ktype=6, limit=limit)
def backtest_double_ma(df, short=20, long=60, initial_capital=100000):
df = df.copy()
df["MA_short"] = df["close"].rolling(short).mean()
df["MA_long"] = df["close"].rolling(long).mean()
# 生成信号:1 表示持仓,0 表示空仓
df["signal"] = 0
df.loc[df["MA_short"] > df["MA_long"], "signal"] = 1
df["position_change"] = df["signal"].diff()
capital = initial_capital
position = 0
trades = []
for idx, row in df.iterrows():
if row["position_change"] == 1 and position == 0: # 买入
position = capital / row["close"]
capital = 0
trades.append(("BUY", idx, row["close"]))
elif row["position_change"] == -1 and position > 0: # 卖出
capital = position * row["close"]
position = 0
trades.append(("SELL", idx, row["close"]))
# 最终资产(如果最后还持有头寸,按最后收盘价平仓)
final_value = capital + (position * df.iloc[-1]["close"] if position > 0 else 0)
total_return = (final_value - initial_capital) / initial_capital * 100
return trades, total_return, final_value
# 获取贵州茅台历史数据
df = fetch_kline_for_backtest("600519", "SH", limit=300)
if df is not None:
trades, ret, final = backtest_double_ma(df)
print(f"总收益率: {ret:.2f}%")
print(f"最终资产: ¥{final:.2f}")
print(f"交易次数: {len(trades)}")
for t in trades[:5]:
print(f"{t[0]} @ {t[2]:.2f} on {t[1].strftime('%Y-%m-%d')}")
回测结果可以帮助你快速验证策略的有效性,而无需先投入真金白银。
四、最佳实践与避坑指南
1. 严格遵守频率限制
免费 API 都有明确的请求频率上限,建议在代码中主动限流:
python
import time
def rate_limited_call(func, min_interval=1.0):
time.sleep(min_interval)
return func()
更优雅的方式是使用 ratelimit 或 tenacity 库。
2. 本地缓存历史数据
每次回测都从 API 拉取历史数据不仅慢,还容易触发限流。推荐将数据存入本地数据库或文件:
python
import sqlite3
def cache_to_sqlite(df, table_name):
conn = sqlite3.connect("market_cache.db")
df.to_sql(table_name, conn, if_exists="replace")
conn.close()
def load_from_cache(table_name):
conn = sqlite3.connect("market_cache.db")
df = pd.read_sql(f"SELECT * FROM {table_name}", conn, parse_dates=["timestamp"])
conn.close()
return df
每天定时增量更新即可。
3. WebSocket 自动重连机制
网络波动可能导致 WebSocket 断开。建议在 on_close 中实现指数退避重连:
python
def on_close(ws, *args):
print("连接断开,5秒后重连...")
time.sleep(5)
ws.run_forever()
4. 交叉验证数据质量
免费数据源难免有异常值。在做实盘决策前,建议用两个独立数据源(例如 iTick 与 AKShare 或 yfinance)交叉验证关键价格和成交量。如果发现差异过大,应暂停策略并人工核查。
5. 注意字段变更和接口升级
数据 API 的返回字段可能随版本更新而变化。建议在代码中增加字段存在性检查,并订阅官方更新通知。
五、总结
免费数据 API 让个人量化交易者能够以零成本搭建专业级的数据采集系统。本文详细介绍了 REST 和 WebSocket 两种接入方式,覆盖了股票、外汇、加密货币等多个市场,并给出了完整的双均线策略回测代码。
最后需要提醒的是:数据只是量化交易的起点,而非终点。再好的数据源,如果没有合理的策略设计、稳健的风险控制和科学的回测验证,也无法带来可持续的收益。希望本文的工具和实践能帮助你迈出稳健的第一步。
声明:本文内容仅供参考,不构成任何投资建议。
参考文档:https://blog.itick.org/stock-api/itick-chanlun-strategy-backtesting-tutorial