gmx.market_depth

Documentation for eth_defi.gmx.market_depth Python module.

GMX Market Depth and Price Impact Analysis Module.

This module provides tools to inspect GMX v2 market depth and estimate price impact before opening a position, allowing traders to optimise position sizing.

Key concepts:

GMX v2 is not an order book – “market depth” means:

  1. How much open interest (OI) can still be added before the pool reserve cap is hit (available_long_oi_usd / available_short_oi_usd).

  2. What price impact a given position size will incur, based on the OI imbalance between longs and shorts.

The price impact formula is implemented in two Solidity contracts in the gmx-synthetics repository:

  • PricingUtils.sol — defines applyImpactFactor, getPriceImpactUsdForSameSideRebalance, and getPriceImpactUsdForCrossoverRebalance.

  • PositionPricingUtils.sol — calls the above helpers from getPriceImpactUsd.

The formula (from PricingUtils.applyImpactFactor):

price_impact = applyImpactFactor(initialDiff) - applyImpactFactor(nextDiff)
applyImpactFactor(diffUsd) = diffUsd ^ exponent * factor

where initialDiff = |longOI - shortOI| and nextDiff = |nextLongOI - nextShortOI|.

A negative impact is a cost to the trader (worsens execution price). A positive impact is a rebate (improves execution price – only when the trade reduces the existing imbalance).

Note

Virtual inventory (cross-market impact) used by PositionPricingUtils.getPriceImpactUsd is intentionally omitted here for simplicity, matching the existing _estimate_price_impact helper in eth_defi.gmx.order.base_order.

Example usage:

from eth_defi.gmx.api import GMXAPI
from eth_defi.gmx.market_depth import (
    estimate_position_price_impact,
    fetch_price_impact_params,
    find_max_position_size,
)

# Get market depth info (REST-based, cached 60 s, no RPC cost)
api = GMXAPI(chain="arbitrum")
eth_markets = api.get_market_depth(market_symbol="ETH")
eth = eth_markets[0]

print(f"Long OI: ${eth.long_open_interest_usd:,.0f}")
print(f"Available long capacity: ${eth.available_long_oi_usd:,.0f}")

# Fetch price impact params from DataStore (on-chain, cached implicitly)
config = GMXConfig(web3)
params = fetch_price_impact_params(config, eth.market_token_address)

# Estimate impact for a $10 000 long position
impact_usd = estimate_position_price_impact(
    long_open_interest_usd=eth.long_open_interest_usd,
    short_open_interest_usd=eth.short_open_interest_usd,
    size_delta_usd=10_000.0,
    is_long=True,
    params=params,
)
impact_bps = abs(impact_usd) / 10_000.0 * 10_000  # basis points
print(f"Price impact for $10k long: ${impact_usd:+.2f} ({impact_bps:.2f} bps)")

# Find the largest position that keeps impact under 5 bps
max_size = find_max_position_size(
    long_open_interest_usd=eth.long_open_interest_usd,
    short_open_interest_usd=eth.short_open_interest_usd,
    is_long=True,
    max_price_impact_bps=5.0,
    params=params,
    max_oi_available_usd=eth.available_long_oi_usd,
)
print(f"Max position size at ≤5 bps impact: ${max_size:,.0f}")

Functions

calculate_max_position_whale_risk(market, ...)

Calculate the maximum position size subject to whale-risk constraints.

estimate_position_price_impact(...)

Estimate price impact for a position using the GMX v2 formula.

fetch_price_impact_params(config, market_address)

Fetch price impact parameters from the GMX DataStore contract.

find_max_position_size(...[, ...])

Find the maximum position size that keeps price impact within a threshold.

parse_market_depth(market_data)

Parse a single market entry from the /markets/info REST response.

Classes

MarketDepthInfo

Market depth snapshot for a single GMX v2 perpetual market.

PositionSizingResult

Result of whale-risk position sizing for one side of a market.

PriceImpactParams

Per-market price impact parameters read from the GMX DataStore contract.

class MarketDepthInfo

Bases: object

Market depth snapshot for a single GMX v2 perpetual market.

Populated from the /markets/info REST endpoint (cached 60 s). All USD values are already divided by 10^30 (the GMX fixed-point precision) and expressed as plain floats.

Pool amounts (long_pool_amount, short_pool_amount) are kept in raw token units as returned by the API, because the conversion to USD requires per-token decimal information.

__init__(market_token_address, market_symbol, index_token_address, long_token_address, short_token_address, long_open_interest_usd, short_open_interest_usd, max_long_open_interest_usd, max_short_open_interest_usd, available_long_oi_usd, available_short_oi_usd, long_pool_amount, short_pool_amount, long_funding_rate, short_funding_rate, long_borrowing_rate, short_borrowing_rate, is_listed)
Parameters
Return type

None

class PositionSizingResult

Bases: object

Result of whale-risk position sizing for one side of a market.

Computed by calculate_max_position_whale_risk(). The maximum position is the tightest of three constraints:

  1. Portfolio: the total capital available (portfolio_usd).

  2. Whale risk: a fraction of the side’s open interest (max_oi_pct * side_oi), so the position doesn’t move the market disproportionately.

  3. Pool capacity: the remaining OI capacity before the reserve cap.

__init__(max_position_usd, pct_of_total_oi, whale_ok, cap_ok, binding_constraint)
Parameters
  • max_position_usd (float) –

  • pct_of_total_oi (float) –

  • whale_ok (bool) –

  • cap_ok (bool) –

  • binding_constraint (str) –

Return type

None

class PriceImpactParams

Bases: object

Per-market price impact parameters read from the GMX DataStore contract.

