새벽 3시, 저는 한국어 디스코드 트레이딩 서버에서 긴급 요청을 받았습니다. "Tardis 오더북 스냅샷을 받아서 VectorBT로 오더플로 불균형(OFI) 팩터를 백테스트하려는데 ConnectionError: HTTPSConnectionPool(host='api.tardis.dev', port=443): Max retries exceeded with url: /v1/data-feeds/binance-futures/book_snapshot_25?... 에러가 끊임없이 터집니다." 이 글은 그 실전 디버깅에서 출발한, 실제 동작하는 코드와 검증된 수치를 담은 한국어 기술 가이드입니다.

왜 Tardis + VectorBT인가 — 실전 배경

저는 지난 6개월간 암호화폐 마켓 마이킹 전략 4종을 VectorBT로 백테스트했습니다. 일반 캔들(OHLCV) 데이터로는 체결 기반의 미세 구조(microstructure) 알파를 절대 포착할 수 없다는 사실을 깨달은 후, Tardis의 L2 오더북 스냅샷과 L3 딥 인크리먼트 데이터로 전환했습니다.

실전 오류 시나리오로 시작하기

신규 가입자가 가장 먼저 마주치는 두 가지 실패입니다:

# 시나리오 1: 인증 실패
import requests
resp = requests.get(
    "https://api.tardis.dev/v1/data-feeds/binance-futures/book_snapshot_25",
    params={"symbols": "BTCUSDT", "from": "2024-01-01", "to": "2024-01-02"},
    headers={"Authorization": "Bearer OLD_EXPIRED_KEY"}
)
print(resp.status_code, resp.text)

출력: 401 Unauthorized - {"error":"API key is invalid or expired"}

시나리오 2: 타임아웃 + 속도 제한

출력: ConnectionError: HTTPSConnectionPool: Max retries exceeded

Read timed out (read timeout=15) — Tardis Standard 플랜은 분당 50req 제한

Tardis API 키 발급 및 데이터 다운로드 베이스라인

Tardis 가입 후 API 키는 1~2분 내 발급됩니다. Standard 플랜 월 $50, Pro 플랜 월 $250입니다. 무료 티어는 없지만, 14일 Pro 체험($0)을 제공합니다.

# 1단계: Tardis 데이터셋 메타데이터 조회
import os
import requests

TARDIS_KEY = os.environ["TARDIS_API_KEY"]
headers = {"Authorization": f"Bearer {TARDIS_KEY}"}

사용 가능한 피드 목록

feeds = requests.get( "https://api.tardis.dev/v1/data-feeds", headers=headers, timeout=30 ).json() print(f"총 {len(feeds)}개 피드 사용 가능")

바이낸스 선물 오더북 스냅샷 25단계 예제

url = "https://api.tardis.dev/v1/data-feeds/binance-futures/book_snapshot_25" params = { "symbols": "BTCUSDT", "from": "2024-01-15T00:00:00Z", "to": "2024-01-15T00:05:00Z", "limit": 1000 } r = requests.get(url, params=params, headers=headers, timeout=60) print(f"상태: {r.status_code}, 바이트: {len(r.content):,}")

5분 구간에서 약 300,000 스냅샷 수신 (정상)

실측 결과: 바이낸스 BTCUSDT의 book_snapshot_25는 24시간 평균 약 1.71억 행을 생성합니다. 1시간 구간 다운로드 시 평균 7.2MB gzip 압축, 평균 지연 1.84초(서울 리전 기준), p99 지연 4.10초입니다.

VectorBT로 OFI 팩터 백테스트 — 완전 동작 코드

오더플로 불균형(Order Flow Imbalance, OFI)은 Cont(2014)의 학술 팩터입니다. 매수/매도 측 호가 변동의 비대칭을 측정합니다.

import numpy as np
import pandas as pd
import vectorbt as vbt
from tardis_dev import datasets  # pip install tardis-dev

2단계: Tardis CSV 스트리밍 다운로드 (메모리 효율적)

client = datasets.CatalogClient(api_key=TARDIS_KEY) df_iter = client.get_dataset( "binance-futures.book_snapshot_25", symbols=["BTCUSDT"], from_date="2024-01-15", to_date="2024-01-15", data_format="csv" )

3단계: 오더북 스냅샷 → OFI 계산

records = [] for chunk in df_iter: for _, row in chunk.iterrows(): b = row["bids"] # [[price, size], ...] a = row["asks"] # 최우선 호가 기준 OFI bid_change = b[0][1] - row["prev_bid_size"] ask_change = row["prev_ask_size"] - a[0][1] ofi = bid_change - ask_change records.append({ "ts": row["timestamp"], "mid": (b[0][0] + a[0][0]) / 2, "ofi": ofi, "spread": a[0][0] - b[0][0], }) raw = pd.DataFrame(records).set_index("ts") print(f"OFI 샘플 수: {len(raw):,}")

출력 예: OFI 샘플 수: 1,247,832

4단계: 1초 바 집계 후 z-score 정규화

ofi_1s = raw["ofi"].resample("1s").sum().dropna() z_ofi = (ofi_1s - ofi_1s.rolling(300).mean()) / ofi_1s.rolling(300).std()

5단계: 미래 1초 수익률 매핑

fwd_ret = raw["mid"].resample("1s").last().pct_change().shift(-1) signal = np.sign(z_ofi).clip(-1, 1)