Arbitrage Bot Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Arbitrage Bot Development
Medium
~1-2 weeks
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Arbitrage Trading Bot Development

Arbitrage is using price differences between markets for profit without (theoretically) market risk. In practice, risk exists: execution risk, latency risk, funding risk. Let's cover real arbitrage strategies and their technical implementation.

Arbitrage Strategy Types

Simple Arbitrage (Cross-Exchange)

Same asset trades at different prices on two exchanges. BTC on Binance — $42,100, on OKX — $42,150. Buy on Binance, sell on OKX, $50 profit is ours.

Main problem: by execution time, prices equalize. Need maximum low latency and pre-positioned balances on both exchanges.

import asyncio
import aiohttp
from decimal import Decimal

class SimpleArbitrageBot:
    def __init__(self):
        self.binance = ccxt.binance({'apiKey': BINANCE_KEY, 'secret': BINANCE_SECRET})
        self.okx = ccxt.okx({'apiKey': OKX_KEY, 'secret': OKX_SECRET})
        self.min_profit_pct = Decimal('0.15')  # minimum 0.15% after fees
    
    async def check_opportunity(self, symbol: str) -> ArbitrageOpportunity | None:
        # Parallel price request from both exchanges
        binance_ticker, okx_ticker = await asyncio.gather(
            self.binance.fetch_ticker(symbol),
            self.okx.fetch_ticker(symbol),
        )
        
        binance_bid = Decimal(str(binance_ticker['bid']))
        binance_ask = Decimal(str(binance_ticker['ask']))
        okx_bid = Decimal(str(okx_ticker['bid']))
        okx_ask = Decimal(str(okx_ticker['ask']))
        
        # Option 1: buy on Binance, sell on OKX
        if okx_bid > binance_ask:
            spread = (okx_bid - binance_ask) / binance_ask * 100
            net_spread = spread - BINANCE_TAKER_FEE - OKX_TAKER_FEE
            if net_spread > self.min_profit_pct:
                return ArbitrageOpportunity(
                    buy_exchange='binance', buy_price=binance_ask,
                    sell_exchange='okx', sell_price=okx_bid,
                    net_profit_pct=net_spread
                )
        
        # Option 2: buy on OKX, sell on Binance
        if binance_bid > okx_ask:
            spread = (binance_bid - okx_ask) / okx_ask * 100
            net_spread = spread - OKX_TAKER_FEE - BINANCE_TAKER_FEE
            if net_spread > self.min_profit_pct:
                return ArbitrageOpportunity(
                    buy_exchange='okx', buy_price=okx_ask,
                    sell_exchange='binance', sell_price=binance_bid,
                    net_profit_pct=net_spread
                )
        
        return None
    
    async def execute_arbitrage(self, opp: ArbitrageOpportunity, quantity: Decimal):
        # Execute both legs simultaneously
        buy_task = self.place_order(opp.buy_exchange, 'buy', quantity, opp.buy_price)
        sell_task = self.place_order(opp.sell_exchange, 'sell', quantity, opp.sell_price)
        
        buy_result, sell_result = await asyncio.gather(buy_task, sell_task, 
                                                        return_exceptions=True)
        
        # Handle partial execution
        if isinstance(buy_result, Exception) or isinstance(sell_result, Exception):
            await self.handle_partial_execution(buy_result, sell_result, opp)

Triangular Arbitrage (Intra-Exchange)

On one exchange: BTC → ETH → USDT → BTC. If product of rates > 1 + fees — opportunity exists.

def find_triangular_opportunity(tickers: dict) -> TriangularPath | None:
    """
    Find path A → B → C → A where final sum > initial
    """
    currencies = ['BTC', 'ETH', 'BNB', 'XRP', 'SOL']
    
    for a, b, c in permutations(currencies, 3):
        pair_ab = f"{a}/{b}"
        pair_bc = f"{b}/{c}"
        pair_ca = f"{c}/{a}"
        
        if not all(p in tickers for p in [pair_ab, pair_bc, pair_ca]):
            continue
        
        # Calculate cycle efficiency
        # Buy A->B: pay ask A/B
        rate_ab = Decimal(str(tickers[pair_ab]['ask']))
        # Buy B->C: pay ask B/C
        rate_bc = Decimal(str(tickers[pair_bc]['ask']))
        # Sell C->A: receive bid C/A
        rate_ca = Decimal(str(tickers[pair_ca]['bid']))
        
        # From 1 unit A we get:
        result = (1 / rate_ab) * (1 / rate_bc) * rate_ca
        
        # Subtract 3 fees (taker each step)
        after_fees = result * ((1 - TAKER_FEE) ** 3)
        
        profit_pct = (after_fees - 1) * 100
        
        if profit_pct > 0.05:  # minimum 0.05% profit
            return TriangularPath(
                a=a, b=b, c=c,
                rates=(rate_ab, rate_bc, rate_ca),
                profit_pct=profit_pct,
            )
    
    return None

