Riy777 commited on
Commit
8e2600a
·
verified ·
1 Parent(s): c3f290a

Update trade_manager.py

Browse files
Files changed (1) hide show
  1. trade_manager.py +35 -25
trade_manager.py CHANGED
@@ -1,5 +1,5 @@
1
  # ============================================================
2
- # 🛡️ trade_manager.py (V35.2 - GEM-Architect: Volume Calculation)
3
  # ============================================================
4
 
5
  import asyncio
@@ -32,7 +32,7 @@ class TradeManager:
32
  "stagnation": {"total": 0, "good": 0, "saved": 0.0, "missed": 0.0}
33
  }
34
  self.execution_lock = asyncio.Lock()
35
- print(f"🛡️ [TradeManager V35.2] 30m-Depth Aware Engine Online.")
36
 
37
  async def initialize_sentry_exchanges(self):
38
  print("🛡️ [TradeManager] Syncing state & Initializing Portfolio...")
@@ -200,10 +200,9 @@ class TradeManager:
200
  except: continue
201
 
202
  if d1 and d5 and d15 and len(d5) >= 6:
203
- # ✅ Calculate 30m Volume (Sum of last 6 candles of 5m)
204
- # candle format: [ts, o, h, l, c, vol]
205
  last_6_5m = d5[-6:]
206
- vol_30m_sum = sum([float(c[5]) * float(c[4]) for c in last_6_5m]) # Approx Volume in USD
207
 
208
  context_data = {
209
  'entry_price': trade['entry_price'],
@@ -214,7 +213,7 @@ class TradeManager:
214
  'system_conf': trade.get('decision_data', {}).get('system_confidence', 0.8),
215
  'highest_price': float(trade['highest_price']),
216
  'time_in_trade_mins': (datetime.now() - datetime.fromisoformat(trade['entry_time'])).total_seconds() / 60,
217
- 'volume_30m_usd': vol_30m_sum # ✅ Pass volume info
218
  }
219
 
220
  decision = self.processor.consult_dual_guardians(symbol, d1, d5, d15, context_data, order_book_snapshot=d_ob)
@@ -317,6 +316,9 @@ class TradeManager:
317
  await self.learning_hub.register_trade_outcome(trade_obj)
318
  except Exception: pass
319
 
 
 
 
320
  async def _execute_exit(self, symbol, price, reason, ai_scores=None):
321
  if symbol not in self.open_positions: return
322
  try:
@@ -324,44 +326,52 @@ class TradeManager:
324
  entry_price = float(trade['entry_price']); exit_price = float(price)
325
  entry_capital = float(trade.get('entry_capital', 100.0)); entry_fee = float(trade.get('entry_fee_usd', 0.0))
326
 
327
- exit_val = (exit_price / entry_price) * entry_capital
328
- exit_fee = exit_val * self.FEE_RATE
329
- net_pnl = (exit_val - exit_fee) - entry_capital
 
 
330
  total_fees = entry_fee + exit_fee
331
 
332
- await self.smart_portfolio.register_closed_position(entry_capital, net_pnl, total_fees)
 
 
 
 
 
 
 
 
 
 
 
333
 
334
- trade.update({'status': 'CLOSED', 'exit_price': exit_price, 'exit_reason': reason, 'profit_pct': (net_pnl/entry_capital)*100, 'net_pnl_usd': net_pnl, 'fees_paid_usd': total_fees})
 
 
 
335
 
 
336
  portfolio = await self.r2.get_portfolio_state_async()
337
  portfolio['total_trades'] = portfolio.get('total_trades', 0) + 1
338
- if net_pnl >= 0:
339
  portfolio['winning_trades'] = portfolio.get('winning_trades', 0) + 1
340
- portfolio['total_profit_usd'] = portfolio.get('total_profit_usd', 0) + net_pnl
341
  trade['result'] = 'WIN'
342
  else:
343
  portfolio['losing_trades'] = portfolio.get('losing_trades', 0) + 1
344
- portfolio['total_loss_usd'] = portfolio.get('total_loss_usd', 0) + abs(net_pnl)
345
  trade['result'] = 'LOSS'
346
 
347
  await self.r2.save_portfolio_state_async(portfolio)
348
  await self.r2.save_open_trades_async(list(self.open_positions.values()))
349
  await self.r2.append_to_closed_trades_history(trade)
350
 
351
- print(f"✅ [EXIT] {symbol} | Net PnL: {(net_pnl/entry_capital)*100:.2f}% (${net_pnl:.2f}) | {reason}")
352
  self._launch_post_exit_analysis(symbol, exit_price, trade.get('exit_time'), entry_capital, ai_scores, trade)
353
  self.latest_guardian_log = f"✅ Closed {symbol} ({reason})"
354
  if symbol in self.sentry_tasks: self.sentry_tasks[symbol].cancel(); del self.sentry_tasks[symbol]
355
 
356
  except Exception as e:
357
  print(f"❌ [Exit Error] {e}"); traceback.print_exc()
358
- if symbol not in self.open_positions: self.open_positions[symbol] = trade
359
-
360
- async def force_exit_by_manager(self, symbol, reason):
361
- p = await self.data_manager.get_latest_price_async(symbol)
362
- async with self.execution_lock: await self._execute_exit(symbol, p, reason)
363
-
364
- async def start_sentry_loops(self): await self.ensure_active_guardians()
365
- async def stop_sentry_loops(self):
366
- self.running = False
367
- for task in self.sentry_tasks.values(): task.cancel()
 
