perp-arbitrage/spread_calculator.py

64 lines
2.3 KiB
Python

import threading
import time
import json
from exchanges.binance import BinancePerpStream
from exchanges.okx import OKXPerpStream
from exchanges.bybit import BybitPerpStream
FEE = 0.0005 # taker fee
FUNDING_WEIGHT = 1 # pondera funding rate (ex: por 8h)
MIN_SPREAD = 0.4 # mínimo spread líquido para registrar
# Lista de exchanges que você quer considerar na arbitragem
ENABLED_EXCHANGES = {"bybit", "okx", "binance"}
# Carrega funding de arquivo externo salvo periodicamente
with open("funding_cache.json", "r") as f:
funding_cache = json.load(f)
def check_arbitrage_opportunities(new_tick, all_ticks):
opportunities = []
symbol = new_tick['symbol']
if new_tick['exchange'].lower() not in ENABLED_EXCHANGES:
return opportunities
for (ex_name, ex_symbol), tick in all_ticks.items():
if ex_symbol != symbol or ex_name == new_tick['exchange']:
continue
for buyer, seller in [(new_tick, tick), (tick, new_tick)]:
if buyer['exchange'].lower() not in ENABLED_EXCHANGES or seller['exchange'].lower() not in ENABLED_EXCHANGES:
continue
buy_price = buyer['ask'] * (1 + FEE)
sell_price = seller['bid'] * (1 - FEE)
if sell_price <= buy_price:
continue
spread = sell_price - buy_price
spread_percent = (spread / buy_price) * 100
size = min(buyer['ask_size'], seller['bid_size'])
buy_funding = funding_cache.get(symbol, {}).get(buyer['exchange'], 0.0) * 100
sell_funding = funding_cache.get(symbol, {}).get(seller['exchange'], 0.0) * 100
funding_carry = sell_funding - buy_funding
net_spread_percent = spread_percent + FUNDING_WEIGHT * funding_carry
if net_spread_percent > MIN_SPREAD:
opportunities.append({
'symbol': symbol,
'buy_exchange': buyer['exchange'],
'buy_price': buyer['ask'],
'sell_exchange': seller['exchange'],
'sell_price': seller['bid'],
'spread_percent': net_spread_percent,
'raw_spread_percent': spread_percent,
'buy_funding': buy_funding,
'sell_funding': sell_funding,
'size': size
})
return opportunities