Tick Structure
Discrete price grid
Midnight enforces a discrete price grid for offers. Offers can only be placed at prices corresponding to valid ticks. This prevents economically meaningless undercutting (offering at a price 1 wei better) and creates natural price levels around which liquidity concentrates.
The market state endpoint gives you tick_granularity , the practical constraint a maker needs before constructing an offer:
// Check what tick values are valid for this market
GET /v0/midnight/markets/{marketId}/state
// In the response:
"tick_granularity": 1Valid ticks must be multiples of this value.
tick_granularity: 1 means every integer tick is validtick_granularity: 2 would mean only even ticks (42, 40, 38...)
Constant relative change
The tick grid is designed so that consecutive ticks correspond to a constant relative change in implied return, not a constant absolute price step. This matters because the end goal of the activity is a return, and a fixed price increment implies different rate increments depending on how far prices are from par.
// The unquantized price at tick n, where δ is the target relative increment in implied return
P(n) = 1 / (1 + (1 + δ)(N/2 − n))
// Consecutive ticks satisfy:
return(n−1) = (1 + δ) × return(n)This means the relative change in implied rate is constant across the grid (each step is the same percentage bigger than the last, not the same absolute amount). δ is fixed at the protocol layer (δ = 0.02, i.e. 2%). All markets share the same tick spacing and δ is not configurable per market.
In order to see the actual tick-to-price mapping where liquidity exists, use the following query:
GET /v0/midnight/books/{marketId}/asks?depth=4
// Each price level shows the tick and its corresponding price:
{
"data": [
{ "tick": 42, "price": "952380952380952320", "units": "10000000000", "count": 3 },
{ "tick": 43, "price": "951474785918173312", "units": "18500000000", "count": 5 },
{ "tick": 44, "price": "950552270869375104", "units": "7200000000", "count": 2 },
{ "tick": 45, "price": "949613146596339456", "units": "4100000000", "count": 1 }
]
}
// tick 42: price ≈ 0.9524 → rate = 5.000%
// tick 43: price ≈ 0.9515 → rate = 5.100% (5.100 / 5.000 = 1.02 exactly)
// tick 44: price ≈ 0.9506 → rate = 5.202% (5.202 / 5.100 = 1.02 exactly)
// tick 45: price ≈ 0.9496 → rate = 5.306% (5.306 / 5.202 = 1.02 exactly)
// Every consecutive pair: rate(n-1) / rate(n) = 1.02 = 1 + δNear par (P ≈ 1), where rate is close to zero, the rate-based spacing becomes impractically fine, so prices are quantized to a granularity of ε = 1×10⁻⁶. This lets the same immutable grid handle both far-from-par and near-par quoting.
The protocol is designed so that tick spacing could be refined per market in the future (only made finer, never coarser). A market would start with wide ticks (δ=2%) and graduate to tighter quoting (δ=1% or δ=0.5%) as liquidity deepens.
The definition of ticks ensures that enabling finer spacing would never invalidate existing offers. This capability is not yet active: all markets currently share a single fixed grid at δ=0.02.