1
  # ============================================================
2
+ # 🛡️ trade_manager.py (V35.3 - GEM-Architect: Math & Fee Sync Fixed)
3
  # ============================================================
4
 
5
  import asyncio
 
32
  "stagnation": {"total": 0, "good": 0, "saved": 0.0, "missed": 0.0}
33
  }
34
  self.execution_lock = asyncio.Lock()
35
+ print(f"🛡️ [TradeManager V35.3] True PnL Math Active.")
36
 
37
  async def initialize_sentry_exchanges(self):
38
  print("🛡️ [TradeManager] Syncing state & Initializing Portfolio...")
 
200
  except: continue
201
 
202
  if d1 and d5 and d15 and len(d5) >= 6:
203
+ # 30m Volume for Context
 
204
  last_6_5m = d5[-6:]
205
+ vol_30m_sum = sum([float(c[5]) * float(c[4]) for c in last_6_5m])
206
 
207
  context_data = {
208
  'entry_price': trade['entry_price'],
 
213
  'system_conf': trade.get('decision_data', {}).get('system_confidence', 0.8),
214
  'highest_price': float(trade['highest_price']),
215
  'time_in_trade_mins': (datetime.now() - datetime.fromisoformat(trade['entry_time'])).total_seconds() / 60,
216
+ 'volume_30m_usd': vol_30m_sum
217
  }
218
 
219
  decision = self.processor.consult_dual_guardians(symbol, d1, d5, d15, context_data, order_book_snapshot=d_ob)
 
316
  await self.learning_hub.register_trade_outcome(trade_obj)
317
  except Exception: pass
318
 
319
+ # ==============================================================================
320
+ # 🔴 Exit Logic (MATH FIXED)
321
+ # ==============================================================================
322
  async def _execute_exit(self, symbol, price, reason, ai_scores=None):
323
  if symbol not in self.open_positions: return
324
  try:
 
326
  entry_price = float(trade['entry_price']); exit_price = float(price)
327
  entry_capital = float(trade.get('entry_capital', 100.0)); entry_fee = float(trade.get('entry_fee_usd', 0.0))
328
 
329
+ # 1. Gross Calculation
330
+ exit_val_gross = (exit_price / entry_price) * entry_capital
331
+
332
+ # 2. Fees
333
+ exit_fee = exit_val_gross * self.FEE_RATE
334
  total_fees = entry_fee + exit_fee
335
 
336
+ # 3. PnL for Portfolio (Gross PnL so portfolio handles fees correctly)
337
+ # Gross PnL = Difference in Asset Value
338
+ gross_pnl_usd = exit_val_gross - entry_capital
339
+
340
+ # 4. PnL for Statistics (True Net PnL)
341
+ # True Net = Gross PnL - All Fees
342
+ true_net_pnl_usd = gross_pnl_usd - total_fees
343
+ true_net_pct = (true_net_pnl_usd / entry_capital) * 100
344
+
345
+ # ✅ Notify Portfolio with Gross PnL (Because it subtracts fees internally)
346
+ # Impact on Wallet = Gross PnL - Total Fees
347
+ await self.smart_portfolio.register_closed_position(entry_capital, gross_pnl_usd, total_fees)
348
 
349
+ trade.update({
350
+ 'status': 'CLOSED', 'exit_price': exit_price, 'exit_reason': reason,
351
+ 'profit_pct': true_net_pct, 'net_pnl_usd': true_net_pnl_usd, 'fees_paid_usd': total_fees
352
+ })
353
 
354
+ # Update Stats with TRUE NET
355
  portfolio = await self.r2.get_portfolio_state_async()
356
  portfolio['total_trades'] = portfolio.get('total_trades', 0) + 1
357
+ if true_net_pnl_usd >= 0:
358
  portfolio['winning_trades'] = portfolio.get('winning_trades', 0) + 1
359
+ portfolio['total_profit_usd'] = portfolio.get('total_profit_usd', 0) + true_net_pnl_usd
360
  trade['result'] = 'WIN'
361
  else:
362
  portfolio['losing_trades'] = portfolio.get('losing_trades', 0) + 1
363
+ portfolio['total_loss_usd'] = portfolio.get('total_loss_usd', 0) + abs(true_net_pnl_usd)
364
  trade['result'] = 'LOSS'
365
 
366
  await self.r2.save_portfolio_state_async(portfolio)
367
  await self.r2.save_open_trades_async(list(self.open_positions.values()))
368
  await self.r2.append_to_closed_trades_history(trade)
369
 
370
+ print(f"✅ [EXIT] {symbol} | True Net PnL: {true_net_pct:.2f}% (${true_net_pnl_usd:.2f}) | {reason}")
371
  self._launch_post_exit_analysis(symbol, exit_price, trade.get('exit_time'), entry_capital, ai_scores, trade)
372
  self.latest_guardian_log = f"✅ Closed {symbol} ({reason})"
373
  if symbol in self.sentry_tasks: self.sentry_tasks[symbol].cancel(); del self.sentry_tasks[symbol]
374
 
375
  except Exception as e:
376
  print(f"❌ [Exit Error] {e}"); traceback.print_exc()
377
+ if symbol not in self.open_positions: self.open_positions[symbol] = trade