Skip to main content

Overview

Cross Exchange Market Making (XEMM) allows you to make markets on one exchange (maker) while hedging filled orders on another exchange (taker). This strategy profits from price differences between exchanges while maintaining market-neutral exposure.

How It Works

  1. Monitor Price Difference: Continuously calculates profitability between maker and taker exchanges
  2. Place Maker Orders: Places limit orders on the maker exchange when profitability threshold is met
  3. Hedge on Taker: When maker order fills, immediately hedges with market order on taker exchange
  4. Capture Spread: Profits from the price difference minus fees
# Profitability calculation from source
profitability = (taker_price - maker_price) / maker_price - fees - slippage
if profitability >= min_profitability:
    place_maker_order()
Unlike pure arbitrage, XEMM places orders on one side and waits for fills, acting as a market maker.

When to Use

Ideal Conditions

  • Consistent price spreads between exchanges
  • Maker exchange offers fee rebates
  • Taker exchange has deep liquidity
  • Stable trading pairs (major assets)

Avoid When

  • Price spreads are unstable
  • High withdrawal fees between exchanges
  • Low liquidity on taker exchange
  • Gateway/DEX with high gas costs as taker

Core Configuration Parameters

Exchange Setup

maker_market_trading_pair
string
required
Trading pair on maker exchange in BASE-QUOTE formatExample: ETH-USDT
taker_market
string
required
The taker exchange connector nameExample: binance, uniswap_ethereum

Profitability

min_profitability
decimal
required
Minimum profit percentage required to place orders. Enter 1 for 1%.Example: 0.5 requires 0.5% profit after all costsRange: -100% to 100%
order_amount
decimal
required
Order size in base assetExample: 0.1 for 0.1 ETH per order

Order Behavior

adjust_order_enabled
bool
default:"true"
Adjust maker order price to be one tick above top bid or below top askThis ensures your orders are at the top of the order book.
order_refresh_mode
union
required
How to refresh orders on the maker exchangeOptions:
  • active_order_refresh: Cancel and replace orders continuously
  • passive_order_refresh: Let orders expire naturally

Passive Order Refresh Parameters

cancel_order_threshold
decimal
default:"5.0"
Profitability threshold to cancel orders in passive mode. Enter 1 for 1%.Example: 2.0 cancels orders when profitability drops below 2%
limit_order_min_expiration
decimal
default:"130.0"
Minimum seconds before orders expire in passive mode

Order Sizing

order_size_taker_volume_factor
decimal
default:"25.0"
Percentage of taker exchange volume to use for order sizing. Enter 1 for 1%.Range: 0% to 100%
order_size_taker_balance_factor
decimal
default:"99.5"
Percentage of taker balance available for hedging. Enter 1 for 1%.Range: 0% to 100%
order_size_portfolio_ratio_limit
decimal
default:"16.67"
Maximum order size as percentage of total portfolio. Enter 50 for 50%.Range: 0% to 100%

Conversion Rates

conversion_rate_mode
union
required
Method to convert between different assets on maker and taker exchangesOptions:
  • rate_oracle_conversion_rate: Use Hummingbot’s rate oracle (recommended)
  • fixed_conversion_rate: Specify manual conversion rates

Fixed Conversion Rate Parameters

taker_to_maker_base_conversion_rate
decimal
default:"1.0"
Conversion rate for base assets (when using fixed mode)Example: 1.25 if 1 DAI = 1.25 USDT
taker_to_maker_quote_conversion_rate
decimal
default:"1.0"
Conversion rate for quote assets (when using fixed mode)

Risk Management

slippage_buffer
decimal
default:"5.0"
Additional buffer for taker market orders to ensure fills. Enter 1 for 1%.Example: 2.0 adds 2% slippage buffer to taker ordersRange: 0% to 100%
top_depth_tolerance
decimal
default:"0.0"
Minimum volume required at top of order bookExample: 1.0 requires 1 base asset at best bid/ask
anti_hysteresis_duration
float
default:"60.0"
Minimum seconds between order adjustmentsPrevents excessive order updates during price fluctuations.

