| """One-time: recover 12 closed trades from daemon logs into runtime DB.""" |
| import sqlite3, pathlib, datetime as _dt |
|
|
| RUNTIME_DB = pathlib.Path.home() / "borsa_uygulamasi_runtime/huggingface-space/paper_trading/trading.db" |
|
|
| |
| FILLS = [ |
| |
| ("2026-02-25", "BUY", 99, "RALYH", 150.7753, 15.67), |
| ("2026-02-26", "BUY", 49, "THYAO", 306.4031, 15.76), |
| ("2026-02-27", "BUY", 1597, "IZENR", 9.4347, 15.82), |
| ("2026-03-02", "SELL", 99, "RALYH", 147.4263, 15.32), |
| ("2026-03-02", "SELL", 49, "THYAO", 287.6061, 14.80), |
| ("2026-03-02", "SELL",1597, "IZENR", 8.9055, 14.93), |
| ("2026-03-02", "BUY", 1484, "AKSA", 9.8749, 15.39), |
| ("2026-03-02", "BUY", 1648, "IZENR", 8.9145, 15.43), |
| ("2026-03-02", "BUY", 79, "ASTOR", 183.3917, 15.21), |
| ("2026-03-02", "BUY", 50, "THYAO", 287.8939, 15.11), |
| ("2026-03-03", "SELL",1648, "IZENR", 8.9455, 15.48), |
| ("2026-03-04", "SELL", 50, "THYAO", 283.8580, 14.90), |
| ("2026-03-04", "BUY", 185, "AKBNK", 78.5392, 15.26), |
| ("2026-03-05", "SELL", 79, "ASTOR", 172.2139, 14.29), |
| ("2026-03-05", "SELL", 185, "AKBNK", 80.9595, 15.73), |
| ("2026-03-05", "BUY", 84, "ASTOR", 172.3862, 15.20), |
| ("2026-03-05", "BUY", 98, "RALYH", 147.2736, 15.15), |
| ("2026-03-05", "BUY", 2702, "BTCIM", 5.4027, 15.33), |
| ("2026-03-06", "SELL",1484, "AKSA", 10.0150, 15.61), |
| ("2026-03-06", "SELL", 98, "RALYH", 143.7281, 14.79), |
| ("2026-03-06", "BUY", 51, "THYAO", 284.1420, 15.22), |
| ("2026-03-09", "SELL", 51, "THYAO", 267.1164, 14.30), |
| ("2026-03-11", "SELL", 84, "ASTOR", 193.7031, 17.08), |
| ("2026-03-12", "SELL",2702, "BTCIM", 6.1269, 17.38), |
| |
| ] |
|
|
| def match_trades(fills): |
| """FIFO matching: pair BUY fills with subsequent SELL fills by (symbol, qty).""" |
| open_positions = [] |
| closed = [] |
| |
| for f in fills: |
| date, action, qty, sym, price, comm = f |
| if action == "BUY": |
| open_positions.append(f) |
| else: |
| |
| for i, op in enumerate(open_positions): |
| if op[3] == sym and op[2] == qty: |
| entry = op |
| exit_ = f |
| closed.append((entry, exit_)) |
| open_positions.pop(i) |
| break |
| return closed |
|
|
| def build_trade_record(entry, exit_): |
| e_date, _, qty, sym, e_price, e_comm = entry |
| x_date, _, _, _, x_price, x_comm = exit_ |
| |
| gross_pnl = round((x_price - e_price) * qty, 4) |
| net_pnl = round(gross_pnl - e_comm - x_comm, 4) |
| return_pct = round((x_price - e_price) / e_price * 100, 4) |
| |
| d1 = _dt.date.fromisoformat(e_date) |
| d2 = _dt.date.fromisoformat(x_date) |
| holding_days = (d2 - d1).days |
| |
| return { |
| "symbol": sym, |
| "side": "BUY", |
| "entry_price": e_price, |
| "exit_price": x_price, |
| "quantity": qty, |
| "entry_date": e_date, |
| "exit_date": x_date, |
| "entry_commission": e_comm, |
| "exit_commission": x_comm, |
| "gross_pnl": gross_pnl, |
| "net_pnl": net_pnl, |
| "return_pct": return_pct, |
| "holding_days": holding_days, |
| "signal_confidence": 0.0, |
| "predicted_return": 0.0, |
| "entry_reason": "ML_BUY_SIGNAL", |
| "exit_reason": "SIGNAL_SELL", |
| "is_closed": 1, |
| "created_at": f"{e_date} 10:30:00", |
| "updated_at": f"{x_date} 10:30:00", |
| } |
|
|
| def main(): |
| pairs = match_trades(FILLS) |
| print(f"Matched {len(pairs)} closed trades from daemon logs\n") |
| |
| records = [] |
| total_net = 0.0 |
| winners = 0 |
| for entry, exit_ in pairs: |
| r = build_trade_record(entry, exit_) |
| records.append(r) |
| total_net += r["net_pnl"] |
| if r["net_pnl"] > 0: |
| winners += 1 |
| print(f" {r['symbol']:6s} {r['entry_date']}→{r['exit_date']} " |
| f"net={r['net_pnl']:+.2f} ret={r['return_pct']:+.2f}% " |
| f"hold={r['holding_days']}d") |
| |
| losers = len(records) - winners |
| win_pnl = sum(r["net_pnl"] for r in records if r["net_pnl"] > 0) |
| loss_pnl = abs(sum(r["net_pnl"] for r in records if r["net_pnl"] <= 0)) |
| pf = win_pnl / loss_pnl if loss_pnl > 0 else 0 |
| |
| print(f"\nSummary: {len(records)} trades, {winners}W/{losers}L") |
| print(f" WR={winners/len(records)*100:.1f}% PF={pf:.2f} Net={total_net:+.2f}") |
| |
| |
| db = sqlite3.connect(str(RUNTIME_DB)) |
| cur = db.cursor() |
| |
| |
| cur.execute("SELECT COUNT(*) FROM trades WHERE is_closed=1") |
| existing = cur.fetchone()[0] |
| if existing > 0: |
| print(f"\n⚠ Already {existing} closed trades in DB. Skipping insert.") |
| db.close() |
| return |
| |
| cols = list(records[0].keys()) |
| placeholders = ",".join(["?"] * len(cols)) |
| col_names = ",".join(cols) |
| |
| for r in records: |
| vals = [r[c] for c in cols] |
| cur.execute(f"INSERT INTO trades ({col_names}) VALUES ({placeholders})", vals) |
| |
| db.commit() |
| print(f"\n✅ Inserted {len(records)} closed trades into {RUNTIME_DB}") |
| |
| |
| cur.execute("SELECT COUNT(*) FROM trades WHERE is_closed=1") |
| print(f" Closed trades in DB: {cur.fetchone()[0]}") |
| cur.execute("SELECT COUNT(*) FROM trades WHERE is_closed=0") |
| print(f" Open trades in DB: {cur.fetchone()[0]}") |
| db.close() |
|
|
| if __name__ == "__main__": |
| main() |
|
|