mgbam commited on
Commit
6a1e668
Β·
verified Β·
1 Parent(s): df2d785

Update app/app.py

Browse files
Files changed (1) hide show
  1. app/app.py +41 -34
app/app.py CHANGED
@@ -7,14 +7,19 @@ real-time signal delivery. This is the definitive money-spinning engine.
7
  import asyncio
8
  import os
9
  from contextlib import asynccontextmanager
 
 
10
  from datetime import datetime, timezone
 
11
  import httpx
12
  import socketio
13
  from fastapi import FastAPI
14
  from fastapi.staticfiles import StaticFiles
15
 
16
- from price_fetcher import PriceFetcher
17
- from arbitrage_analyzer import ArbitrageAnalyzer
 
 
18
 
19
  OPPORTUNITY_THRESHOLD = 0.001
20
 
@@ -26,24 +31,26 @@ socket_app = socketio.ASGIApp(sio)
26
  @asynccontextmanager
27
  async def lifespan(app: FastAPI):
28
  print("πŸš€ Initializing Sentinel Arbitrage Engine v10.0...")
29
- price_fetcher = PriceFetcher(httpx.AsyncClient())
30
- arbitrage_analyzer = ArbitrageAnalyzer(httpx.AsyncClient())
31
-
32
- # Launch the engine as a background task, passing the Socket.IO server instance
33
- arbitrage_task = asyncio.create_task(
34
- run_arbitrage_detector(price_fetcher, arbitrage_analyzer)
35
- )
36
-
37
- print("βœ… Engine is online and hunting for opportunities.")
38
- yield
39
-
40
- print("⏳ Shutting down engine...")
41
- arbitrage_task.cancel()
42
- try: await arbitrage_task
43
- except asyncio.CancelledError: print("Engine shut down gracefully.")
 
44
 
45
  async def run_arbitrage_detector(price_fetcher, analyzer):
46
  """The core engine loop. Now directly emits events via Socket.IO."""
 
47
  while True:
48
  try:
49
  await price_fetcher.update_prices_async()
@@ -55,18 +62,18 @@ async def run_arbitrage_detector(price_fetcher, analyzer):
55
  if pyth_price and chainlink_price:
56
  spread = abs(pyth_price - chainlink_price) / chainlink_price
57
  if spread > OPPORTUNITY_THRESHOLD:
58
- opportunity = {
59
- "pyth_price": pyth_price,
60
- "chainlink_price": chainlink_price,
61
- "spread_pct": spread * 100
62
- }
63
- print(f"⚑️ Discrepancy Detected: {opportunity['spread_pct']:.3f}%")
64
- briefing = await analyzer.get_alpha_briefing(opportunity)
65
- if briefing:
66
- signal = {**opportunity, **briefing, "timestamp": datetime.now(timezone.utc).isoformat()}
67
- # --- THE FIX: Directly emit to all connected clients ---
68
- await sio.emit('new_signal', signal)
69
- print(f"βœ… Signal Emitted: {signal['strategy']}")
70
  except Exception as e:
71
  print(f"❌ ERROR in engine loop: {e}")
72
 
@@ -75,9 +82,6 @@ async def run_arbitrage_detector(price_fetcher, analyzer):
75
  # --- FastAPI App Setup ---
76
  app = FastAPI(lifespan=lifespan)
77
 
78
- # This serves the index.html and any other static files (like JS or CSS)
79
- app.mount("/", StaticFiles(directory="static", html=True), name="static")
80
-
81
  @sio.event
82
  async def connect(sid, environ):
83
  print(f"βœ… Client connected: {sid}")
@@ -86,5 +90,8 @@ async def connect(sid, environ):
86
  async def disconnect(sid):
87
  print(f"πŸ”₯ Client disconnected: {sid}")
88
 
89
- # Mount the Socket.IO app on top of the FastAPI app
90
- app.mount('/socket.io', socket_app)
 
 
 
 
7
  import asyncio
8
  import os
9
  from contextlib import asynccontextmanager
10
+ import json
11
+ import time # Added import
12
  from datetime import datetime, timezone
13
+
14
  import httpx
15
  import socketio
16
  from fastapi import FastAPI
17
  from fastapi.staticfiles import StaticFiles
18
 
19
+ # Relative imports now work perfectly because of the package structure
20
+ from .price_fetcher import PriceFetcher
21
+ from .arbitrage_analyzer import ArbitrageAnalyzer
22
+ from .broker import signal_broker
23
 
24
  OPPORTUNITY_THRESHOLD = 0.001
25
 
 
31
  @asynccontextmanager
32
  async def lifespan(app: FastAPI):
33
  print("πŸš€ Initializing Sentinel Arbitrage Engine v10.0...")
34
+ # Use a single httpx client for the application's lifespan
35
+ async with httpx.AsyncClient() as client:
36
+ app.state.price_fetcher = PriceFetcher(client)
37
+ app.state.arbitrage_analyzer = ArbitrageAnalyzer(client)
38
+
39
+ arbitrage_task = asyncio.create_task(
40
+ run_arbitrage_detector(app.state.price_fetcher, app.state.arbitrage_analyzer)
41
+ )
42
+
43
+ print("βœ… Engine is online and hunting for opportunities.")
44
+ yield
45
+
46
+ print("⏳ Shutting down engine...")
47
+ arbitrage_task.cancel()
48
+ try: await arbitrage_task
49
+ except asyncio.CancelledError: print("Engine shut down gracefully.")
50
 
51
  async def run_arbitrage_detector(price_fetcher, analyzer):
52
  """The core engine loop. Now directly emits events via Socket.IO."""
53
+ last_opportunity_time = 0
54
  while True:
55
  try:
56
  await price_fetcher.update_prices_async()
 
62
  if pyth_price and chainlink_price:
63
  spread = abs(pyth_price - chainlink_price) / chainlink_price
64
  if spread > OPPORTUNITY_THRESHOLD:
65
+ current_time = time.time()
66
+ if current_time - last_opportunity_time > 30: # Throttle Gemini calls
67
+ last_opportunity_time = current_time
68
+ opportunity = {
69
+ "pyth_price": pyth_price, "chainlink_price": chainlink_price, "spread_pct": spread * 100
70
+ }
71
+ print(f"⚑️ Discrepancy Detected: {opportunity['spread_pct']:.3f}%")
72
+ briefing = await analyzer.get_alpha_briefing(opportunity)
73
+ if briefing:
74
+ signal = {**opportunity, **briefing, "timestamp": datetime.now(timezone.utc).isoformat()}
75
+ await sio.emit('new_signal', signal)
76
+ print(f"βœ… Signal Emitted: {signal['strategy']}")
77
  except Exception as e:
78
  print(f"❌ ERROR in engine loop: {e}")
79
 
 
82
  # --- FastAPI App Setup ---
83
  app = FastAPI(lifespan=lifespan)
84
 
 
 
 
85
  @sio.event
86
  async def connect(sid, environ):
87
  print(f"βœ… Client connected: {sid}")
 
90
  async def disconnect(sid):
91
  print(f"πŸ”₯ Client disconnected: {sid}")
92
 
93
+ # Mount the Socket.IO app on a specific path
94
+ app.mount('/socket.io', socket_app)
95
+
96
+ # Serve the static files (like index.html) from the 'static' directory
97
+ app.mount("/", StaticFiles(directory="static", html=True), name="static")