Skip to main content

Workflow

Chain operators, loops, conditionals, sleeps, waits, retries, and chain modifiers. The composition primitives that turn the CLI into a scripting language.


Chain operators

buy $100 ; cancel ; close
buy $100 & cancel
OperatorBehavior
;Top-level chain separator. Fire-and-don't-await.
&Identical semantics to ;.
sleepThe only step the runner blocks on (carries block: true).
legacy @cmd prefixStripped silently (one-time warning per call). Skipped when @<word> is a known user var.

Fire-and-don't-await means each step launches without waiting for the previous step's exchange round-trip. This is intentional — most chains are fire-then-react, not strictly sequential. When you actually need to wait on a specific result, use wait or capture syntax.


sleep

FormEffect
sleep 55 seconds (default unit is seconds)
sleep 250ms250 ms
sleep 5s5 seconds (explicit)
sleep 2m2 minutes

Hard cap 10 minutes. Source: SleepCommand.ts, preprocess/sleep.ts.


wait

Condition-blocked sleep. Polls the local exchange store at 100 ms.

wait <condition> [timeout=<dur>] [for=<dur>]

Condition forms

FormMeaning
wait 5s / wait 250msBare duration — same as sleep
wait time HHMMWait until next occurrence of HHMM UTC
wait position [SYM]Any position, focused or named
wait long [SYM] / wait short [SYM]Side-filtered
wait anypositionAny account, any symbol
wait price > 50000Spot the trigger — uses ask on upside, bid on downside, falls back to last
wait mark > 50000 / wait index < 50000Mark / index price
wait pnl > 200 / pnl < -50uPnL on focused symbol
wait fundingrate > 0.0001Funding rate
wait premium > 5Premium
wait fill / wait fill BTCUSDTWait for any fill on the symbol
wait fill <id> / <id1>,<id2>Wait for a specific order to fill
wait @stop > 0LHS can be a user var (resolves via tracker/live/static)

Comparators

> < >= <= == !=. The exact-compare forms are rarely useful for prices but they exist for integer / zero checks.

Combinators

wait both (price > 50000) and (pnl > 0)
wait either (price < 49000) or (price > 51000)

Combinators nest. Source: preprocess/conditions.ts.

Modifiers

ModifierDefaultCapBehavior
timeout=<dur>30 s10 mGive up after this long
for=<dur>Condition must hold continuously for this window (anti-fakeout)

wait time 1200 and it's currently 12:00:00 UTC — the parser interprets that as "next 12:00 UTC", i.e. ~24 hours from now. Use wait time 1201 if you want the next-minute case.


loop

Fan out one step per matching position. Symbol is appended to the body.

loop <variant>: <body>
<variant>Matches
longsAll long positions
shortsAll short positions
openposAll open positions (open accepted as alias)
allposEvery position (synonym for openpos)
allSame
loop longs: buy 1$
loop shorts: close
loop allpos: cancel

Multi-statement bodies are not supported. If you need one, alias the body and loop the alias:

alias cleanup "cancel; close"
loop longs: cleanup

Source: preprocess/loop.ts.


repeat

repeat 5 (buy 1$; sleep 1m)
CapValue
Max iterations1000
Max nesting depth8

Source: preprocess/repeat.ts.


if / else / end

if (<condition>) (<then-body>) [else (<else-body>)]

<condition> uses the same vocabulary as wait. Evaluated once at preprocess time against current store state, so this is a one-shot conditional, not a runtime loop.

The body is fully reprocessed — nested if, repeat, loop, retry, set ec all compose inside it.

if (long) (close)
if (pnl > 50) (close) else (sleep 5m)
if (position) (chase sell %all% 100% reduce) else (echo "nothing to close")

end

A bare end in the chain (or inside an if branch) terminates the outer chain. Anything after is dropped.

buy $100 at $entry -1%
wait fill
if (pnl < -10) (close; end)
buy $100 at $entry +1%

If the if fires, end cancels the trailing buy.

Source: preprocess/ifElse.ts, preprocess.ts:204-213 (end), :218-275 (if recursion).


retry

retry N <body>

Re-runs <body> up to N times after a failure. First attempt is "try 0", so retry 3 means up to 4 total attempts.

BoundBehavior
N = 0Same as not using retry
N ∈ [0, 10]Accepted
N > 10Falls through as a normal step — the dispatcher will reject it
retry 3 chase buy $100 to 1%
retry 5 close

Source: preprocess/preprocess.ts:31-32, 146-157. Runner side at apps/cli/src/repl.ts:1618+.


Chain modifiers

Mid-chain flags that apply to every subsequent step in the same chain. Idempotent — won't double-inject if the keyword is already on the step.

ModifierEffect
set ecContinue-on-error — subsequent failures print as warnings, chain runs on
set ro / unset roInject reduce into subsequent buy/sell/scale/swarm/chase/twap
set po / unset poInject po into subsequent buy/sell heads. Market orders ignore it
set ec
cancel
close
nuke # all three continue even if one fails
set ro
close # reduce-only is implicit now
cancel
buy $100 # still gets reduce injected
set po
buy $100 at 50000
sell $100 at 50100
unset po
buy $50 best # market-best, post-only no longer active

Source: preprocess/preprocess.ts:20-57, 133-142, 332-356.


po keyword on a single order

You can mark one order post-only without affecting the rest of the chain:

buy $100 at 50000 po

Same effect as set po; buy $100 at 50000; unset po.


Composition cheatsheet

A few canonical combinations:

# retry × repeat × sleep × set ec
repeat 5 (set ec; retry 2 buy 1$; sleep 1m)

# one-shot conditional
if (long) (close)

# fan-out reduce-only chase
loop longs: chase sell 50% reduce

# capture + wait fill + close
@o = buy $100 at 50000; wait fill @o; close

# soft-error cleanup
set ec; cancel; close; nuke

# chain reduce-only
set ro; close; cancel; buy $100

# mid-chain post-only toggle
set po; buy $100 at 50000; sell $100 at 50100; unset po; buy $50 best