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:
How much open interest (OI) can still be added before the pool reserve cap is hit (
available_long_oi_usd/available_short_oi_usd).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, andgetPriceImpactUsdForCrossoverRebalance.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 the maximum position size subject to whale-risk constraints. |
Estimate price impact for a position using the GMX v2 formula. |
|
|
Fetch price impact parameters from the GMX DataStore contract. |
|
Find the maximum position size that keeps price impact within a threshold. |
|
Parse a single market entry from the |
Classes
Market depth snapshot for a single GMX v2 perpetual market. |
|
Result of whale-risk position sizing for one side of a market. |
|
Per-market price impact parameters read from the GMX DataStore contract. |
- class MarketDepthInfo
Bases:
objectMarket depth snapshot for a single GMX v2 perpetual market.
Populated from the
/markets/infoREST endpoint (cached 60 s). All USD values are already divided by10^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)
- 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)
- 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_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.
- __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
market_token_address (eth_typing.evm.HexAddress) –
market_symbol (str) –
index_token_address (eth_typing.evm.HexAddress) –
long_token_address (eth_typing.evm.HexAddress) –
short_token_address (eth_typing.evm.HexAddress) –
long_open_interest_usd (float) –
short_open_interest_usd (float) –
max_long_open_interest_usd (float) –
max_short_open_interest_usd (float) –
available_long_oi_usd (float) –
available_short_oi_usd (float) –
long_pool_amount (float) –
short_pool_amount (float) –
long_funding_rate (float) –
short_funding_rate (float) –
long_borrowing_rate (float) –
short_borrowing_rate (float) –
is_listed (bool) –
- Return type
None
- class PriceImpactParams
Bases:
objectPer-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().- max_positive_factor: int
Maximum position impact factor cap for positive impact (30-decimal int).
0means no explicit cap applies.
- max_negative_factor: int
Maximum position impact factor cap for negative impact (30-decimal int).
0means no explicit cap applies.
- __init__(positive_factor, negative_factor, positive_exponent, negative_exponent, max_positive_factor, max_negative_factor)
- parse_market_depth(market_data)
Parse a single market entry from the
/markets/infoREST response.- Parameters
market_data (dict[str, Any]) – Raw market dictionary as returned inside
response["markets"].- Returns
Structured
MarketDepthInfofor this market.- Return type
- 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
PriceImpactParamsobtained viafetch_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
initialDiffandnextDiffare 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_impacthelper ineth_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) –
Truefor a long position,Falsefor shortparams (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
- 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 individualgetUintcalls on the DataStore contract.- Parameters
config (eth_defi.gmx.config.GMXConfig) – Initialised GMX configuration with web3 connection
market_address (eth_typing.evm.HexAddress) – GMX market token address (
MarketDepthInfo.market_token_address)
- Returns
Populated
PriceImpactParams- Return type
- 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) –
Truefor a long position,Falsefor shortmax_price_impact_bps (float) – Maximum acceptable price impact expressed in basis points (1 bps = 0.01 %). E.g.
5.0means 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 toGMX_DEFAULT_SEARCH_MAX_USD($100 M), which covers typical GMX market sizes. UseMarketDepthInfo.available_long_oi_usdorMarketDepthInfo.available_short_oi_usdhere 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_bpsbasis points. Returns0.0if even the smallest position exceeds the threshold.- Return type
- class PositionSizingResult
Bases:
objectResult 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:Portfolio: the total capital available (
portfolio_usd).Whale risk: a fraction of the side’s open interest (
max_oi_pct * side_oi), so the position doesn’t move the market disproportionately.Pool capacity: the remaining OI capacity before the reserve cap.
- 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_pctof 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 000on 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.025means 2.5 %.is_long (bool) –
Truefor long side,Falsefor short side
- Returns
PositionSizingResultwith the capped position and diagnostics- Return type