fix: correct DSL mistakes from observed R1 failures

- ADX: clarify it is a FuncName inside {"kind":"func","name":"adx",...},
  not a Condition kind — with inline usage example (ADX > 25 filter)
- Expr "kind" field: add explicit note that every Expr object requires
  "kind"; {"field":"close"} without "kind" is rejected by the API
- MACD: add Example 4 showing full crossover strategy composed from
  bin_op(sub, ema12, ema26) and apply_func(ema,9) as signal line

All three mistakes were observed across consecutive R1-32B runs and
caused repeated API submission failures. Each prompt addition follows
the same pattern as the successful bollinger_upper fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-09 20:11:05 +02:00
parent 55e41b6795
commit 8d53d6383d

View File

@@ -52,6 +52,10 @@ sma, ema, wma, rsi, std_dev, sum, highest, lowest, atr, supertrend, adx,
bollinger_upper, bollinger_lower — applied to any candle field (open/high/low/close/volume) bollinger_upper, bollinger_lower — applied to any candle field (open/high/low/close/volume)
with configurable period and optional offset. with configurable period and optional offset.
These are FuncNames used INSIDE `{{"kind":"func","name":"...","period":N}}` expressions.
`atr`, `adx`, and `supertrend` use OHLC internally and ignore the `field` parameter.
To use ADX as a trend-strength filter: `{{"kind":"compare","left":{{"kind":"func","name":"adx","period":14}},"op":">","right":{{"kind":"literal","value":"25"}}}}`
### Composed indicators (apply_func) ### Composed indicators (apply_func)
Apply rolling functions to arbitrary expressions: EMA of EMA, Hull MA (WMA of expression), Apply rolling functions to arbitrary expressions: EMA of EMA, Hull MA (WMA of expression),
VWAP (sum of close*volume / sum of volume), standard deviation of returns, etc. VWAP (sum of close*volume / sum of volume), standard deviation of returns, etc.
@@ -146,6 +150,8 @@ Common mistakes to NEVER make:
- `"kind": "bars_since_entry"` is a valid standalone Expr (no extra fields needed). - `"kind": "bars_since_entry"` is a valid standalone Expr (no extra fields needed).
Do NOT put `"bars_since_entry"` as a `"name"` inside `{{"kind":"func",...}}` — that is WRONG. Do NOT put `"bars_since_entry"` as a `"name"` inside `{{"kind":"func",...}}` — that is WRONG.
- `"kind": "expr_field"` does NOT exist. Use `{{"kind":"field","field":"close"}}`. - `"kind": "expr_field"` does NOT exist. Use `{{"kind":"field","field":"close"}}`.
- Every Expr object MUST have a `"kind"` field. `{{"field":"close"}}` is WRONG — missing `"kind"`.
CORRECT: `{{"kind":"field","field":"close"}}`. The `"kind"` is never optional.
- `rsi`, `adx`, `supertrend` are NOT valid inside `apply_func`. Use only `apply_func` - `rsi`, `adx`, `supertrend` are NOT valid inside `apply_func`. Use only `apply_func`
with `ApplyFuncName` values: `highest`, `lowest`, `sma`, `ema`, `wma`, `std_dev`, `sum`, with `ApplyFuncName` values: `highest`, `lowest`, `sma`, `ema`, `wma`, `std_dev`, `sum`,
`bollinger_upper`, `bollinger_lower`. `bollinger_upper`, `bollinger_lower`.
@@ -154,6 +160,9 @@ Common mistakes to NEVER make:
- `bollinger_upper` and `bollinger_lower` are FUNC NAMES, not Expr kinds. To compare close to the upper band: - `bollinger_upper` and `bollinger_lower` are FUNC NAMES, not Expr kinds. To compare close to the upper band:
`{{"kind":"compare","left":{{"kind":"field","field":"close"}},"op":">","right":{{"kind":"func","name":"bollinger_upper","period":20}}}}` `{{"kind":"compare","left":{{"kind":"field","field":"close"}},"op":">","right":{{"kind":"func","name":"bollinger_upper","period":20}}}}`
NEVER write `{{"kind":"bollinger_upper",...}}` — `bollinger_upper` is not an Expr kind. NEVER write `{{"kind":"bollinger_upper",...}}` — `bollinger_upper` is not an Expr kind.
- `adx` is a FUNC NAME, not a Condition kind. To filter for strong trends (ADX > 25):
`{{"kind":"compare","left":{{"kind":"func","name":"adx","period":14}},"op":">","right":{{"kind":"literal","value":"25"}}}}`
NEVER write `{{"kind":"adx",...}}` — `adx` is not a Condition kind, it is a FuncName used inside `{{"kind":"func",...}}`.
- `roc` (rate of change), `hma` (Hull MA), `vwap`, `macd`, `cci`, `stoch` are NOT supported. - `roc` (rate of change), `hma` (Hull MA), `vwap`, `macd`, `cci`, `stoch` are NOT supported.
Use `sma`, `ema`, `wma`, `rsi`, `atr`, `adx`, `supertrend`, `std_dev`, `sum`, `highest`, `lowest`, Use `sma`, `ema`, `wma`, `rsi`, `atr`, `adx`, `supertrend`, `std_dev`, `sum`, `highest`, `lowest`,
`bollinger_upper`, `bollinger_lower` only. `bollinger_upper`, `bollinger_lower` only.
@@ -324,6 +333,95 @@ Common mistakes to NEVER make:
}} }}
``` ```
### Example 4 — MACD crossover (composed from primitives)
MACD has no native support, but can be composed from `func` and `apply_func`.
The MACD line is `EMA(12) - EMA(26)`; the signal line is `EMA(9)` of the MACD line.
```json
{{
"type": "rule_based",
"candle_interval": "4h",
"rules": [
{{
"comment": "Buy: MACD line crosses above signal line",
"when": {{
"kind": "all_of",
"conditions": [
{{"kind": "position", "state": "flat"}},
{{
"kind": "cross_over",
"left": {{
"kind": "bin_op", "op": "sub",
"left": {{"kind": "func", "name": "ema", "period": 12}},
"right": {{"kind": "func", "name": "ema", "period": 26}}
}},
"right": {{
"kind": "apply_func", "name": "ema", "period": 9,
"expr": {{
"kind": "bin_op", "op": "sub",
"left": {{"kind": "func", "name": "ema", "period": 12}},
"right": {{"kind": "func", "name": "ema", "period": 26}}
}}
}}
}}
]
}},
"then": {{"side": "buy", "quantity": "0.001"}}
}},
{{
"comment": "Sell: MACD crosses below signal, OR 2% stop-loss, OR 72-bar time exit",
"when": {{
"kind": "all_of",
"conditions": [
{{"kind": "position", "state": "long"}},
{{
"kind": "any_of",
"conditions": [
{{
"kind": "cross_under",
"left": {{
"kind": "bin_op", "op": "sub",
"left": {{"kind": "func", "name": "ema", "period": 12}},
"right": {{"kind": "func", "name": "ema", "period": 26}}
}},
"right": {{
"kind": "apply_func", "name": "ema", "period": 9,
"expr": {{
"kind": "bin_op", "op": "sub",
"left": {{"kind": "func", "name": "ema", "period": 12}},
"right": {{"kind": "func", "name": "ema", "period": 26}}
}}
}}
}},
{{
"kind": "compare",
"left": {{"kind": "field", "field": "close"}},
"op": "<",
"right": {{"kind": "bin_op", "op": "mul",
"left": {{"kind": "entry_price"}},
"right": {{"kind": "literal", "value": "0.98"}}}}
}},
{{
"kind": "compare",
"left": {{"kind": "bars_since_entry"}},
"op": ">=",
"right": {{"kind": "literal", "value": "72"}}
}}
]
}}
]
}},
"then": {{"side": "sell", "quantity": "0.001"}}
}}
]
}}
```
Key pattern: `apply_func` wraps any `Expr` tree, enabling EMA-of-expression (signal line),
WMA-of-expression (Hull MA), or std_dev-of-returns. There is NO native `macd` func name —
always compose it as `bin_op(sub, func(ema,12), func(ema,26))` as shown above.
## Anti-patterns to avoid ## Anti-patterns to avoid
- Don't use the same indicator for both entry and exit (circular logic) - Don't use the same indicator for both entry and exit (circular logic)