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

# Strategy spec

> The typed condition tree the backtest + paper-trading engines consume.

A strategy is a JSON object with three condition trees — `entry`,
`take_profit`, `stop_loss` — plus an `execution_params` block. The
same shape powers the visual Strategy Builder, the backtest engine,
and the paper trader.

## Top-level shape

```json theme={null}
{
  "name": "Endgame BTC 5m",
  "ticker": "BTC",
  "event_type": "5m",
  "trade_logic": "always_down",
  "entry": { ... condition tree ... },
  "take_profit": { ... condition tree ... },
  "stop_loss":  { ... condition tree ... },
  "execution_params": {
    "size_usd": 7.5,
    "fill_mode": "walk_book",
    "max_fill_price": 0.985,
    "max_trades_per_market": 1
  }
}
```

## Condition tree

A tree node is either a **group** (AND / OR over children) or a
**leaf** (a typed primitive condition).

### Group node

```json theme={null}
{
  "op": "AND",
  "children": [ <node>, <node>, ... ]
}
```

`op` is `"AND"` or `"OR"`. Children can themselves be groups, so trees
nest arbitrarily.

### Leaf node primitives

```json theme={null}
{ "type": "token_price",            "side": "yes", "op": "<=", "value": 0.985 }
{ "type": "spread",                 "side": "yes", "op": ">=", "value": 0.02  }
{ "type": "time_to_resolution_s",                  "op": "<=", "value": 120   }
{ "type": "time_since_market_open_s",              "op": ">=", "value": 30    }
{ "type": "coin_move_since_open_usd",              "op": "<=", "value": -50   }
{ "type": "coin_move_since_open_pct",              "op": "<=", "value": -0.15 }
{ "type": "coin_price_volatility",   "window_sec": 60, "op": ">=", "value": 50 }
{ "type": "token_price_volatility",  "side": "yes", "window_sec": 60, "op": ">=", "value": 0.01 }
```

| Field        | Notes                                                                |
| ------------ | -------------------------------------------------------------------- |
| `type`       | Required. One of the eight primitives above.                         |
| `side`       | `"yes"` or `"no"` — only for token-side primitives.                  |
| `op`         | `">=", "<=", ">", "<", "==", "!=", "crosses_above", "crosses_below"` |
| `value`      | Comparison RHS. Number.                                              |
| `window_sec` | Only for volatility primitives. Lookback.                            |

`crosses_above` / `crosses_below` use the immediately-preceding
snapshot — true if the threshold was crossed in this step.

## Empty trees

An empty tree is equivalent to a constant:

* `entry: {op: "AND", children: []}` → always fires on first fillable
  snapshot.
* `take_profit / stop_loss: {op: "AND", children: []}` → never fires
  via that path; trade exits only at resolution.

## Resolution risk modeling

If a market resolves to an outcome other than `Up` / `Down` (UMA
dispute, N/A), the position can resolve to a **refund** rather than $0
/ $1. The engine models this via the `resolution_risk` block in the
backtest response — each trade's `pnl` is the engine's best estimate
given Polymarket's actual outcome.

## Worked example — endgame

The "endgame sniper" strategy our [public audit](https://polyquantlab.com/audit)
tracks looks like:

```json theme={null}
{
  "ticker": "BTC",
  "event_type": "5m",
  "trade_logic": "always_down",
  "entry": {
    "op": "AND",
    "children": [
      { "type": "time_to_resolution_s",       "op": "<=", "value": 120  },
      { "type": "token_price", "side": "no",   "op": "<=", "value": 0.985 },
      { "type": "coin_move_since_open_pct",    "op": "<=", "value": -0.15 }
    ]
  },
  "take_profit": { "op": "AND", "children": [] },
  "stop_loss":   { "op": "AND", "children": [] },
  "execution_params": {
    "size_usd": 7.5,
    "fill_mode": "walk_book",
    "max_fill_price": 0.985,
    "max_trades_per_market": 1
  }
}
```

POST to [`/v1/backtest`](/docs/api-reference/backtest/run); the engine
replays it across the most-recent N markets and returns realised PnL.
