Files
hedge/market.py

327 lines
12 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
import os
import asyncio
import requests
from datetime import datetime
from flextrade.flextrade_client import Client
from flextrade.constants.markets import (
BASE_MARKET_ETH_USD, BASE_MARKET_BTC_USD, BASE_MARKET_BNB_USD,
BASE_MARKET_SHIB_USD, BASE_MARKET_PEPE_USD, BASE_MARKET_SUI_USD,
BASE_MARKET_DOGE_USD, BASE_MARKET_AAVE_USD, BASE_MARKET_HBAR_USD,
BASE_MARKET_VIRTUAL_USD, BASE_MARKET_ADA_USD, BASE_MARKET_PENDLE_USD,
BASE_MARKET_TRX_USD, BASE_MARKET_AVAX_USD, BASE_MARKET_UNI_USD,
BASE_MARKET_SOL_USD, BASE_MARKET_LINK_USD, BASE_MARKET_XRP_USD,
BASE_MARKET_TON_USD
)
from dotenv import load_dotenv
load_dotenv()
RPC_URL = os.getenv("RPC_URL")
PRIVATE_KEY = os.getenv("PRIVATE_KEY")
# List of all markets to test
MARKETS = [
# BASE_MARKET_ETH_USD,
# BASE_MARKET_BTC_USD,
# BASE_MARKET_BNB_USD,
# BASE_MARKET_SHIB_USD,
# BASE_MARKET_PEPE_USD,
# BASE_MARKET_SUI_USD,
# BASE_MARKET_DOGE_USD,
# BASE_MARKET_AAVE_USD,
# BASE_MARKET_HBAR_USD,
# BASE_MARKET_VIRTUAL_USD,
# BASE_MARKET_ADA_USD,
# BASE_MARKET_PENDLE_USD,
# BASE_MARKET_TRX_USD,
# BASE_MARKET_AVAX_USD,
# BASE_MARKET_UNI_USD,
BASE_MARKET_SOL_USD,
# BASE_MARKET_LINK_USD,
# BASE_MARKET_XRP_USD,
# BASE_MARKET_TON_USD
]
# Global variable to store latest prices with timestamps
latest_prices = {}
# Binance API configuration
BINANCE_API_BASE_URL = "https://api.binance.com"
# Mapping FlexTrade markets to Binance symbols
FLEXTRADE_TO_BINANCE_MAPPING = {
"ETHUSD": "ETHUSDC",
"BTCUSD": "BTCUSDC",
"BNBUSD": "BNBUSDC",
"SOLUSD": "SOLUSDC",
"DOGEUSD": "DOGEUSDC",
"AAVEUSD": "AAVEUSDC",
"ADAUSD": "ADAUSDC",
"TRXUSD": "TRXUSDC",
"AVAXUSD": "AVAXUSDC",
"UNIUSD": "UNIUSDC",
"LINKUSD": "LINKUSDC",
"XRPUSD": "XRPUSDC"
}
def print_market_info(market_info, debug=False):
if debug:
timestamp = datetime.now().strftime("%H:%M:%S")
print('[{0}] {1} : {2:.4f}'.format(timestamp, market_info["market"], market_info["price"]))
def get_binance_price(symbol, debug=False):
"""Fetch current price from Binance API"""
try:
url = f"{BINANCE_API_BASE_URL}/api/v3/ticker/price"
params = {"symbol": symbol}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
price = float(data["price"])
if debug:
timestamp = datetime.now().strftime("%H:%M:%S")
print(f'[{timestamp}] Binance {symbol}: {price:.4f}')
return price
except requests.exceptions.RequestException as e:
if debug:
print(f"❌ Binance API request error for {symbol}: {e}")
return None
except (KeyError, ValueError) as e:
if debug:
print(f"❌ Binance API data error for {symbol}: {e}")
return None
except Exception as e:
if debug:
print(f"❌ Unexpected error fetching Binance price for {symbol}: {e}")
return None
def get_all_binance_prices(debug=False):
"""Fetch prices for all mapped symbols from Binance"""
binance_prices = {}
if debug:
print("Fetching prices from Binance API...")
for flextrade_market, binance_symbol in FLEXTRADE_TO_BINANCE_MAPPING.items():
price = get_binance_price(binance_symbol, debug)
if price is not None:
current_timestamp = datetime.now()
binance_prices[flextrade_market] = {
'price': price,
'binance_symbol': binance_symbol,
'timestamp': current_timestamp,
'timestamp_str': current_timestamp.strftime("%Y-%m-%d %H:%M:%S"),
'source': 'binance'
}
else:
if debug:
print(f"⚠️ Failed to fetch price for {flextrade_market} ({binance_symbol})")
# Small delay to avoid rate limiting
time.sleep(0.1)
return binance_prices
def compare_prices(flextrade_prices, binance_prices, debug=False):
"""Compare FlexTrade and Binance prices"""
comparison_results = {}
if debug:
print("\n" + "="*80)
print("PRICE COMPARISON: FlexTrade vs Binance")
print("="*80)
for market in flextrade_prices:
if market in binance_prices:
ft_price = flextrade_prices[market]['price']
bn_price = binance_prices[market]['price']
# Calculate difference
price_diff = ft_price - bn_price
price_diff_pct = (price_diff / bn_price) * 100 if bn_price > 0 else 0
comparison_results[market] = {
'flextrade_price': ft_price,
'binance_price': bn_price,
'difference': price_diff,
'difference_pct': price_diff_pct,
'flextrade_timestamp': flextrade_prices[market]['timestamp_str'],
'binance_timestamp': binance_prices[market]['timestamp_str']
}
if debug:
status = "📈" if price_diff > 0 else "📉" if price_diff < 0 else "➡️"
print(f"{status} {market:<12} | FlexTrade: ${ft_price:>8.4f} | Binance: ${bn_price:>8.4f} | Diff: {price_diff:>+7.4f} ({price_diff_pct:>+6.2f}%)")
elif debug:
print(f"⚠️ {market:<12} | Only available on FlexTrade")
# Check for Binance-only prices
if debug:
for market in binance_prices:
if market not in flextrade_prices:
bn_price = binance_prices[market]['price']
print(f" {market:<12} | Only available on Binance: ${bn_price:.4f}")
print("="*80)
return comparison_results
def market_info(debug=False, include_binance=True):
"""Fetch market information once and update global prices"""
client = Client(
eth_private_key=PRIVATE_KEY,
rpc_url=RPC_URL
)
if debug:
print("Fetching market data...\n")
# Fetch FlexTrade prices
for market in MARKETS:
try:
market_info_data = client.public.get_market_info(market)
print_market_info(market_info_data, debug)
# Store the latest price and timestamp in global dictionary
market_name = market_info_data["market"]
current_timestamp = datetime.now()
latest_prices[market_name] = {
'price': market_info_data["price"],
'timestamp': current_timestamp,
'timestamp_str': current_timestamp.strftime("%Y-%m-%d %H:%M:%S"),
'source': 'flextrade'
}
time.sleep(15) # Wait 15 seconds between requests to avoid rate limiting
except Exception as e:
if debug:
print(f"Error fetching market {market}: {e}")
print('-' * 50)
# Skip this market and continue with the next one
continue
# Fetch Binance prices and compare if enabled
if include_binance:
try:
binance_prices = get_all_binance_prices(debug)
# Store Binance prices in a separate section of latest_prices
for market, price_data in binance_prices.items():
binance_key = f"{market}_BINANCE"
latest_prices[binance_key] = price_data
# Compare prices if both sources have data
flextrade_only = {k: v for k, v in latest_prices.items() if not k.endswith('_BINANCE') and v.get('source') == 'flextrade'}
if flextrade_only and binance_prices:
comparison = compare_prices(flextrade_only, binance_prices, debug)
# Store comparison results
latest_prices['_comparison'] = {
'timestamp': datetime.now(),
'results': comparison
}
except Exception as e:
if debug:
print(f"❌ Error fetching Binance prices: {e}")
# Continue without Binance data
def market_info_loop(debug=False, include_binance=True):
"""Continuously fetch market information in a loop"""
if debug:
print("Starting market data loop - press Ctrl+C to stop")
print("-" * 50)
try:
while True:
try:
market_info(debug, include_binance)
# if debug:
# print(f"\nSleeping for 30 seconds...\n")
# time.sleep(30) # Wait 30 seconds between full cycles
except Exception as e:
if debug:
print(f"Error in market_info cycle: {e}")
print("Waiting 15 seconds before retry...")
time.sleep(15) # Wait 15 seconds before retrying on error
continue
# except KeyboardInterrupt:
# if debug:
# print("\nMarket data loop stopped by user")
except Exception as e:
if debug:
print(f"Fatal error occurred: {e}")
print("Market data loop stopped")
def get_latest_price(market_name):
"""Get the latest price for a specific market"""
market_data = latest_prices.get(market_name, None)
return market_data['price'] if market_data else None
def get_latest_price_with_timestamp(market_name):
"""Get the latest price with timestamp for a specific market"""
return latest_prices.get(market_name, None)
def get_all_latest_prices():
"""Get all latest prices with timestamps"""
return latest_prices.copy()
def get_all_latest_prices_only():
"""Get all latest prices without timestamps (backward compatibility)"""
return {market: data['price'] for market, data in latest_prices.items()}
def get_binance_price_for_market(market_name):
"""Get the latest Binance price for a specific market"""
binance_key = f"{market_name}_BINANCE"
market_data = latest_prices.get(binance_key, None)
return market_data['price'] if market_data else None
def get_price_comparison(market_name):
"""Get price comparison data for a specific market"""
comparison_data = latest_prices.get('_comparison', {})
results = comparison_data.get('results', {})
return results.get(market_name, None)
def get_all_price_comparisons():
"""Get all price comparison data"""
comparison_data = latest_prices.get('_comparison', {})
return comparison_data.get('results', {})
def get_market_arbitrage_opportunities(min_percentage_diff=0.5):
"""Find arbitrage opportunities between FlexTrade and Binance"""
comparisons = get_all_price_comparisons()
opportunities = []
for market, data in comparisons.items():
abs_diff_pct = abs(data['difference_pct'])
if abs_diff_pct >= min_percentage_diff:
opportunity = {
'market': market,
'flextrade_price': data['flextrade_price'],
'binance_price': data['binance_price'],
'difference_pct': data['difference_pct'],
'action': 'buy_flextrade_sell_binance' if data['difference_pct'] < 0 else 'buy_binance_sell_flextrade',
'potential_profit_pct': abs_diff_pct
}
opportunities.append(opportunity)
# Sort by potential profit percentage (highest first)
opportunities.sort(key=lambda x: x['potential_profit_pct'], reverse=True)
return opportunities
if __name__ == '__main__':
# Enable debug when running directly
print("🚀 Starting market data collection with Binance price comparison...")
print("📊 Number of FlexTrade markets being monitored:", len(MARKETS))
print("🔗 Binance symbols mapped:", list(FLEXTRADE_TO_BINANCE_MAPPING.values()))
print("=" * 80)
market_info_loop(debug=True, include_binance=True)