update 03-28 11:38

This commit is contained in:
2026-03-28 11:38:53 +09:00
parent 49e033f373
commit 710949f034
9 changed files with 138 additions and 38 deletions

View File

@@ -16,6 +16,7 @@ import signal
import sys
import time
import uuid
from collections import deque
from dataclasses import dataclass, field
from typing import Optional
@@ -120,8 +121,10 @@ class PaperExecutionEngine:
self._fees = fees
self._log = get_logger("paper_engine")
self._positions: dict[str, VirtualPosition] = {}
self._closed_trades: list[VirtualTradeRecord] = []
self._closed_trades: deque[VirtualTradeRecord] = deque(maxlen=10000)
self._total_pnl: float = 0.0
self._win_count: int = 0
self._loss_count: int = 0
# ------------------------------------------------------------------
# Public API
@@ -141,10 +144,10 @@ class PaperExecutionEngine:
@property
def win_rate(self) -> float:
if not self._closed_trades:
total = self._win_count + self._loss_count
if total == 0:
return 0.0
wins = sum(1 for t in self._closed_trades if t.pnl > 0)
return wins / len(self._closed_trades)
return self._win_count / total
def open_position(
self,
@@ -234,6 +237,10 @@ class PaperExecutionEngine:
)
self._closed_trades.append(record)
self._total_pnl += pnl
if pnl > 0:
self._win_count += 1
else:
self._loss_count += 1
# Update the trade record in DB
self._db.update_trade(
@@ -302,12 +309,15 @@ class PaperTradingBot:
self._signal_agg: Optional[SignalAggregator] = None
self._oracle: Optional[OracleMonitor] = None
# Discovered markets cache
self._active_markets: list[ActiveMarket] = []
# Discovered markets cache (keyed by condition_id to prevent duplicates)
self._active_markets: dict[str, ActiveMarket] = {}
# Live orderbook state (token_id → snapshot)
self._orderbooks: dict[str, OrderBookSnapshot] = {}
# Queue drop counter for monitoring
self._queue_drop_count: int = 0
# Pending strategy evaluations (initialized in start())
self._eval_queue: Optional[asyncio.Queue] = None
@@ -349,7 +359,11 @@ class PaperTradingBot:
if window.market is not None and self._eval_queue is not None:
try:
self._eval_queue.put_nowait((symbol, price, window, orderbooks))
except (asyncio.QueueFull, Exception):
except asyncio.QueueFull:
self._queue_drop_count += 1
if self._queue_drop_count % 100 == 1:
self._log.warning("eval_queue_full", drops=self._queue_drop_count)
except Exception:
pass
def _on_orderbook_update(
@@ -532,7 +546,8 @@ class PaperTradingBot:
def _on_new_markets(self, markets: list[ActiveMarket]) -> None:
"""Callback when MarketDiscovery finds new markets."""
self._active_markets.extend(markets)
for mkt in markets:
self._active_markets[mkt.condition_id] = mkt
if self._tracker is not None:
for mkt in markets:
self._tracker.link_market(
@@ -697,6 +712,11 @@ class PaperTradingBot:
today_pnl=round(self._db.get_today_pnl(), 4),
total_pnl=round(self._db.get_total_pnl(), 4),
)
# Periodic DB maintenance (prune old data, WAL checkpoint)
try:
self._db.periodic_maintenance(retention_days=7)
except Exception:
self._log.exception("db_maintenance_error")
# ------------------------------------------------------------------
# Lifecycle
@@ -736,7 +756,7 @@ class PaperTradingBot:
)
self._log.info("running_initial_discovery")
initial_markets = await self._discovery.discover()
self._active_markets = initial_markets
self._active_markets = {m.condition_id: m for m in initial_markets}
self._log.info(
"initial_discovery_complete",
count=len(initial_markets),
@@ -790,7 +810,7 @@ class PaperTradingBot:
self._summary_loop(),
]
if self._oracle and self._oracle._initialized:
tasks.append(self._oracle.poll_loop(interval=5.0))
tasks.append(self._oracle.poll_loop(interval=5.0, shutdown_event=self._shutdown_event))
tasks.append(self._oracle_snapshot_loop())
try:
await asyncio.gather(*tasks)
@@ -808,10 +828,18 @@ class PaperTradingBot:
if self._poly_feed is not None:
await self._poly_feed.stop()
# Close discovery session
if self._discovery is not None:
await self._discovery._close_session_if_owned()
# Print final summary
if self._engine is not None:
self._engine.print_summary()
# Close database connection
if self._db is not None:
self._db.close()
self._log.info("paper_bot_stopped")