Market LabDocs
Scripting

Built-In Functions

Market Lab helper functions exposed to JavaScript scripts.

Built-In Functions

Scripts can call helper functions through ctx.study inside onData(ctx, input, history).

These helpers execute the same Rust functions used by Market Lab's built-in study commands. JavaScript only passes inputs and receives the serialized result; it does not maintain a separate calculation implementation.

Candle Functions

Candle helpers use a retained candle list from history.source(selector).

Available helpers:

  • ctx.study.sma(candles, { field, window })
  • ctx.study.ema(candles, { field, window })

Example:

export function onData(ctx, input, history) {
  const candles = history.source('candles@binancef@mmt')
  const sma20 = ctx.study.sma(candles, { field: 'c', window: 20 })

  return {
    metrics: {
      sma20: sma20.latest,
    },
  }
}

ctx.study.sma

Calculates a simple moving average.

const result = ctx.study.sma(candles, {
  field: 'c',
  window: 20,
})

Returns:

{
  latest: number | null
  previous: number | null
  points: Array<number | null>
}

ctx.study.ema

Calculates an exponential moving average.

const result = ctx.study.ema(candles, {
  field: 'c',
  window: 20,
})

EMA is seeded with the SMA of the first full window.

ctx.study.cvd

Calculates cumulative volume delta from MMT VD candles only.

Do not pass normal OHLCVT candles into this helper. CVD in Market Lab is tied to the vd source because MMT already buckets the underlying trades by notional size.

const vd = history.source('vd@hyperliquid@mmt')
const result = ctx.study.cvd(vd, {
  bucket: input.source_configs['vd@hyperliquid@mmt'].bucket,
})

You can also pass a single live record:

const current = history.source('vd@hyperliquid@mmt', 0)
const result = ctx.study.cvd(current, {
  bucket: input.source_configs['vd@hyperliquid@mmt'].bucket,
})

Returns:

{
  latest: number | null
  previous: number | null
  delta: number
  bucket: number
  points: Array<{
    t: number | null
    delta: number
    cumulative: number
  }>
}

Window VD example:

export function onData(ctx, input, history) {
  const selector = 'vd@hyperliquid@mmt'
  const cvd = ctx.study.cvd(history.source(selector), {
    bucket: input.source_configs[selector].bucket,
  })

  return {
    metrics: {
      cvd_delta: cvd.delta,
      latest_cvd: cvd.latest,
      points: cvd.points.length,
    },
  }
}

Live VD example:

export function onData(ctx, input, history) {
  const selector = 'vd@hyperliquid@mmt'
  if (input.source !== selector) return

  const current = history.source(selector, 0)
  if (!current) return

  const cvd = ctx.study.cvd(current, {
    bucket: input.source_configs[selector].bucket,
  })

  return {
    metrics: {
      vd_delta: cvd.delta,
      latest_cvd: cvd.latest,
    },
  }
}

Orderbook Functions

Orderbook helpers use a snapshot from history.source(selector, 0).

Available helpers:

  • ctx.study.spread(book)
  • ctx.study.depth(book, { levels })
  • ctx.study.imbalance(book, { depth })
  • ctx.study.slippage(book, { side, notional })
  • ctx.study.vamp(book, { dollar_depth })

Example:

export function onData(ctx, input, history) {
  const book = history.source('orderbook@bulk', 0)
  if (!book) return
  const spread = ctx.study.spread(book)
  const slippage = ctx.study.slippage(book, {
    side: 'buy',
    notional: 100000,
  })

  return {
    metrics: {
      spread_bps: spread.spread_bps,
      slippage_bps: slippage.slippage_bps,
    },
  }
}

ctx.study.spread

Calculates best bid, best ask, absolute spread, spread in basis points, and mid price.

const result = ctx.study.spread(book)

Returns:

{
  best_bid: number
  best_ask: number
  spread_abs: number
  spread_bps: number
  mid: number
}

ctx.study.depth

Sums base and quote depth across a fixed number of levels.

const result = ctx.study.depth(book, {
  levels: 20,
})

Returns:

{
  bid_base: number
  ask_base: number
  bid_quote: number
  ask_quote: number
  total_quote: number
}

ctx.study.imbalance

Calculates book imbalance across a fixed depth.

const result = ctx.study.imbalance(book, {
  depth: 20,
})

Returns:

{
  bid_volume: number
  ask_volume: number
  imbalance: number
}

ctx.study.slippage

Estimates market-order slippage against available book levels.

const result = ctx.study.slippage(book, {
  side: 'buy',
  notional: 100000,
})

Returns:

{
  avg_fill_price: number
  best_price: number
  slippage_abs: number
  slippage_bps: number
  levels_consumed: number
}

ctx.study.vamp

Calculates VAMP from bid and ask VWAP at a target quote depth.

const result = ctx.study.vamp(book, {
  dollar_depth: 250000,
})

Returns:

{
  ask_vwap: number
  bid_vwap: number
  vamp: number
  ask_levels_consumed: number
  bid_levels_consumed: number
  max_reachable_quote_ask: number
  max_reachable_quote_bid: number
  complete: boolean
}

On this page