Skip to content

Strategy DSL

A strategy is a small directed graph that turns market features into a target exposure in [−1, +1], evaluated on every 15-minute bar.

{
"schema": "pnl.strategy.v1",
"name": "Funding Momentum Squeeze",
"targetMarket": "ETH-PERP",
"leverageCap": 2000000,
"deadband": 250000,
"adjustmentRate": 1000000,
"output": "out",
"nodes": [
{ "id": "trend", "type": "indicator", "scope": "local",
"indicator": "EMA_SPREAD", "params": { "fast": "3h", "slow": "12h" },
"zscore": "7d" },
{ "id": "carry", "type": "indicator", "scope": "local",
"indicator": "FUNDING_ZSCORE", "params": { "window": "7d" } },
{ "id": "mix", "type": "linear_combination",
"inputs": [{ "nodeId": "trend", "weight": 650000 },
{ "nodeId": "carry", "weight": -350000 }] },
{ "id": "band", "type": "deadband", "input": "mix", "threshold": 150000 },
{ "id": "out", "type": "activation", "input": "band",
"function": "tanh", "gain": 1750000 }
]
}

Numbers are scaled integers. 650000 is 0.65, at 1e6 fixed point. A float round-trips through JSON as 0.65 in one runtime and 0.6500000000000001 in another after a single arithmetic step — two different hashes for one strategy. Integers have exactly one spelling. The interface shows you 0.65.

Windows are durations, not bar counts. "7d", never 168. A bar count means something different at a different bar size; a duration means the same thing always.

Local — the traded market’s own series: EMA_SPREAD, RSI, BOLLINGER_PCT_B, FUNDING_ZSCORE, RETURN.

Global — the whole venue’s cross-section, shared by every strategy: BENCHMARK_MOM, VENUE_FUNDING_BIAS, MEDIAN_RETURN, VENUE_BREADTH, RELATIVE_STRENGTH.

Global sensors are computed over the markets listed at that moment, not over today’s list applied backwards. A cross-section built from today’s listings quietly drops every market that has since died — and the ones that die are the ones that did badly, so every median would be biased upward for every strategy at once.

node does
linear_combination weighted sum of inputs
deadband zero inside a threshold, continuous at its edge
smooth EMA with a half-life, to damp single-bar noise
activation tanh, softsign or clamp, bounding the output

The output node must be an activation, so the target exposure is bounded by construction rather than by hoping the weights stay small.