mgbam commited on
Commit
6ca5793
·
verified ·
1 Parent(s): 1e89dad

Update app/app.py

Browse files
Files changed (1) hide show
  1. app/app.py +28 -42
app/app.py CHANGED
@@ -1,15 +1,13 @@
1
  """
2
- Sentinel Arbitrage Engine - v4.0 FINAL
3
 
4
- High-frequency arbitrage detection and AI-powered risk analysis.
5
  """
6
  import asyncio
7
  import os
8
  from contextlib import asynccontextmanager
9
  from datetime import datetime, timezone
10
- from typing import Dict, Optional
11
  import json
12
-
13
  import httpx
14
  from fastapi import FastAPI, Request
15
  from fastapi.responses import HTMLResponse, StreamingResponse
@@ -18,7 +16,7 @@ from fastapi.templating import Jinja2Templates
18
  from .price_fetcher import PriceFetcher
19
  from .arbitrage_analyzer import ArbitrageAnalyzer
20
 
21
- OPPORTUNITY_THRESHOLD = 0.003 # 0.3% price difference to trigger a signal
22
 
23
  @asynccontextmanager
24
  async def lifespan(app: FastAPI):
@@ -26,51 +24,38 @@ async def lifespan(app: FastAPI):
26
  app.state.price_fetcher = PriceFetcher(client=client)
27
  app.state.arbitrage_analyzer = ArbitrageAnalyzer(client=client)
28
  app.state.signal_queue: asyncio.Queue = asyncio.Queue()
29
-
30
- arbitrage_task = asyncio.create_task(run_arbitrage_detector(app, 5)) # Run every 5 seconds
31
 
32
- print("🚀 Sentinel Arbitrage Engine started successfully.")
33
  yield
34
 
35
- print("⏳ Shutting down arbitrage engine...")
36
  arbitrage_task.cancel()
37
- try:
38
- await arbitrage_task
39
- except asyncio.CancelledError:
40
- print("Engine shut down.")
41
 
42
  async def run_arbitrage_detector(app: FastAPI, interval_seconds: int):
43
- last_opportunity = {}
44
  while True:
45
  await app.state.price_fetcher.update_prices_async()
46
  prices = app.state.price_fetcher.get_current_prices()
47
 
48
- valid_prices = {k: v for k, v in prices.items() if v is not None}
49
- if len(valid_prices) < 2:
50
- await asyncio.sleep(interval_seconds)
51
- continue
52
-
53
- min_exchange = min(valid_prices, key=valid_prices.get)
54
- max_exchange = max(valid_prices, key=valid_prices.get)
55
-
56
- buy_price = valid_prices[min_exchange]
57
- sell_price = valid_prices[max_exchange]
58
 
59
- if buy_price > 0 and (sell_price - buy_price) / buy_price > OPPORTUNITY_THRESHOLD:
60
- opportunity = {
61
- "id": f"{min_exchange}-{max_exchange}",
62
- "buy_exchange": min_exchange.capitalize(), "buy_price": buy_price,
63
- "sell_exchange": max_exchange.capitalize(), "sell_price": sell_price,
64
- "spread_pct": ((sell_price - buy_price) / buy_price) * 100
65
- }
66
- # Only analyze if it's a new opportunity
67
- if last_opportunity.get("id") != opportunity["id"]:
68
- print(f"⚡️ Arbitrage Opportunity Detected: {opportunity['spread_pct']:.2f}% spread")
69
  briefing = await app.state.arbitrage_analyzer.get_alpha_briefing(opportunity)
70
  if briefing:
71
  signal = {**opportunity, **briefing, "timestamp": datetime.now(timezone.utc).isoformat()}
72
  await app.state.signal_queue.put(signal)
73
- last_opportunity = opportunity
74
 
75
  await asyncio.sleep(interval_seconds)
76
 
@@ -80,17 +65,18 @@ templates = Jinja2Templates(directory="templates")
80
  def render_signal_card(payload: dict) -> str:
81
  s = payload
82
  time_str = datetime.fromisoformat(s['timestamp']).strftime('%H:%M:%S UTC')
 
 
