Automated Action 73b706f0eb Set up Solana Arbitrage Trading System
- Created Alembic migrations for SQLite database
- Set up database initialization on app startup
- Fixed linting issues with Ruff
- Updated README with comprehensive documentation
- Configured startup tasks and health checks
2025-06-05 19:34:12 +00:00

166 lines
5.9 KiB
Python

import logging
import time
from typing import Dict, List, Optional, Any
import httpx
from app.services.dex.base import BaseDexService
from app.services.solana import USDC_TOKEN_ADDRESS
logger = logging.getLogger(__name__)
# Jupiter API V6 endpoints
JUPITER_API_BASE = "https://quote-api.jup.ag/v6"
PRICE_ENDPOINT = f"{JUPITER_API_BASE}/price"
QUOTE_ENDPOINT = f"{JUPITER_API_BASE}/quote"
class JupiterDexService(BaseDexService):
"""Service for Jupiter DEX price monitoring"""
def __init__(self):
super().__init__("jupiter")
self.http_client = httpx.AsyncClient(timeout=10.0)
async def get_token_price(self, token_address: str, quote_token_address: Optional[str] = None) -> Dict[str, Any]:
"""Get token price from Jupiter"""
if not quote_token_address:
quote_token_address = USDC_TOKEN_ADDRESS
try:
params = {
"ids": token_address,
"vsToken": quote_token_address
}
response = await self.http_client.get(PRICE_ENDPOINT, params=params)
response.raise_for_status()
data = response.json()
if "data" in data and token_address in data["data"]:
price_data = data["data"][token_address]
return {
"price": float(price_data["price"]),
"liquidity": float(price_data.get("liquidity", 0)),
"timestamp": int(time.time()),
"metadata": {
"raw_data": price_data
}
}
else:
logger.warning(f"No price data returned from Jupiter for {token_address}")
return {
"price": 0.0,
"liquidity": 0.0,
"timestamp": int(time.time()),
"metadata": {
"error": "No price data returned"
}
}
except Exception as e:
logger.error(f"Error getting Jupiter price for {token_address}: {str(e)}")
return {
"price": 0.0,
"liquidity": 0.0,
"timestamp": int(time.time()),
"metadata": {
"error": str(e)
}
}
async def get_token_prices(self, token_addresses: List[str], quote_token_address: Optional[str] = None) -> Dict[str, Dict[str, Any]]:
"""Get prices for multiple tokens from Jupiter"""
if not quote_token_address:
quote_token_address = USDC_TOKEN_ADDRESS
try:
params = {
"ids": ",".join(token_addresses),
"vsToken": quote_token_address
}
response = await self.http_client.get(PRICE_ENDPOINT, params=params)
response.raise_for_status()
data = response.json()
result = {}
if "data" in data:
price_data = data["data"]
timestamp = int(time.time())
for token_address in token_addresses:
if token_address in price_data:
token_price_data = price_data[token_address]
result[token_address] = {
"price": float(token_price_data["price"]),
"liquidity": float(token_price_data.get("liquidity", 0)),
"timestamp": timestamp,
"metadata": {
"raw_data": token_price_data
}
}
else:
result[token_address] = {
"price": 0.0,
"liquidity": 0.0,
"timestamp": timestamp,
"metadata": {
"error": "No price data returned"
}
}
return result
except Exception as e:
logger.error(f"Error getting Jupiter prices: {str(e)}")
timestamp = int(time.time())
return {
token_address: {
"price": 0.0,
"liquidity": 0.0,
"timestamp": timestamp,
"metadata": {
"error": str(e)
}
}
for token_address in token_addresses
}
async def get_swap_quote(self, input_token: str, output_token: str, amount: float, slippage_bps: int = 50) -> Dict[str, Any]:
"""
Get a swap quote from Jupiter
Args:
input_token: Address of the input token
output_token: Address of the output token
amount: Amount of input token to swap
slippage_bps: Slippage tolerance in basis points (1 bps = 0.01%)
Returns:
Quote data or error
"""
try:
# Convert amount to raw format
raw_amount = self.parse_token_amount(input_token, amount)
params = {
"inputMint": input_token,
"outputMint": output_token,
"amount": str(raw_amount),
"slippageBps": slippage_bps,
"onlyDirectRoutes": False,
"asLegacyTransaction": False,
}
response = await self.http_client.get(QUOTE_ENDPOINT, params=params)
response.raise_for_status()
data = response.json()
return data
except Exception as e:
logger.error(f"Error getting Jupiter swap quote: {str(e)}")
return {
"error": str(e)
}