跳到主要内容

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
;Sequential — waits for all prior steps to finish before this one runs.
&Parallel — launches without waiting; runs alongside the prior step.
sleep / waitAlways block the chain (carry block: true), regardless of separator.
legacy @cmd prefixStripped silently (one-time warning per call). Skipped when @<word> is a known user var.

; is a barrier: the runner drains every in-flight step before dispatching the next, so close all; buy $1000 waits for the close to complete before buying. & is parallelclose all & buy $1000 fires both at once. Mix them freely: a & b; c runs a and b together, then waits for both before c. repeat joins its iterations with ;, so iterations are sequential by default. For condition-based waits use wait; to act on a specific order use 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