83
 
84
  return f"""
85
- <tr id="trade-row-{s['id']}" hx-swap-oob="true">
86
- <td><strong>BTC</strong></td>
87
- <td><span class="buy">{s['buy_exchange']}</span><br>${s['buy_price']:,.2f}</td>
88
- <td><span class="sell">{s['sell_exchange']}</span><br>${s['sell_price']:,.2f}</td>
89
  <td><strong>{s['spread_pct']:.3f}%</strong></td>
90
  <td><span class="risk-{s.get('risk', 'low').lower()}">{s.get('risk', 'N/A')}</span></td>
91
- <td>{s.get('strategy', 'N/A')}</td>
92
- <td><strong>${s.get('profit_usd', 0):,.2f}</strong></td>
93
- <td><button class="trade-btn">Simulate Trade</button></td>
94
  </tr>
95
  <div id="last-update-time" hx-swap-oob="true">{time_str}</div>
96
  """
 
1
  """
2
+ Sentinel Arbitrage Engine - v5.0 FINAL (Anti-Geoblock)
3
 
4
+ Detects on-chain vs. off-chain price discrepancies and provides AI-powered analysis.
5
  """
6
  import asyncio
7
  import os
8
  from contextlib import asynccontextmanager
9
  from datetime import datetime, timezone
 
10
  import json
 
11
  import httpx
12
  from fastapi import FastAPI, Request
13
  from fastapi.responses import HTMLResponse, StreamingResponse
 
16
  from .price_fetcher import PriceFetcher
17
  from .arbitrage_analyzer import ArbitrageAnalyzer
18
 
19
+ OPPORTUNITY_THRESHOLD = 0.001 # 0.1% price difference to trigger a signal
20
 
21
  @asynccontextmanager
22
  async def lifespan(app: FastAPI):
 
24
  app.state.price_fetcher = PriceFetcher(client=client)
25
  app.state.arbitrage_analyzer = ArbitrageAnalyzer(client=client)
26
  app.state.signal_queue: asyncio.Queue = asyncio.Queue()
27
+ arbitrage_task = asyncio.create_task(run_arbitrage_detector(app, 10))
 
28
 
29
+ print("🚀 Sentinel Arbitrage Engine v5.0 started successfully.")
30
  yield
31
 
32
+ print("⏳ Shutting down engine...")
33
  arbitrage_task.cancel()
34
+ try: await arbitrage_task
35
+ except asyncio.CancelledError: print("Engine shut down.")
 
 
36
 
37
  async def run_arbitrage_detector(app: FastAPI, interval_seconds: int):
 
38
  while True:
39
  await app.state.price_fetcher.update_prices_async()
40
  prices = app.state.price_fetcher.get_current_prices()
41
 
42
+ on_chain = prices.get("on_chain_pyth")
43
+ off_chain = prices.get("off_chain_agg")
 
 
 
 
 
 
 
 
44
 
45
+ if on_chain and off_chain:
46
+ spread = abs(on_chain - off_chain) / off_chain
47
+ if spread > OPPORTUNITY_THRESHOLD:
48
+ opportunity = {
49
+ "id": f"{int(datetime.now().timestamp())}",
50
+ "on_chain_price": on_chain,
51
+ "off_chain_price": off_chain,
52
+ "spread_pct": spread * 100
53
+ }
54
+ print(f"⚡️ Discrepancy 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
+ on_chain_class = "buy" if s['on_chain_price'] < s['off_chain_price'] else "sell"
69
+ off_chain_class = "sell" if s['on_chain_price'] < s['off_chain_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="{on_chain_class}">On-Chain (Pyth)</span><br>${s['on_chain_price']:,.2f}</td>
75
+ <td><span class="{off_chain_class}">Off-Chain (Agg)</span><br>${s['off_chain_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>
79
+ <td><button class="trade-btn">{s.get('strategy', 'N/A')}</button></td>
 
80
  </tr>
81
  <div id="last-update-time" hx-swap-oob="true">{time_str}</div>
82
  """