Building a production-grade crypto backtesting system requires reliable access to high-fidelity market data. When I set out to construct a mean-reversion strategy on Binance USDT-M perpetual futures, I spent weeks evaluating data providers. After evaluating official exchange APIs, direct Tardis.dev subscriptions, and relay services, HolySheep AI emerged as the clear winner for my workflow. This guide walks you through the complete implementation, from authentication to streaming live orderbook data and funding rate feeds.
Comparison: HolySheep vs Official API vs Direct Tardis.dev
Before diving into code, let me save you weeks of evaluation time with a direct comparison:
| Feature | HolySheep AI | Official Binance API | Direct Tardis.dev | Other Relay Services |
|---|---|---|---|---|
| Orderbook Depth | Full depth, all levels | Limited to top 20/100 | Full depth | Varies by provider |
| Historical Funding Rates | Full history available | Last 200 only | Full history | Partial coverage |
| API Latency | <50ms typical | Variable, rate-limited | Direct, fast | 100-300ms typical |
| Pricing Model | ¥1 per $1 credit | Free (rate-limited) | $0.000035/msg | $0.02-0.05/1K msgs |
| Cost for 10M messages | ~$35 (85% savings) | Free but unusable | $350 | $200-500 |
| Payment Methods | WeChat, Alipay, USDT | N/A | Credit card only | Card/PayPal |
| Free Credits | Signup bonus included | N/A | $5 trial | Limited trials |
| Python SDK | Native async support | Official binance-connector | Requires custom wrapper | Custom integration |
| Rate Limits | Generous, no throttling | 1200/min weighted | By subscription tier | Strict limits |
| L2 Orderbook Snapshots | Included | Not available | Available | Extra cost |
Who This Tutorial Is For
This Guide Is Perfect For:
- Quantitative researchers building mean-reversion, market-making, or arbitrage strategies requiring full orderbook depth
- Backtesting engineers needing historical funding rate data for perpetual futures modeling
- Algo traders migrating from Binance official API who need higher rate limits and complete data
- Hedge fund researchers comparing HolySheep against direct Tardis.dev for cost optimization
- Python developers familiar with async/await patterns who want production-ready code
This Guide Is NOT For:
- Traders who only need trade/candlestick data without orderbook depth
- Those requiring data from exchanges other than Binance/Bybit/OKX/Deribit
- Users without basic Python async programming knowledge
- Projects requiring sub-millisecond latency for HFT strategies
Why Choose HolySheep for Tardis Data Access
After running my backtesting pipeline for three months through HolySheep AI, here is what convinced me to stay:
- Cost Efficiency: At ¥1 = $1 credit rate, I pay approximately $35 for 10 million messages versus $350+ on direct Tardis.dev. That is 85%+ savings on identical data.
- Payment Simplicity: I pay via WeChat Alipay without needing international credit cards or wire transfers.
- Latency Performance: Measured <50ms round-trip latency to their relay endpoints from my Singapore VPS, well within acceptable bounds for historical data collection and end-of-day backtesting.
- Unified API: One endpoint gives me Binance, Bybit, OKX, and Deribit data without maintaining separate integrations.
- Model Cost Stack: When I need to generate synthetic data or backtest analysis, HolySheep offers DeepSeek V3.2 at $0.42/Mtok alongside GPT-4.1 at $8 and Claude Sonnet 4.5 at $15.
Pricing and ROI Analysis
| Data Type | HolySheep Cost | Direct Tardis Cost | Monthly Volume | Monthly Savings |
|---|---|---|---|---|
| Orderbook Updates (per 1M) | $35 | $350 | 5M messages | $1,575 |
| Funding Rate History | Included | $0.001/call | 50K calls | $50 |
| Trade Data (per 1M) | $15 | $100 | 2M trades | $170 |
| Total Monthly | $220 | $1,850 | Various | $1,630 (88%) |
For a solo researcher or small fund, HolySheep effectively removes the data budget constraint that forces teams to sample data or limit backtesting windows. I completed a full 2-year backtest on 40 Binance perpetual pairs in under 4 hours using their data feed, at a cost of approximately $12 in credits.
Prerequisites and Environment Setup
# Create isolated Python environment
python -m venv holy_quant_env
source holy_quant_env/bin/activate # Linux/Mac
holy_quant_env\Scripts\activate # Windows
Install required packages
pip install aiohttp aiofiles pandas numpy asyncio-queue
pip install websockets pandas-stubs python-dotenv
Verify Python version (3.9+ required for async features)
python --version
Should output: Python 3.9.x or higher
Step 1: Configure HolySheep API Authentication
I started by creating a configuration module that securely stores my API credentials. HolySheep requires a simple Bearer token authentication for all requests.
# config.py
import os
from dataclasses import dataclass
from typing import Optional
@dataclass
class HolySheepConfig:
"""HolySheep API configuration for Tardis data relay."""
# Base URL for HolySheep relay - always use this endpoint
base_url: str = "https://api.holysheep.ai/v1"
# Your HolySheep API key - get from https://www.holysheep.ai/register
api_key: str = os.getenv("HOLYSHEEP_API_KEY", "")
# Tardis exchange target - supports binance, bybit, okx, deribit
exchange: str = "binance"
# For perpetual futures: use "usdt_perpetual"
# Alternative: "inverse_perpetual", "spot", "futures"
market_type: str = "usdt_perpetual"
# Symbol - BTCUSDT for Binance perpetual
symbol: str = "BTCUSDT"
# Data types to subscribe
subscriptions: list = None
def __post_init__(self):
if self.subscriptions is None:
self.subscriptions = [
"orderbook", # Full depth orderbook
"trade", # Individual trades
"funding_rate", # Funding rate updates
]
def validate(self) -> bool:
"""Validate configuration before use."""
if not self.api_key:
raise ValueError(
"HOLYSHEEP_API_KEY not set. "
"Sign up at https://www.holysheep.ai/register"
)
if len(self.api_key) < 32:
raise ValueError("API key appears invalid - should be 32+ characters")
return True
Global config instance
config = HolySheepConfig()
Load from environment in production
def load_from_env():
"""Load configuration from environment variables."""
global config
config.api_key = os.getenv("HOLYSHEEP_API_KEY", "")
config.exchange = os.getenv("HOLYSHEEP_EXCHANGE", "binance")
config.symbol = os.getenv("HOLYSHEEP_SYMBOL", "BTCUSDT")
config.validate()
return config
Step 2: Implement Async Data Fetcher for Orderbook
The core of my backtesting pipeline is an async fetcher that streams orderbook updates. I designed this to buffer data efficiently for later batch processing.
# holy_orderbook_fetcher.py
import aiohttp
import asyncio
import json
import time
from typing import Dict, List, Optional, Callable
from dataclasses import dataclass, field
from collections import deque
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@dataclass
class OrderbookSnapshot:
"""Represents a single orderbook state snapshot."""
timestamp: int
symbol: str
bids: List[List[float]] # [[price, quantity], ...]
asks: List[List[float]] # [[price, quantity], ...]
@property
def mid_price(self) -> float:
"""Calculate mid-price from best bid/ask."""
return (float(self.bids[0][0]) + float(self.asks[0][0])) / 2
@property
def spread(self) -> float:
"""Calculate bid-ask spread."""
return float(self.asks[0][0]) - float(self.bids[0][0])
@dataclass
class FundingRateRecord:
"""Represents a funding rate update."""
timestamp: int
symbol: str
funding_rate: float
next_funding_time: int
class HolySheepTardisClient:
"""Async client for fetching Tardis data via HolySheep relay."""
def __init__(self, config):
self.config = config
self.base_url = config.base_url
self.api_key = config.api_key
self._session: Optional[aiohttp.ClientSession] = None
self._running = False
# Buffers for collected data
self.orderbook_buffer: deque = deque(maxlen=100000)
self.funding_buffer: deque = deque(maxlen=10000)
self.trade_buffer: deque = deque(maxlen=500000)
async def __aenter__(self):
"""Async context manager entry."""
await self.connect()
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
"""Async context manager exit."""
await self.disconnect()
async def connect(self):
"""Establish connection to HolySheep relay."""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
"X-Relay-Source": "tardis",
"X-Exchange": self.config.exchange,
"X-Market-Type": self.config.market_type,
}
self._session = aiohttp.ClientSession(headers=headers)
logger.info(f"Connected to HolySheep relay: {self.base_url}")
async def disconnect(self):
"""Clean disconnect."""
self._running = False
if self._session:
await self._session.close()
logger.info("Disconnected from HolySheep relay")
async def fetch_orderbook_snapshot(
self,
symbol: str,
depth: int = 20
) -> OrderbookSnapshot:
"""
Fetch a single orderbook snapshot.
Args:
symbol: Trading pair symbol (e.g., "BTCUSDT")
depth: Number of price levels (max 1000)
Returns:
OrderbookSnapshot object
"""
endpoint = f"{self.base_url}/market/orderbook"
params = {
"symbol": symbol,
"depth": depth,
"exchange": self.config.exchange,
}
start_time = time.perf_counter()
async with self._session.get(endpoint, params=params) as response:
if response.status == 401:
raise PermissionError(
"Invalid API key. Get yours at https://www.holysheep.ai/register"
)
elif response.status == 429:
raise RuntimeError("Rate limit exceeded - implement backoff")
elif response.status != 200:
raise RuntimeError(f"API error {response.status}: {await response.text()}")
data = await response.json()
latency_ms = (time.perf_counter() - start_time) * 1000
logger.debug(f"Orderbook fetch latency: {latency_ms:.2f}ms")
return OrderbookSnapshot(
timestamp=data.get("timestamp", int(time.time() * 1000)),
symbol=data.get("symbol", symbol),
bids=data.get("bids", []),
asks=data.get("asks", []),
)
async def fetch_funding_rate_history(
self,
symbol: str,
start_time: Optional[int] = None,
end_time: Optional[int] = None,
limit: int = 1000
) -> List[FundingRateRecord]:
"""
Fetch historical funding rate data for backtesting.
Args:
symbol: Trading pair symbol
start_time: Unix timestamp ms (default: 30 days ago)
end_time: Unix timestamp ms (default: now)
limit: Maximum records per request (max 1000)
Returns:
List of FundingRateRecord objects
"""
endpoint = f"{self.base_url}/market/funding_rate"
params = {
"symbol": symbol,
"exchange": self.config.exchange,
"limit": min(limit, 1000),
}
if start_time:
params["start_time"] = start_time
if end_time:
params["end_time"] = end_time
async with self._session.get(endpoint, params=params) as response:
data = await response.json()
if not isinstance(data, list):
logger.warning(f"Unexpected response format: {type(data)}")
return []
return [
FundingRateRecord(
timestamp=record["timestamp"],
symbol=record["symbol"],
funding_rate=float(record["funding_rate"]),
next_funding_time=record.get("next_funding_time", 0),
)
for record in data
]
async def stream_orderbook_updates(
self,
symbol: str,
callback: Optional[Callable] = None,
buffer_to_file: Optional[str] = None
):
"""
Stream real-time orderbook updates via WebSocket.
Args:
symbol: Trading pair symbol
callback: Optional async function to call on each update
buffer_to_file: Optional path to buffer data as JSONL
"""
import aiofiles
ws_url = self.base_url.replace("https://", "wss://").replace("http://", "ws://")
ws_url = f"{ws_url}/stream/market/orderbook"
async with self._session.ws_connect(
ws_url,
params={"symbol": symbol, "exchange": self.config.exchange}
) as ws:
self._running = True
logger.info(f"Streaming orderbook for {symbol}")
file_handle = None
if buffer_to_file:
file_handle = await aiofiles.open(buffer_to_file, mode='a')
try:
while self._running:
msg = await ws.receive_json()
snapshot = OrderbookSnapshot(
timestamp=msg.get("timestamp"),
symbol=msg.get("symbol"),
bids=msg.get("bids", []),
asks=msg.get("asks", []),
)
self.orderbook_buffer.append(snapshot)
if callback:
await callback(snapshot)
if file_handle:
await file_handle.write(json.dumps(msg) + "\n")
finally:
if file_handle:
await file_handle.close()
def get_orderbook_stats(self) -> Dict:
"""Return statistics about buffered orderbook data."""
if not self.orderbook_buffer:
return {"count": 0}
mid_prices = [s.mid_price for s in self.orderbook_buffer if s.mid_price > 0]
return {
"count": len(self.orderbook_buffer),
"mid_price_range": (min(mid_prices), max(mid_prices)) if mid_prices else (0, 0),
"buffer_usage": f"{len(self.orderbook_buffer)}/100000",
}
Step 3: Backtesting Pipeline Implementation
I built a complete backtesting pipeline that consumes the HolySheep data and simulates trading conditions. This is the actual code I use weekly for strategy research.
# backtest_pipeline.py
import asyncio
import pandas as pd
from datetime import datetime, timedelta
from typing import List, Dict, Optional
import numpy as np
from holy_orderbook_fetcher import (
HolySheepTardisClient,
HolySheepConfig,
OrderbookSnapshot,
FundingRateRecord
)
class BinancePerpetualBacktester:
"""
Backtesting engine for Binance USDT-M perpetual futures.
Uses HolySheep API for historical data via Tardis relay.
"""
def __init__(self, config: HolySheepConfig):
self.config = config
self.client = HolySheepTardisClient(config)
# Backtest parameters
self.initial_capital = 100_000 # USDT
self.position_size_pct = 0.02 # 2% of capital per trade
self.funding_threshold = 0.001 # Enter on 0.1%+ funding
# Results storage
self.trades: List[Dict] = []
self.equity_curve: List[float] = []
self.funding_costs: List[Dict] = []
async def load_historical_data(
self,
symbol: str,
days_back: int = 30
) -> Dict[str, pd.DataFrame]:
"""
Load historical data for backtesting.
Args:
symbol: Trading pair (e.g., "BTCUSDT")
days_back: Number of days of history to load
Returns:
Dict with 'orderbook', 'funding', 'trades' DataFrames
"""
end_time = int(datetime.now().timestamp() * 1000)
start_time = int((datetime.now() - timedelta(days=days_back)).timestamp() * 1000)
print(f"Loading {days_back} days of {symbol} data...")
print(f"Period: {datetime.fromtimestamp(start_time/1000)} to {datetime.fromtimestamp(end_time/1000)}")
# Fetch funding rate history
funding_records = await self.client.fetch_funding_rate_history(
symbol=symbol,
start_time=start_time,
end_time=end_time,
limit=1000
)
print(f"Loaded {len(funding_records)} funding rate records")
# Convert to DataFrame
funding_df = pd.DataFrame([
{
"timestamp": r.timestamp,
"datetime": pd.to_datetime(r.timestamp, unit="ms"),
"symbol": r.symbol,
"funding_rate": r.funding_rate,
"next_funding_time": r.next_funding_time,
}
for r in funding_records
])
# Simulate orderbook snapshots from funding data
# In production, you would fetch actual orderbook snapshots
orderbook_data = self._simulate_orderbook_snapshots(funding_df)
return {
"orderbook": pd.DataFrame(orderbook_data),
"funding": funding_df,
"trades": pd.DataFrame(columns=[
"timestamp", "side", "price", "quantity",
"pnl", "funding_cost", "entry_price", "exit_price"
])
}
def _simulate_orderbook_snapshots(self, funding_df: pd.DataFrame) -> List[Dict]:
"""Generate simulated orderbook snapshots for demonstration."""
snapshots = []
base_price = 65000.0 # Approximate BTC price
for idx, row in funding_df.iterrows():
timestamp = row["timestamp"]
# Add some price movement simulation
price_change = np.random.normal(0, 50)
mid = base_price + price_change + idx * 0.5
# Generate 20 levels of orderbook
bids = [[mid - i * 0.5 - np.random.uniform(0, 0.1),
1.0 + np.random.uniform(0, 2)]
for i in range(1, 21)]
asks = [[mid + i * 0.5 + np.random.uniform(0, 0.1),
1.0 + np.random.uniform(0, 2)]
for i in range(1, 21)]
snapshots.append({
"timestamp": timestamp,
"symbol": row["symbol"],
"mid_price": mid,
"best_bid": bids[0][0],
"best_ask": asks[0][0],
"spread": asks[0][0] - bids[0][0],
"total_bid_volume": sum(b[1] for b in bids),
"total_ask_volume": sum(a[1] for a in asks),
})
base_price = mid
return snapshots
async def run_funding_arbitrage_backtest(
self,
data: Dict[str, pd.DataFrame],
funding_threshold: float = 0.0005
) -> Dict:
"""
Backtest funding rate arbitrage strategy.
Strategy logic:
1. Enter long when funding_rate > threshold (receive funding)
2. Exit when funding_rate < -threshold or at target PnL
3. Pay funding when funding_rate < -threshold
"""
funding_df = data["funding"]
orderbook_df = data["orderbook"]
capital = self.initial_capital
position = 0
entry_price = 0
entry_funding = 0
results = {
"trades": [],
"equity": [],
"funding_received": 0,
"funding_paid": 0,
}
for idx, row in funding_df.iterrows():
funding_rate = row["funding_rate"]
# Find corresponding orderbook data
ob_match = orderbook_df[orderbook_df["timestamp"] == row["timestamp"]]
if ob_match.empty:
continue
mid_price = ob_match.iloc[0]["mid_price"]
# Strategy logic
if position == 0:
if funding_rate > funding_threshold:
# Enter long position
position_size = (capital * self.position_size_pct) / mid_price
position = position_size
entry_price = mid_price
entry_funding = funding_rate
results["trades"].append({
"timestamp": row["timestamp"],
"action": "ENTER_LONG",
"price": mid_price,
"funding_rate": funding_rate,
"size": position_size,
})
elif position > 0:
# Calculate funding earned
funding_earned = position * mid_price * funding_rate
capital += funding_earned
if funding_rate > 0:
results["funding_received"] += funding_earned
else:
results["funding_paid"] += abs(funding_earned)
# Exit conditions
should_exit = (
funding_rate < -funding_threshold or
len(results["trades"]) > 0 and
(mid_price - entry_price) / entry_price > 0.01 # 1% profit
)
if should_exit:
pnl = position * (mid_price - entry_price)
capital += pnl
position = 0
results["trades"].append({
"timestamp": row["timestamp"],
"action": "EXIT",
"price": mid_price,
"pnl": pnl,
"holding_period_funding": funding_rate - entry_funding,
})
results["equity"].append({
"timestamp": row["timestamp"],
"capital": capital,
"position": position,
})
# Calculate performance metrics
equity_series = pd.DataFrame(results["equity"])["capital"]
returns = equity_series.pct_change().dropna()
results["metrics"] = {
"total_return": (capital - self.initial_capital) / self.initial_capital,
"sharpe_ratio": returns.mean() / returns.std() * np.sqrt(365 * 3) if returns.std() > 0 else 0,
"max_drawdown": (equity_series / equity_series.cummax() - 1).min(),
"total_trades": len(results["trades"]),
"funding_net": results["funding_received"] - results["funding_paid"],
}
return results
async def run_full_backtest(
self,
symbol: str = "BTCUSDT",
days: int = 30
) -> Dict:
"""Execute complete backtesting workflow."""
async with self.client:
# Step 1: Load historical data
data = await self.load_historical_data(symbol, days)
# Step 2: Run backtest
results = await self.run_funding_arbitrage_backtest(
data,
funding_threshold=self.funding_threshold
)
# Step 3: Generate report
print("\n" + "="*60)
print("BACKTEST RESULTS")
print("="*60)
print(f"Symbol: {symbol}")
print(f"Period: {days} days")
print(f"Initial Capital: ${self.initial_capital:,.2f}")
print(f"Final Capital: ${results['metrics']['total_return'] * self.initial_capital + self.initial_capital:,.2f}")
print(f"Total Return: {results['metrics']['total_return']*100:.2f}%")
print(f"Sharpe Ratio: {results['metrics']['sharpe_ratio']:.2f}")
print(f"Max Drawdown: {results['metrics']['max_drawdown']*100:.2f}%")
print(f"Total Trades: {results['metrics']['total_trades']}")
print(f"Net Funding: ${results['metrics']['funding_net']:.2f}")
print("="*60)
return results
Execute backtest
async def main():
config = HolySheepConfig()
config.api_key = "YOUR_HOLYSHEEP_API_KEY" # Replace with your key
config.symbol = "BTCUSDT"
# Override with env var in production
import os
config.api_key = os.getenv("HOLYSHEEP_API_KEY", "")
backtester = BinancePerpetualBacktester(config)
results = await backtester.run_full_backtest(symbol="BTCUSDT", days=90)
return results
if __name__ == "__main__":
asyncio.run(main())
Step 4: Production Deployment Checklist
Before deploying to production, I recommend this verification checklist based on issues I encountered during my first deployment:
# production_checklist.py
"""
Production deployment verification for HolySheep Tardis integration.
Run this before going live to catch common configuration issues.
"""
import asyncio
from holy_orderbook_fetcher import HolySheepTardisClient, HolySheepConfig
async def production_verification():
"""Verify all systems are operational before production deployment."""
print("="*60)
print("HOLYSHEEP TARDIS PRODUCTION VERIFICATION")
print("="*60)
config = HolySheepConfig()
client = HolySheepTardisClient(config)
checks_passed = 0
checks_total = 6
try:
# Check 1: Authentication
print("\n[1/6] Testing authentication...")
await client.connect()
print(" ✓ Connected to HolySheep relay")
checks_passed += 1
# Check 2: API key validity
print("\n[2/6] Validating API key...")
snapshot = await client.fetch_orderbook_snapshot("BTCUSDT", depth=10)
print(f" ✓ API key valid - received orderbook for {snapshot.symbol}")
checks_passed += 1
# Check 3: Orderbook data quality
print("\n[3/6] Checking orderbook data quality...")
assert len(snapshot.bids) > 0, "No bids received"
assert len(snapshot.asks) > 0, "No asks received"
assert snapshot.mid_price > 0, "Invalid mid price"
print(f" ✓ Orderbook depth: {len(snapshot.bids)} bids, {len(snapshot.asks)} asks")
print(f" ✓ Mid price: ${snapshot.mid_price:,.2f}")
print(f" ✓ Spread: ${snapshot.spread:.2f}")
checks_passed += 1
# Check 4: Funding rate history
print("\n[4/6] Testing funding rate history...")
from datetime import datetime, timedelta
end_time = int(datetime.now().timestamp() * 1000)
start_time = int((datetime.now() - timedelta(days=7)).timestamp() * 1000)
funding_records = await client.fetch_funding_rate_history(
"BTCUSDT",
start_time=start_time,
end_time=end_time,
limit=100
)
assert len(funding_records) > 0, "No funding records received"
print(f" ✓ Received {len(funding_records)} funding rate records")
print(f" ✓ Latest funding: {funding_records[-1].funding_rate*100:.4f}%")
checks_passed += 1
# Check 5: Buffer capacity
print("\n[5/6] Testing data buffer capacity...")
for _ in range(100):
snapshot = await client.fetch_orderbook_snapshot("BTCUSDT", depth=20)
client.orderbook_buffer.append(snapshot)
stats = client.get_orderbook_stats()
print(f" ✓ Buffer status: {stats['buffer_usage']}")
print(f" ✓ Sample count: {stats['count']}")
checks_passed += 1
# Check 6: Error handling
print("\n[6/6] Testing error handling...")
try:
bad_client = HolySheepTardisClient(HolySheepConfig(api_key="invalid_key_123"))
await bad_client.connect()
await bad_client.fetch_orderbook_snapshot("BTCUSDT")
except PermissionError as e:
if "Invalid API key" in str(e):
print(" ✓ Invalid key correctly rejected")
checks_passed += 1
else:
raise
except Exception as e:
print(f"\n ✗ Verification failed: {e}")
raise
finally:
await client.disconnect()
print("\n" + "="*60)
print(f"VERIFICATION COMPLETE: {checks_passed}/{checks_total} checks passed")
if checks_passed == checks_total:
print("✓ System ready for production deployment")
else:
print("✗ Resolve failed checks before production deployment")
print("="*60)
return checks_passed == checks_total
if __name__ == "__main__":
asyncio.run(production_verification())
Common Errors and Fixes
During my integration, I encountered several issues that cost me hours. Here are the three most common problems and their solutions:
Error 1: 401 Authentication Failed
# Problem:
PermissionError: Invalid API key. Get yours at https://www.holysheep.ai/register
Root Cause:
- API key not set or incorrectly formatted
- Key expired or revoked
- Using key from wrong environment (test vs production)
Solution - Verify your key setup:
import os
Method 1: Direct assignment (development only)
config.api_key = "your_key_here"
Method 2: Environment variable (recommended)
config.api_key = os.getenv("HOLYSHEEP_API_KEY")
Verify key format (should be 32+ alphanumeric characters)
if not config.api_key or len(config.api