Statistical Arbitrage (Pairs Trading)

More complex: find statistically cointegrated pairs (BTC/ETH historically move together). On spread divergence beyond threshold — long laggard, short leader.

Execution Risks and Mitigation

Execution Risk

Between spotting opportunity and execution, price can move. Binance WebSocket latency — 10–50 ms. Another bot can "eat" the opportunity.

Mitigation:

  • Colocation: server in same datacenter as exchange (AWS Tokyo for Binance, AWS Frankfurt for OKX)
  • WebSocket instead of REST: subscribe to orderbook updates, not polling
  • Pre-placed orders: limit orders close to market
class LowLatencyArbitrageBot:
    def __init__(self):
        # Subscribe to WebSocket, update cache
        self.price_cache = {}  # current prices without request latency
    
    async def subscribe_prices(self, symbol: str):
        """WebSocket subscription — update cache on each tick"""
        async with websockets.connect(BINANCE_WS_URL) as ws:
            await ws.send(json.dumps({
                'method': 'SUBSCRIBE',
                'params': [f'{symbol.lower()}@bookTicker'],
                'id': 1
            }))
            async for msg in ws:
                data = json.loads(msg)
                # bookTicker gives best bid/ask without delay
                self.price_cache[symbol] = {
                    'bid': Decimal(data['b']),
                    'ask': Decimal(data['a']),
                    'ts': time.time_ns(),
                }
                await self.check_opportunity_fast(symbol)

Inventory Risk

If one leg executed but other didn't — open position with market risk. Called "leg risk".

Transfer Risk (Cross-Exchange)

Cross-exchange arbitrage requires maintaining balances on both exchanges. Transfer between takes 10–60 minutes (multiple blockchain confirmations). Price can shift.

Solution: capital-intensive model — hold sufficient balance on each exchange ahead of time. Rebalance every few hours when imbalance exceeds threshold.

async def check_balance_rebalance(self):
    """If imbalance > threshold — auto-transfer"""
    for exchange, balance in self.get_all_balances().items():
        for currency, amount in balance.items():
            target = self.target_balances[exchange][currency]
            deviation = abs(amount - target) / target * 100
            
            if deviation > 20:  # imbalance more than 20%
                await self.initiate_transfer(exchange, currency, target - amount)

P&L and Monitoring

class ArbitragePnL:
    def record_trade(self, trade: ArbitrageTrade):
        gross_profit = trade.sell_amount - trade.buy_amount
        fees = trade.buy_fee + trade.sell_fee + trade.transfer_fee
        net_profit = gross_profit - fees
        
        self.daily_pnl += net_profit
        self.total_volume += trade.quantity
        
        if net_profit < 0:
            self.losing_trades += 1
            log.warning(f"Losing arbitrage: net {net_profit:.4f} USDT")
    
    def get_stats(self) -> dict:
        return {
            'daily_pnl': self.daily_pnl,
            'win_rate': self.winning_trades / max(self.total_trades, 1),
            'avg_profit_per_trade': self.daily_pnl / max(self.total_trades, 1),
            'volume': self.total_volume,
        }
Arbitrage Type Required Capital Complexity Competition
Cross-exchange spot High Medium Very High
Triangular (intra-exchange) Medium Medium High
Statistical / Pairs Medium High Moderate
Cross-chain (DeFi) Medium Very High Moderate
Funding rate Medium Low Moderate

Development Timeline

  • Simple cross-exchange arbitrage with 2 exchanges: 4–6 weeks
  • Triangular arbitrage: 3–4 weeks
  • Statistical arbitrage: 6–10 weeks (includes cointegration research)
  • Production-ready system with monitoring and auto-rebalancing: 3–4 months