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:
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:
Perfect Arbitrage - Models multiple simultaneous arbitrageurs - Achieves optimal price alignment - Used for ideal market conditions
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:
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)
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
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:
Standard Fee Calculation (calculate_reserves_with_fees)
Handles regular trading with fees
Supports both perfect and imperfect arbitrage
Considers gas costs and arbitrage thresholds
Zero Fee Calculation (calculate_reserves_zero_fees)
Special case for fee-less trading
Useful for theoretical analysis
Maintains arbitrage modeling
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
GPU Acceleration
All core calculations are JAX-accelerated
Supports parallel processing of trades
Efficient handling of large datasets
Memory Usage
Optimized for long simulations
Efficient precalculation of common values
Smart broadcasting of parameters
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