Example Configurations

Basic CEX to CEX

strategy: cross_exchange_market_making
maker_market_trading_pair: BTC-USDT
taker_market: binance
min_profitability: 0.3
order_amount: 0.01
order_refresh_mode:
  active_order_refresh: {}
adjust_order_enabled: true
conversion_rate_mode:
  rate_oracle_conversion_rate: {}
slippage_buffer: 1.0
This setup:
  • Makes markets for BTC-USDT
  • Hedges on Binance
  • Requires 0.3% minimum profit
  • Uses rate oracle for conversions

CEX to AMM (Gateway)

strategy: cross_exchange_market_making
maker_market_trading_pair: ETH-USDC
taker_market: uniswap_ethereum
min_profitability: 2.0
order_amount: 0.5
order_refresh_mode:
  passive_order_refresh:
    cancel_order_threshold: 1.5
    limit_order_min_expiration: 180
adjust_order_enabled: true
conversion_rate_mode:
  rate_oracle_conversion_rate: {}
slippage_buffer: 3.0
order_size_taker_balance_factor: 90.0
Key adjustments for AMM:
  • Higher min_profitability to account for gas costs
  • Larger slippage_buffer for AMM slippage
  • Passive order refresh to reduce gas usage

With Fixed Conversion Rates

strategy: cross_exchange_market_making
maker_market_trading_pair: USDT-USD
taker_market: kraken
min_profitability: 0.1
order_amount: 1000
order_refresh_mode:
  active_order_refresh: {}
conversion_rate_mode:
  fixed_conversion_rate:
    taker_to_maker_base_conversion_rate: 1.0001
    taker_to_maker_quote_conversion_rate: 1.0
slippage_buffer: 0.5
Useful for stablecoin pairs where rate oracle may be unreliable.

Advanced Configuration

Order Refresh Modes

order_refresh_mode:
  active_order_refresh: {}
  • Continuously cancels and replaces orders
  • Best for volatile markets
  • Higher API usage
  • Recommended for CEX-to-CEX

Profitability Calculation

The strategy calculates profitability including all costs:
# Simplified from source code
hedge_price = taker_best_price * (1 + slippage_buffer)
maker_price = calculated_maker_price
fees = maker_fee + taker_fee
conversion_cost = base_conversion_rate + quote_conversion_rate

profitability_pct = (
    (hedge_price - maker_price) / maker_price 
    - fees 
    - conversion_cost
) * 100

can_place_order = profitability_pct >= min_profitability

Tips for Success

Ensure sufficient balances on both maker and taker exchanges. The bot needs quote asset on maker and base asset on taker (or vice versa for sell orders).
Include in your min_profitability:
  • Maker and taker exchange fees
  • Withdrawal fees (if rebalancing)
  • Gas costs (for DEX takers)
  • Spread costs on taker
Start with minimum order sizes to verify the strategy works as expected before scaling up.
For most scenarios, rate_oracle_conversion_rate is more reliable than fixed rates, especially for volatile pairs.

Risk Management

Key Risks:
  • Execution Risk: Taker order fails after maker fills
  • Price Risk: Market moves between maker fill and taker hedge
  • Balance Risk: Insufficient taker balance for hedging
  • Gas Risk: High gas costs eat into profits (DEX takers)
Mitigation:
  1. Set conservative min_profitability (>= 0.5% for CEX, >= 2% for DEX)
  2. Use adequate slippage_buffer (2-3% for AMMs)
  3. Monitor and rebalance exchange balances regularly
  4. Use order_size_taker_balance_factor to reserve capital

Source Code Reference

Configuration: /source/hummingbot/strategy/cross_exchange_market_making/cross_exchange_market_making_config_map_pydantic.py:198 Strategy Implementation: /source/hummingbot/strategy/cross_exchange_market_making/cross_exchange_market_making.py

Build docs developers (and LLMs) love