- Fix realized_pnl always being 0 on SELL (use amount*price instead of amount_usdt) - Add debug logging for all-HOLD LLM cycles (log sample HOLD reasons) - Fix nonce collision in Bitfinex API auth (add counter) - Fix timezone to UTC+8 in main, trade_logger, sync_cost_basis, check_errors - Fix stop-loss retry with longer delay after cancel - Add min order amount check in trader before BUY - Fix risk_manager to skip positions with amount <= 0 - Cap trade_history to 500 entries to prevent unbounded growth - Fix greedy regex in LLM response parser - Reset cost_tracking start dates to null Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
46 lines
1.4 KiB
Python
46 lines
1.4 KiB
Python
"""Persistent trade history logger — appends every trade to a CSV file."""
|
|
|
|
import csv
|
|
import os
|
|
from datetime import datetime, timezone, timedelta
|
|
|
|
_TZ_UTC8 = timezone(timedelta(hours=8))
|
|
|
|
import config
|
|
|
|
TRADE_LOG_FILE = "trade_history.csv"
|
|
FIELDS = [
|
|
"timestamp", "datetime", "symbol", "name", "action", "amount",
|
|
"price", "amount_usdt", "confidence", "reason", "mode", "status",
|
|
]
|
|
|
|
|
|
def _ensure_header():
|
|
if not os.path.exists(TRADE_LOG_FILE):
|
|
with open(TRADE_LOG_FILE, "w", newline="") as f:
|
|
writer = csv.DictWriter(f, fieldnames=FIELDS)
|
|
writer.writeheader()
|
|
|
|
|
|
def log_trade(trade: dict):
|
|
"""Append a trade record to the CSV log."""
|
|
_ensure_header()
|
|
sym = trade.get("symbol", "")
|
|
row = {
|
|
"timestamp": trade.get("timestamp", ""),
|
|
"datetime": datetime.now(_TZ_UTC8).isoformat(timespec="seconds"),
|
|
"symbol": sym,
|
|
"name": config.SYMBOL_NAMES.get(sym, sym),
|
|
"action": trade.get("action", ""),
|
|
"amount": trade.get("amount", 0),
|
|
"price": trade.get("price", 0),
|
|
"amount_usdt": trade.get("amount_usdt", 0),
|
|
"confidence": trade.get("confidence", 0),
|
|
"reason": trade.get("reason", ""),
|
|
"mode": trade.get("mode", ""),
|
|
"status": trade.get("status", ""),
|
|
}
|
|
with open(TRADE_LOG_FILE, "a", newline="") as f:
|
|
writer = csv.DictWriter(f, fieldnames=FIELDS)
|
|
writer.writerow(row)
|