The NetworkShowcase
Arbitrage Algorithms
Triangular and inter-CEX arbitrage detection systems from the Lagrange era
Arbitrage Algorithms
Status: Archived (algorithms active) | Era: 2021-2023 | Repository: Triangular-Arbitrage-Data-master
The arbitrage detection system identified price discrepancies across markets for profitable trading opportunities, using graph algorithms and genetic optimization.
Overview
Purpose
Detect and quantify arbitrage opportunities across:
- Currency triangles (forex)
- DEX pools (DeFi)
- Centralized exchanges (CEX)
Types of Arbitrage
| Type | Description | Example |
|---|---|---|
| Triangular | Price discrepancy in currency triangle | USD→EUR→GBP→USD |
| Inter-CEX | Same asset different prices on exchanges | BTC on Binance vs Coinbase |
| DEX-CEX | On-chain vs off-chain price differences | SOL on Raydium vs Kraken |
| Cross-chain | Same asset on different blockchains | USDC on Solana vs Ethereum |
Triangular Arbitrage
Theory
For currencies A, B, C, arbitrage exists when:
Rate(A→B) × Rate(B→C) × Rate(C→A) ≠ 1.0Profitable when:
Rate(A→B) × Rate(B→C) × Rate(C→A) > 1.0 + feesImplementation
import networkx as nx
from typing import List, Tuple
class TriangularArbitrage:
def __init__(self, currencies: List[str]):
self.graph = nx.DiGraph()
self.currencies = currencies
def update_rate(self, from_curr: str, to_curr: str, rate: float):
"""Update exchange rate in graph"""
# Store negative log for Bellman-Ford
self.graph.add_edge(
from_curr,
to_curr,
weight=-math.log(rate)
)
def find_arbitrage(self) -> List[Tuple[List[str], float]]:
"""Find all arbitrage opportunities using Bellman-Ford"""
opportunities = []
for source in self.currencies:
# Run Bellman-Ford from each currency
distances, predecessors = self._bellman_ford(source)
# Check for negative cycles
for u, v, data in self.graph.edges(data=True):
if distances[u] + data['weight'] < distances[v]:
# Negative cycle found = arbitrage opportunity
cycle = self._extract_cycle(v, predecessors)
profit = self._calculate_profit(cycle)
if profit > 0:
opportunities.append((cycle, profit))
return opportunities
def _calculate_profit(self, cycle: List[str]) -> float:
"""Calculate profit percentage for a cycle"""
rate = 1.0
for i in range(len(cycle) - 1):
edge_data = self.graph[cycle[i]][cycle[i+1]]
rate *= math.exp(-edge_data['weight'])
# Return profit as percentage
return (rate - 1.0) * 100Graph Visualization
EUR
/ \
/ \
1.08 0.85
/ \
/ \
USD ────────── GBP
1.27
If USD→EUR→GBP→USD > 1.0, arbitrage existsInter-Exchange Arbitrage
Price Monitoring
from dataclasses import dataclass
from typing import Dict
@dataclass
class ExchangeQuote:
exchange: str
symbol: str
bid: float
ask: float
bid_size: float
ask_size: float
timestamp: float
class InterExchangeArbitrage:
def __init__(self, exchanges: List[str]):
self.quotes: Dict[str, Dict[str, ExchangeQuote]] = {}
self.fee_rates = {
'binance': 0.001,
'coinbase': 0.006,
'kraken': 0.0026,
'ftx': 0.0007, # RIP
}
def update_quote(self, quote: ExchangeQuote):
"""Update quote for exchange/symbol pair"""
if quote.symbol not in self.quotes:
self.quotes[quote.symbol] = {}
self.quotes[quote.symbol][quote.exchange] = quote
def find_opportunities(self, symbol: str) -> List[Dict]:
"""Find arbitrage opportunities for a symbol"""
quotes = self.quotes.get(symbol, {})
opportunities = []
exchanges = list(quotes.keys())
for i, buy_ex in enumerate(exchanges):
for sell_ex in exchanges[i+1:]:
buy_quote = quotes[buy_ex]
sell_quote = quotes[sell_ex]
# Buy on exchange with lower ask, sell where bid is higher
profit = self._calculate_profit(
buy_quote, sell_quote,
self.fee_rates[buy_ex], self.fee_rates[sell_ex]
)
if profit > 0:
opportunities.append({
'buy_exchange': buy_ex,
'sell_exchange': sell_ex,
'buy_price': buy_quote.ask,
'sell_price': sell_quote.bid,
'profit_pct': profit,
'max_size': min(buy_quote.ask_size, sell_quote.bid_size),
})
return opportunities
def _calculate_profit(
self,
buy: ExchangeQuote,
sell: ExchangeQuote,
buy_fee: float,
sell_fee: float
) -> float:
"""Calculate net profit after fees"""
buy_cost = buy.ask * (1 + buy_fee)
sell_revenue = sell.bid * (1 - sell_fee)
return ((sell_revenue / buy_cost) - 1) * 100Genetic Optimization
Route Optimization
import random
from typing import Callable
class GeneticOptimizer:
"""Genetic algorithm for optimal arbitrage route finding"""
def __init__(
self,
fitness_fn: Callable,
population_size: int = 100,
mutation_rate: float = 0.1,
generations: int = 50
):
self.fitness_fn = fitness_fn
self.pop_size = population_size
self.mutation_rate = mutation_rate
self.generations = generations
def optimize(self, routes: List[List[str]]) -> List[str]:
"""Find optimal route using genetic algorithm"""
# Initialize population
population = self._initialize_population(routes)
for generation in range(self.generations):
# Evaluate fitness
fitness_scores = [
(route, self.fitness_fn(route))
for route in population
]
# Selection (tournament)
selected = self._tournament_selection(fitness_scores)
# Crossover
offspring = self._crossover(selected)
# Mutation
population = self._mutate(offspring)
# Return best route
best = max(population, key=self.fitness_fn)
return best
def _tournament_selection(self, scored: List, k: int = 3):
"""Tournament selection for genetic diversity"""
selected = []
for _ in range(self.pop_size):
tournament = random.sample(scored, k)
winner = max(tournament, key=lambda x: x[1])
selected.append(winner[0])
return selectedA* Pathfinding
import heapq
from typing import Dict, Set
def find_best_route(
graph: Dict[str, Dict[str, float]],
start: str,
end: str
) -> Tuple[List[str], float]:
"""
A* search for optimal arbitrage route
Args:
graph: Currency graph with edge weights as -log(rate)
start: Starting currency
end: Target currency
Returns:
(route, profit) tuple
"""
# Priority queue: (estimated_cost, actual_cost, node, path)
pq = [(0, 0, start, [start])]
visited: Set[str] = set()
while pq:
est_cost, actual_cost, current, path = heapq.heappop(pq)
if current == end and len(path) > 1:
# Calculate actual profit
profit = math.exp(-actual_cost) - 1
return (path, profit * 100)
if current in visited:
continue
visited.add(current)
for neighbor, weight in graph.get(current, {}).items():
if neighbor not in visited:
new_cost = actual_cost + weight
# Heuristic: estimate remaining cost
heuristic = self._estimate_remaining(neighbor, end)
heapq.heappush(pq, (
new_cost + heuristic,
new_cost,
neighbor,
path + [neighbor]
))
return ([], 0)What Evolved
Current Arbitrage Engine
The algorithms are now integrated into the fXYZ Network:
| Lagrange Component | Current fXYZ Component |
|---|---|
| Triangular detection | Price oracle aggregation |
| Inter-exchange monitoring | Multi-source price feeds |
| Route optimization | Trade routing engine |
| Real-time alerts | Fixie market analysis |
Fixie Integration
The Florin Fixie uses these algorithms for market analysis:
// Florin Fixie arbitrage detection
const arbitrageOpportunities = await florin.detectArbitrage({
currencies: ['USD', 'EUR', 'GBP', 'SOL'],
minProfit: 0.1, // 0.1% minimum
maxHops: 4,
});Data Sources
Historical Data Used
archive/fxyz-knowledge-project/old-projects/lagrange-repos/Triangular-Arbitrage-Data-master/
├── data/
│ ├── forex_rates_2021.csv
│ ├── forex_rates_2022.csv
│ ├── dex_prices/
│ └── cex_prices/
├── models/
│ ├── bellman_ford.py
│ ├── genetic.py
│ └── astar.py
└── analysis/
└── backtest_results.ipynbPerformance Metrics
| Metric | Value | Notes |
|---|---|---|
| Detection latency | <100ms | Graph algorithm performance |
| Backtest profit | 0.2-0.5% per cycle | Before fees |
| Net profit (after fees) | 0.05-0.15% | Depends on execution |
| False positive rate | <5% | Stale quotes filtered |
Lessons Learned
What Worked
- Graph algorithms: Bellman-Ford efficient for cycle detection
- Genetic optimization: Found non-obvious route combinations
- Real-time monitoring: WebSocket feeds essential for freshness
What Didn't Work
- Execution speed: By the time trade executed, opportunity often gone
- Fee complexity: Multi-hop fees ate into profits
- Slippage: Large orders moved prices, reducing actual profit