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.

market_token_address: eth_typing.evm.HexAddress

GMX market token address (identifies the GM liquidity pool)

market_symbol: str

Human-readable market name, e.g. "ETH/USD [WETH-USDC]"

index_token_address: eth_typing.evm.HexAddress

Address of the index token (the asset being traded)

long_token_address: eth_typing.evm.HexAddress

Address of the long collateral token

short_token_address: eth_typing.evm.HexAddress

Address of the short collateral token (usually USDC)

long_open_interest_usd: float

Current long open interest in USD

short_open_interest_usd: float

Current short open interest in USD

max_long_open_interest_usd: float

Maximum long OI the pool can accept before hitting the reserve cap (USD). Computed as long_open_interest_usd + available_long_oi_usd.

max_short_open_interest_usd: float

Maximum short OI the pool can accept before hitting the reserve cap (USD). Computed as short_open_interest_usd + available_short_oi_usd.

available_long_oi_usd: float

Remaining long OI capacity in USD. This is the USD amount of new long positions the pool can absorb.

available_short_oi_usd: float

Remaining short OI capacity in USD. This is the USD amount of new short positions the pool can absorb.

long_pool_amount: float

Long pool token amount (raw token units as returned by the API)

short_pool_amount: float

Short pool token amount (raw token units as returned by the API)

long_funding_rate: float

Long funding rate, annualised (REST fundingRateLong / 10^30). Positive means longs receive funding; negative means longs pay. Multiply by 100 for annual percentage.

short_funding_rate: float

Short funding rate, annualised (REST fundingRateShort / 10^30). Positive means shorts receive funding; negative means shorts pay. Multiply by 100 for annual percentage.

long_borrowing_rate: float

Long borrowing rate, annualised (REST borrowingRateLong / 10^30). Always non-negative. Multiply by 100 for annual percentage.

short_borrowing_rate: float

Short borrowing rate, annualised (REST borrowingRateShort / 10^30). Always non-negative. Multiply by 100 for annual percentage.

is_listed: bool

Whether this market is currently listed for trading

__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 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().

positive_factor: int

Impact factor for positive (balance-improving) trades (30-decimal int)

negative_factor: int

Impact factor for negative (balance-worsening) trades (30-decimal int)

positive_exponent: int

Exponent factor for positive impact (30-decimal int)

negative_exponent: int

Exponent factor for negative impact (30-decimal int)

max_positive_factor: int

Maximum position impact factor cap for positive impact (30-decimal int). 0 means no explicit cap applies.

max_negative_factor: int

Maximum position impact factor cap for negative impact (30-decimal int). 0 means no explicit cap applies.

__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

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

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

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.

max_position_usd: float

Maximum position size in USD after applying all constraints

pct_of_total_oi: float

The maximum position as a percentage of total (both-side) OI

whale_ok: bool

True if the full portfolio fits within the whale-risk threshold

cap_ok: bool

True if the full portfolio fits within pool capacity

binding_constraint: str

The constraint that limits the position: "none", "whale", or "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

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.

Example:

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