From 591f045cde3166fbc6945c68b4add2ff6fb8e858 Mon Sep 17 00:00:00 2001 From: AdrianoDev Date: Wed, 27 May 2026 10:04:54 +0200 Subject: [PATCH] feat: capitale virtuale $1000 USDC, PnL tracking realistico con fee Co-Authored-By: Claude Opus 4.7 (1M context) --- src/live/paper_trader.py | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/live/paper_trader.py b/src/live/paper_trader.py index 82867de..85144cd 100644 --- a/src/live/paper_trader.py +++ b/src/live/paper_trader.py @@ -13,7 +13,7 @@ from src.live.signal_engine import SignalEngine LOG_DIR = Path(__file__).resolve().parents[2] / "data" / "paper_trades" INSTRUMENT = "ETH_USDC-PERPETUAL" -TRAIN_INSTRUMENT = "ETH-PERPETUAL" # storico più lungo per training +TRAIN_INSTRUMENT = "ETH-PERPETUAL" CURRENCY = "USDC" RESOLUTION = "15" LEVERAGE = 3 @@ -22,6 +22,7 @@ HOLD_BARS = 3 POLL_SECONDS = 60 LOOKBACK_DAYS = 60 TRAIN_LOOKBACK_DAYS = 365 +VIRTUAL_CAPITAL = 1000.0 # simula capitale reale, ignora balance testnet class PaperTrader: @@ -29,10 +30,12 @@ class PaperTrader: self.client = CerberoClient() self.engine = SignalEngine(bb_w=14, sq_thr=0.8, ml_thr=0.70) + self.virtual_capital = VIRTUAL_CAPITAL self.in_position = False self.position_entry_time: datetime | None = None self.position_direction: str | None = None self.position_entry_price: float = 0 + self.position_size: float = 0 self.bars_held = 0 self.last_bar_ts: int = 0 @@ -52,9 +55,11 @@ class PaperTrader: def save_status(self): status = { + "virtual_capital": round(self.virtual_capital, 2), "in_position": self.in_position, "direction": self.position_direction, "entry_price": self.position_entry_price, + "position_size": self.position_size, "entry_time": self.position_entry_time.isoformat() if self.position_entry_time else None, "bars_held": self.bars_held, "last_update": datetime.now(timezone.utc).isoformat(), @@ -91,10 +96,8 @@ class PaperTrader: def open_position(self, direction: str, signal: dict): ticker = self.client.get_ticker(INSTRUMENT) price = ticker["last_price"] - account = self.client.get_account_summary() - equity = account["equity"] - notional = equity * POSITION_PCT + notional = self.virtual_capital * POSITION_PCT * LEVERAGE amount = round(notional / price, 3) amount = max(amount, 0.001) @@ -104,7 +107,8 @@ class PaperTrader: "side": side, "amount": amount, "price": price, - "equity": equity, + "virtual_capital": round(self.virtual_capital, 2), + "notional": round(notional, 2), "signal": signal, }) @@ -120,6 +124,7 @@ class PaperTrader: self.in_position = True self.position_direction = side self.position_entry_price = price + self.position_size = amount self.position_entry_time = datetime.now(timezone.utc) self.bars_held = 0 self.log("OPENED", {"order_result": result}) @@ -134,27 +139,43 @@ class PaperTrader: exit_price = ticker["last_price"] if self.position_direction == "buy": - pnl_pct = (exit_price - self.position_entry_price) / self.position_entry_price * 100 + trade_pnl = (exit_price - self.position_entry_price) * self.position_size else: - pnl_pct = (self.position_entry_price - exit_price) / self.position_entry_price * 100 + trade_pnl = (self.position_entry_price - exit_price) * self.position_size + + fee = self.position_size * (self.position_entry_price + exit_price) * 0.001 + net_pnl = trade_pnl - fee + pnl_pct = net_pnl / self.virtual_capital * 100 self.log("CLOSING", { "reason": reason, "entry_price": self.position_entry_price, "exit_price": exit_price, + "size": self.position_size, + "trade_pnl": round(trade_pnl, 2), + "fee": round(fee, 2), + "net_pnl": round(net_pnl, 2), "pnl_pct": round(pnl_pct, 3), "bars_held": self.bars_held, + "capital_before": round(self.virtual_capital, 2), }) try: result = self.client.close_position(INSTRUMENT) - self.log("CLOSED", {"result": result, "pnl_pct": round(pnl_pct, 3)}) + self.virtual_capital += net_pnl + self.log("CLOSED", { + "result": result, + "net_pnl": round(net_pnl, 2), + "pnl_pct": round(pnl_pct, 3), + "virtual_capital": round(self.virtual_capital, 2), + }) except Exception as e: self.log("CLOSE_FAILED", {"error": str(e)}) self.in_position = False self.position_direction = None self.position_entry_price = 0 + self.position_size = 0 self.position_entry_time = None self.bars_held = 0 @@ -215,7 +236,8 @@ class PaperTrader: account = self.client.get_account_summary() self.log("STARTUP", { - "equity": account["equity"], + "virtual_capital": self.virtual_capital, + "testnet_equity": account["equity"], "testnet": account.get("testnet", True), })