mgbam commited on
Commit
d944095
Β·
verified Β·
1 Parent(s): 647387c

Update app/main.py

Browse files
Files changed (1) hide show
  1. app/main.py +34 -20
app/main.py CHANGED
@@ -1,8 +1,8 @@
1
  """
2
- Sentinel Arbitrage Engine - v16.0 FINAL (Correct Object Naming)
3
 
4
- This is the definitive version with the correct object names to match
5
- the startup script, ensuring a successful launch.
6
  """
7
  import asyncio
8
  import os
@@ -16,31 +16,41 @@ import socketio
16
  from fastapi import FastAPI
17
  from fastapi.staticfiles import StaticFiles
18
 
 
19
  from .price_fetcher import PriceFetcher
20
  from .arbitrage_analyzer import ArbitrageAnalyzer
21
 
22
  OPPORTUNITY_THRESHOLD = 0.0015
23
 
24
  # --- Socket.IO Server Setup ---
 
25
  sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*')
26
 
27
  # --- Background Engine ---
28
  async def run_arbitrage_detector(price_fetcher, analyzer):
29
- # This logic is correct and does not need to change.
30
  while True:
31
  try:
32
  await price_fetcher.update_prices_async()
33
  all_prices = price_fetcher.get_all_prices()
 
34
  for asset, prices in all_prices.items():
35
- pyth_price, chainlink_price = prices.get("pyth"), prices.get("chainlink_agg")
 
 
36
  if pyth_price and chainlink_price and pyth_price > 0:
37
  spread = abs(pyth_price - chainlink_price) / chainlink_price
38
  if spread > OPPORTUNITY_THRESHOLD:
39
  current_time = time.time()
 
40
  if not hasattr(analyzer, 'last_call') or current_time - analyzer.last_call.get(asset, 0) > 60:
41
  analyzer.last_call = getattr(analyzer, 'last_call', {})
42
  analyzer.last_call[asset] = current_time
43
- opportunity = {"asset": asset, "pyth_price": pyth_price, "chainlink_price": chainlink_price, "spread_pct": spread * 100}
 
 
 
 
44
  print(f"⚑️ Dislocation for {asset}: {opportunity['spread_pct']:.3f}%")
45
  briefing = await analyzer.get_alpha_briefing(asset, opportunity)
46
  if briefing:
@@ -49,6 +59,7 @@ async def run_arbitrage_detector(price_fetcher, analyzer):
49
  print(f"βœ… Signal Emitted for {asset}: {signal['strategy']}")
50
  except Exception as e:
51
  print(f"❌ ERROR in engine loop: {e}")
 
52
  await asyncio.sleep(15)
53
 
54
  # --- FastAPI Lifespan (for background task) ---
@@ -56,28 +67,31 @@ async def run_arbitrage_detector(price_fetcher, analyzer):
56
  async def lifespan(app: FastAPI):
57
  print("πŸš€ Initializing Sentinel Arbitrage Engine v16.0...")
58
  async with httpx.AsyncClient() as client:
59
- price_fetcher = PriceFetcher(client)
60
- arbitrage_analyzer = ArbitrageAnalyzer(client)
61
- sio.background_task = sio.start_background_task(run_arbitrage_detector, price_fetcher, arbitrage_analyzer)
 
 
 
62
  print("βœ… Engine is online and hunting for opportunities.")
63
  yield
64
- print("⏳ Shutting down engine...")
65
- sio.background_task.cancel()
66
- try: await sio.background_task
67
- except asyncio.CancelledError: print("Engine shut down gracefully.")
68
 
69
- # --- FastAPI App & Socket.IO Mount ---
70
- # THE FIX: We name the main FastAPI instance 'app' to match the startup script.
71
  app = FastAPI(lifespan=lifespan)
72
 
73
- # The primary app is the Socket.IO server, which wraps our FastAPI app.
74
- # The startup script should point to THIS object.
75
- app = socketio.ASGIApp(sio, other_asgi_app=app)
76
 
77
- # Serve the static files. This route is now handled by the wrapped app.
78
- sio.mount("/", StaticFiles(directory="static", html=True), name="static")
 
79
 
80
 
 
81
  @sio.event
82
  async def connect(sid, environ):
