# Built-In Functions (/scripting/built-ins)



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-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:

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

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

## `ctx.study.sma` [#ctxstudysma]

Calculates a simple moving average.

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

Returns:

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

## `ctx.study.ema` [#ctxstudyema]

Calculates an exponential moving average.

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

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

## `ctx.study.cvd` [#ctxstudycvd]

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.

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

You can also pass a single live record:

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

Returns:

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

Window VD example:

```js
export function onData(ctx, input, history) {
  const selector = 'btc@vd@hyperliquidf@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:

```js
export function onData(ctx, input, history) {
  const selector = 'btc@vd@hyperliquidf@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-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:

```js
export function onData(ctx, input, history) {
  const book = history.source('btc@orderbook@bulkf', 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` [#ctxstudyspread]

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

```js
const result = ctx.study.spread(book)
```

Returns:

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

## `ctx.study.depth` [#ctxstudydepth]

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

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

Returns:

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

## `ctx.study.imbalance` [#ctxstudyimbalance]

Calculates book imbalance across a fixed depth.

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

Returns:

```ts
{
  bid_volume: number
  ask_volume: number
  imbalance: number
}
```

## `ctx.study.slippage` [#ctxstudyslippage]

Estimates market-order slippage against available book levels.

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

Returns:

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

## `ctx.study.vamp` [#ctxstudyvamp]

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

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

Returns:

```ts
{
  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
}
```
