Pack format
A pack is a JSON file. One file, one pack. Put it in ~/.krellbot/packs/.
The client reads the file. It does not execute code from it. A pack is not an order.
There are two formats. Legacy packs (id + public_label only) still list but do not run. New packs include schema_version: 1 and follow the DSL below.
DSL packs
Required keys: schema_version, id, version, label, author, timeframe, indicators, entry, exit, risk, markets. Optional: origin.
schema_versionis1.idis lowercase letters, digits, and dashes; 1 to 32 characters.versionisMAJOR.MINOR.PATCH.timeframeis1h,4h, or1d.label,author,originare at most 120 characters each.indicatorsis a map of names to whitelist functions:sma,ema,wma,vwma,stdev,roc,efficiency_ratio,hma,power_mean,atr,highest,lowest,roofing_filter. Each has its ownlen(2 to 600).entryandexitare conditions. A leaf is[left, op, right]whereopis one of>,<,>=,<=,crosses_above,crosses_below. Conditions nest with{all: [...]}or{any: [...]}up to depth 3.risk.max_account_pctis an integer 1 to 100.risk.stopis either{type: pct, pct: number}or{type: atr, len: int, mult: number}.marketsis 1 to 4 items of{venue: kraken|coinbase, pair: ...}.
The engine never reads a pack file as code. Indicators and stops are computed locally. The engine evaluates the last bar only and returns a single decision: long or flat, plus a stop price.
{
"schema_version": 1,
"id": "trend-follow",
"version": "1.0.0",
"label": "Trend follow",
"author": "krellbot",
"origin": "Written on this machine.",
"timeframe": "1h",
"indicators": {
"sma20": {"fn": "sma", "src": "close", "len": 20}
},
"entry": ["close", ">", "sma20"],
"exit": ["close", "<", "sma20"],
"risk": {
"max_account_pct": 25,
"stop": {"type": "pct", "pct": 5}
},
"markets": [{"venue": "kraken", "pair": "SUIUSD"}]
}
Save that as ~/.krellbot/packs/trend-follow.json, then run krellbot lint ~/.krellbot/packs/trend-follow.json.
Legacy packs
A file with id + public_label and no schema_version is a legacy pack. krellbot list prints it with the marker legacy: not runnable. The engine does not evaluate it.
Required:
id— short name, no spacespublic_label— the namekrellbot listprints
Optional:
rule— one sentence, your wordstimeframe— such as1hvenue_of_history— the venue the history came from
Do not invent a return. A number without dates is not a result.
{
"id": "mine",
"public_label": "Mine",
"rule": "Replace this sentence with your own rule.",
"origin": "Written on this machine.",
"timeframe": "1h"
}
The packs we maintain are not in this repository.