diff --git a/triangular_arbitrage/detector.py b/triangular_arbitrage/detector.py index f3755c4..7a80804 100644 --- a/triangular_arbitrage/detector.py +++ b/triangular_arbitrage/detector.py @@ -44,6 +44,7 @@ def get_last_prices(exchange_time, tickers, ignored_symbols, whitelisted_symbols and (whitelisted_symbols is None or str(get_symbol_from_key(key)) in whitelisted_symbols) ] + def get_best_opportunity(tickers: List[ShortTicker]) -> Tuple[List[ShortTicker], float]: # Build a directed graph of currencies graph = nx.DiGraph() @@ -56,32 +57,33 @@ def get_best_opportunity(tickers: List[ShortTicker]) -> Tuple[List[ShortTicker], 1 / ticker.last_price, reversed=True)) best_profit = 0 - best_cycle = None + best_triplet = None - # Find all cycles in the graph (not just len = 3) for cycle in nx.simple_cycles(graph): - profit = 1 - tickers_in_cycle = [] + if len(cycle) != 3: + continue + + a, b, c = cycle + a_to_b = graph[a][b]['ticker'] + b_to_c = graph[b][c]['ticker'] + c_to_a = graph[c][a]['ticker'] - # Calculate the profits along the cycle - for i, base in enumerate(cycle): - quote = cycle[(i + 1) % len(cycle)] # Wrap around to complete the cycle - ticker = graph[base][quote]['ticker'] - tickers_in_cycle.append(ticker) - profit *= ticker.last_price + profit = a_to_b.last_price * b_to_c.last_price * c_to_a.last_price if profit > best_profit: best_profit = profit - best_cycle = tickers_in_cycle - - if best_cycle is not None: - best_cycle = [ - ShortTicker(symbols.Symbol(f"{ticker.symbol.quote}/{ticker.symbol.base}"), ticker.last_price, reversed=True) - if ticker.reversed else ticker - for ticker in best_cycle + best_triplet = [a_to_b, b_to_c, c_to_a] + + if best_triplet is not None: + # restore original symbols for reversed pairs + best_triplet = [ + ShortTicker(symbols.Symbol(f"{triplet.symbol.quote}/{triplet.symbol.base}"), triplet.last_price, + reversed=True) + if triplet.reversed else triplet + for triplet in best_triplet ] - return best_cycle, best_profit + return best_triplet, best_profit async def get_exchange_data(exchange_name): @@ -102,4 +104,4 @@ async def get_exchange_last_prices(exchange_name, ignored_symbols, whitelisted_s async def run_detection(exchange_name, ignored_symbols=None, whitelisted_symbols=None): last_prices = await get_exchange_last_prices(exchange_name, ignored_symbols or [], whitelisted_symbols) best_opportunity, best_profit = get_best_opportunity(last_prices) - return best_opportunity, best_profit + return best_opportunity, best_profit \ No newline at end of file