mgbam commited on
Commit
b50b626
·
verified ·
1 Parent(s): 1d7515b

Update app/app.py

Browse files
Files changed (1) hide show
  1. app/app.py +27 -39
app/app.py CHANGED
@@ -1,8 +1,8 @@
1
  """
2
- Sentinel Arbitrage Engine - v7.0 FINAL (WebSocket-Powered)
3
 
4
- Utilizes a real-time WebSocket data stream for high-frequency discrepancy
5
- detection between CeFi and DeFi price sources.
6
  """
7
  import asyncio
8
  import os
@@ -25,47 +25,37 @@ async def lifespan(app: FastAPI):
25
  app.state.price_fetcher = PriceFetcher(client=client)
26
  app.state.arbitrage_analyzer = ArbitrageAnalyzer(client=client)
27
  app.state.signal_queue: asyncio.Queue = asyncio.Queue()
 
28
 
29
- # Launch the persistent WebSocket listener
30
- websocket_task = asyncio.create_task(app.state.price_fetcher.run_websocket_listener())
31
- # Launch the discrepancy detector
32
- arbitrage_task = asyncio.create_task(run_arbitrage_detector(app, 2)) # Can run much faster now!
33
-
34
- print("🚀 Sentinel Arbitrage Engine v7.0 (WebSocket) started successfully.")
35
  yield
36
 
37
  print("⏳ Shutting down engine...")
38
- websocket_task.cancel()
39
  arbitrage_task.cancel()
40
- try: await asyncio.gather(websocket_task, arbitrage_task)
41
  except asyncio.CancelledError: print("Engine shut down.")
42
 
43
  async def run_arbitrage_detector(app: FastAPI, interval_seconds: int):
44
- last_opportunity_time = 0
45
  while True:
46
- # This now gets the latest price from the websocket and a fresh price from Pyth
47
- prices = await app.state.price_fetcher.get_current_prices()
48
 
49
- on_chain = prices.get("on_chain_pyth")
50
- off_chain = prices.get("realtime_binance")
51
 
52
- if on_chain and off_chain:
53
- spread = abs(on_chain - off_chain) / off_chain
54
  if spread > OPPORTUNITY_THRESHOLD:
55
- # Throttle Gemini calls to once every 30 seconds max
56
- current_time = time.time()
57
- if current_time - last_opportunity_time > 30:
58
- last_opportunity_time = current_time
59
- opportunity = {
60
- "id": f"{int(current_time)}",
61
- "on_chain_price": on_chain, "off_chain_price": off_chain,
62
- "spread_pct": spread * 100
63
- }
64
- print(f"⚡️ Discrepancy Detected: {opportunity['spread_pct']:.3f}%")
65
- briefing = await app.state.arbitrage_analyzer.get_alpha_briefing(opportunity)
66
- if briefing:
67
- signal = {**opportunity, **briefing, "timestamp": datetime.now(timezone.utc).isoformat()}
68
- await app.state.signal_queue.put(signal)
69
 
70
  await asyncio.sleep(interval_seconds)
71
 
@@ -75,14 +65,14 @@ templates = Jinja2Templates(directory="templates")
75
  def render_signal_card(payload: dict) -> str:
76
  s = payload
77
  time_str = datetime.fromisoformat(s['timestamp']).strftime('%H:%M:%S UTC')
78
- on_chain_class = "buy" if s['on_chain_price'] < s['off_chain_price'] else "sell"
79
- off_chain_class = "sell" if s['on_chain_price'] < s['off_chain_price'] else "buy"
80
 
81
  return f"""
82
  <tr id="trade-row-{s['id']}" hx-swap-oob="afterbegin:#opportunities-table">
83
  <td><strong>BTC/USD</strong></td>
84
- <td><span class="{off_chain_class}">CEX (Binance)</span><br>${s['off_chain_price']:,.2f}</td>
85
- <td><span class="{on_chain_class}">DEX (Pyth)</span><br>${s['on_chain_price']:,.2f}</td>
86
  <td><strong>{s['spread_pct']:.3f}%</strong></td>
87
  <td><span class="risk-{s.get('risk', 'low').lower()}">{s.get('risk', 'N/A')}</span></td>
88
  <td>{s.get('rationale', 'N/A')}</td>
@@ -104,6 +94,4 @@ async def signal_stream(request: Request):
104
  html_card = render_signal_card(payload)
105
  data_payload = html_card.replace('\n', ' ').strip()
106
  yield f"event: message\ndata: {data_payload}\n\n"
107
- return StreamingResponse(event_generator(), media_type="text/event-stream")
108
-
109
- # Need to add 'import time' at the top of main.py
 
1
  """
