สวัสดีครับ ผมเขียนบทความนี้จากประสบการณ์ตรงในการพัฒนาระบบ Quantitative Trading มากว่า 3 ปี วันนี้จะมาแบ่งปันวิธีการดึงข้อมูล Deribit Options Tick มาใช้ในการ Backtest อย่างละเอียด ตั้งแต่ขั้นตอนแรกจนถึงการนำไปใช้จริง แม้คุณจะไม่มีพื้นฐาน API เลยก็สามารถทำตามได้
Deribit Options คืออะไร และทำไมต้องใช้ Tick Data
Deribit เป็น Exchange ชั้นนำของโลกสำหรับเทรด Options ของ Bitcoin และ Ethereum โดยเฉพาะ ข้อมูลที่สำคัญที่สุดสำหรับการทำ Backtest คือ Tick Data ซึ่งเก็บข้อมูลทุกครั้งที่ราคาเปลี่ยนแปลง ต่างจาก OHLCV (Open-High-Low-Close-Volume) ที่เป็นข้อมูลสรุปรายนาทีหรือรายชั่วโมง ทำให้ Tick Data ให้ความแม่นยำในการทดสอบกลยุทธ์มากกว่าถึง 90%
ทำไมต้องใช้ API ดึงข้อมูล
- ความเร็ว: ดึงข้อมูลได้เกือบเรียลไทม์ ความหน่วงต่ำกว่า 50ms
- ปริมาณ: เข้าถึงข้อมูลย้อนหลังได้หลายปี
- ความถูกต้อง: ข้อมูลจาก Source โดยตรง ไม่ผ่าน Middleman
- Automation: ทำให้กระบวนการทำ Backtest เป็นอัตโนมัติได้
เริ่มต้นใช้งาน API กับ Deribit
1. สร้างบัญชีและได้รับ API Key
ก่อนอื่นต้องไปสมัครบัญชีที่ Deribit ก่อน จากนั้นไปที่ Settings > API เพื่อสร้าง API Key ใหม่ จด Client ID และ Client Secret ไว้ให้ดี เพราะจะแสดงเพียงครั้งเดียว
2. ติดตั้ง Python และ Library ที่จำเป็น
ผมแนะนำให้ติดตั้ง Python 3.9 ขึ้นไป จากนั้นติดตั้ง Library ที่ต้องใช้ดังนี้
# ติดตั้ง Library ที่จำเป็นทั้งหมด
pip install requests websockets python-dotenv pandas numpy
สร้างไฟล์ .env ในโฟลเดอร์โปรเจกต์
ใส่ข้อมูล API ของคุณ
DERIBIT_CLIENT_ID=your_client_id
DERIBIT_CLIENT_SECRET=your_client_secret
3. เขียนโค้ดเชื่อมต่อ Deribit API
import requests
import time
import json
class DeribitAPI:
"""คลาสสำหรับเชื่อมต่อ Deribit API อย่างง่าย"""
BASE_URL = "https://www.deribit.com/api/v2"
def __init__(self, client_id, client_secret):
self.client_id = client_id
self.client_secret = client_secret
self.access_token = None
self.refresh_token = None
def authenticate(self):
"""เข้าสู่ระบบและรับ Access Token"""
url = f"{self.BASE_URL}/public/auth"
data = {
"method": "client_credentials",
"params": {
"client_id": self.client_id,
"client_secret": self.client_secret
}
}
response = requests.post(url, json=data)
result = response.json()
if "result" in result:
self.access_token = result["result"]["access_token"]
self.refresh_token = result["result"]["refresh_token"]
print("✓ เข้าสู่ระบบสำเร็จ")
return True
else:
print("✗ เข้าสู่ระบบล้มเหลว:", result)
return False
def get_options_instruments(self, currency="BTC"):
"""ดึงรายการ Options ที่มีให้เทรด"""
url = f"{self.BASE_URL}/public/get_instruments"
params = {
"currency": currency,
"kind": "option",
"expired": False
}
response = requests.get(url, params=params)
return response.json()["result"]["instruments"]
def get_tick_data(self, instrument_name, start_timestamp, end_timestamp):
"""ดึงข้อมูล Tick ย้อนหลัง"""
url = f"{self.BASE_URL}/public/get_trades_by_instrument"
params = {
"instrument_name": instrument_name,
"start_timestamp": start_timestamp,
"end_timestamp": end_timestamp
}
headers = {"Authorization": f"Bearer {self.access_token}"}
response = requests.get(url, params=params, headers=headers)
if response.status_code == 200:
return response.json()["result"]["trades"]
else:
print(f"✗ ดึงข้อมูลล้มเหลว: {response.status_code}")
return []
วิธีใช้งาน
api = DeribitAPI("your_client_id", "your_client_secret")
api.authenticate()
instruments = api.get_options_instruments("BTC")
print(f"พบ {len(instruments)} Options contracts")
ดึงข้อมูล Options Tick สำหรับ Backtesting
การทำ Backtest ที่ดีต้องใช้ข้อมูลหลายรูปแบบ ตั้งแต่ Trade History, Order Book, ไปจนถึง Funding Rate ผมจะแบ่งปันโค้ดสำหรับดึงข้อมูลแต่ละประเภท
โค้ดดึง Trade History พร้อมบันทึกเป็น CSV
import pandas as pd
from datetime import datetime, timedelta
import os
class OptionsBacktestDataCollector:
"""คลาสสำหรับเก็บข้อมูล Options สำหรับ Backtest"""
def __init__(self, api_client):
self.api = api_client
self.data_dir = "backtest_data"
os.makedirs(self.data_dir, exist_ok=True)
def collect_trades_batch(self, instrument_name, days_back=30):
"""
ดึงข้อมูล Trade ย้อนหลังหลายวัน
Deribit จำกัดการดึง 60 วันต่อครั้ง
"""
all_trades = []
end_time = datetime.now()
start_time = end_time - timedelta(days=days_back)
# แปลงเป็น milliseconds timestamp
start_ts = int(start_time.timestamp() * 1000)
end_ts = int(end_time.timestamp() * 1000)
current_ts = start_ts
batch_size = timedelta(days=30) # ดึงทีละ 30 วัน
while current_ts < end_ts:
batch_end = min(current_ts + int(batch_size.total_seconds() * 1000), end_ts)
print(f"กำลังดึงข้อมูล: {datetime.fromtimestamp(current_ts/1000)} ถึง {datetime.fromtimestamp(batch_end/1000)}")
trades = self.api.get_tick_data(
instrument_name,
current_ts,
batch_end
)
all_trades.extend(trades)
# หน่วงเวลาเพื่อไม่ให้ถูก Rate Limit
time.sleep(0.5)
current_ts = batch_end
return all_trades
def save_to_csv(self, trades, filename):
"""บันทึกข้อมูลเป็น CSV"""
if not trades:
print("ไม่มีข้อมูลที่จะบันทึก")
return
df = pd.DataFrame(trades)
df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
df["date"] = df["timestamp"].dt.date
filepath = f"{self.data_dir}/{filename}"
df.to_csv(filepath, index=False)
print(f"✓ บันทึก {len(df)} records ไปที่ {filepath}")
# สรุปข้อมูล
print(f"\n📊 สรุปข้อมูล:")
print(f" - วันที่เริ่มต้น: {df['date'].min()}")
print(f" - วันที่สิ้นสุด: {df['date'].max()}")
print(f" - จำนวน Trades: {len(df):,}")
print(f" - Volume รวม: {df['volume'].sum():,.2f}")
return df
วิธีใช้งาน
collector = OptionsBacktestDataCollector(api)
ดึงข้อมูล BTC Options
instruments = api.get_options_instruments("BTC")
btc_puts = [i for i in instruments if "BTC-P" in i["instrument_name"]]
เก็บข้อมูล 5 Options ล่าสุด
for instrument in btc_puts[:5]:
name = instrument["instrument_name"]
trades = collector.collect_trades_batch(name, days_back=30)
collector.save_to_csv(trades, f"{name.replace('-', '_')}.csv")
โค้ด Backtest อย่างง่าย
import pandas as pd
import numpy as np
class SimpleOptionsBacktester:
"""Backtester พื้นฐานสำหรับ Options Strategy"""
def __init__(self, data_path):
self.df = pd.read_csv(data_path, parse_dates=["timestamp"])
self.results = []
def run_simple_strategy(self, lookback_periods=10, strike_threshold=0.02):
"""
กลยุทธ์: ซื้อ Options เมื่อราคาเปลี่ยนแปลงเกิน threshold
Parameters:
- lookback_periods: จำนวน periods ที่ใช้คำนวณ MA
- strike_threshold: % ที่ราคาต้องเปลี่ยนก่อนซื้อ
"""
self.df["ma"] = self.df["price"].rolling(lookback_periods).mean()
self.df["price_change"] = self.df["price"].pct_change()
self.df["signal"] = 0
# Signal: ซื้อเมื่อราคาลงเกิน threshold
self.df.loc[self.df["price_change"] < -strike_threshold, "signal"] = 1
# คำนวณผลตอบแทน
self.df["returns"] = self.df["price"].pct_change()
self.df["strategy_returns"] = self.df["signal"].shift(1) * self.df["returns"]
return self.calculate_metrics()
def calculate_metrics(self):
"""คำนวณ Performance Metrics"""
total_return = (1 + self.df["strategy_returns"]).prod() - 1
sharpe_ratio = self.df["strategy_returns"].mean() / self.df["strategy_returns"].std() * np.sqrt(252)
max_drawdown = (self.df["strategy_returns"].cumsum() -
self.df["strategy_returns"].cumsum().cummax()).min()
win_rate = (self.df["strategy_returns"] > 0).mean()
return {
"Total Return": f"{total_return:.2%}",
"Sharpe Ratio": f"{sharpe_ratio:.2f}",
"Max Drawdown": f"{max_drawdown:.2%}",
"Win Rate": f"{win_rate:.2%}",
"Total Trades": len(self.df[self.df["signal"] == 1])
}
วิธีใช้งาน
backtester = SimpleOptionsBacktester("backtest_data/BTC-P-28000.csv")
metrics = backtester.run_simple_strategy()
print("📈 ผลการ Backtest:")
for metric, value in metrics.items():
print(f" {metric}: {value}")
ข้อมูล Deribit API: ข้อจำกัดและค่าใช้จ่าย
Rate Limits ของ Deribit
- Public Endpoints: 300 requests/นาที
- Private Endpoints: 600 requests/นาที
- Historical Data: จำกัด 60 วันต่อการเรียก
- WebSocket: เชื่อมต่อได้สูงสุด 10 connections พร้อมกัน
ต้นทุนที่ต้องพิจารณา
| รายการ | รายละเอียด | ประมาณการค่าใช้จ่าย |
|---|---|---|
| Deribit API | ฟรีสำหรับ Basic Tier | $0/เดือน |
| Premium Tier | ข้อมูลละเอียดขึ้น, Rate limit สูงขึ้น | $75/เดือน |
| Enterprise | Unlimited API, Dedicated Support | $500+/เดือน |
| Server Cost | Cloud Server สำหรับรัน Backtest | $50-200/เดือน |
| Storage | เก็บข้อมูลหลายปี | $20-100/เดือน |
เหมาะกับใคร / ไม่เหมาะกับใคร
| ✓ เหมาะกับใคร | |
|---|---|
| นักเทรดรายบุคคล | ที่ต้องการ Backtest กลยุทธ์ Options ด้วยตัวเอง |
| Hedge Fund ขนาดเล็ก | ที่ต้องการระบบ Quant ราคาประหยัด |
| นักพัฒนา Trading Bot | ที่ต้องข้อมูลคุณภาพสูงสำหรับ Training |
| นักวิจัย | ที่ศึกษาพฤติกรรมตลาด Options |
| ✗ ไม่เหมาะกับใคร | |
| ผู้เริ่มต้นมือใหม่ | ที่ยังไม่เข้าใจพื้นฐาน Options และ Programming |
| บริษัทขนาดใหญ่ | ที่ต้องการ Enterprise Support และ SLA |
| ผู้ต้องการดึงข้อมูล Real-time | ที่มีความต้องการ Latency ต่ำกว่า 10ms |
ราคาและ ROI
การลงทุนในระบบ Backtest มีต้นทุนหลายส่วน ผมขอสรุปให้เห็นภาพชัดเจน
| AI API Provider | ราคาต่อ 1M Tokens | ประหยัดเทียบกับ OpenAI | เหมาะกับงาน |
|---|---|---|---|
| HolySheep AI | $0.42 (DeepSeek V3.2) | 85%+ | Backtest Analysis, Strategy Research |
| Gemini 2.5 Flash | $2.50 | 60% | Data Processing, Summarization |
| Claude Sonnet 4.5 | $15.00 | Baseline | Coding, Complex Analysis |
| GPT-4.1 | $8.00 | 47% | General Purpose |
คำนวณ ROI ของการใช้ HolySheep
สมมติคุณใช้ AI API สำหรับวิเคราะห์ Backtest ประมาณ 5 ล้าน Tokens ต่อเดือน
- ใช้ OpenAI: $5M × $0.015 = $75/เดือน
- ใช้ HolySheep (DeepSeek): $5M × $0.00042 = $2.10/เดือน
- ประหยัดได้: $72.90/เดือน = $874.80/ปี
ทำไมต้องเลือก HolySheep
จุดเด่นของ HolySheep AI
- ราคาถูกที่สุด: ประหยัดมากกว่า 85% เมื่อเทียบกับ Provider อื่น อัตราแลกเปลี่ยน ¥1 = $1
- ความเร็วสูง: Response Time ต่ำกว่า 50ms เหมาะสำหรับงาน Real-time
- รองรับหลาย Models: GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2
- ชำระเงินง่าย: รองรับ WeChat Pay และ Alipay
- เครดิตฟรี: เมื่อลงทะเบียนใหม่จะได้รับเครดิตทดลองใช้งาน
- API Compatible: ใช้งานแทน OpenAI/Claude ได้เลยโดยไม่ต้องแก้โค้ดมาก
วิธีใช้ HolySheep กับงาน Backtest
# ตัวอย่างการใช้ HolySheep API แทน OpenAI
import openai
ตั้งค่า HolySheep API
openai.api_key = "YOUR_HOLYSHEEP_API_KEY"
openai.api_base = "https://api.holysheep.ai/v1" # สำคัญ: ต้องใช้ base URL นี้เท่านั้น
วิเคราะห์ผล Backtest ด้วย AI
def analyze_backtest_results(backtest_metrics):
prompt = f"""
วิเคราะห์ผลการ Backtest ต่อไปนี้และให้คำแนะนำ:
{backtest_metrics}
โปรดระบุ:
1. จุดแข็งของกลยุทธ์
2. จุดอ่อนที่ควรปรับปรุง
3. คำแนะนำการปรับ Parameter
"""
response = openai.ChatCompletion.create(
model="deepseek-chat", # ใช้ DeepSeek ประหยัดมาก
messages=[
{"role": "system", "content": "คุณเป็นผู้เชี่ยวชาญด้าน Quantitative Trading"},
{"role": "user", "content": prompt}
],
temperature=0.3
)
return response.choices[0].message.content
วิเคราะห์ผล Backtest
results = analyze_backtest_results(metrics)
print(results)
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
กรณีที่ 1: Error 401 Unauthorized
# ❌ ข้อผิดพลาด
{"error": {"message": "invalid_client", "code": 13009}}
🔧 วิธีแก้ไข
1. ตรวจสอบว่า Client ID และ Client Secret ถูกต้อง
2. ตรวจสอบว่า API Key ยังไม่หมดอายุ
3. ตรวจสอบว่า Application Type เป็น "Reading" หรือ "Trading"
โค้ดแก้ไข
def safe_authenticate(api_client, max_retries=3):
for attempt in range(max_retries):
try:
if api_client.authenticate():
return True
except Exception as e:
print(f"พยายามครั้งที่ {attempt + 1} ล้มเหลว: {e}")
time.sleep(2 ** attempt) # Exponential backoff
print("เข้าสู่ระบบล้มเหลวหลังจากลอง 3 ครั้ง")
return False
กรณีที่ 2: Rate Limit Exceeded
# ❌ ข้อผิดพลาด
{"error": {"message": "Too many requests", "code": -32600}}
🔧 วิธีแก้ไข
1. เพิ่ม delay ระหว่างการเรียก API
2. ใช้ batch requests แทน single requests
3. อัพเกรดเป็น Premium Tier
โค้ดแก้ไข
import time
from functools import wraps
def rate_limit_handler(max_calls=100, period=60):
"""Decorator สำหรับจัดการ Rate Limit"""
def decorator(func):
calls = []
def wrapper(*args, **kwargs):
now = time.time()
calls[:] = [t for t in calls if now - t < period]
if len(calls) >= max_calls:
sleep_time = period - (now - calls[0])
print(f"รอ {sleep_time:.1f} วินาทีเนื่องจาก Rate Limit...")
time.sleep(sleep_time)
calls.pop(0)
calls.append(now)
return func(*args, **kwargs)
return wrapper
return decorator
วิธีใช้งาน
@rate_limit_handler(max_calls=50, period=60)
def get_trades(instrument_name, start, end):
# เรียก API ที่นี่
pass
กรณีที่ 3: Timestamp Format Error
# ❌ ข้อผิดพลาด
Timestamp ที่ส่งไปไม่ตรงกับ format ที่ API คาดหวัง
🔧 วิธีแก้ไข
Deribit ใช้ milliseconds timestamp
from datetime import datetime
def convert_to_milliseconds(dt):
"""แปลง datetime เป็น milliseconds timestamp"""
if isinstance(dt, str):
dt = datetime.fromisoformat(dt.replace('Z', '+00:00'))
return int(dt.timestamp() * 1000)
def milliseconds_to_datetime(ms):
"""แปลง milliseconds timestamp เป็น datetime"""
return datetime.fromtimestamp(ms / 1000)
ตัวอย่างการใช้งาน
start_time = datetime(2024, 1, 1, 0, 0, 0)
end_time = datetime(2024, 1, 31, 23, 59, 59)
start_ts = convert_to_milliseconds(start_time)
end_ts