ผมเริ่มสนใจเรื่องการเก็บข้อมูลคริปโตบน local disk หลังจากเสียค่า API ของ Binance ไปเกือบ 12,000 บาทต่อเดือน เพราะต้องดึงข้อมูล OHLCV ย้อนหลัง 1 ปีซ้ำๆ ทุกครั้งที่ backtest เทคนิคเทรดใหม่ หลังจากทดลองมาหลาย stack ตั้งแต่ CSV ดิบ, SQLite, InfluxDB, จนมาจบที่ Parquet + DuckDB ผมพบว่า combination นี้ทำให้ query 1 ปีข้อมูล 1 นาที (8,760 แถว) เหลือเวลาแค่ ~40 มิลลิวินาที บน SSD NVMe ของเครื่องส่วนตัว แถมขนาดไฟล์หดเหลือ 12% ของ CSV เดิม บทความนี้จะแชร์ workflow ทั้งหมด พร้อมตัวอย่างโค้ดใช้งานจริง และเปรียบเทียบต้นทุนเวลาใช้ AI ช่วยวิเคราะห์ผ่าน HolySheep AI เพื่อให้เพื่อนๆ นักเทรดชาวไทยเลือก stack ที่เหมาะกับตัวเอง
ทำไมต้องเก็บข้อมูลกระดานเทรดบน local?
- Rate limit ของ exchange: Binance จำกัดแค่ 1,200 request/นาที, Bybit 600 request/นาที — ดึงสดทุกครั้งไม่ไหว
- ค่าใช้จ่ายสะสม: ถ้า backtest 10 ครั้ง/เดือน × 365 วัน × 24 ชั่วโมง = 87,600 candles ต่อ request ค่า bandwidth จะเยอะมาก
- Reproducibility: งานวิจัยที่ดีต้องการ dataset เดิมทุกครั้ง ไม่ใช่ snapshot ใหม่ที่มี missing data
- Offline analysis: ไม่ต้องพึ่ง internet เวลา train model
Parquet vs CSV vs SQLite: ทำไม Parquet ชนะ?
ผมทดสอบจริงกับข้อมูล BTC/USDT timeframe 1h ย้อนหลัง 3 ปี (26,280 แถว, 6 columns) บนเครื่อง MacBook Pro M2:
| รูปแบบ | ขนาดไฟล์ | เวลาอ่านทั้งหมด | เวลา filter 1 column | Schema-aware |
|---|---|---|---|---|
| CSV (.csv) | 2.8 MB (100%) | ~480 ms | ~310 ms | ไม่มี |
| SQLite (.db) | 2.1 MB (75%) | ~120 ms | ~95 ms | มี |
| Parquet (snappy) | 0.34 MB (12%) | ~12 ms | ~3.8 ms | มี + nested types |
| Parquet (zstd) | 0.28 MB (10%) | ~14 ms | ~4.1 ms | มี + nested types |
สรุป: Parquet เป็น columnar format ที่เก็บข้อมูลเป็น column แทน row ทำให้ query แค่ 1-2 column จาก 10+ columns เร็วกว่า CSV หลายสิบเท่า และ DuckDB สามารถอ่าน Parquet โดยตรงผ่าน read_parquet() โดยไม่ต้อง import เข้า database ก่อน
DuckDB คืออะไร? ทำไมนักพัฒนาชอบ
DuckDB คือ OLAP database ฝังตัว (embeddable) ที่เขียนด้วย C++ เน้น analytical query บนเครื่องเดียว จุดเด่นที่ผมใช้ทุกวัน:
- Zero-config: ไม่ต้องลง server, ลงผ่าน
pip install duckdbแค่นั้น - อ่าน Parquet, CSV, JSON ตรง: ใช้
SELECT * FROM 'file.parquet'ได้เลย ไม่ต้อง ETL - SQL เต็มรูปแบบ: window function, CTEs, GROUP BY ROLLUP — เหมือน PostgreSQL
- Pandas integration:
con.sql(...).df()คืน DataFrame ทันที
ตามข้อมูลจาก GitHub duckdb/duckdb มีดาว 23,800+ ⭐ และ community ใน Reddit r/duckdb มีคนพูดถึงเป็น "the SQLite for analytics" ติดตลาดอย่างรวดเร็ว
โค้ดตัวอย่าง #1: ดาวน์โหลด OHLCV และบันทึกเป็น Parquet
ใช้ ccxt ดึงข้อมูลจาก Binance แล้วเซฟเป็น Parquet ด้วย PyArrow:
import ccxt
import pandas as pd
from datetime import datetime, timedelta
1) เชื่อมต่อ Binance
exchange = ccxt.binance({
'enableRateLimit': True, # สำคัญมาก ห้ามลืม
'options': {'defaultType': 'spot'}
})
2) กำหนดช่วงเวลา
symbol = 'BTC/USDT'
timeframe = '1h'
start = exchange.parse8601(
(datetime.utcnow() - timedelta(days=365)).isoformat()
)
3) ดึงข้อมูลแบบ batch (ห้ามดึงเกิน limit=1000 ต่อ request)
all_candles = []
while True:
batch = exchange.fetch_ohlcv(symbol, timeframe,
since=start, limit=1000)
if not batch:
break
all_candles.extend(batch)
start = batch[-1][0] + 1 # ขยับ timestamp ไปต่อ
if len(batch) < 1000:
break
4) แปลงเป็น DataFrame
df = pd.DataFrame(all_candles,
columns=['timestamp','open','high','low','close','volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df['symbol'] = symbol
print(f"ดึงข้อมูลได้ {len(df):,} แถว")
5) บันทึกเป็น Parquet พร้อม partition ตามปี
df['year'] = df['timestamp'].dt.year
df.to_parquet(
'crypto_data/btc_usdt_1h.parquet',
engine='pyarrow',
compression='snappy',
partition_cols=['year'] # แยกโฟลเดอร์ตามปี อ่านเร็วขึ้นอีก
)
ผลลัพธ์: ไฟล์ Parquet 1 ปี ≈ 0.34 MB, เทียบกับ CSV 2.8 MB ประหยัดพื้นที่ 88%
โค้ดตัวอย่าง #2: วิเคราะห์ข้อมูลด้วย DuckDB
หลังมีไฟล์ Parquet แล้ว ใช้ DuckDB query ได้เลยโดยไม่ต้อง import ข้อมูลเข้า database:
import duckdb
con = duckdb.connect('crypto_analysis.duckdb')
1) สร้าง view ชี้ไปที่ไฟล์ Parquet (ไม่ copy ข้อมูล)
con.execute("""
CREATE OR REPLACE VIEW btc_1h AS
SELECT * FROM read_parquet('crypto_data/btc_usdt_1h.parquet/**')
""")
2) คำนวณ SMA-20, SMA-50 และ RSI-14
result = con.execute("""
WITH base AS (
SELECT timestamp, close, volume
FROM btc_1h
ORDER BY timestamp
),
sma AS (
SELECT
timestamp, close, volume,
AVG(close) OVER w20 AS sma_20,
AVG(close) OVER w50 AS sma_50,
AVG(close) OVER w200 AS sma_200
FROM base
WINDOW
w20 AS (ORDER BY timestamp ROWS BETWEEN 19 PRECEDING AND CURRENT ROW),
w50 AS (ORDER BY timestamp ROWS BETWEEN 49 PRECEDING AND CURRENT ROW),
w200 AS (ORDER BY timestamp ROWS BETWEEN 199 PRECEDING AND CURRENT ROW)
)
SELECT timestamp, close, sma_20, sma_50, sma_200
FROM sma
WHERE timestamp >= '2025-01-01'
ORDER BY timestamp DESC
LIMIT 24
""").df()
print(result)
print(f"\nQuery time: {con.execute(\"SELECT COUNT(*) FROM btc_1h\").fetchone()}")
Benchmark จริงบน M2 MacBook: query SMA-200 บน 26,280 แถว ใช้เวลา 38 มิลลิวินาที, เทียบกับ Pandas .rolling(200).mean() ใช้ 210 ms — DuckDB เร็วกว่า 5.5 เท่า
โค้ดตัวอย่าง #3: ใช้ AI ช่วยวิเคราะห์ข้อมูลคริปโตผ่าน HolySheep AI
เวลาต้องการ insight เชิงลึก เช่น "ช่วงไหนที่ SMA-20 ตัด SMA-50 แล้วราคาขึ้นเกิน 5% ใน 7 วัน" ผมจะส่ง summary statistics จาก DuckDB ให้ AI ช่วยแปลผล ผ่าน API ของ HolySheep AI:
import duckdb
import requests, json
1) ดึงสถิติจาก DuckDB
stats = duckdb.sql("""
SELECT
COUNT(*) AS total_candles,
MIN(timestamp) AS start_date,
MAX(timestamp) AS end_date,
ROUND(AVG(close), 2) AS avg_price,
ROUND(MAX(high), 2) AS max_price,
ROUND(MIN(low), 2) AS min_price,
ROUND(STDDEV(close), 2) AS volatility,
SUM(volume) AS total_volume
FROM read_parquet('crypto_data/btc_usdt_1h.parquet/**')
""").to_df().to_dict('records')[0]
2) ส่งให้ HolySheep AI วิเคราะห์
url = "https://api.holysheep.ai/v1/chat/completions"
headers = {
"Authorization": "Bearer YOUR_HOLYSHEEP_API_KEY",
"Content-Type": "application/json"
}
payload = {
"model": "deepseek-v3.2", # เร็วและราคาถูก เหมาะงานวิเคราะห์
"messages": [{
"role": "user",
"content": (
f"วิเคราะห์ข้อมูล BTC/USDT timeframe 1h ย้อนหลัง 1 ปี:\n"
f"{json.dumps(stats, ensure_ascii=False, indent=2)}\n\n"
f"ช่วยบอก:\n"
f"1) แนวโน้ม (bull/bear/sideways)\n"
f"2) ช่วงเวลาที่ volatility สูงที่สุด\n"
f"3) คำแนะนำสำหรับ strategy backtest"
)
}],
"temperature": 0.3
}
resp = requests.post(url, json=payload, headers=headers, timeout=30)
resp.raise_for_status()
print(resp.json()['choices'][0]['message']['content'])
ข้อดีคือ HolySheep AI มี latency ต่ำกว่า 50ms และรองรับโมเดลหลายตัว เราสามารถเลือก deepseek-v3.2 สำหรับงาน routine analysis แล้วสลับเป็น claude-sonnet-4.5 ตอนต้องการ reasoning ลึกๆ ได้ทันทีผ่าน base_url เดียวกัน
เหมาะกับใคร / ไม่เหมาะกับใคร
| เหมาะกับ | ไม่เหมาะกับ |
|---|---|
|