All factor and exponent values use GMX’s 30-decimal fixed-point format (integers). Pass them directly to estimate_position_price_impact().

__init__(positive_factor, negative_factor, positive_exponent, negative_exponent, max_positive_factor, max_negative_factor)
Parameters
  • positive_factor (int) –

  • negative_factor (int) –

  • positive_exponent (int) –

  • negative_exponent (int) –

  • max_positive_factor (int) –

  • max_negative_factor (int) –

Return type

None

calculate_max_position_whale_risk(market, portfolio_usd, max_oi_pct, is_long)

Calculate the maximum position size subject to whale-risk constraints.

Analogous to sizing a position in a Uniswap pool so as not to become too large relative to the pool’s liquidity. On GMX, we don’t want to represent more than max_oi_pct of one side’s open interest, because:

  • Exiting a large position will move OI against us.

  • Other traders may push OI further, increasing funding/borrowing drag.

  • In extreme cases the pool capacity cap prevents new positions entirely.

The maximum position is:

max_position = min(portfolio_usd, max_oi_pct * side_oi, available_cap)

For a $100 000 portfolio with max_oi_pct = 0.025 (2.5 %), a market with $1 M long OI allows at most $25 000 on the long side — meaning 10 equally weighted positions would already be constrained.

from eth_defi.gmx.api import GMXAPI
from eth_defi.gmx.market_depth import calculate_max_position_whale_risk

api = GMXAPI(chain="arbitrum")
markets = api.get_market_depth()

for m in markets:
    result = calculate_max_position_whale_risk(
        market=m,
        portfolio_usd=100_000,
        max_oi_pct=0.025,
        is_long=True,
    )
    print(f"{m.market_symbol}: max ${result.max_position_usd:,.0f}  ({result.pct_of_total_oi:.2f}% of OI)  {'OK' if result.whale_ok and result.cap_ok else result.binding_constraint}")
Parameters
  • market (eth_defi.gmx.market_depth.MarketDepthInfo) – Market depth snapshot

  • portfolio_usd (float) – Total portfolio value in USD

  • max_oi_pct (float) – Maximum share of one side’s OI the position may represent. E.g. 0.025 means 2.5 %.

  • is_long (bool) – True for long side, False for short side

Returns

PositionSizingResult with the capped position and diagnostics

Return type

eth_defi.gmx.market_depth.PositionSizingResult

estimate_position_price_impact(long_open_interest_usd, short_open_interest_usd, size_delta_usd, is_long, params)

Estimate price impact for a position using the GMX v2 formula.

This is a pure-Python implementation – no RPC calls are needed. Pass PriceImpactParams obtained via fetch_price_impact_params().

The GMX price impact formula from PricingUtils.sol (called by PositionPricingUtils.sol):

applyImpactFactor(diffUsd) = diffUsd ^ exponent * factor
impact = applyImpactFactor(initialDiff) - applyImpactFactor(nextDiff)

where initialDiff and nextDiff are the absolute OI imbalances before and after the trade respectively.

Note

Virtual inventory (cross-market impact) is not modelled here, matching the behaviour of the existing _estimate_price_impact helper in eth_defi.gmx.order.base_order.

Parameters
  • long_open_interest_usd (float) – Current long open interest in USD

  • short_open_interest_usd (float) – Current short open interest in USD

  • size_delta_usd (float) – Position size to open in USD (must be positive)

  • is_long (bool) – True for a long position, False for short

  • params (eth_defi.gmx.market_depth.PriceImpactParams) – Price impact parameters fetched from the DataStore contract

Returns

Price impact in USD. Negative values are a cost to the trader (execution price worsens). Positive values are a rebate.

Return type

float

fetch_price_impact_params(config, market_address)

Fetch price impact parameters from the GMX DataStore contract.

Reads the six per-market parameters needed by estimate_position_price_impact() via individual getUint calls on the DataStore contract.

Parameters
Returns

Populated PriceImpactParams

Return type

eth_defi.gmx.market_depth.PriceImpactParams

find_max_position_size(long_open_interest_usd, short_open_interest_usd, is_long, max_price_impact_bps, params, max_oi_available_usd=0.0, search_precision_usd=100.0)

Find the maximum position size that keeps price impact within a threshold.

Uses binary search over the price impact curve, which is monotonically increasing with position size for balance-worsening trades.

Parameters
  • long_open_interest_usd (float) – Current long open interest in USD

  • short_open_interest_usd (float) – Current short open interest in USD

  • is_long (bool) – True for a long position, False for short

  • max_price_impact_bps (float) – Maximum acceptable price impact expressed in basis points (1 bps = 0.01 %). E.g. 5.0 means 5 bps = 0.05 %.

  • params (eth_defi.gmx.market_depth.PriceImpactParams) – Price impact parameters from fetch_price_impact_params()

  • max_oi_available_usd (float) – Upper bound for the search in USD. If 0 (the default), falls back to GMX_DEFAULT_SEARCH_MAX_USD ($100 M), which covers typical GMX market sizes. Use MarketDepthInfo.available_long_oi_usd or MarketDepthInfo.available_short_oi_usd here for accuracy.

  • search_precision_usd (float) – The binary search halts when the range is narrower than this value (USD). Default 100.0 (i.e., $100 precision).

Returns

Maximum position size in USD at which the absolute price impact stays at or below max_price_impact_bps basis points. Returns 0.0 if even the smallest position exceeds the threshold.

Return type

float

parse_market_depth(market_data)

Parse a single market entry from the /markets/info REST response.

Parameters

market_data (dict[str, Any]) – Raw market dictionary as returned inside response["markets"].

Returns

Structured MarketDepthInfo for this market.

Return type

eth_defi.gmx.market_depth.MarketDepthInfo