KarlQuant commited on
Commit
edbea9d
·
verified ·
1 Parent(s): a1b90b7

Upload 2 files

Browse files
Files changed (2) hide show
  1. hub_dashboard_service.py +18 -10
  2. ranker_logging.py +10 -5
hub_dashboard_service.py CHANGED
@@ -88,16 +88,22 @@ class TradeLogParser:
88
  r'(?:TRADE CLOSED|no-cid fallback|FORCE-CLOSED.*?timeout).*?(?:pnl|profit)=([+-]?[\d.]+)'
89
  )
90
 
91
- # FIX v2.2: Dedicated regex for Line 2 of the two-line close event.
92
- # The ranker emits TWO TRADE CLOSED lines per close:
93
- # Line 1 pnl + return% (no exit_price)
94
- # Line 2 pnl + exit_price + status + contract_id
95
- # The old STRICT regex used an optional group (?:.*?exit_price=...)?
96
- # which Python's NFA engine would skip (zero-width match) because the
97
- # overall pattern succeeds without it — so exit_price was always None.
98
- # This dedicated regex has NO optional groups and matches Line 2 only.
 
 
 
 
 
99
  TRADE_CLOSE_RE_WITH_EXIT = re.compile(
100
- r'TRADE CLOSED \| ID=(\S+) \| pnl=([+-]?[\d.]+) \| exit_price=([\d.]+)'
 
101
  )
102
 
103
  # Fallback for Line 1: pnl + return%, no exit_price
@@ -259,7 +265,9 @@ class TradeLogParser:
259
  if m2e:
260
  trade_id = m2e.group(1)
261
  pnl = float(m2e.group(2))
262
- _exit_price = float(m2e.group(3))
 
 
263
  logger.debug(
264
  f"[TradeLogParser] Matched CLOSE+EXIT: {trade_id} "
265
  f"pnl={pnl} exit_price={_exit_price}"
 
88
  r'(?:TRADE CLOSED|no-cid fallback|FORCE-CLOSED.*?timeout).*?(?:pnl|profit)=([+-]?[\d.]+)'
89
  )
90
 
91
+ # FIX v2.3: Dual-format regex for trade close lines that carry exit_price.
92
+ # Root cause (v2.2 bug): ranker_logging.trade_close() wrote exit_price ONLY
93
+ # into the trailing JSON metadata blob, e.g.:
94
+ # TRADE CLOSED | ID=... | pnl=... | return=...% | {"exit_price": 4364.21}
95
+ # but this regex looked for it as a pipe-delimited text field:
96
+ # TRADE CLOSED | ID=... | pnl=... | exit_price=... <- never present
97
+ # so TRADE_CLOSE_RE_WITH_EXIT never matched and exit_price was always None.
98
+ #
99
+ # Fix has TWO parts:
100
+ # 1. ranker_logging.py now writes exit_price into the message text too.
101
+ # 2. This regex matches BOTH formats so old log files still parse correctly:
102
+ # Group 3 - pipe-delimited text field (new format, post-fix)
103
+ # Group 4 - JSON metadata field (old format, pre-fix)
104
  TRADE_CLOSE_RE_WITH_EXIT = re.compile(
105
+ r'TRADE CLOSED \| ID=(\S+) \| pnl=([+-]?[\d.]+)'
106
+ r'.*?(?:\| exit_price=([\d.]+)|"exit_price":\s*([\d.]+))'
107
  )
108
 
109
  # Fallback for Line 1: pnl + return%, no exit_price
 
265
  if m2e:
266
  trade_id = m2e.group(1)
267
  pnl = float(m2e.group(2))
268
+ # Group 3 = pipe-delimited "| exit_price=..." (new format, post-fix)
269
+ # Group 4 = JSON metadata '"exit_price": ...' (old format, pre-fix)
270
+ _exit_price = float(m2e.group(3) or m2e.group(4))
271
  logger.debug(
272
  f"[TradeLogParser] Matched CLOSE+EXIT: {trade_id} "
273
  f"pnl={pnl} exit_price={_exit_price}"
ranker_logging.py CHANGED
@@ -244,14 +244,19 @@ class RankerLogger:
244
  asset=asset, metadata=metadata)
245
 
246
  def trade_close(self, trade_id: str, asset: str, pnl: float, return_pct: float, exit_price: Optional[float] = None):
247
- """Log trade closing. ✅ FIX v2.1: Now accepts exit_price for dashboard."""
248
  metadata = {"trade_id": trade_id, "pnl": pnl, "return_pct": return_pct}
249
- # ✅ FIX: Include exit_price in metadata if provided
250
  if exit_price is not None:
251
  metadata["exit_price"] = exit_price
252
- self._log(LogLevel.INFO, EventCategory.TRADE,
253
- f"TRADE CLOSED | ID={trade_id} | pnl={pnl:+.4f} | return={return_pct:+.2%}",
254
- asset=asset, metadata=metadata)
 
 
 
 
 
255
 
256
  def ranking_update(self, rankings: List[Dict], top_asset: str, top_score: float):
257
  """Log ranking cycle results."""
 
244
  asset=asset, metadata=metadata)
245
 
246
  def trade_close(self, trade_id: str, asset: str, pnl: float, return_pct: float, exit_price: Optional[float] = None):
247
+ """Log trade closing. ✅ FIX v2.2: exit_price written into message text AND metadata."""
248
  metadata = {"trade_id": trade_id, "pnl": pnl, "return_pct": return_pct}
249
+ # Include exit_price in metadata for JSON export
250
  if exit_price is not None:
251
  metadata["exit_price"] = exit_price
252
+ # ✅ FIX v2.2: Also embed exit_price in the pipe-delimited message so the
253
+ # dashboard regex (TRADE_CLOSE_RE_WITH_EXIT) can capture it directly.
254
+ # Previously exit_price lived only in the trailing JSON metadata, which the
255
+ # regex never reached — causing the EXIT column to always display "—".
256
+ msg = f"TRADE CLOSED | ID={trade_id} | pnl={pnl:+.4f} | return={return_pct:+.2%}"
257
+ if exit_price is not None:
258
+ msg += f" | exit_price={exit_price}"
259
+ self._log(LogLevel.INFO, EventCategory.TRADE, msg, asset=asset, metadata=metadata)
260
 
261
  def ranking_update(self, rankings: List[Dict], top_asset: str, top_score: float):
262
  """Log ranking cycle results."""