Skip to content

Commit 9b49004

Browse files
committed
fix(fast_entry_engine): enhance error handling and logging, improve price drop detection logic, and refactor market token fetching to use httpx directly
1 parent 758e4d1 commit 9b49004

1 file changed

Lines changed: 64 additions & 16 deletions

File tree

agents/application/fast_entry_engine.py

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
from typing import Optional, Callable, Dict, Any, List
1212
from datetime import datetime, timezone
1313
import json
14+
import httpx
1415

1516
from agents.polymarket.polymarket import Polymarket
16-
from agents.application.position_manager import PositionManager, ActiveTrade
17+
from agents.application.position_manager import PositionManager, ActiveTrade, TradeAction
1718
from agents.application.latency_stats import LatencyStats
1819
from src.utils.logger import get_logger
1920
from src.utils.exceptions import APIError, BotError
@@ -246,6 +247,12 @@ def _detect_dislocation(self, token_id: str) -> Optional[DislocationSignal]:
246247
current = history[-1]
247248
baseline = history[0] # Oldest in window
248249

250+
# Avoid division by zero if baseline mid_price is zero (valid but rare for probability prices).
251+
# If baseline is zero we cannot compute a meaningful percentage drop, so skip detection.
252+
if baseline.mid_price <= 0.0:
253+
logger.debug(f"Baseline mid_price is zero for {token_id}, skipping dislocation detection")
254+
return None
255+
249256
# Calculate price drop percentage
250257
price_drop_pct = ((baseline.mid_price - current.mid_price) / baseline.mid_price) * 100.0
251258

@@ -264,8 +271,10 @@ def _detect_dislocation(self, token_id: str) -> Optional[DislocationSignal]:
264271
if speed_ratio < self.speed_ratio_threshold:
265272
return None # Not fast enough
266273

267-
# Determine side: if price dropped, buy (expecting bounce)
268-
side = "UP" if "up" in token_id.lower() or current.mid_price < baseline.mid_price else "DOWN"
274+
# Determine side: if price dropped, buy (expecting bounce).
275+
# Use price movement only — do not rely on substring matches in token_id,
276+
# which may produce false positives (e.g. token IDs containing "up" in other words).
277+
side = "UP" if current.mid_price < baseline.mid_price else "DOWN"
269278

270279
t_detect = self._monotonic_ms()
271280

@@ -540,11 +549,8 @@ async def _monitor_token(self, token_id: str) -> None:
540549
async def _get_active_market_tokens(self) -> List[str]:
541550
"""Get token IDs for active 15m markets."""
542551
try:
543-
# Use connection pooling for better performance
544-
client = self.polymarket._get_http_client()
545-
546-
# Fetch markets from Gamma API
547-
response = client.get(
552+
# Fetch markets from Gamma API (use httpx directly)
553+
response = httpx.get(
548554
f"{self.polymarket.gamma_url}/markets",
549555
params={"active": "true", "closed": "false"},
550556
timeout=5
@@ -610,6 +616,9 @@ async def start(self) -> None:
610616
tokens = await self._get_active_market_tokens()
611617
logger.info(f"Monitoring {len(tokens)} tokens")
612618

619+
# Ensure cleanup_task is always defined so finally blocks can safely cancel it
620+
cleanup_task = None
621+
613622
# WebSocket mode: use real-time updates
614623
if self.use_websocket and self.ws_client:
615624
logger.info("Using WebSocket for real-time price updates (lower latency)")
@@ -653,8 +662,20 @@ def on_ws_update(update: "OrderBookUpdate"):
653662
except Exception as e:
654663
logger.error(f"Engine error: {e}")
655664
finally:
665+
# Stop websocket client if running
656666
if self.ws_client:
657-
await self.ws_client.stop()
667+
try:
668+
await self.ws_client.stop()
669+
except Exception:
670+
logger.exception("Error stopping ws_client")
671+
# Ensure cleanup task is cancelled
672+
if cleanup_task is not None:
673+
cleanup_task.cancel()
674+
try:
675+
await cleanup_task
676+
except asyncio.CancelledError:
677+
pass
678+
self.running = False
658679

659680
else:
660681
# REST polling mode (fallback)
@@ -672,9 +693,14 @@ def on_ws_update(update: "OrderBookUpdate"):
672693
logger.info("Engine stopped")
673694
except Exception as e:
674695
logger.error(f"Engine error: {e}")
675-
finally:
676-
self.running = False
677-
cleanup_task.cancel()
696+
finally:
697+
self.running = False
698+
if cleanup_task is not None:
699+
cleanup_task.cancel()
700+
try:
701+
await cleanup_task
702+
except asyncio.CancelledError:
703+
pass
678704

679705
def stop(self) -> None:
680706
"""Stop the engine."""
@@ -702,20 +728,42 @@ def add_size_by_trade_id(self, trade_id: str, additional_size_usdc: float) -> bo
702728
return False
703729

704730
try:
731+
# Execute market order
705732
self.polymarket.execute_order(
706733
price=trade.leg1_price,
707734
size=additional_size_usdc,
708735
side="BUY",
709736
token_id=trade.token_id,
710737
)
711-
738+
739+
# Update trade state via PositionManager to keep totals/idempotency consistent.
740+
# Generate a unique action_id for idempotency tracking.
741+
action_id = f"add_{trade_id}_{int(time.time() * 1000)}"
742+
try:
743+
result = self.position_manager.process_confirmation(
744+
trade_id=trade_id,
745+
action=TradeAction.ADD,
746+
action_id=action_id,
747+
additional_size=additional_size_usdc,
748+
)
749+
except Exception as e:
750+
logger.exception(f"PositionManager.process_confirmation failed for ADD on {trade_id}: {e}")
751+
result = {"ok": False, "message": str(e)}
752+
753+
if not result.get("ok"):
754+
logger.warning(f"ADD processed but position update failed for {trade_id}: {result.get('message')}")
755+
756+
# Refresh trade object (may have been mutated)
757+
trade = self.position_manager.get_trade(trade_id)
758+
712759
self._log_ms("ADD_SIZE", {
713760
"trade_id": trade_id,
714-
"entry_id": trade.leg1_entry_id,
761+
"entry_id": trade.leg1_entry_id if trade else None,
715762
"additional_size_usdc": additional_size_usdc,
716-
"total_size": trade.total_size,
763+
"total_size": trade.total_size if trade else None,
764+
"status": trade.status.value if trade else None,
717765
})
718-
766+
719767
return True
720768
except Exception as e:
721769
logger.error(f"Add size failed: {e}")

0 commit comments

Comments
 (0)