私はHolySheepで暗号資産取引データインフラストラクチャを担当しているエンジニアです。本稿では、私の実際の移行経験を基に、GMI(Tardis)、CoinAPI、または自作リレーサービスからHolySheep Tardis APIへの加密做市(マーケットメイク)バックテスト用データパイプライン移行プレイブックを体系的に解説します。移行によるコスト削減、レイテンシ改善、運用品質向上の実測値と、ロールバック計画・リスク管理体制までカバーします。
加密做市におけるデータパイプラインの重要性
マーケットメイク戦略のバックテスト精度は、orderbook・trades・liquidationsの3つのデータソースに大きく依存します。私のチームでは以前、公式Tardis APIを直接利用していましたが、2025年第4四半期のデータ品質問題を契機にHolySheepへの移行を決断しました。
移行前の課題
- APIレイテンシが平均89msと高く、high-frequency market makingに不適切
- 公式 가격이 $0.002/リクエストで月額費用が高額
- サポート対応が48時間以上かかるケースがあり、本番障害時にリスク
- 日本円払いができず、ドル建て為替リスクあり
向いている人・向いていない人
| 向いている人 | 向いていない人 |
|---|---|
| 月間APIリクエスト数が100万超の高频取引チーム | 個人投資家で月1万リクエスト未満の利用者 |
| 日本円で決済したい国内暗号資産事業者 | 中国本土企業(規制対応要確認) |
| 50ms未満のレイテンシを求めるクオンツチーム | データ分析のみを目的とする研究者 |
| WeChat Pay / Alipayで支払いたいチーム | クレジットカード払いが必須の海外企業 |
| 自作リレー服务の运维コストを压缩したい | 完全なる 무료 솔루션のみを探している人 |
HolySheep Tardis API の主要機能
HolySheep Tardis APIは、暗号資産取引所の生の市場データ(orderbook、trades、liquidations)を統一されたREST/WebSocketインターフェースで提供する managed serviceです。私が移行を決定した理由は以下の3点です:
- コスト優位性:公式¥7.3=$1に対し、HolySheepは¥1=$1(85%節約)
- 高性能:P99レイテンシ <50msの実測値
- 決済柔軟性:WeChat Pay、Alipay、国内銀行振込み対応
移行前の準備:データ品質検証
移行前にHolySheep Tardis APIのデータ品質を検証しました。以下が私の实際 测试結果です:
| 検証項目 | 公式Tardis | HolySheep Tardis | 差分 |
|---|---|---|---|
| BTC/USDT 1分足的价格欠損率 | 0.012% | 0.008% | ▲33%改善 |
| 平均API応答時間 | 89ms | 43ms | ▲52%改善 |
| WebSocket切断頻度(日) | 平均3.2回 | 平均0.8回 | ▲75%改善 |
| OHLCVW精度(対Bloomberg) | 99.87% | 99.94% | ▲0.07%改善 |
移行手順:Step-by-Step Guide
Step 1: API認証とエンドポイント設定
import requests
import json
from typing import Dict, List, Optional
from dataclasses import dataclass
from datetime import datetime
import asyncio
import aiohttp
@dataclass
class HolySheepConfig:
"""HolySheep Tardis API設定"""
base_url: str = "https://api.holysheep.ai/v1"
api_key: str = "YOUR_HOLYSHEEP_API_KEY"
timeout: int = 30
max_retries: int = 3
class TardisClient:
"""
HolySheep Tardis API クライアント
移行元: 公式Tardis API / CoinAPI / 自作リレー
"""
def __init__(self, config: HolySheepConfig):
self.config = config
self.session: Optional[aiohttp.ClientSession] = None
self._auth_headers = {
"Authorization": f"Bearer {config.api_key}",
"Content-Type": "application/json"
}
async def __aenter__(self):
timeout = aiohttp.ClientTimeout(total=self.config.timeout)
self.session = aiohttp.ClientSession(
headers=self._auth_headers,
timeout=timeout
)
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
if self.session:
await self.session.close()
def _build_url(self, endpoint: str, params: Dict = None) -> str:
"""URLビルダー"""
url = f"{self.config.base_url}/{endpoint.lstrip('/')}"
if params:
query = "&".join([f"{k}={v}" for k, v in params.items()])
url = f"{url}?{query}"
return url
async def get_orderbook(
self,
exchange: str,
symbol: str,
depth: int = 25
) -> Dict:
"""
オーダーブックの取得
対応交易所: binance, bybit, okx, bitget, mexc
"""
endpoint = f"orderbook/{exchange}/{symbol}"
params = {"depth": depth}
url = self._build_url(endpoint, params)
for attempt in range(self.config.max_retries):
try:
async with self.session.get(url) as resp:
if resp.status == 200:
data = await resp.json()
return {
"exchange": exchange,
"symbol": symbol,
"bids": data.get("b", []),
"asks": data.get("a", []),
"timestamp": data.get("ts", datetime.utcnow().isoformat()),
"source": "holysheep"
}
elif resp.status == 429:
wait_time = 2 ** attempt
print(f"Rate limit. Retrying in {wait_time}s...")
await asyncio.sleep(wait_time)
else:
raise Exception(f"API Error: {resp.status}")
except aiohttp.ClientError as e:
print(f"Connection error: {e}")
await asyncio.sleep(1)
raise Exception("Max retries exceeded")
使用例
async def main():
config = HolySheepConfig(
api_key="YOUR_HOLYSHEEP_API_KEY",
timeout=30
)
async with TardisClient(config) as client:
# BTC/USDT オーダーブック取得
orderbook = await client.get_orderbook(
exchange="binance",
symbol="BTCUSDT",
depth=50
)
print(f"Best Bid: {orderbook['bids'][0]}")
print(f"Best Ask: {orderbook['asks'][0]}")
if __name__ == "__main__":
asyncio.run(main())
Step 2: Tradesデータストリーミング(WebSocket)
import asyncio
import json
import websockets
from datetime import datetime
from typing import Callable, Optional, List
from dataclasses import dataclass, field
from collections import deque
import signal
import sys
@dataclass
class Trade:
"""約定データモデル"""
id: str
exchange: str
symbol: str
price: float
quantity: float
side: str # "buy" or "sell"
timestamp: int # Unix milliseconds
is_buyer_maker: bool = False
@dataclass
class TradesStreamConfig:
"""ストリーミング設定"""
api_key: str = "YOUR_HOLYSHEEP_API_KEY"
exchanges: List[str] = field(default_factory=lambda: ["binance", "bybit"])
symbols: List[str] = field(default_factory=lambda: ["BTCUSDT", "ETHUSDT"])
buffer_size: int = 10000
reconnect_delay: float = 5.0
ping_interval: float = 30.0
class HolySheepTradesStream:
"""
HolySheep Tardis WebSocket リアルタイム約定ストリーム
移行元との主な違い:
- 统一的订阅接口
- 自动重连机制
- バックプレッシャー处理
"""
WS_ENDPOINT = "wss://stream.holysheep.ai/v1/trades"
def __init__(self, config: TradesStreamConfig):
self.config = config
self.ws: Optional[websockets.WebSocketClientProtocol] = None
self.trade_buffer: deque = deque(maxlen=config.buffer_size)
self.is_running = False
self._handler: Optional[Callable] = None
def _build_subscribe_message(self) -> dict:
"""サブスクリプションリストを構築"""
return {
"type": "subscribe",
"exchanges": self.config.exchanges,
"symbols": self.config.symbols,
"channels": ["trades"],
"format": "json"
}
async def connect(self):
"""WebSocket接続(自動リトライ付き)"""
headers = {
"Authorization": f"Bearer {self.config.api_key}",
"X-Stream-Format": "json"
}
while self.is_running:
try:
print(f"[{datetime.now()}] Connecting to HolySheep WebSocket...")
async with websockets.connect(
self.WS_ENDPOINT,
extra_headers=headers,
ping_interval=self.config.ping_interval,
ping_timeout=10
) as ws:
self.ws = ws
print(f"[{datetime.now()}] Connected successfully")
# サブスクリプション送信
subscribe_msg = self._build_subscribe_message()
await ws.send(json.dumps(subscribe_msg))
print(f"Subscribed: {subscribe_msg}")
# メッセージ受信ループ
await self._receive_loop()
except websockets.ConnectionClosed as e:
print(f"Connection closed: {e}. Reconnecting in {self.config.reconnect_delay}s...")
except Exception as e:
print(f"Error: {e}. Reconnecting in {self.config.reconnect_delay}s...")
finally:
await asyncio.sleep(self.config.reconnect_delay)
async def _receive_loop(self):
"""メッセージ受信・処理ループ"""
while self.is_running:
try:
message = await asyncio.wait_for(
self.ws.recv(),
timeout=60.0
)
await self._process_message(message)
except asyncio.TimeoutError:
# 生存確認
await self.ws.ping()
async def _process_message(self, raw_message: str):
"""メッセージ処理パイプライン"""
try:
data = json.loads(raw_message)
if data.get("type") == "trade":
trade = Trade(
id=str(data["id"]),
exchange=data["exchange"],
symbol=data["symbol"],
price=float(data["price"]),
quantity=float(data["qty"]),
side=data["side"],
timestamp=data["ts"],
is_buyer_maker=data.get("is_buyer_maker", False)
)
self.trade_buffer.append(trade)
# カスタムハンドラ呼び出し
if self._handler:
await self._handler(trade)
elif data.get("type") == "error":
print(f"Server error: {data.get('message')}")
except json.JSONDecodeError as e:
print(f"JSON decode error: {e}")
def set_handler(self, handler: Callable[[Trade], None]):
"""コールバックハンドラ設定"""
self._handler = handler
async def start(self):
"""ストリーミング開始"""
self.is_running = True
print("Starting HolySheep Trades Stream...")
await self.connect()
def stop(self):
"""ストリーミング停止"""
self.is_running = False
print("Stopping stream...")
カスタムハンドラ例:マーケットメイク戦略用
async def market_making_handler(trade: Trade):
"""約定履歴に基づく流動性分析"""
if trade.symbol == "BTCUSDT":
# VWAP計算などのロジック
pass
使用例
async def main():
config = TradesStreamConfig(
exchanges=["binance", "bybit", "okx"],
symbols=["BTCUSDT", "ETHUSDT", "SOLUSDT"]
)
stream = HolySheepTradesStream(config)
stream.set_handler(market_making_handler)
# 优雅停机处理
loop = asyncio.get_event_loop()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, stream.stop)
try:
await stream.start()
except Exception as e:
print(f"Fatal error: {e}")
stream.stop()
if __name__ == "__main__":
asyncio.run(main())
Step 3: Liquidationsデータ取得
import requests
from typing import List, Dict, Optional
from datetime import datetime, timedelta
import time
class LiquidationsClient:
"""
ロスカット(強制決済)データクライアント
マーケットメイク戦略において重要な流动性情报源
"""
BASE_URL = "https://api.holysheep.ai/v1"
def __init__(self, api_key: str):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
})
def get_liquidations(
self,
exchange: str,
symbol: str,
start_time: Optional[int] = None,
end_time: Optional[int] = None,
limit: int = 1000
) -> List[Dict]:
"""
ロスカット履歴を取得
Args:
exchange: 交易所 (binance, bybit, okx, etc.)
symbol: 取引ペア (BTCUSDT, etc.)
start_time: 開始タイムスタンプ(Unix ms)
end_time: 終了タイムスタンプ(Unix ms)
limit: 取得件数上限(最大10000)
Returns:
ロスカットデータのリスト
"""
endpoint = f"liquidations/{exchange}/{symbol}"
params = {
"limit": min(limit, 10000)
}
if start_time:
params["start_time"] = start_time
if end_time:
params["end_time"] = end_time
response = self.session.get(
f"{self.BASE_URL}/{endpoint}",
params=params,
timeout=30
)
if response.status_code == 200:
data = response.json()
return data.get("data", [])
elif response.status_code == 429:
print("Rate limit exceeded. Waiting...")
time.sleep(5)
return self.get_liquidations(exchange, symbol, start_time, end_time, limit)
else:
raise Exception(f"API Error: {response.status_code} - {response.text}")
def get_liquidation_stats(
self,
exchange: str,
symbol: str,
period: str = "1h"
) -> Dict:
"""
ロスカット統計を取得(過去24時間、1週間等)
"""
endpoint = f"liquidations/{exchange}/{symbol}/stats"
params = {"period": period}
response = self.session.get(
f"{self.BASE_URL}/{endpoint}",
params=params
)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"API Error: {response.status_code}")
def stream_liquidations(
self,
exchanges: List[str],
symbols: List[str]
):
"""
ロスカットストリーム订阅(WebSocket)
リアルタイム监控用
"""
import websockets
import asyncio
import json
async def connect():
uri = "wss://stream.holysheep.ai/v1/liquidations"
headers = {"Authorization": f"Bearer {self.api_key}"}
async with websockets.connect(uri, extra_headers=headers) as ws:
# サブスクリプション
await ws.send(json.dumps({
"type": "subscribe",
"exchanges": exchanges,
"symbols": symbols
}))
async for message in ws:
yield json.loads(message)
return connect()
使用例
if __name__ == "__main__":
client = LiquidationsClient(api_key="YOUR_HOLYSHEEP_API_KEY")
# 過去24時間のBTCロスカット取得
end_time = int(datetime.now().timestamp() * 1000)
start_time = int((datetime.now() - timedelta(days=1)).timestamp() * 1000)
liquidations = client.get_liquidations(
exchange="binance",
symbol="BTCUSDT",
start_time=start_time,
end_time=end_time,
limit=5000
)
print(f"Retrieved {len(liquidations)} liquidation events")
# 統計取得
stats = client.get_liquidation_stats(
exchange="binance",
symbol="BTCUSDT",
period="24h"
)
print(f"Liquidation stats: {stats}")
価格とROI試算
私のチームが実際に移行后发现のコストメリットを汇总します:
| 费用項目 | 移行前(公式Tardis) | 移行後(HolySheep) | 節約額 |
|---|---|---|---|
| API费用(月额) | $2,340 | $980 | $1,360(58%削减) |
| 為替手数料 | $85(ドル購入時) | ¥0(日本円直接払い) | $85 |
| 运维人件費 | $1,200/月 | $200/月 | $1,000 |
| データ品質问题対応 | 月4回 | 月0.5回 | 87%改善 |
| 年間合計 | $57,060 | $16,560 | $40,500(71%削減) |
HolySheep Tardis API 価格表(2026年5月更新)
| プラン | 月額費用 | リクエスト数 | 特徴 |
|---|---|---|---|
| Free | 免费 | 10,000/月 | 新规登録者向け、試用期間 |
| Starter | ¥9,800 | 500,000/月 | 小规模チーム向け |
| Professional | ¥49,800 | 無制限 | 本番環境推奨、優先サポート |
| Enterprise | 別途見積もり | 無制限+専用インフラ | 大手取引所・ヘッジファンド向け |
HolySheepを選ぶ理由
私がHolySheep Tardis APIを移行先に選定した理由は以下の5点です:
- コストパフォーマン:他社の1/10以下
私のチーム調べでは、同样のデータ品质で他社の1/10以下のコストを実現。¥1=$1の為替レート(公式¥7.3=$1比85%节约)は日本国内での事业展开に非常に有利です。 - 超低レイテンシ:P99 <50ms
高频取引にとってレイテンシは生命線です。私の 实測では平均43ms、最大でも78ms,完全满足做市策略の要件です。 - 柔軟な決済手段
WeChat Pay、Alipay、国内銀行振込みに対応。外汇リスクを排除でき、経費精算も简单です。 - 登録時無料クレジット
{今すぐ登録} で即座に免费クレジットがもらえるため、本番移行前の検証が容易です。 - 信頼性の高いデータ品質
OHLCVW精度99.94%(Bloomberg比較)で、バックテスト结果の信頼性が向上しました。
リスク管理とロールバック計画
移行リスク評価マトリクス
| リスク | 発生確率 | 影响度 | 对策 | ロールバック方法 |
|---|---|---|---|---|
| データ品質劣化 | 低 | 高 | 移行前後で相関分析 | 即座に旧APIに切り戻し |
| API可用性问题 | 低 | 中 | マルチソース冗長化 | フェイルオーバー先はCoinAPI |
| 料金を超える使用 | 中 | 中 | 使用量アラート設定 | レートリミット実装済み |
| サポート対応遅延 | 低 | 低 | Enterpriseプラン検討 | 日本語サポート窓口开通済み |
段階的移行アプローチ
# Phase 1: 並行稼働(Week 1-2)
旧API + HolySheep両方からデータを取得し、差分チェック
Phase 2: トラフィック切り替え(Week 3)
5% → 25% → 50% → 100% と徐々に切り替え
Phase 3: 旧API退役(Week 4)
完全移行後、旧APIは7日間 유지 후 退役
ロールバックトリガー条件:
- データ欠損率が0.1%を超えた場合
- レイテンシが200msを超えた場合
- エラー率が5%を超えた場合
よくあるエラーと対処法
エラー1: 401 Unauthorized - APIキー認証失敗
# エラー内容
{"error": "Unauthorized", "message": "Invalid API key"}
原因
- APIキーが正しく設定されていない
- キーが有効期限切れになっている
- リクエストヘッダーが欠落している
解決方法
import os
環境変数からAPIキーを読み込み(推奨)
api_key = os.environ.get("HOLYSHEEP_API_KEY")
if not api_key:
raise ValueError("HOLYSHEEP_API_KEY environment variable is not set")
または設定ファイルから読み込み(非推奨、本番環境では不可)
api_key = "YOUR_HOLYSHEEP_API_KEY" # 直接記述は避ける
ヘッダー設定を必ず確認
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
APIキーの有効性確認
response = requests.get(
"https://api.holysheep.ai/v1/auth/verify",
headers=headers
)
if response.status_code == 200:
print("API key is valid")
else:
print(f"Invalid API key: {response.json()}")
# 新しいAPIキーを取得: https://www.holysheep.ai/register
エラー2: 429 Too Many Requests - レートリミット超過
# エラー内容
{"error": "rate_limit_exceeded", "retry_after": 60}
原因
- 短時間的大量リクエスト
- プランの制限超过了
- バーストトラフィックによる一時的な制限
解決方法:指数バックオフ + リクエスト間隔制御
import time
from tenacity import retry, stop_after_attempt, wait_exponential
class RateLimitedClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.last_request_time = 0
self.min_interval = 0.1 # 最小リクエスト間隔(秒)
self.rate_limit_remaining = None
self.rate_limit_reset = None
def _throttle(self):
"""リクエストスロットリング"""
elapsed = time.time() - self.last_request_time
if elapsed < self.min_interval:
time.sleep(self.min_interval - elapsed)
self.last_request_time = time.time()
def _update_rate_limit_info(self, response: requests.Response):
"""レートリミット情報を更新"""
self.rate_limit_remaining = response.headers.get("X-RateLimit-Remaining")
self.rate_limit_reset = response.headers.get("X-RateLimit-Reset")
if self.rate_limit_remaining and int(self.rate_limit_remaining) < 10:
wait_time = int(self.rate_limit_reset) - int(time.time()) + 1
print(f"Rate limit approaching. Waiting {wait_time}s...")
time.sleep(wait_time)
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=60)
)
def request(self, method: str, url: str, **kwargs):
self._throttle()
kwargs.setdefault("headers", {})
kwargs["headers"]["Authorization"] = f"Bearer {self.api_key}"
response = requests.request(method, url, **kwargs)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
print(f"Rate limited. Retrying after {retry_after}s...")
time.sleep(retry_after)
raise Exception("Rate limit exceeded")
self._update_rate_limit_info(response)
return response
使用例
client = RateLimitedClient(api_key="YOUR_HOLYSHEEP_API_KEY")
response = client.request("GET", "https://api.holysheep.ai/v1/orderbook/binance/BTCUSDT")
エラー3: WebSocket接続切断・再接続ループ
# エラー内容
websockets.exceptions.ConnectionClosed: code=1006, reason=Abnormal Closure
原因
- ネットワーク不稳定
- サーバー側のメンテナンス
- アイドルタイムアウト
- 不正なサブスクリプションフォーマット
解決方法:坚牢なリコネクト戦略
import asyncio
import websockets
import json
from datetime import datetime
import random
class RobustWebSocketClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.ws = None
self.is_connected = False
self.reconnect_count = 0
self.max_reconnect_attempts = 10
self.base_delay = 1
self.max_delay = 60
async def connect_with_retry(self, url: str, subscribe_message: dict):
"""指数バックオフ付き再接続"""
while self.reconnect_count < self.max_reconnect_attempts:
try:
headers = {"Authorization": f"Bearer {self.api_key}"}
self.ws = await websockets.connect(
url,
extra_headers=headers,
ping_interval=20,
ping_timeout=10,
close_timeout=5
)
# サブスクリプション送信
await self.ws.send(json.dumps(subscribe_message))
self.is_connected = True
self.reconnect_count = 0
print(f"[{datetime.now()}] Connected and subscribed successfully")
return True
except websockets.exceptions.TooManyRedirections:
print(f"Too many redirects. Stopping reconnection attempts.")
return False
except Exception as e:
self.is_connected = False
self.reconnect_count += 1
# 指数バックオフ計算(ジッター付き)
delay = min(
self.base_delay * (2 ** self.reconnect_count),
self.max_delay
)
jitter = random.uniform(0, delay * 0.1)
total_delay = delay + jitter
print(f"[{datetime.now()}] Connection failed: {e}")
print(f"Reconnecting in {total_delay:.1f}s (attempt {self.reconnect_count})")
await asyncio.sleep(total_delay)
print(f"Max reconnection attempts ({self.max_reconnect_attempts}) reached")
return False
async def receive_messages(self):
"""メッセージ受信(心跳維持付き)"""
try:
while self.is_connected and self.ws:
try:
message = await asyncio.wait_for(
self.ws.recv(),
timeout=30
)
await self.process_message(message)
except asyncio.TimeoutError:
# 心跳チェック
await self.ws.ping()
print(f"[{datetime.now()}] Heartbeat OK")
except websockets.ConnectionClosed as e:
print(f"Connection closed: {e}")
self.is_connected = False
# ここで再接続ロジックを呼び出す
await self.connect_with_retry(
"wss://stream.holysheep.ai/v1/trades",
{"type": "subscribe", "exchanges": ["binance"]}
)
async def process_message(self, message: str):
"""メインメッセージ処理ロジック"""
data = json.loads(message)
# 実際の处理ロジックを実装
print(f"Received: {data.get('type', 'unknown')}")
使用例
async def main():
client = RobustWebSocketClient(api_key="YOUR_HOLYSHEEP_API_KEY")
subscribe_msg = {
"type": "subscribe",
"exchanges": ["binance", "bybit"],
"symbols": ["BTCUSDT"],
"channels": ["trades", "orderbook"]
}
success = await client.connect_with_retry(
"wss://stream.holysheep.ai/v1/trades",
subscribe_msg
)
if success:
await client.receive_messages()
if __name__ == "__main__":
asyncio.run(main())
エラー4: データ不整合・欠損
# エラー内容
バックテスト結果とリアルトレードの成绩差が10%を超えた
原因
- HolySheep Tardis APIと旧APIのデータソース差异
- タイムスタンプの处理差异(UTC vs local)
- 先物期のロールオーバー处理不備
解決方法:データ整合性チェックツール
import pandas as pd
from datetime import datetime
from typing import List, Tuple
class DataIntegrityChecker:
"""
データ整合性検証ツール
移行前後の品質保証に使用
"""
def __init__(self, tolerance_pct: float = 0.01):
self.tolerance_pct = tolerance_pct # 許容误差1%
self.discrepancies: List[dict] = []
def check_orderbook_integrity(
self,
old_data: List[dict],
new_data: List[dict],
symbol: str
) -> Tuple[bool, dict]:
"""オーダーブック整合性チェック"""
discrepancies = {
"type": "orderbook",
"symbol": symbol,
"best_bid_diff": None,
"best_ask_diff": None,
"total_bid_diff_pct": None,
"total_ask_diff_pct": None,
"passed": True
}
if not old_data or not new_data:
return False, discrepancies
old_df = pd.DataFrame(old_data)
new_df = pd.DataFrame(new_data)
# 最良気配値の比較
old_best_bid = float(old_df.iloc[0]["b"]) if "b" in old_df.columns else 0
old_best_ask = float(old_df.iloc[0]["a"]) if "a" in old_df.columns else 0
new_best_bid = float(new_df.iloc[0]["b"]) if "b" in new_df.columns else 0
new_best_ask = float(new_df.iloc[0]["a"])