update 03-28 11:38
This commit is contained in:
@@ -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")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user