2
+ Sentinel Arbitrage Engine - v8.0 FINAL (Multi-Oracle)
3
 
4
+ Detects and analyzes price dislocations between major decentralized oracles.
5
+ This architecture is robust and immune to CEX geoblocking.
6
  """
7
  import asyncio
8
  import os
 
25
  app.state.price_fetcher = PriceFetcher(client=client)
26
  app.state.arbitrage_analyzer = ArbitrageAnalyzer(client=client)
27
  app.state.signal_queue: asyncio.Queue = asyncio.Queue()
28
+ arbitrage_task = asyncio.create_task(run_arbitrage_detector(app, 15)) # Check every 15 seconds
29
 
30
+ print("🚀 Sentinel Arbitrage Engine v8.0 (Multi-Oracle) started.")
 
 
 
 
 
31
  yield
32
 
33
  print("⏳ Shutting down engine...")
 
34
  arbitrage_task.cancel()
35
+ try: await arbitrage_task
36
  except asyncio.CancelledError: print("Engine shut down.")
37
 
38
  async def run_arbitrage_detector(app: FastAPI, interval_seconds: int):
 
39
  while True:
40
+ await app.state.price_fetcher.update_prices_async()
41
+ prices = app.state.price_fetcher.get_current_prices()
42
 
43
+ pyth_price = prices.get("pyth")
44
+ chainlink_price = prices.get("chainlink_agg")
45
 
46
+ if pyth_price and chainlink_price:
47
+ spread = abs(pyth_price - chainlink_price) / chainlink_price
48
  if spread > OPPORTUNITY_THRESHOLD:
49
+ opportunity = {
50
+ "id": f"{int(datetime.now().timestamp())}",
51
+ "pyth_price": pyth_price, "chainlink_price": chainlink_price,
52
+ "spread_pct": spread * 100
53
+ }
54
+ print(f"⚡️ Oracle Dislocation Detected: {opportunity['spread_pct']:.3f}%")
55
+ briefing = await app.state.arbitrage_analyzer.get_alpha_briefing(opportunity)
56
+ if briefing:
57
+ signal = {**opportunity, **briefing, "timestamp": datetime.now(timezone.utc).isoformat()}
58
+ await app.state.signal_queue.put(signal)
 
 
 
 
59
 
60
  await asyncio.sleep(interval_seconds)
61
 
 
65
  def render_signal_card(payload: dict) -> str:
66
  s = payload
67
  time_str = datetime.fromisoformat(s['timestamp']).strftime('%H:%M:%S UTC')
68
+ pyth_class = "buy" if s['pyth_price'] < s['chainlink_price'] else "sell"
69
+ chainlink_class = "sell" if s['pyth_price'] < s['chainlink_price'] else "buy"
70
 
71
  return f"""
72
  <tr id="trade-row-{s['id']}" hx-swap-oob="afterbegin:#opportunities-table">
73
  <td><strong>BTC/USD</strong></td>
74
+ <td><span class="{pyth_class}">Pyth Network</span><br>${s['pyth_price']:,.2f}</td>
75
+ <td><span class="{chainlink_class}">Chainlink Agg.</span><br>${s['chainlink_price']:,.2f}</td>
76
  <td><strong>{s['spread_pct']:.3f}%</strong></td>
77
  <td><span class="risk-{s.get('risk', 'low').lower()}">{s.get('risk', 'N/A')}</span></td>
78
  <td>{s.get('rationale', 'N/A')}</td>
 
94
  html_card = render_signal_card(payload)
95
  data_payload = html_card.replace('\n', ' ').strip()
96
  yield f"event: message\ndata: {data_payload}\n\n"
97
+ return StreamingResponse(event_generator(), media_type="text/event-stream")