quant系トレーダーや自動売買戦略 개발자にとって、高品質な歷史tickデータ 확보は全ての始まりです。本稿ではTardis APIを使用してOKX(オケーエックス)の永続契約(Perpetual Future)からtickデータを取得し、CSV形式て保存する実践的な方法を解説します。實際に筆者が直面したエラーとその解決策含め、日から始められるコードを提供します。
筆者が最初に直面した課題
私怨は2024年にOKXのBTC/USDT永続契約でスキャルピング戦略のバックテストをしようとした際、
ConnectionError: HTTPSConnectionPool(host='api.tardis.dev', port=443):
Max retries exceeded with url: /v1/feeds/okex.swap:BTC-USDT
(Caused by NewConnectionError: '<urllib3.connection.HTTPSConnection object@0x...>:
Failed to establish a new connection: timeout'))
このタイムアウトエラーに直面しました。原因是Tardis APIの無料プランではリクエスト频率に制限があり、大量データ取得時にレートリミットに達するためです。以下てはこの問題を解消も含めた実践的な解决方案を雰囲います。
Tardis APIとは
Tardis Machineは криптобиржの歷史Market Dataを提供するSaaSです。OKXを含む30校上の取引所からtick、ポジション、板情報などを取得できQuant/research用途に廣く利用されています。
前提條件
- Python 3.8以上
- Tardis API アカウント(公式サイトで無料トライアル可)
- requests、pandas、python-dotenvライブラリ
pip install requests pandas python-dotenv
実践コード:OKX永続契約tickデータ取得
1. 基本設定とAPIクライアント
import requests
import pandas as pd
from datetime import datetime, timedelta
import time
import os
from dotenv import load_dotenv
環境変数からAPI Key読み込み
load_dotenv()
TARDIS_API_KEY = os.getenv("TARDIS_API_KEY")
基本設定
BASE_URL = "https://api.tardis.dev/v1"
HEADERS = {
"Authorization": f"Bearer {TARDIS_API_KEY}",
"Content-Type": "application/json"
}
def get_okex_perpetual_symbols():
"""OKXのBTC/USDT永続契約シンボル一覧取得"""
response = requests.get(
f"{BASE_URL}/feeds",
headers=HEADERS,
params={"exchange": "okex", "type": "futures"}
)
response.raise_for_status()
feeds = response.json()
# 永続契約(swap)のみをフィルタリング
perpetual_symbols = [
f["symbol"] for f in feeds
if "swap" in f.get("symbol", "").lower()
and "usdt" in f.get("symbol", "").lower()
]
return perpetual_symbols
シンボル一覧取得
symbols = get_okex_perpetual_symbols()
print(f"OKX 永続契約 symbols: {symbols[:5]}") # 先頭5件表示
2. Tickデータ取得してCSV保存
def download_tick_data(symbol, start_date, end_date, output_dir="data"):
"""
指定期間のtickデータを取得しCSV保存
Args:
symbol: シンボル名(例: okex.swap:BTC-USDT)
start_date: 開始日(YYYY-MM-DD)
end_date: 終了日(YYYY-MM-DD)
output_dir: 出力ディレクトリ
"""
os.makedirs(output_dir, exist_ok=True)
# 日付範囲を生成
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
end_dt = datetime.strptime(end_date, "%Y-%m-%d")
all_data = []
current_date = start_dt
while current_date <= end_dt:
date_str = current_date.strftime("%Y-%m-%d")
# 1日分のデータをリクエスト
url = f"{BASE_URL}/feeds/{symbol}"
params = {
"from": f"{date_str}T00:00:00Z",
"to": f"{date_str}T23:59:59Z",
"limit": 50000 # 1リクエストあたりの上限
}
try:
response = requests.get(url, headers=HEADERS, params=params)
response.raise_for_status()
data = response.json()
if data and "messages" in data:
# Tickデータを展開
for msg in data["messages"]:
if msg.get("type") == "tick":
all_data.append({
"timestamp": msg.get("timestamp"),
"symbol": msg.get("symbol"),
"last_price": msg.get("last"),
"bid_price": msg.get("bid"),
"ask_price": msg.get("ask"),
"bid_size": msg.get("bidSize"),
"ask_size": msg.get("askSize"),
"volume": msg.get("volume"),
"open_interest": msg.get("openInterest")
})
print(f"✓ {date_str}: {len(data['messages'])}件のメッセージ取得")
except requests.exceptions.HTTPError as e:
if response.status_code == 429:
# レートリミット時の處理
print(f"⚠ {date_str}: レートリミット - 60秒待機")
time.sleep(60)
continue
else:
print(f"✗ {date_str}: HTTPエラー - {e}")
except requests.exceptions.Timeout:
print(f"⚠ {date_str}: タイムアウト - 30秒待機后再試行")
time.sleep(30)
continue
current_date += timedelta(days=1)
time.sleep(0.5) # API負荷軽減のための間隔
# DataFrameに変換してCSV保存
if all_data:
df = pd.DataFrame(all_data)
filename = f"{output_dir}/{symbol.replace(':', '_')}_{start_date}_{end_date}.csv"
df.to_csv(filename, index=False)
print(f"\n✅ 合計 {len(df)} 件のtickデータを {filename} に保存")
return df
else:
print("⚠ データが見つかりませんでした")
return None
實際にBTC/USDT永続契約の1週間分を取得
df_btc = download_tick_data(
symbol="okex.swap:BTC-USDT",
start_date="2024-11-01",
end_date="2024-11-07",
output_dir="okex_tick_data"
)
3. バックテスト用データ前処理
def prepare_backtest_data(csv_path, target_symbol="okex.swap:BTC-USDT"):
"""
バックテスト用の清洗済みデータを作成
- タイムスタンプdatetime変換
- 欠損値補間
- 異常値除去
"""
df = pd.read_csv(csv_path)
# タイムスタンプ変換
df["timestamp"] = pd.to_datetime(df["timestamp"])
df = df.sort_values("timestamp").reset_index(drop=True)
# .price系の欠損値を前後補間
price_cols = ["last_price", "bid_price", "ask_price"]
for col in price_cols:
if col in df.columns:
df[col] = df[col].interpolate(method="linear")
# サイズが0の레코드除去
df = df[(df["bid_size"] > 0) & (df["ask_size"] > 0)]
# スプレッド異常値除去(bid-askスプレッドが крайние 99%除外)
df["spread"] = df["ask_price"] - df["bid_price"]
spread_99 = df["spread"].quantile(0.99)
df = df[df["spread"] <= spread_99]
# 出力
output_path = csv_path.replace(".csv", "_cleaned.csv")
df.to_csv(output_path, index=False)
print(f"✅ 清洗済みデータ: {len(df)} 件")
print(f" 時間範囲: {df['timestamp'].min()} ~ {df['timestamp'].max()}")
print(f" 平均スプレッド: {df['spread'].mean():.4f}")
return df
清洗済みデータ作成
df_clean = prepare_backtest_data("okex_tick_data/okex.swap_BTC-USDT_2024-11-01_2024-11-07.csv")
取得可能なデータタイプ
| データタイプ | 説明 | バックテスト用途 |
|---|---|---|
| tick | 約定・板変動 | 高頻度取引戦略、スプレッド分析 |
| book | 板情報( Level 2) | 、指値注文最適化、板予測 |
| trade | Individual trades | 成行注文執行分析大口約定検出 |
| position | 建玉情報 | Liquidation予測 |
料金体系とコスト最適化
Tardis APIはリクエスト量ベースの従量課金です,大量データ取得にはコストがかさみます。私はHolySheep AIをAI APIのプロキシとして活用しており、GPT-4.1が$8/MTok、Claude Sonnet 4.5が$15/MTokという破格の料金で量化戦略の分析やレポーティング自动化を可能にしています。HolySheepはWeChat Pay/Alipayにも対応しており、日本円建てで¥1=$1(公式¥7.3=$1の85%節約)で利用可能。登録すれば無料クレジット付き。
よくあるエラーと対処法
エラー1:401 Unauthorized
# エラー内容
HTTPError: 401 Client Error: Unauthorized
原因:API Keyが無効または期限切れ
解決:正しいAPI Keyを設定
TARDIS_API_KEY = "your_valid_api_key_here"
環境変数確認
import os
print(os.getenv("TARDIS_API_KEY"))
エラー2:429 Rate Limit Exceeded
# エラー内容
HTTPError: 429 Client Error: Too Many Requests
原因:短時間での大量リクエスト
解決:リクエスト間に延迟を追加
import time
def download_with_retry(..., max_retries=3):
for attempt in range(max_retries):
try:
response = requests.get(url, headers=HEADERS, params=params)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if response.status_code == 429:
wait_time = 2 ** attempt # 指数バックオフ: 2, 4, 8秒
print(f"レートリミット: {wait_time}秒待機...")
time.sleep(wait_time)
else:
raise
raise Exception("最大リトライ回数を超過")
エラー3:504 Gateway Timeout
# エラー内容
HTTPError: 504 Server Error: Gateway Timeout
原因:サーバー負荷または不安定なネットワーク
解決:タイムアウト設定とリトライ実装
response = requests.get(
url,
headers=HEADERS,
params=params,
timeout=(10, 30) # (接続タイムアウト, 読み取りタイムアウト)
)
または個別のサーキットブレーカー実装
from functools import wraps
def circuit_breaker(max_failures=5, recovery_timeout=60):
failures = 0
last_failure_time = None
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
nonlocal failures, last_failure_time
if failures >= max_failures:
elapsed = time.time() - last_failure_time
if elapsed < recovery_timeout:
raise Exception("Circuit breaker open")
try:
result = func(*args, **kwargs)
failures = 0
return result
except Exception as e:
failures += 1
last_failure_time = time.time()
raise
return wrapper
return decorator
エラー4:データ欠損(Gap in data)
# エラー内容:特定時間帯のデータが存在しない
原因:メンテナンス期间的API提供不可、またはプラン制限
解決:欠損確認と補間
def check_data_gaps(df, expected_interval_ms=100):
"""tick間隔の異常を検出"""
df["timestamp"] = pd.to_datetime(df["timestamp"])
df = df.sort_values("timestamp")
# マイクロ秒単位の差分計算
time_diff = df["timestamp"].diff().dt.total_seconds() * 1000
# 閾値(例: 1秒以上の間隔)を異常として検出
gap_threshold = 1000 # 1秒
gaps = time_diff[time_diff > gap_threshold]
if len(gaps) > 0:
print(f"⚠ {len(gaps)}件のデータ欠損を検出")
print(gaps.head(10))
# 欠損時間を確認
gap_times = df.loc[gaps.index, "timestamp"]
print(f"\n欠損時間帯: {gap_times.min()} ~ {gap_times.max()}")
else:
print("✅ データ欠損なし")
return gaps
実行
gaps = check_data_gaps(df_clean)
まとめ
本稿ではTardis APIを用いたOKX永続契約からのtickデータ取得からCSV保存、バックテスト用データ前処理までの一連の流れを解説しました。實際に直面しやすいタイムアウトやレートリミットエラーへの対処含め、クイズなPythonコードを提供しました。
高頻度取引や量化戦略の開發において、データ品質が成果を大きく左右します。Tardis APIで取得したデータを元に、HolySheep AIの高速・低コストなAI APIを活用すれば、分析・最適化サイクルを加速できます。
HolySheep AIは<50msのサービスを提供しており、API调用の遅延敏感的用途にも適しています。レートも¥1=$1で業界最安級。量化戦略开发にAIを活用したい方はぜひ试一试ください。
👉 HolySheep AI に登録して無料クレジットを獲得