diff --git a/src/dsl-schema.json b/src/dsl-schema.json index e18d80a..7581447 100644 --- a/src/dsl-schema.json +++ b/src/dsl-schema.json @@ -74,6 +74,11 @@ { "$ref": "#/definitions/SizingFixedUnits" }, { "$ref": "#/definitions/Expr" } ] + }, + "reverse": { + "type": "boolean", + "default": false, + "description": "Flip-through-zero flag (futures only). When true and an opposite position is currently open, the submitted order quantity becomes position_qty + configured_qty, closing the existing position and immediately opening a new one in the opposite direction in a single order. When flat the flag has no effect and configured_qty is used as normal. Omit or set false for standard close-only behaviour." } } }, diff --git a/src/prompts.rs b/src/prompts.rs index fad84d2..36abc4d 100644 --- a/src/prompts.rs +++ b/src/prompts.rs @@ -121,6 +121,24 @@ CRITICAL — the `"method"` vs `"kind"` distinction: `multiplier` field. Only `amount` is accepted alongside `method`. - NEVER add extra fields to SizingMethod objects — they use `additionalProperties: false`. +### Reverse / flip-through-zero (futures only) + +Setting `"reverse": true` on a rule action enables a single-order position flip on futures. +When an opposite position is open, quantity = `position_qty + configured_qty`, which closes +the existing position and opens a new one in the opposite direction in one order (fees split +proportionally). When flat the flag has no effect — `configured_qty` is used normally. + +This lets you collapse a 4-rule long+short strategy (separate open/close for each leg) into +2 rules, reducing round-trip fees and keeping logic compact: + +```json +{{"side": "sell", "quantity": {{"method": "percent_of_balance", "percent": "10", "asset": "usdc"}}, "reverse": true}} +``` + +Use `reverse` when you always want to be in a position — the signal flips you from long to +short (or vice versa) rather than first exiting and then re-entering separately. Do NOT use +`reverse` on spot markets (short selling is not supported there). + ### Multi-timeframe Any expression can reference a different timeframe via "timeframe" field. Use higher timeframes as trend filters, lower timeframes for entry precision. @@ -557,7 +575,58 @@ Key short-specific notes: - Stop-loss for short = close > entry_price * (1 + stop_pct), e.g. `* 1.02` for 2% stop - Take-profit for short = close < entry_price * (1 - target_pct), e.g. `* 0.97` for 3% target - Short exit uses `"side": "buy"` with `{"kind": "position_quantity"}` (same as long exit uses sell) -- `percent_of_balance` for short entry uses `"usdc"` as the asset (the collateral currency)"##; +- `percent_of_balance` for short entry uses `"usdc"` as the asset (the collateral currency) + +### Example 6 — Futures flip-through-zero: 2-rule EMA trend-follower using `reverse` + +When you always want to be in a position (long during uptrends, short during downtrends), +use `"reverse": true` to flip from one side to the other in a single order. This uses half +the round-trip fee count compared to a 4-rule separate-entry/exit approach. + +```json +{ + "type": "rule_based", + "candle_interval": "4h", + "rules": [ + { + "comment": "Go long (or flip short→long): EMA9 crosses above EMA21 while above EMA50", + "when": { + "kind": "all_of", + "conditions": [ + {"kind": "any_of", "conditions": [ + {"kind": "position", "state": "flat"}, + {"kind": "position", "state": "short"} + ]}, + {"kind": "ema_crossover", "fast_period": 9, "slow_period": 21, "direction": "above"}, + {"kind": "ema_trend", "period": 50, "direction": "above"} + ] + }, + "then": {"side": "buy", "quantity": {"method": "percent_of_balance", "percent": "10", "asset": "usdc"}, "reverse": true} + }, + { + "comment": "Go short (or flip long→short): EMA9 crosses below EMA21 while below EMA50", + "when": { + "kind": "all_of", + "conditions": [ + {"kind": "any_of", "conditions": [ + {"kind": "position", "state": "flat"}, + {"kind": "position", "state": "long"} + ]}, + {"kind": "ema_crossover", "fast_period": 9, "slow_period": 21, "direction": "below"}, + {"kind": "ema_trend", "period": 50, "direction": "below"} + ] + }, + "then": {"side": "sell", "quantity": {"method": "percent_of_balance", "percent": "10", "asset": "usdc"}, "reverse": true} + } + ] +} +``` + +Key flip-strategy notes: +- Gate each rule on `flat OR opposite` (using `any_of`) so it fires both on initial entry and on flip +- `reverse: true` handles the flip math automatically — no need to size for `position_qty + new_qty` +- This pattern works best for trend-following where you want continuous market exposure +- Still add a time-based or ATR stop if you want a safety exit when the trend stalls"##; /// Build the user message for the first iteration (no prior results). /// `prior_summary` contains a formatted summary of results from previous runs, if any.