CoW Pools

This tutorial explains CoW (Coincidence of Wants) pools, which implement the CoW Protocol AMM design where post-trade quoted prices must match execution prices.

CoW pools are a unique type of AMM that ensures the quoted price for a trade matches the execution price. This design helps prevent price manipulation and provides better price discovery.

Key Features

  • Fixed weights for token pairs (configurable in advanced usage)

  • Price-responsive reserve adjustments through sophisticated arbitrage modeling

  • Support for dynamic trading fees and parameters

  • Flexible arbitrage quality modeling

Core Mechanics

CoW pools maintain price consistency using the following key equation:

\[P_{exec} = P_{quote}\]

where: - \(P_{exec}\) is the execution price - \(P_{quote}\) is the quoted price

Basic Usage

Here’s how to create and simulate a basic CoW pool:

from quantammsim.runners.jax_runners import do_run_on_historic_data

# Configure the simulation
run_fingerprint = {
    'tokens': ['ETH', 'USDC'],
    'rule': 'cow',
    'initial_pool_value': 1000000.0,  # $1M initial pool value
    'fees': 0.001,                    # 0.1% fee per trade
    'gas_cost': 0.0001,               # Minimum profit threshold for arbitrage
    'arb_frequency': 1,               # How often arbitrageurs can act
    'arb_quality': 0.8                # Blend of perfect/imperfect arbitrage
}

# Run the simulation
result = do_run_on_historic_data(run_fingerprint)

Advanced Features

Arbitrage Modeling

The simulator provides two arbitrage models that can be combined:

  1. Perfect Arbitrage - Models multiple simultaneous arbitrageurs - Achieves optimal price alignment - Used for ideal market conditions

  2. Single Arbitrageur - Models scenarios with limited arbitrage activity - More conservative price alignment - Represents real-world friction

The arb_quality parameter (0-1) allows blending between these models: - 1.0 = perfect arbitrage - 0.0 = single arbitrageur - Values between represent partial market efficiency

Dynamic Parameters

CoW pools support several dynamic parameters that can vary over time:

  1. Trading Fees

    • Configurable per-minute fees or set as a single value

    • Can respond to market conditions

    • Per minute fees are specified through fees_array (but can be a single value fees in the run fingerprint)

  2. Arbitrage Parameters

    • Threshold for profitable arbitrage (arb_thresh_array) often coterminous with gas costs (but can be a single value arb_fees in the run fingerprint)

    • Arbitrage fees (arb_fees_array), the fees the arbitrageur has to pay to liquidate the position they have after the arbitrage trade

  3. Trade Execution

    • Support for user-specified trades via trade_array

    • Format: [token_in_idx, token_out_idx, amount_in]

    • Can model specific trading patterns

Parameter Configuration

For sophisticated simulations with time-varying parameters:

from quantammsim.runners.jax_runners import do_run_on_historic_data
import pandas as pd
import numpy as np

# Create time series data for dynamic parameters
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
fees_df = pd.DataFrame({
    'date': dates,
    'fee': np.linspace(0.001, 0.002, len(dates))  # Fees increasing over time
})

gas_cost_df = pd.DataFrame({
    'date': dates,
    'gas_cost': np.full(len(dates), 0.0001)  # Constant gas costs
})

arb_fees_df = pd.DataFrame({
    'date': dates,
    'arb_fee': np.full(len(dates), 0.0002)  # Constant arbitrage fees
})

# Define specific trades to execute
raw_trades = pd.DataFrame({
    'date': dates[:10],  # First 10 days
    'token_in_idx': [0, 1, 0, 1] * 2 + [0, 1],  # Alternating tokens
    'token_out_idx': [1, 0, 1, 0] * 2 + [1, 0],
    'amount_in': [1000.0] * 10  # Constant trade size
})

# Run simulation with dynamic parameters
result = do_run_on_historic_data(
    run_fingerprint,
    fees_df=fees_df,
    gas_cost_df=gas_cost_df,
    arb_fees_df=arb_fees_df,
    raw_trades=raw_trades,
    do_test_period=True  # Enable test period simulation
)

Arbitrage Configuration

Fine-tune arbitrage behavior:

run_fingerprint.update({
    'gas_cost': 0.0001,              # Minimum profit threshold
    'arb_fees': 0.0002,              # External arbitrage costs
    'arb_frequency': 5,              # Check every 5 minutes
    'arb_quality': 0.8,              # Blend between perfect/imperfect arbitrage
    'all_sig_variations': [...],     # Custom arbitrage patterns
})

The arb_quality parameter (0-1) controls how efficiently arbitrage opportunities are captured:

  • 1.0 = perfect arbitrage (multiple simultaneous arbitrageurs perfectly compete, resulting in rebalancing at the true price)

  • 0.0 = single arbitrageur (more pessimistic market conditions, the one arbitrageur is able to capture the arbitrage opportunity giving the pool less surplus)

  • Values between represent partial market efficiency

  • Default is 0.8 (mostly efficient but not perfect)

This allows simulating different market conditions, from ideal (perfect arbitrage) to more realistic scenarios with market frictions and limited arbitrageur participation.

Implementation Details

The pool implements three main calculation modes:

  1. Standard Fee Calculation (calculate_reserves_with_fees)

    • Handles regular trading with fees

    • Supports both perfect and imperfect arbitrage

    • Considers gas costs and arbitrage thresholds

  2. Zero Fee Calculation (calculate_reserves_zero_fees)

    • Special case for fee-less trading

    • Useful for theoretical analysis

    • Maintains arbitrage modeling

  3. Dynamic Input Calculation (calculate_reserves_with_dynamic_inputs)

    • Supports time-varying parameters

    • Handles custom trade sequences

    • Most flexible configuration

The implementation uses JAX for efficient computation and supports both CPU and GPU execution. This functions are called by the do_run_on_historic_data function, which is the main entry point for running simulations.

For implementation details, see the source code in quantammsim.pools.FM_AMM.cow_pool.

Performance Considerations

  1. GPU Acceleration

    • All core calculations are JAX-accelerated

    • Supports parallel processing of trades

    • Efficient handling of large datasets

  2. Memory Usage

    • Optimized for long simulations

    • Efficient precalculation of common values

    • Smart broadcasting of parameters

  3. Numerical Stability

    • Uses 64-bit precision

    • Handles edge cases in calculations

    • Robust arbitrage detection

Next Steps

To learn more about:

  • Different pool types, see Core Concepts

  • Implementation details, see Pools

  • Mathematical foundations, see the CoW Protocol documentation