Crypto Bots

Crypto Market Making: How Bots Profit from the Bid-Ask Spread

Market making is one of the most consistent strategies in crypto. Learn how automated market makers work, how bots capture the spread, and how to build your own market making system.

A
AI Agents Hubยท2025-04-01ยท4 min readยท730 words

Builder of AI agents, crypto trading bots, and open-source automation tools. Sharing practical guides on how to build, deploy, and profit from AI and DeFi technology.

What Is Market Making?

A market maker is a trader who continuously quotes both buy and sell prices for an asset, profiting from the spread between them.

Example:

  • Market maker buys ETH at $3,000 (bid)
  • Market maker sells ETH at $3,003 (ask)
  • Spread = $3 per ETH

Every time a buyer buys and a seller sells, the market maker captures that $3 spread.

At scale โ€” thousands of trades per day โ€” this adds up quickly.

Why Crypto Is Perfect for Market Making

  • 24/7 markets โ€” More trading hours = more spread captures
  • High volatility โ€” Creates more trading opportunities
  • Multiple exchanges โ€” Each venue needs liquidity
  • Lower barriers โ€” Anyone can be a market maker on DEXs (just provide liquidity)
  • Less regulation โ€” No licensed market maker requirements

Types of Market Making

1. CEX Order Book Market Making

Place limit orders on both sides of the book on centralized exchanges. Constantly update quotes based on market movement.

2. DEX Liquidity Provision (AMM)

Deposit tokens into a liquidity pool (Uniswap, Curve). The AMM algorithm acts as your market maker automatically.

3. Cross-Exchange Market Making

Be the market maker on a smaller exchange while hedging on a larger one. Profit from the liquidity premium on the smaller exchange.

Building a Simple CEX Market Maker

import ccxt
import time
import asyncio

class SimpleMarketMaker:
    def __init__(self, exchange_id: str, symbol: str, spread_pct: float = 0.002):
        self.exchange = getattr(ccxt, exchange_id)({
            'apiKey': '...',
            'secret': '...',
            'enableRateLimit': True
        })
        self.symbol = symbol
        self.spread_pct = spread_pct  # 0.2% spread
        self.order_size = 0.01  # BTC
    
    async def get_mid_price(self) -> float:
        ticker = await self.exchange.fetch_ticker(self.symbol)
        return (ticker['bid'] + ticker['ask']) / 2
    
    async def place_orders(self):
        mid = await self.get_mid_price()
        
        bid_price = mid * (1 - self.spread_pct / 2)
        ask_price = mid * (1 + self.spread_pct / 2)
        
        # Cancel existing orders first
        await self.exchange.cancel_all_orders(self.symbol)
        
        # Place new orders
        buy_order = await self.exchange.create_limit_buy_order(
            self.symbol, self.order_size, bid_price
        )
        sell_order = await self.exchange.create_limit_sell_order(
            self.symbol, self.order_size, ask_price
        )
        
        print(f"Bid: ${bid_price:.2f} | Ask: ${ask_price:.2f} | Spread: {self.spread_pct*100:.2f}%")
        return buy_order, sell_order
    
    async def run(self):
        print(f"Starting market maker for {self.symbol}...")
        while True:
            try:
                await self.place_orders()
                await asyncio.sleep(10)  # Refresh every 10 seconds
            except Exception as e:
                print(f"Error: {e}")
                await asyncio.sleep(5)

# Run
mm = SimpleMarketMaker('binance', 'BTC/USDT', spread_pct=0.002)
asyncio.run(mm.run())

Inventory Management: The Critical Challenge

The biggest risk for market makers is inventory imbalance. If you only get buys and BTC price drops, you're stuck holding depreciating assets.

Solutions:

def check_inventory_and_skew(self, buy_fill_count: int, sell_fill_count: int) -> float:
    """
    Adjust spread based on inventory imbalance.
    If we have too much inventory, tighten the sell side to offload faster.
    """
    imbalance = buy_fill_count - sell_fill_count
    
    if imbalance > 3:  # Too much base currency
        skew = 0.001  # Widen bid, tighten ask
    elif imbalance < -3:  # Too much quote currency
        skew = -0.001  # Tighten bid, widen ask
    else:
        skew = 0
    
    return skew

Risk Management for Market Makers

1. Maximum Inventory Limits

MAX_INVENTORY_BTC = 0.5  # Never hold more than 0.5 BTC
if current_btc_balance > MAX_INVENTORY_BTC:
    pause_buy_orders()

2. Volatility-Adjusted Spreads

When volatility spikes, widen your spread to reduce adverse selection:

def dynamic_spread(base_spread: float, volatility: float) -> float:
    vol_multiplier = max(1.0, volatility / 0.01)  # Normalize to 1% baseline
    return base_spread * vol_multiplier

3. Stop-Loss on Inventory

If your base currency position loses >2%, pause and reassess.

DEX Liquidity Provision: The Passive Version

For less hands-on market making, provide liquidity on Uniswap V3:

  • Choose a tight price range (e.g., ETH between $2,800โ€“$3,200)
  • Deposit both ETH and USDC proportionally
  • Earn 0.05% or 0.3% of every trade through your range
  • An auto-rebalancing bot keeps your position in range

This is essentially automated market making with lower complexity but also lower returns per dollar.

Expected Returns

| Strategy | Monthly Return | Risk | Capital Required | |----------|---------------|------|------------------| | Simple CEX MM | 1โ€“4% | Medium | $1,000+ | | Advanced CEX MM | 3โ€“8% | Medium-High | $5,000+ | | Uniswap V3 LP | 1โ€“5% | Medium (IL risk) | $1,000+ | | Cross-Exchange MM | 2โ€“6% | Medium | $3,000+ |

Get the Full Market Maker Bot

Our market maker bot includes inventory management, dynamic spread adjustment, and multi-exchange support. Download from the Tools page.

Related Articles