kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
171 lines (135 loc) • 9.06 kB
Markdown
# First Plan — a bounded-risk contingent program
A **Plan** is a standing, bounded-risk contingent program: **trigger → actions → bracket →
invalidation → TTL**. The agent authors it once; the runtime fires it at machine speed and
informs the author in parallel — **fire-then-inform**. The agent is never in the hot path.
This page reads one Plan clause by clause.
```kestrel id=plan-open-drive check=roundtrip
PLAN open-drive budget 0.25R ttl 15:55
USING signal SPX exec ODX 0dte
WHEN spot crosses above hod
DO buy 2 +1 C @ ask
TP 2x frac 0.5 @ fair
EXIT spot < vwap held 120s @ fair
```
This Plan is the marquee `kestrel card first-plan` prints, and it is **authored to run on
the free 0DTE options cell** — the one `kestrel sim` lists with the `ODX` instrument. Run it
with `kestrel sim <that-cell> --plans <file>`, copy it verbatim, and it *fills*. Every choice
below is made against that one tape; the recurring lesson is that **a Plan must be authored
to the tape it will run on** — its instrument universe, the series it writes, and how it
fills.
## The header: bounded risk is a type
```
PLAN open-drive budget 0.25R ttl 15:55
```
Every Plan is defined-risk before it can arm. `budget 0.25R` is a **positive risk
fraction** — the position is bounded by construction, and a non-positive budget is refused
at parse time. `ttl 15:55` is the time-to-live: the Plan expires at the clock.
This Plan carries **no `regime` gate**, so it arms the moment it is submitted — which is what
you want on a synthetic or free-tier tape. An optional `regime {scope: value}` clause is a
**hard arming gate**, not a label: a Plan that carries one stays `authored (blocked)` — it
never arms, never fires — until the session's tape writes a matching `REGIME` event, and a
tape with no regime writer can *never* satisfy it. Free and synthetic tapes carry no regime
stream, so a gated Plan silently places zero orders on them; **omit the gate to trade a free
cell**, and add one only when your tape (or a live feed) actually writes the regime you gate
on. `validate --arm` warns you at author time when a gate can never fire on the context you
hand it — the same dead-on-arrival verdict a run surfaces, so you never learn it from an
empty blotter.
`USING signal SPX exec ODX 0dte` sets scoped defaults for the document — read the signal off
one instrument, **execute on another** — so each leg need not repeat them.
**The exec instrument must live on the tape you will run against — this is the first way a
Plan is authored to its tape.** A leg executes on the ambient `exec` symbol, and the runtime
can only fill a leg whose instrument is actually quoted on the session's tape. The free
options cell here is an **`ODX` 0DTE chain**, so `exec ODX` resolves against a real chain and
fills. Name an *off-tape* instrument instead — `exec SPY 0dte` on this ODX cell — and the
option leg is **unresolvable**: there is no SPY chain to price the strike against, so the
runtime fail-closes the leg and the Plan places **zero orders**. It is not an error you see;
it is a silent, empty blotter — the same dead-on-arrival outcome as a trigger that reads a
series the tape never writes (below). Match `exec` to the tape's instrument universe: name
the cell's own instrument — here `ODX`, the symbol `kestrel sim` lists for the free cell.
Run the cell and the blotter tells you plainly — an on-tape exec fills, an off-tape one
places nothing.
## The trigger: WHEN it may fire
```
WHEN spot crosses above hod
```
The `WHEN` clause is the trigger algebra: named series (`spot`, `hod`) and predicates
(`crosses above`) composed with `AND / OR / NOT`. Here the opening drive fires on a clean
break of the high-of-day — the momentum signal the cell is built around. This same algebra
is shared with Wake and Grade; see the [shared lexical core](./lexical-core.md).
**Every series in a `WHEN` must be a stream the tape actually writes — the second way a Plan
is authored to its tape.** You could tighten this trigger with an acceleration gate,
`WHEN spot crosses above hod AND velocity(5m) >= p95` — `p95` is a **baseline-relative**
threshold (the 95th percentile of that window's own trailing distribution, not an absolute
number, so the Plan stays portable across instruments). But `velocity(5m)` is a *derived
series a tape has to carry*, and a coarse free or synthetic tape may not write one. A `WHEN`
that reads an unwritten series never resolves true, so the Plan expires having placed **zero
orders** — the same silent empty blotter as an off-tape `exec`. So the marquee arms on the
bare `crosses above hod`, which the free cell does write; add the velocity gate only once
your tape (or a live feed) carries velocity — and the same check applies: run the cell and
let the blotter confirm the trigger actually fires.
## The action: what fires, and at what price
```
DO buy 2 +1 C @ ask
```
When the trigger confirms, the runtime places the order: buy two calls, one strike out
(`+1`). The price expression is the discipline. On a fast opening drive you want the fill
*now*, so this leg **lifts the offer** (`@ ask`) — it prices through the resting queue and
crosses immediately. This is the **third way a Plan is authored to its tape**: the runtime
only fills what actually crosses the book, and on the short free cell a limit resting *below*
the market never gets there before the tape settles. Lift the offer and the marquee fills;
rest under it and you get another silent empty blotter.
Lifting the offer is the right call *on a momentum entry you must not miss*. A patient
entry — a fade, or any thesis where a worse price is a better one — inverts the discipline:
there you rest, and you cap what you will pay. `fair` is a **value** anchor (model worth);
`mid` is a **book** anchor (where the queue sits). `@ min(fair, mid) peg cap fair` rests at
the better of the two, `peg` re-prices as the market moves, and `cap fair` guarantees you
**never pay past fair value** — a quote is where the queue is, never what a thing is worth.
The [shared lexical core](./lexical-core.md) shows that resting, capped discipline on the
fade Plan.
The leg above is an **option** leg — a quantity, a strike (`+1`), and a right (`C`/`P`). To
buy the underlying instead, write an **equity** leg: the `shares` marker replaces the
strike+right, and the ambient `exec` symbol is the instrument (ADR-0017).
```
DO buy 100 shares @ spot
```
`buy 100 shares` is complete — an equity/spot leg carries no strike or right, and `spot` is
its price anchor. Omit `shares` and write `buy 100 @ spot` and the parser refuses it,
naming both continuations: a strike for an option leg, or `shares` for an equity leg.
## The bracket: taking profit
```
TP 2x frac 0.5 @ fair
```
`TP` (take-profit) banks a fraction of the position at a multiple — here, half the position
at 2x, resting at a value anchor. Take-profit tiers run in the manage phase of every fired
Plan.
## The out: EXIT on the underlying, never on the mark
```
EXIT spot < vwap held 120s @ fair
```
An `EXIT` is an active out — the thesis is dead, get flat. Crucially it conditions on the
**underlying** (`spot < vwap held 120s`), never on the option's mark. A quote is a health
signal, not a value; an EXIT that watched the mark would be refused at parse time. Giveback
that holds for two minutes below VWAP means the drive is over.
## Two more contingent clauses
Two clauses this Plan does not use, but every author should know, express the rest of the
contingency:
- **RELOAD** adds rungs into the thesis on further confirmation — for a fade, a worse price
is a *better* entry, so the ladder itself is the thesis.
- **INVALIDATE** is distinct from EXIT: the thesis broke, so **stop adding** and ride the
bounded remainder — it does not flatten.
The [shared lexical core](./lexical-core.md) page shows a fade Plan built from RELOAD and
INVALIDATE, next to a Wake and a Grade over the same series.
## What is real today
The Plan runtime is the most exercised part of Kestrel — it drives a Plan through authored →
armed → fired → managing → done and has been run end-to-end in a **mechanically-graded
practice** session. That is not a certified result; the [certified honest-tier cohort is
0](./capability-truth.md). Read each clause's runtime and evidence axes on the [status
page](./status.md) before treating any of it as proven trading edge.
## Next
- **[First Grade](./first-grade.md)** — the fourth kind: *did it actually work?* The honest
result of a run — graded, never asserted.
- **[Adopt](./adopt.md)** — the exit escape hatch: when your `EXIT` sits in a *replacement* plan
that opened no leg, `ARM … foreach held leg` carries the held position across the wake so the
covered sell can close it. Walks the whole fill → adopt → exit loop with a runnable example.
- **[The shared lexical core](./lexical-core.md)** — the series and price expressions a Plan
shares with the other three statement kinds.