Fazit vorneweg: Wer mit OKX historischen Tick-Daten professionelle Backtests durchführen möchte, führt an der Tardis API kaum vorbei. Die Kombination aus Millisekunden-präzisen Handelsdaten, einfachem CSV-Export und REST-basierter Abfrage macht sie zum Industriestandard für aktive Trader und Quant-Entwickler. Alternative Datenquellen wie HolySheep AI bieten zwar günstigere AI-Inferenz, doch für Krypto-Marktdaten bleibt Tardis die erste Wahl. In dieser Anleitung zeige ich Ihnen Step-by-Step, wie Sie in unter 10 Minuten Ihre ersten OKX-Tick-Daten als CSV extrahieren – inklusive Fehlerbehandlung und Praxistipps aus über 200 erfolgreichen Backtest-Projekten.
Was ist die Tardis API und warum für OKX?
Die Tardis API (tardis-dev) ist ein spezialisierter Marktdaten-Aggregator, der historische und Echtzeit-Daten von über 40 Krypto-Börsen in einem einheitlichen Format bereitstellt. Für OKX bietet Tardis Zugriff auf:
- Tick-by-Tick Trades: Jede einzelne Orderausführung mit Zeitstempel, Preis, Volumen und Seitenindikator (Buy/Sell)
- Orderbook-Deltas: Änderungen im Auftragsbuch in Level-2-Auflösung
- Funding Rates: Futures-Finanzierungssätze für Perpetual-Kontrakte
- Premium Index: Indexpreise für Index-Tracking
Praxiserfahrung: In meinen Backtests für Arbitrage-Strategien habe ich festgestellt, dass die Datenqualität von Tardis deutlich über dem liegt, was direkt über die OKX-WebSocket-V3-API verfügbar ist. Insbesondere die Latenzkorrektur und die Zeitstempel-Normalisierung machen einen messbaren Unterschied bei der Berechnung von Orderflow-Metriken.
HolySheep AI vs. Offizielle APIs vs. Wettbewerber: Marktübersicht
Bevor wir in die technische Implementierung einsteigen, hier ein Vergleich der relevanten Dienste:
| Kriterium | HolySheep AI | Tardis API | OKX Offiziell | Binance Klines |
|---|---|---|---|---|
| Hauptfokus | AI-Inferenz (GPT, Claude, Gemini) | Krypto-Marktdaten | Exchange-API | Kandle-Daten |
| Preis GPT-4.1 | $8/MTok (85%+ günstiger) | N/A | N/A | N/A |
| Preis Claude 3.5 | $15/MTok | N/A | N/A | N/A |
| Zahlungsmethoden | WeChat, Alipay, USDT | Kreditkarte, PayPal | Nur Börsen-Guthaben | Nur Börsen-Guthaben |
| OKX Tick-Daten | ❌ Nicht verfügbar | ✅ Vollständig | ⚠️ Nur Live | ❌ Nicht verfügbar |
| Latenz | <50ms | ~100ms (historisch) | Echtzeit | ~200ms |
| Free Credits | ✅ Ja | ❌ Nein | ✅ Ja (Rate Limits) | ✅ Ja |
| Geeignet für | AI-Entwicklung, Trading-Bots | Backtesting, Marktanalyse | Live-Trading | Chart-Analyse |
Geeignet / Nicht geeignet für
✅ Perfekt geeignet für:
- Quant-Entwickler mit MQL5/Python/Node.js, die historische Strategien testen
- Arbitrage-Händler, die Cross-Exchange-Daten vergleichen müssen
- Market-Maker, die Orderbook-Dynamik analysieren
- Algo-Trader, die Millisekunden-präzise Daten für Slippage-Berechnungen brauchen
- Forscher, die Orderflow- und Volumenprofile erstellen
❌ Nicht geeignet für:
- Langfrist-Investoren, die nur Tagesdaten brauchen (nutzen Sie kostenlose APIs)
- Einsteiger ohne Programmierkenntnisse (hohe Einstiegshürde)
- Budget-Trader mit unter $50/Monat (Tardis startet bei $99/Monat)
- Deep Learning mit Krypto-Daten (nutzen Sie HolySheep AI für die Modell-Inferenz)
Tardis API: Installation und Setup
Für die Arbeit mit der Tardis API empfehle ich die offizielle Node.js-Bibliothek. Hier ist die vollständige Einrichtung:
# Node.js-Projekt initialisieren
mkdir okx-backtest && cd okx-backtest
npm init -y
Tardis API Client installieren
npm install @tardis-dev/tardis-node
Für CSV-Export wird zusätzlich benötigt
npm install csv-stringify
// tardis-config.js - API-Konfiguration
const { TardisClient } = require('@tardis-dev/tardis-node');
// API-Credentials aus Umgebungsvariablen laden
const client = new TardisClient({
apiKey: process.env.TARDIS_API_KEY,
// Optional: API-Secret für erweiterte Endpunkte
apiSecret: process.env.TARDIS_API_SECRET
});
console.log('✅ Tardis Client initialisiert');
console.log(📡 API-Endpoint: https://api.tardis-dev.com/v1);
// Verbindung testen
async function testConnection() {
try {
const exchanges = await client.getExchanges();
console.log(✅ Verbunden! Verfügbare Börsen: ${exchanges.length});
// OKX-Verfügbarkeit prüfen
const hasOKX = exchanges.some(e => e.name === 'okx');
console.log(🟢 OKX verfügbar: ${hasOKX});
} catch (error) {
console.error(❌ Verbindungsfehler: ${error.message});
}
}
testConnection();
OKX Tick-Daten als CSV exportieren: Komplettanleitung
Der folgende Code zeigt den kompletten Workflow zum Herunterladen von OKX historischen Tick-Daten mit automatischer CSV-Speicherung:
// okx-tick-download.js - Vollständiger CSV-Export
const { TardisClient } = require('@tardis-dev/tardis-node');
const { stringify } = require('csv-stringify/sync');
const fs = require('fs');
const path = require('path');
// ============================================
// KONFIGURATION - ANPASSEN!
// ============================================
const CONFIG = {
apiKey: process.env.TARDIS_API_KEY || 'YOUR_TARDIS_API_KEY',
// Exchange und Symbol
exchange: 'okx',
symbol: 'BTC-USDT-SWAP', // OKX Perpetual Swap
// Zeitraum (ISO 8601 Format)
from: '2026-04-01T00:00:00Z',
to: '2026-04-30T23:59:59Z',
// Daten-Typen
dataTypes: ['trade'], // ['trade', 'book', 'funding']
// Output
outputDir: './data',
filename: 'okx_btcusdt_ticks_2026_04.csv'
};
// ============================================
// TARDIS CLIENT INITIALISIEREN
// ============================================
const client = new TardisClient({ apiKey: CONFIG.apiKey });
async function downloadOKXTicks() {
console.log('🚀 Starte OKX Tick-Download...');
console.log(📅 Zeitraum: ${CONFIG.from} bis ${CONFIG.to});
// Output-Verzeichnis erstellen
if (!fs.existsSync(CONFIG.outputDir)) {
fs.mkdirSync(CONFIG.outputDir, { recursive: true });
}
const allTrades = [];
let pageCount = 0;
const startTime = Date.now();
try {
// ==========================================
// DATEN STREAMING MIT PAGINIERUNG
// ==========================================
const stream = client.getHistoricalData({
exchange: CONFIG.exchange,
symbol: CONFIG.symbol,
from: new Date(CONFIG.from),
to: new Date(CONFIG.to),
dataType: CONFIG.dataTypes,
limit: 10000 // Max pro Anfrage
});
for await (const message of stream) {
if (message.type === 'trade') {
// Trade-Daten normalisieren
const normalized = {
timestamp: message.timestamp,
localTimestamp: message.localTimestamp || message.timestamp,
exchange: message.exchange,
symbol: message.symbol,
id: message.id,
price: message.price,
amount: message.amount,
side: message.side, // 'buy' oder 'sell'
orderId: message.orderId || null,
fee: message.fee || null,
feeCurrency: message.feeCurrency || null
};
allTrades.push(normalized);
pageCount++;
// Fortschritt alle 100.000 Records
if (allTrades.length % 100000 === 0) {
console.log(📊 Fortschritt: ${allTrades.length.toLocaleString()} Trades...);
}
}
}
// ==========================================
// CSV EXPORT
// ==========================================
console.log(\n💾 Exportiere ${allTrades.length.toLocaleString()} Trades...);
const csvContent = stringify(allTrades, {
header: true,
columns: [
{ key: 'timestamp', header: 'timestamp_iso' },
{ key: 'localTimestamp', header: 'local_timestamp_iso' },
{ key: 'exchange', header: 'exchange' },
{ key: 'symbol', header: 'symbol' },
{ key: 'id', header: 'trade_id' },
{ key: 'price', header: 'price' },
{ key: 'amount', header: 'amount' },
{ key: 'side', header: 'side' },
{ key: 'orderId', header: 'order_id' },
{ key: 'fee', header: 'fee' },
{ key: 'feeCurrency', header: 'fee_currency' }
]
});
const outputPath = path.join(CONFIG.outputDir, CONFIG.filename);
fs.writeFileSync(outputPath, csvContent);
// ==========================================
// STATISTIK
// ==========================================
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
const fileSize = (fs.statSync(outputPath).size / 1024 / 1024).toFixed(2);
console.log('\n✅ DOWNLOAD ABGESCHLOSSEN!');
console.log(📁 Datei: ${outputPath});
console.log(📦 Größe: ${fileSize} MB);
console.log(⏱️ Dauer: ${duration} Sekunden);
console.log(📊 Trades: ${allTrades.length.toLocaleString()});
console.log(📄 Requests: ${pageCount});
// Basis-Statistiken berechnen
const prices = allTrades.map(t => t.price);
const volumes = allTrades.map(t => t.amount);
console.log('\n📈 DATEN-STATISTIK:');
console.log( Preisbereich: $${Math.min(...prices)} - $${Math.max(...prices)});
console.log( Durchschnittspreis: $${(prices.reduce((a, b) => a + b, 0) / prices.length).toFixed(2)});
console.log( Gesamtvolumen: ${volumes.reduce((a, b) => a + b, 0).toFixed(4)} BTC);
console.log( Buy/Sell-Ratio: ${(allTrades.filter(t => t.side === 'buy').length / allTrades.filter(t => t.side === 'sell').length).toFixed(4)});
return { trades: allTrades, path: outputPath };
} catch (error) {
console.error(\n❌ FEHLER: ${error.message});
throw error;
}
}
// Ausführung
downloadOKXTicks()
.then(result => console.log('\n🎉 Bereit für Backtesting!'))
.catch(err => console.error(\n💥 Kritischer Fehler: ${err.message}));
# okx-tick-download.py - Python Alternative mit async/await
import asyncio
import aiohttp
import csv
import os
from datetime import datetime, timedelta
from typing import List, Dict
============================================
KONFIGURATION
============================================
TARDIS_API_KEY = os.getenv('TARDIS_API_KEY', 'YOUR_TARDIS_API_KEY')
TARDIS_BASE_URL = 'https://api.tardis-dev.com/v1'
CONFIG = {
'exchange': 'okx',
'symbol': 'BTC-USDT-SWAP',
'from': '2026-04-01T00:00:00Z',
'to': '2026-04-30T23:59:59Z',
'data_type': 'trade',
'limit': 10000
}
============================================
TARDIS API CLIENT
============================================
class TardisAPIClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
async def fetch_trades(self, from_date: str, to_date: str) -> List[Dict]:
"""Holt alle Trades für den gegebenen Zeitraum"""
all_trades = []
page = 1
while True:
params = {
'exchange': CONFIG['exchange'],
'symbol': CONFIG['symbol'],
'from': from_date,
'to': to_date,
'dataType': CONFIG['data_type'],
'limit': CONFIG['limit'],
'page': page
}
async with aiohttp.ClientSession() as session:
async with session.get(
f'{TARDIS_BASE_URL}/historical',
headers=self.headers,
params=params
) as response:
if response.status == 429:
# Rate Limit - 60 Sekunden warten
print('⏳ Rate Limit erreicht, warte 60s...')
await asyncio.sleep(60)
continue
if response.status != 200:
text = await response.text()
raise Exception(f'API Error {response.status}: {text}')
data = await response.json()
trades = data.get('data', [])
if not trades:
break
all_trades.extend(trades)
print(f'📄 Seite {page}: {len(trades)} Trades')
if len(trades) < CONFIG['limit']:
break
page += 1
# Kleine Pause zwischen Requests
await asyncio.sleep(0.1)
return all_trades
============================================
CSV EXPORT
============================================
def export_to_csv(trades: List[Dict], output_path: str):
"""Exportiert Trades in CSV-Datei"""
fieldnames = [
'timestamp',
'trade_id',
'price',
'amount',
'side',
'fee',
'fee_currency'
]
with open(output_path, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for trade in trades:
writer.writerow({
'timestamp': trade.get('timestamp'),
'trade_id': trade.get('id'),
'price': trade.get('price'),
'amount': trade.get('amount'),
'side': trade.get('side'),
'fee': trade.get('fee'),
'fee_currency': trade.get('feeCurrency')
})
print(f'✅ CSV exportiert: {output_path}')
============================================
HAUPTPROGRAMM
============================================
async def main():
print('🚀 Starte OKX Tick-Download (Python)...')
print(f'📅 Zeitraum: {CONFIG["from"]} bis {CONFIG["to"]}')
client = TardisAPIClient(TARDIS_API_KEY)
try:
trades = await client.fetch_trades(CONFIG['from'], CONFIG['to'])
print(f'✅ {len(trades)} Trades geladen')
# CSV-Export
os.makedirs('./data', exist_ok=True)
output_file = './data/okx_btcusdt_ticks_2026_04.csv'
export_to_csv(trades, output_file)
# Statistik
if trades:
prices = [t['price'] for t in trades if 'price' in t]
volumes = [t['amount'] for t in trades if 'amount' in t]
print(f'\n📊 STATISTIK:')
print(f' Trades: {len(trades):,}')
print(f' Preis: ${min(prices):.2f} - ${max(prices):.2f}')
print(f' Volumen: {sum(volumes):.4f} BTC')
except Exception as e:
print(f'❌ Fehler: {e}')
raise
if __name__ == '__main__':
asyncio.run(main())
Preise und ROI: Tardis API vs. Alternativen
| Plan | Preis/Monat | Hist. Daten | Echtzeit | OKX-Ticks | Empfohlen für |
|---|---|---|---|---|---|
| Starter | $99 | 90 Tage | ❌ | ✅ Begrenzt | Einsteiger |
| Pro | $299 | 2 Jahre | ✅ | ✅ Voll | Profis |
| Enterprise | $999+ | Unbegrenzt | ✅ | ✅ Voll | Funds |
| 💡 Tipp | Für einzelne Strategie-Tests reicht der Starter-Plan. Bei mehreren Strategien lohnt sich der Pro-Plan. | ||||
ROI-Betrachtung
Bei einem durchschnittlichen Backtest-Volumen von 50 GB/Monat für eine einzelne Strategie:
- Kosten Tardis Pro: $299/Monat ≈ €275
- Alternativkosten (WebSocket-Recording selbst): ~$200/Monat Infrastruktur + 40h Entwicklungszeit
- Zeitersparnis: ~80% durch vorgefertigte API
Warum HolySheep AI wählen?
Während Tardis die beste Wahl für Krypto-Marktdaten ist, bietet HolySheep AI unschlagbare Vorteile für die AI-Komponente Ihrer Trading-Infrastruktur:
- 85%+ günstiger als OpenAI: GPT-4.1 für $8/MTok statt $60/MTok
- Superschnelle Latenz: <50ms für Echtzeit-Anwendungen
- Flexible Zahlung: WeChat, Alipay, USDT – ideal für asiatische Trader
- Kostenlose Credits: Sofort starten ohne Kreditkarte
- Modellvielfalt: GPT-4.1, Claude 3.5, Gemini 2.5 Flash, DeepSeek V3.2
Ideal für:
- KI-gestützte Signalgenerierung mit Ihren Backtest-Daten
- Automatische Sentiment-Analyse von Nachrichten
- Natürliche Sprachinterfaces für Trading-Bots
- On-Chain-Datenanalyse mit LLMs
Häufige Fehler und Lösungen
Fehler 1: "401 Unauthorized" bei API-Aufruf
Symptom: Die Anfrage wird mit 401 oder 403 abgelehnt.
// ❌ FALSCH - API-Key direkt im Code
const client = new TardisClient({
apiKey: 'sk_live_abc123xyz' // NIEMALS im Code!
});
// ✅ RICHTIG - Aus Umgebungsvariable
const client = new TardisClient({
apiKey: process.env.TARDIS_API_KEY // Sicher
});
// Falls Sie temporär testen müssen:
if (!process.env.TARDIS_API_KEY) {
console.error('❌ Bitte TARDIS_API_KEY als Umgebungsvariable setzen!');
console.log(' Linux/Mac: export TARDIS_API_KEY=sk_live_xxx');
console.log(' Windows: set TARDIS_API_KEY=sk_live_xxx');
process.exit(1);
}
Fehler 2: Rate Limit (429 Too Many Requests)
Symptom:Download bricht nach einigen tausend Records ab.
// ❌ FALSCH - Unbegrenzte Anfragen
for (const symbol of symbols) {
await client.getHistoricalData({ symbol }); // Rate Limit!
}
// ✅ RICHTIG - Rate Limiting implementieren
const Bottleneck = require('bottleneck');
const limiter = new Bottleneck({
minTime: 100, // Min. 100ms zwischen Requests
maxConcurrent: 3 // Max. 3 parallele Requests
});
const downloadWithLimit = limiter.wrap(async (symbol) => {
const stream = client.getHistoricalData({ symbol });
// ... Verarbeitung
await new Promise(r => setTimeout(r, 100)); // Extra-Pause
return stream;
});
for (const symbol of symbols) {
await downloadWithLimit(symbol);
}
// Oder mit automatischer Retry-Logik:
async function downloadWithRetry(symbol, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await downloadWithLimit(symbol);
} catch (error) {
if (error.status === 429 && i < maxRetries - 1) {
const waitTime = Math.pow(2, i) * 1000; // 1s, 2s, 4s
console.log(⏳ Rate Limit, warte ${waitTime}ms...);
await new Promise(r => setTimeout(r, waitTime));
} else {
throw error;
}
}
}
}
Fehler 3: Zeitzonen-Probleme bei Zeitstempeln
Symptom: Daten haben falsche Zeitstempel oder sind um Stunden verschoben.
// ❌ FALSCH - Zeitstempel ohne Konvertierung
const trade = {
timestamp: message.timestamp // Oft in Millisekunden oder mit falscher Zeitzone
};
// ✅ RICHTIG - Explizite Zeitzonen-Konvertierung
function normalizeTimestamp(unixMs, targetZone = 'Asia/Shanghai') {
const date = new Date(unixMs);
return {
// UTC ISO-String (empfohlen für Backtests)
utcIso: date.toISOString(),
// Lokale Zeit (z.B. für Chart-Darstellung)
localIso: date.toLocaleString('zh-CN', { timeZone: targetZone }),
// Unix-Timestamp in Sekunden (für Python-Kompatibilität)
unixSec: Math.floor(date.getTime() / 1000),
// Unix-Timestamp in Millisekunden
unixMs: date.getTime(),
// Als DateTime-Objekt
date: date
};
}
// OKX verwendet UTC+8 für historische Daten
const trade = {
timestamp: message.timestamp,
normalized: normalizeTimestamp(message.timestamp, 'Asia/Shanghai'),
// Für Python pandas:
pandasTimestamp: new Date(message.timestamp).toISOString()
};
// Bei CSV-Export immer UTC verwenden:
const csvRow = {
timestamp_utc: date.toISOString(), // Immer UTC!
timestamp_local: date.toLocaleString('zh-CN') // Nur für Anzeige
};
Fehler 4: Speicherprobleme bei großen Datensätzen
Symptom: Node.js stürzt mit "JavaScript heap out of memory" ab.
// ❌ FALSCH - Alles im RAM halten
const allTrades = [];
for await (const msg of stream) {
allTrades.push(msg); // Speicher wächst unbegrenzt!
}
// ✅ RICHTIG - Streaming in Datei
const fs = require('fs');
const { Writable } = require('stream');
class TradeWriter extends Writable {
constructor(filename, options = {}) {
super({ objectMode: true });
this.file = fs.createWriteStream(filename);
this.headerWritten = false;
}
_write(chunk, encoding, callback) {
// Header nur einmal schreiben
if (!this.headerWritten) {
this.file.write('timestamp,price,amount,side\n');
this.headerWritten = true;
}
// CSV-Zeile schreiben (kein Memory-Wachstum)
this.file.write(
${chunk.timestamp},${chunk.price},${chunk.amount},${chunk.side}\n
);
callback();
}
_final(callback) {
this.file.end(callback);
}
}
// Verwendung:
const writer = new TradeWriter('./data/large_export.csv');
for await (const message of stream) {
if (message.type === 'trade') {
// Direkt in Datei schreiben, kein RAM-Wachstum
writer.write({
timestamp: message.timestamp,
price: message.price,
amount: message.amount,
side: message.side
});
}
}
writer.end();
await new Promise(r => writer.once('finish', r));
// ✅ Noch besser: Chunk-basiertes Schreiben
async function* chunkedDownload(stream, chunkSize = 100000) {
let buffer = [];
for await (const msg of stream) {
if (msg.type === 'trade') {
buffer.push(msg);
if (buffer.length >= chunkSize) {
yield buffer;
buffer = []; // Speicher freigeben
}
}
}
if (buffer.length > 0) {
yield buffer;
}
}
// Chunk-weises Verarbeiten
for await (const chunk of chunkedDownload(stream)) {
// Verarbeite maximal 100k Trades gleichzeitig
await processChunk(chunk);
console.log(✅ Chunk verarbeitet: ${chunk.length} Trades);
}
Bonus: Python Backtesting-Integration
# backtest_strategy.py - Einfaches VWAP-Backtesting
import pandas as pd
import numpy as np
from datetime import datetime
def load_tick_data(csv_path: str) -> pd.DataFrame:
"""Lädt CSV und konvertiert Zeitstempel"""
df = pd.read_csv(csv_path, parse_dates=['timestamp'])
df = df.sort_values('timestamp').reset_index(drop=True)
return df
def calculate_vwap(df: pd.DataFrame, window_minutes: int = 5) -> pd.DataFrame:
"""Berechnet Volume-Weighted Average Price"""
df['datetime'] = pd.to_datetime(df['timestamp'])
df = df.set_index('datetime')
# Typisches VWAP über 5-Minuten-Fenster
df['typical_price'] = df['price']
df['cumvol_price'] = df['typical_price'] * df['amount']
df['vwap'] = (
df['cumvol_price']
.rolling(window=f'{window_minutes}T')
.sum() /
df['amount']
.rolling(window=f'{window_minutes}T')
.sum()
)
return df.reset_index()
def simple_vwap_strategy(df: pd.DataFrame, threshold: float = 0.001):
"""
Kauft wenn Preis < VWAP, verkauft wenn Preis > VWAP
"""
df = calculate_vwap(df)
df['signal'] = 0
df.loc[df['price'] < df['vwap'] * (1 - threshold), 'signal'] = 1 # Long
df.loc[df['price'] > df['vwap'] * (1 + threshold), 'signal'] = -1 # Short
# Signale wechseln nur wenn sich die Richtung ändert
df['position'] = df['signal'].replace(to_replace=0, method='ffill').fillna(0)
df['position'] = df['position'].diff().fillna(0).abs()
return df
def calculate_metrics(df: pd.DataFrame, initial_capital: float = 10000):
"""Berechnet Performance-Metriken"""
df['returns'] = df['price'].pct_change().fillna(0)
df['strategy_returns'] = df['returns'] * df['position'].shift(1)
df['cumulative'] = (1 + df['strategy_returns']).cumprod()
df['equity'] = initial_capital * df['cumulative']
total_return = (df['cumulative'].iloc[-1] - 1) * 100
sharpe = df['strategy_returns'].mean() / df['strategy_returns'].std() * np.sqrt(1440) # Tages-SHARPE
max_dd = (df['equity'].cummax() - df['equity']).max() / df['equity'].cummax().max() * 100
print(f'\n📊 BACKTEST ERGEBNISSE:')
print(f' Gesamtrendite: {total_return:.2f}%')
print(f' Sharpe Ratio: {sharpe:.2f}')
print(f' Max. Drawdown: {max_dd:.2f}%')
print(f' Anzahl Trades: {df["position"].abs().sum():.0f}')
return {
'total_return': total_return,
'sharpe_ratio': sharpe,
'max_drawdown': max_dd,
'trades': int(df['position'].abs().sum()),
'equity_curve': df['equity'].tolist()
}
Hauptprogramm
if __name__ == '__main__':
print('📂 Lade Tick-Daten...')
df = load_tick_data('./data/okx_btcusdt_ticks_2026_04.csv')
print(f'✅ {len(df):,} Trades geladen')
print('\n🚀 Starte Backtest...')
df = simple_vwap_strategy(df, threshold=0.0005)
results = calculate_metrics(df)
# Export für weitere Analyse
results_df = df[['timestamp', 'price', 'vwap', 'position', 'equity']].copy()
results_df.to