> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sandmark.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Strategy specification

> Every field of a backtest request, and how the engine reads it.

A request body has three required fields, `start`, `end` and `structure`, and five optional sections with
sensible defaults.

```json theme={null}
{
  "name": "My strategy",
  "asset": "DER.BTC_USD",
  "start": "2026-05-01",
  "end": "2026-10-31",
  "structure": { "legs": [ ... ], "expiry": { ... }, "hedge": { ... }, "shared_strike": "..." },
  "lifecycle": { "rules": [ ... ], "entry_weekdays": [ ... ], "exit_weekdays": [ ... ] },
  "capital":   { "initial_equity": 100, "sizing": { ... } },
  "costs":     { "fill": "mark", ... },
  "clock":     { "decision_hour_utc": 8, ... }
}
```

## Top level

**start** `date` *required*

First day, `YYYY-MM-DD`. Must fall inside your [backtest lookback](https://docs.sandmark.com/backtesting/plans-and-limits.md).

**end** `date` *required*

Last day, inclusive.

**asset** `string` (default: DER.BTC\_USD)

`DER.BTC_USD` or `DER.ETH_USD` (inverse, history from September 2021), `DER.SOL_USDC` (from February 2024)
or `DER.XRP_USDC` (from March 2024).

**name** `string` (default: backtest)

A label for the run. It names the files of the `csv` and `xlsx` formats.

## Structure

What to trade. Each position the strategy opens is one instance of this structure.

**structure.legs** `Leg[]` *required*

One to eight legs.

**Leg fields**

**id** `string` *required*

Your name for the leg, such as `call` or `short_put`. Rules refer to it as `leg:<id>`.

**type** `string` *required*

`call`, `put` or `future`.

**direction** `string` *required*

`long` or `short`.

**strike** `object`

How the strike is chosen. Omit on a `future` leg.

* `{"by": "delta", "value": 0.25}`: the strike nearest 25 delta (absolute value, for calls and puts alike)
* `{"by": "moneyness", "value": 1.03}`: the strike nearest 103% of the forward
* `{"by": "absolute", "value": 120000}`: a fixed strike price

**ratio** `number` (default: 1.0)

Relative size. `2` with a `1` on another leg builds a ratio spread. The sign lives in `direction`.

**expiry** `object`

Overrides `structure.expiry` for this leg, which is how calendars and diagonals are built. Same fields as
below.

**structure.expiry** `object`

Which expiry the legs trade.

**Expiry fields**

**by** `string` (default: monthly)

`monthly` (last Friday of the month), `third_friday`, or `listed` (every listed expiry, including weeklies
and dailies).

**nth** `integer` (default: 1)

Take the nth qualifying expiry. `2` is the second monthly, for a back leg.

**min\_dte** `number` (default: 0)

Skip expiries closer than this many days.

**target\_dte** `number`

Aim for a tenor instead: the listed expiry nearest this many days (above `min_dte`). Better than a floor
where the expiry ladder has gaps.

**weekdays** `string[]`

Only expiries settling on these days, such as `["friday"]`. Applied before `nth`, `min_dte` and
`target_dte`.

**structure.shared\_strike** `string`

The `id` of a leg whose strike every other option leg adopts. Two legs both asking for 50 delta land on
different strikes; anchoring them makes a true straddle. Use it for calendars too.

**structure.hedge** `object`

Optional hedge, off by default.

**Hedge fields**

**enabled** `boolean` (default: false)

Turn the hedge on.

**greek** `string` (default: delta)

`delta` is hedged with dated futures. `vega` and `gamma` are hedged with a listed option (a future has
neither), and that option's delta is then hedged in futures.

**band** `number` (default: 0.05)

Net delta tolerated before rebalancing, absolute.

**numeraire** `string` (default: coin)

Hedge in `coin` or `usd` terms. With `usd`, `holding_hedge_ratio` can also hedge part of the coin balance.

**match\_expiry** `boolean` (default: true)

Hedge with the future of the same expiry as the options.

**min\_dte** `number` (default: 1)

Roll the hedge future before this many days to expiry.

**allow\_perpetual** `boolean` (default: false)

Allow the perpetual as a hedge. Off by default because funding is not modelled.

**option\_delta** `number` (default: 0.5)

For vega or gamma hedges: delta of the hedge option.

**option\_min\_dte** `number` (default: 30)

For vega or gamma hedges: minimum tenor of the hedge option, and when it is rolled.

**option\_band** `number` (default: 0.1)

For vega or gamma hedges: residual tolerated, as a fraction of the book's own greek.

## Lifecycle

When positions open and close. With no rules and no weekdays, a position opens whenever the strategy is flat
and is held to expiry.

**lifecycle.rules** `Rule[]`

Up to 16 exit rules, checked in order at every decision time. The first rule that fires closes the position,
and its `name` is recorded as the trade's `reason`.

```json theme={null}
{
  "name": "take_profit_50",
  "when": { "predicate": { "subject": "structure", "metric": "premium", "op": "below",
                           "value": -0.5, "unit": "percent", "reference": "entry" } },
  "do": { "action": "close_all" }
}
```

**Predicate fields**

**subject** `string` (default: structure)

What is measured: `structure`, `leg:<id>`, `underlying` or `portfolio`.

**metric** `string` *required*

`premium`, `pnl`, `pnl_pct`, `delta`, `contract_delta`, `gamma`, `vega`, `theta`, `iv`, `dte`,
`days_held`, `underlying_price` or `equity`.

**op** `string` (default: above)

`above` and `below` test the level at every decision time. `crosses_above` and `crosses_below` fire only
at the moment it is crossed.

**value** `number` *required*

The threshold.

**unit** `string` (default: absolute)

How `value` is read. `absolute` is the metric itself. `percent` is a fractional change from `reference`:
`-0.75` is a 75% fall, `1.0` a doubling. `coin`, `ticks`, `days` and `vol_points` are changes in those
units.

**reference** `string` (default: absolute)

What a change is measured from: `entry`, `prev_bar`, `high_water` or `low_water` (best or worst since
entry). Use `absolute` for a plain level.

Combine predicates with `any` or `all`, which can nest:

```json theme={null}
"when": { "any": [
  { "predicate": { "metric": "premium", "op": "above", "value": 0.5, "unit": "percent", "reference": "entry" } },
  { "predicate": { "metric": "dte", "op": "below", "value": 7 } }
] }
```

`do.action` is `close_all` (the whole structure) or `close` (only `do.target`, such as `leg:short_call`).

**lifecycle.entry\_weekdays** `string[]`

Open new positions only on these days, such as `["friday"]`.

**lifecycle.exit\_weekdays** `string[]`

Close whatever is open on these days, at the decision hour. Together with `entry_weekdays` this builds
weekend and weekly strategies.

## Capital and sizing

**capital.initial\_equity** `number` (default: 100)

Starting equity in coin.

**capital.sizing** `object`

How big each new position is.

**Sizing fields**

**mode** `string` (default: percent\_of\_equity)

* `contracts`: a fixed number of contracts
* `coin_notional`: a fixed notional in coin
* `percent_of_equity`: a fraction of current equity, so size compounds
* `percent_of_initial_equity`: a fraction of starting equity, so size stays flat
* `premium_budget`: spend a fraction of equity on premium, for long-premium strategies

**value** `number` (default: 0.5)

The amount for `mode`: `0.2` is 20% for the percentage modes.

**lot\_step** `number` (default: 0.1)

Round sizes to this contract increment.

**min\_contracts** `number` (default: 0.1)

Smallest position size, in contracts.

## Costs

**costs.fill** `string` (default: mark)

`mark` fills at the mark price. `bid_ask` crosses the spread: buys at the ask and sells at the bid, falling
back to `fallback_spread_pct` around the mark when no quote exists.

**costs.slippage\_bps** `number` (default: 0)

Extra slippage on every fill, in basis points.

**costs.taker\_fee\_rate** `number` (default: 0.0003)

Taker fee rate applied to every fill.

**costs.fee\_premium\_cap** `number` (default: 0.125)

Fees are capped at this fraction of the option's premium, as on the exchange.

**costs.fallback\_spread\_pct** `number` (default: 0.05)

Assumed spread when `fill` is `bid_ask` and no quote is available.

## Clock

**clock.decision\_hour\_utc** `integer | null` (default: 8)

The hour, UTC, at which the strategy looks at the market once a day. 08:00 is the expiry time. Set `null` to
look every hour: much finer, but about 24 times more data, so keep hourly runs to short windows.

**clock.max\_dte** `number` (default: 400)

Ignore contracts further out than this.

**clock.trim\_to\_first\_trade** `boolean` (default: true)

Start the reported equity curve at the first trade, so a slow start doesn't dilute the statistics.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.