83
  print(f"βœ… Client connected: {sid}")
 
1
  """
2
+ Sentinel Arbitrage Engine - v16.0 FINAL (Correct Mount)
3
 
4
+ The definitive, money-spinning engine. This version uses the correct
5
+ FastAPI and Socket.IO mounting strategy for guaranteed execution.
6
  """
7
  import asyncio
8
  import os
 
16
  from fastapi import FastAPI
17
  from fastapi.staticfiles import StaticFiles
18
 
19
+ # Relative imports for our package structure
20
  from .price_fetcher import PriceFetcher
21
  from .arbitrage_analyzer import ArbitrageAnalyzer
22
 
23
  OPPORTUNITY_THRESHOLD = 0.0015
24
 
25
  # --- Socket.IO Server Setup ---
26
+ # This creates the server instance that will handle all real-time communication.
27
  sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*')
28
 
29
  # --- Background Engine ---
30
  async def run_arbitrage_detector(price_fetcher, analyzer):
31
+ """The core engine loop; detects opportunities and emits them via Socket.IO."""
32
  while True:
33
  try:
34
  await price_fetcher.update_prices_async()
35
  all_prices = price_fetcher.get_all_prices()
36
+
37
  for asset, prices in all_prices.items():
38
+ pyth_price = prices.get("pyth")
39
+ chainlink_price = prices.get("chainlink_agg")
40
+
41
  if pyth_price and chainlink_price and pyth_price > 0:
42
  spread = abs(pyth_price - chainlink_price) / chainlink_price
43
  if spread > OPPORTUNITY_THRESHOLD:
44
  current_time = time.time()
45
+ # Simple throttle to avoid spamming Gemini for the same opportunity
46
  if not hasattr(analyzer, 'last_call') or current_time - analyzer.last_call.get(asset, 0) > 60:
47
  analyzer.last_call = getattr(analyzer, 'last_call', {})
48
  analyzer.last_call[asset] = current_time
49
+
50
+ opportunity = {
51
+ "asset": asset, "pyth_price": pyth_price,
52
+ "chainlink_price": chainlink_price, "spread_pct": spread * 100
53
+ }
54
  print(f"⚑️ Dislocation for {asset}: {opportunity['spread_pct']:.3f}%")
55
  briefing = await analyzer.get_alpha_briefing(asset, opportunity)
56
  if briefing:
 
59
  print(f"βœ… Signal Emitted for {asset}: {signal['strategy']}")
60
  except Exception as e:
61
  print(f"❌ ERROR in engine loop: {e}")
62
+
63
  await asyncio.sleep(15)
64
 
65
  # --- FastAPI Lifespan (for background task) ---
 
67
  async def lifespan(app: FastAPI):
68
  print("πŸš€ Initializing Sentinel Arbitrage Engine v16.0...")
69
  async with httpx.AsyncClient() as client:
70
+ # The background task is started using the Socket.IO server's robust method
71
+ sio.start_background_task(
72
+ run_arbitrage_detector,
73
+ PriceFetcher(client),
74
+ ArbitrageAnalyzer(client)
75
+ )
76
  print("βœ… Engine is online and hunting for opportunities.")
77
  yield
78
+ # No explicit shutdown needed for the background task here,
79
+ # as it's tied to the server process.
 
 
80
 
81
+ # --- FastAPI App & Final ASGI App ---
82
+ # We define the FastAPI app instance first, including its lifespan.
83
  app = FastAPI(lifespan=lifespan)
84
 
85
+ # THE CRITICAL FIX: We mount the Socket.IO ASGI app ONTO the FastAPI app.
86
+ # This makes FastAPI the main application.
87
+ app.mount('/socket.io', socketio.ASGIApp(sio))
88
 
89
+ # THE SECOND CRITICAL FIX: We mount the StaticFiles ONTO the FastAPI app as well.
90
+ # This correctly assigns the responsibility of serving files to FastAPI.
91
+ app.mount("/", StaticFiles(directory="static", html=True), name="static")
92
 
93
 
94
+ # --- Socket.IO Event Handlers ---
95
  @sio.event
96
  async def connect(sid, environ):
97
  print(f"βœ… Client connected: {sid}")