自動売買のログをSQLiteで一元管理する設計〜AIデバッグ・最適化を助ける方法
カテゴリ: AI×自動売買 Week 1 Python実装・コード
AI×自動売買システムの改善には、「なぜシグナルが発生したか」「なぜ注文が失敗したか」を後から追えるログが不可欠です。本記事ではSQLiteを使ってトレードログ・シグナルログ・システムログを一元管理する設計を解説します。
なぜSQLiteなのか
- Python標準ライブラリに内蔵(インストール不要)
- ファイル1つで完結するデータベース
- SQLでシグナル条件・勝率・利益率を簡単に集計可能
- pandasとの相性が良い
DB設計:3テーブル構成
import sqlite3
from pathlib import Path
from datetime import datetime
DB_PATH = Path("logs/trading.db")
DB_PATH.parent.mkdir(exist_ok=True)
def init_db(db_path=DB_PATH):
conn = sqlite3.connect(db_path)
cur = conn.cursor()
# トレードログテーブル
cur.execute('''
CREATE TABLE IF NOT EXISTS trades (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
symbol TEXT NOT NULL,
side TEXT NOT NULL,
qty REAL NOT NULL,
price REAL,
status TEXT,
order_id TEXT,
strategy TEXT,
notes TEXT
)
''')
# シグナルログテーブル
cur.execute('''
CREATE TABLE IF NOT EXISTS signals (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
symbol TEXT NOT NULL,
signal TEXT NOT NULL,
score REAL,
model TEXT,
features TEXT
)
''')
# システムログテーブル
cur.execute('''
CREATE TABLE IF NOT EXISTS system_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
level TEXT NOT NULL,
message TEXT NOT NULL,
module TEXT
)
''')
conn.commit()
conn.close()
print(f"DB初期化完了: {db_path}")
init_db()
LogManagerクラスの実装
import sqlite3
import json
from pathlib import Path
from datetime import datetime, timezone
class LogManager:
def __init__(self, db_path="logs/trading.db"):
self.db_path = db_path
def _now(self):
return datetime.now(timezone.utc).isoformat()
def log_trade(self, symbol, side, qty, price=None, status="submitted",
order_id=None, strategy=None, notes=None):
with sqlite3.connect(self.db_path) as conn:
conn.execute(
'''INSERT INTO trades
(timestamp,symbol,side,qty,price,status,order_id,strategy,notes)
VALUES (?,?,?,?,?,?,?,?,?)''',
(self._now(), symbol, side, qty, price, status, order_id, strategy, notes)
)
def log_signal(self, symbol, signal, score=None, model=None, features=None):
features_json = json.dumps(features) if features else None
with sqlite3.connect(self.db_path) as conn:
conn.execute(
'''INSERT INTO signals
(timestamp,symbol,signal,score,model,features)
VALUES (?,?,?,?,?,?)''',
(self._now(), symbol, signal, score, model, features_json)
)
def log_system(self, level, message, module=None):
with sqlite3.connect(self.db_path) as conn:
conn.execute(
'''INSERT INTO system_logs (timestamp,level,message,module)
VALUES (?,?,?,?)''',
(self._now(), level, message, module)
)
使い方の例
logger = LogManager()
# シグナル記録
logger.log_signal("SPY", "BUY", score=0.82, model="llm-v1",
features={"rsi": 32, "trend": "up"})
# 注文記録
logger.log_trade("SPY", "buy", qty=1, price=523.45,
status="filled", order_id="abc123", strategy="llm-momentum")
# システムログ
logger.log_system("INFO", "ボット起動完了", module="main")
pandasで分析
import pandas as pd
import sqlite3
conn = sqlite3.connect("logs/trading.db")
df = pd.read_sql("SELECT * FROM trades ORDER BY timestamp DESC LIMIT 20", conn)
conn.close()
print(df[["timestamp","symbol","side","qty","price","status"]])
勝率・利益集計SQL
-- シンボル別勝率
SELECT symbol,
SUM(CASE WHEN status='filled' THEN 1 ELSE 0 END) AS total,
AVG(CASE WHEN status='filled' THEN 1.0 ELSE 0.0 END) * 100 AS win_rate_pct
FROM trades
GROUP BY symbol;
-- ストラテジー別平均スコア
SELECT t.strategy, AVG(s.score) AS avg_score
FROM trades t
JOIN signals s ON DATE(t.timestamp) = DATE(s.timestamp) AND t.symbol = s.symbol
GROUP BY t.strategy;
まとめ
- SQLiteはPython標準込みでインストール不要
- trades/signals/system_logsの3テーブル構成が基本
- LogManagerクラスで全記録操作を一元化
- pandas + SQLでAIデバッグ・最適化が嬧1步進む
