Kairos staged trader — backtest report   gemma4:31b-cloud

Variant comparison across BTC + WETH on identical window.

window: 2026-02-06T00:00:00Z → 2026-02-12T00:00:00Z tick: 1h initial vault: $10,000 model: gemma4:31b-cloud generated: 2026-05-06 14:41:48 UTC

Variant ranking — aggregate across asset

#VariantTradesΣ PnL ($)Avg PnL %Distribution
1 full-counter-trend 2 +$187.21 +0.94%
2 full-plus-sizing 18 +$143.04 +0.72%
3 reversal-guard 15 $-167.18 -0.84%
4 base 11 $-617.94 -3.09%

Per-asset breakdown

VariantPairTradesFinal $PnL ($)PnL %
base btcusdc 4 $9975.94 $-24.06 -0.24%
base wethusdc 7 $9406.12 $-593.88 -5.94%
full-counter-trend btcusdc 2 $10187.21 +$187.21 +1.87%
full-counter-trend wethusdc 0 $10000.00 +$0.00 +0.00%
full-plus-sizing btcusdc 6 $10086.17 +$86.17 +0.86%
full-plus-sizing wethusdc 12 $10056.86 +$56.86 +0.57%
reversal-guard btcusdc 8 $9738.54 $-261.46 -2.61%
reversal-guard wethusdc 7 $10094.28 +$94.28 +0.94%

Findings

Prompt variants — what each one changes vs base

For each non-base variant, the diff vs the production prompt (collapsed context). Click to expand the full text.

full-counter-trend overrides 1 stage: 02-decide
02-decide.md  diff vs base
You are the **decide** stage of the trading workflow.
… 16 unchanged lines …
Test exits in priority order. First match wins.
+ **Min-hold protection (counter-trend):** When `previous.open_position_entry_path ∈ {"B", "E"}` AND `previous.open_position_ticks_since_buy < 2`, the only exits allowed are `stop` (safety) and `tp` (full take-profit). Skip `scalp`, `trailing`, and `reversal` — counter-trend entries need at least 2 tick bars to let the rebound develop. If neither stop nor tp fires within this window → `hold`.
+
**Stop-loss:** `previous.price <= previous.open_position_stop_loss_usd` → `sell`, `path: "stop"`, full close.
… 4 unchanged lines …
**Trailing exit:** the orchestrator does not have a way to compute "NET PnL" without arithmetic, so this path requires `previous.tf_15m` flipping to `SELL` AND `previous.macd_15m_histogram < 0` AND `previous.price > previous.open_position_cost_basis_usd / previous.vault_position_token_amount`. (The position is up vs cost basis AND momentum is rolling over.) → `sell`, `path: "trailing"`.
- **Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` → `sell`, `path: "reversal"`.
+ **Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` AND `previous.open_position_entry_path ∉ {"B", "E"}` → `sell`, `path: "reversal"`. **Excluded for B/E entries**: those paths enter deliberately counter-trend, so a still-bearish HTF is the entry premise, not a reversal — let stop/tp/scalp/trailing handle the exit.
If none fire → `hold`.
… 42 unchanged lines …
- `previous.tf_4h ∈ {BUY, STRONG_BUY, NEUTRAL}` (4h reversing up)
- `previous.tf_1h ∈ {BUY, STRONG_BUY}` AND `previous.rsi_15m >= 50`
+ - `previous.macd_15m_flipped_positive == true` (15m momentum confirms — required to avoid catching a falling knife)
Size: 65% aggressive / 50% moderate / 30% conservative.
… 29 unchanged lines …
show full prompt (variant)
You are the **decide** stage of the trading workflow.

Apply the strict v30 rules to research's output and pick exactly one action. **NO arithmetic.** Compare values directly with the listed thresholds. Do not derive flags, do not recompute MACD/RSI/EMA, do not interpolate.

## Previous stage output

```json
{{previous}}
```

## Decision rules

**Default = HOLD.** Only emit `buy` / `sell` when an explicit rule fires below.

Risk thresholds come from `strategy.config` in the system prompt: `entryRsiThreshold`, `fullAlignmentBars`, `spotEntryPct`, `maxExposurePct`, `scalpRsiThreshold`. Defaults below assume the aggressive tier; moderate / conservative override via the config knobs.

### Position-already-open path (`previous.vault_position_token_amount > 0`)

Test exits in priority order. First match wins.

**Min-hold protection (counter-trend):** When `previous.open_position_entry_path ∈ {"B", "E"}` AND `previous.open_position_ticks_since_buy < 2`, the only exits allowed are `stop` (safety) and `tp` (full take-profit). Skip `scalp`, `trailing`, and `reversal` — counter-trend entries need at least 2 tick bars to let the rebound develop. If neither stop nor tp fires within this window → `hold`.

**Stop-loss:** `previous.price <= previous.open_position_stop_loss_usd` → `sell`, `path: "stop"`, full close.

**Full take-profit:** `previous.price >= previous.open_position_tp_target_usd` → `sell`, `path: "tp"`, full close.

**Quick scalp (33%):** `previous.price >= previous.open_position_scalp_target_usd` AND (`previous.rsi_1h >= scalpRsiThreshold` OR `previous.rsi_15m >= scalpRsiThreshold + 5`) → `sell`, `path: "scalp"`, `scalp_pct: 33`.

**Trailing exit:** the orchestrator does not have a way to compute "NET PnL" without arithmetic, so this path requires `previous.tf_15m` flipping to `SELL` AND `previous.macd_15m_histogram < 0` AND `previous.price > previous.open_position_cost_basis_usd / previous.vault_position_token_amount`. (The position is up vs cost basis AND momentum is rolling over.) → `sell`, `path: "trailing"`.

**Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` AND `previous.open_position_entry_path ∉ {"B", "E"}` → `sell`, `path: "reversal"`. **Excluded for B/E entries**: those paths enter deliberately counter-trend, so a still-bearish HTF is the entry premise, not a reversal — let stop/tp/scalp/trailing handle the exit.

If none fire → `hold`.

### No-position path (`previous.vault_position_token_amount == 0`)

**HARD GUARD — read before everything else in this section.** When `previous.vault_position_token_amount == 0` you hold zero of the trading token, so you have NOTHING to sell. Exits (`stop`, `tp`, `scalp`, `trailing`, `reversal`) are FORBIDDEN here regardless of how bearish the timeframes look — they exist ONLY in the Position-already-open path above. The only valid emissions when position is 0 are: `hold`, or `buy` with one of the entry paths A / B / C / D / E. Emitting `{"decision":"sell", ...}` with `vault_position_token_amount == 0` is a hard contract violation: there is no inventory to dispose of and the orchestrator will reject it.

Test in priority order. First match wins. Use `config.entryRsiThreshold` (default 45 aggressive / 42 moderate / 40 conservative) where shown.

#### Path A — Short-timeframe mean-reversion

LONG fires when ALL hold:
- `previous.rsi_1h < config.entryRsiThreshold`
- `previous.rsi_15m_crossed_up_from_below_35 == true` (15m oversold reversal confirmed)
- `previous.macd_15m_flipped_positive == true` (15m momentum flipped within the last 2 bars)
- `previous.tf_daily ∉ {SELL, STRONG_SELL}` (1d not bearish — daily-flat-or-better)

Size: `config.spotEntryPct.A` (default 50% aggressive / 35% moderate / 20% conservative).

#### Path E — Capitulation oversold (BYPASS HTF wall, SPOT-ONLY)

LONG fires when ALL hold:
- `previous.rsi_1h < 22` (aggressive), `< 27` (moderate), `< 18` (conservative). DO NOT relax — this is the extreme-tail entry.
- `previous.rsi_15m > 30` (some recovery from the bottom)
- `previous.macd_15m_flipped_positive == true` (early momentum flip confirmed)
- `previous.close_above_low_12_pct >= 0.3` (proof the local bottom is in)

No HTF filter. Size: 30% aggressive / 20% moderate / 12% conservative. 60-min anti-wash window after this entry's exit (no Path A re-entry inside that window).

#### Path C — Trend continuation pullback

LONG fires when ALL hold:
- `previous.tf_buy_count >= 3` (3-of-4 timeframes BUY or STRONG_BUY)
- `previous.rsi_1h < 60` (not yet overbought — leaves room)
- `previous.macd_15m_histogram > 0` (15m is going up)
- `previous.atr_pct >= 1.0` (enough volatility for a meaningful continuation)
- `previous.regime != "bear"`

Catches the **mid-trend pullback** that Path A (oversold) and Path D (4/4 + breakout) both miss. Size: 35% aggressive / 25% moderate / 15% conservative. 30-min anti-wash window.

#### Path B — Deep-value counter-trend

LONG fires when ALL hold:
- `previous.rsi_daily < 30` AND `previous.rsi_weekly < 35`
- `previous.tf_4h ∈ {BUY, STRONG_BUY, NEUTRAL}` (4h reversing up)
- `previous.tf_1h ∈ {BUY, STRONG_BUY}` AND `previous.rsi_15m >= 50`
- `previous.macd_15m_flipped_positive == true` (15m momentum confirms — required to avoid catching a falling knife)

Size: 65% aggressive / 50% moderate / 30% conservative.

#### Path D — Confirmed momentum

LONG fires when ALL hold:
- `previous.tf_buy_count >= config.fullAlignmentBars` (default 4 = strict, 3 = looser)
- `previous.breakout_last_24_periods == true` (15m close above the 24-bar high)
- `previous.volume_confirm_15m == true` (15m vol_ratio ≥ 1.3)
- `previous.atr_pct >= 1.5`

Size: 65% aggressive / 50% moderate / 30% conservative.

### Default

If no path fires → `hold`.

## Anti-wash trade rule

After a full take-profit / final scalp / stop / trailing / reversal exit, the next 30 min ONLY allows Path A (oversold dip) or Path E (capitulation). Path B / Path C / Path D are forbidden in that window regardless of signal. The runtime SELL GUARD + 2h BUY cooldown back this up at the code level — your job is to not even propose a forbidden re-entry.

## Output schema (your last message MUST be a single-line JSON object — no markdown fences, just one line)

```json
{"decision":"<buy|sell|hold>","path":"<A|B|C|D|E|stop|tp|scalp|trailing|reversal|null>","size_pct":<number 0-100 or null>,"scalp_pct":<33|null>,"reasoning":"<one short sentence>"}
```

The orchestrator parses your LAST line as JSON. Emit it on a single line, no code fence, no trailing prose. The skip_condition `previous.decision == "hold"` requires a parseable JSON; if you wrap the line in markdown the orchestrator falls back to a string and execute spawns wastefully.

If `previous.unavailable == true` → `{"decision":"hold","path":null,"size_pct":null,"scalp_pct":null,"reasoning":"indicators unavailable"}`.
full-plus-sizing overrides 1 stage: 02-decide
02-decide.md  diff vs base
You are the **decide** stage of the trading workflow.
… 10 unchanged lines …
**Default = HOLD.** Only emit `buy` / `sell` when an explicit rule fires below.
- Risk thresholds come from `strategy.config` in the system prompt: `entryRsiThreshold`, `fullAlignmentBars`, `spotEntryPct`, `maxExposurePct`, `scalpRsiThreshold`. Defaults below assume the aggressive tier; moderate / conservative override via the config knobs.
+ **Tier override = MODERATE.** Use the moderate tier values everywhere a tier is mentioned (`entryRsiThreshold = 42`, sizing as listed below). This caps the exposure on counter-trend entries vs the aggressive default.
### Position-already-open path (`previous.vault_position_token_amount > 0`)
Test exits in priority order. First match wins.
+ **Min-hold protection (counter-trend):** When `previous.open_position_entry_path ∈ {"B", "E"}` AND `previous.open_position_ticks_since_buy < 2`, the only exits allowed are `stop` (safety) and `tp` (full take-profit). Skip `scalp`, `trailing`, and `reversal` — counter-trend entries need at least 2 tick bars to let the rebound develop. If neither stop nor tp fires within this window → `hold`.
+
**Stop-loss:** `previous.price <= previous.open_position_stop_loss_usd` → `sell`, `path: "stop"`, full close.
… 4 unchanged lines …
**Trailing exit:** the orchestrator does not have a way to compute "NET PnL" without arithmetic, so this path requires `previous.tf_15m` flipping to `SELL` AND `previous.macd_15m_histogram < 0` AND `previous.price > previous.open_position_cost_basis_usd / previous.vault_position_token_amount`. (The position is up vs cost basis AND momentum is rolling over.) → `sell`, `path: "trailing"`.
- **Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` → `sell`, `path: "reversal"`.
+ **Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` AND `previous.open_position_entry_path ∉ {"B", "E"}` → `sell`, `path: "reversal"`. **Excluded for B/E entries**: those paths enter deliberately counter-trend, so a still-bearish HTF is the entry premise, not a reversal — let stop/tp/scalp/trailing handle the exit.
If none fire → `hold`.
… 3 unchanged lines …
**HARD GUARD — read before everything else in this section.** When `previous.vault_position_token_amount == 0` you hold zero of the trading token, so you have NOTHING to sell. Exits (`stop`, `tp`, `scalp`, `trailing`, `reversal`) are FORBIDDEN here regardless of how bearish the timeframes look — they exist ONLY in the Position-already-open path above. The only valid emissions when position is 0 are: `hold`, or `buy` with one of the entry paths A / B / C / D / E. Emitting `{"decision":"sell", ...}` with `vault_position_token_amount == 0` is a hard contract violation: there is no inventory to dispose of and the orchestrator will reject it.
- Test in priority order. First match wins. Use `config.entryRsiThreshold` (default 45 aggressive / 42 moderate / 40 conservative) where shown.
+ Test in priority order. First match wins. Use **moderate tier**: `entryRsiThreshold = 42`.
#### Path A — Short-timeframe mean-reversion
LONG fires when ALL hold:
- - `previous.rsi_1h < config.entryRsiThreshold`
+ - `previous.rsi_1h < 42` (moderate threshold)
- `previous.rsi_15m_crossed_up_from_below_35 == true` (15m oversold reversal confirmed)
- `previous.macd_15m_flipped_positive == true` (15m momentum flipped within the last 2 bars)
- `previous.tf_daily ∉ {SELL, STRONG_SELL}` (1d not bearish — daily-flat-or-better)
- Size: `config.spotEntryPct.A` (default 50% aggressive / 35% moderate / 20% conservative).
+ Size: **35%** (moderate).
#### Path E — Capitulation oversold (BYPASS HTF wall, SPOT-ONLY)
LONG fires when ALL hold:
- - `previous.rsi_1h < 22` (aggressive), `< 27` (moderate), `< 18` (conservative). DO NOT relax — this is the extreme-tail entry.
+ - `previous.rsi_1h < 27` (moderate threshold). DO NOT relax — this is the extreme-tail entry.
- `previous.rsi_15m > 30` (some recovery from the bottom)
- `previous.macd_15m_flipped_positive == true` (early momentum flip confirmed)
- `previous.close_above_low_12_pct >= 0.3` (proof the local bottom is in)
- No HTF filter. Size: 30% aggressive / 20% moderate / 12% conservative. 60-min anti-wash window after this entry's exit (no Path A re-entry inside that window).
+ No HTF filter. Size: **20%** (moderate). 60-min anti-wash window after this entry's exit.
#### Path C — Trend continuation pullback
LONG fires when ALL hold:
- `previous.tf_buy_count >= 3` (3-of-4 timeframes BUY or STRONG_BUY)
- - `previous.rsi_1h < 60` (not yet overbought — leaves room)
+ - `previous.rsi_1h < 60` (not yet overbought)
- `previous.macd_15m_histogram > 0` (15m is going up)
- - `previous.atr_pct >= 1.0` (enough volatility for a meaningful continuation)
+ - `previous.atr_pct >= 1.0`
- `previous.regime != "bear"`
- Catches the **mid-trend pullback** that Path A (oversold) and Path D (4/4 + breakout) both miss. Size: 35% aggressive / 25% moderate / 15% conservative. 30-min anti-wash window.
+ Size: **25%** (moderate). 30-min anti-wash window.
#### Path B — Deep-value counter-trend
… 3 unchanged lines …
- `previous.tf_4h ∈ {BUY, STRONG_BUY, NEUTRAL}` (4h reversing up)
- `previous.tf_1h ∈ {BUY, STRONG_BUY}` AND `previous.rsi_15m >= 50`
+ - `previous.macd_15m_flipped_positive == true` (15m momentum confirms — required to avoid catching a falling knife)
- Size: 65% aggressive / 50% moderate / 30% conservative.
+ Size: **50%** (moderate, down from 65% aggressive).
#### Path D — Confirmed momentum
LONG fires when ALL hold:
- - `previous.tf_buy_count >= config.fullAlignmentBars` (default 4 = strict, 3 = looser)
- - `previous.breakout_last_24_periods == true` (15m close above the 24-bar high)
- - `previous.volume_confirm_15m == true` (15m vol_ratio ≥ 1.3)
+ - `previous.tf_buy_count >= 3` (moderate alignment, looser than aggressive 4/4)
+ - `previous.breakout_last_24_periods == true`
+ - `previous.volume_confirm_15m == true`
- `previous.atr_pct >= 1.5`
- Size: 65% aggressive / 50% moderate / 30% conservative.
+ Size: **50%** (moderate).
### Default
… 3 unchanged lines …
## Anti-wash trade rule
- After a full take-profit / final scalp / stop / trailing / reversal exit, the next 30 min ONLY allows Path A (oversold dip) or Path E (capitulation). Path B / Path C / Path D are forbidden in that window regardless of signal. The runtime SELL GUARD + 2h BUY cooldown back this up at the code level — your job is to not even propose a forbidden re-entry.
+ After a full take-profit / final scalp / stop / trailing / reversal exit, the next 30 min ONLY allows Path A (oversold dip) or Path E (capitulation). Path B / Path C / Path D are forbidden in that window regardless of signal.
## Output schema (your last message MUST be a single-line JSON object — no markdown fences, just one line)
… 3 unchanged lines …
```
- The orchestrator parses your LAST line as JSON. Emit it on a single line, no code fence, no trailing prose. The skip_condition `previous.decision == "hold"` requires a parseable JSON; if you wrap the line in markdown the orchestrator falls back to a string and execute spawns wastefully.
+ The orchestrator parses your LAST line as JSON. Emit it on a single line, no code fence, no trailing prose.
If `previous.unavailable == true` → `{"decision":"hold","path":null,"size_pct":null,"scalp_pct":null,"reasoning":"indicators unavailable"}`.
show full prompt (variant)
You are the **decide** stage of the trading workflow.

Apply the strict v30 rules to research's output and pick exactly one action. **NO arithmetic.** Compare values directly with the listed thresholds. Do not derive flags, do not recompute MACD/RSI/EMA, do not interpolate.

## Previous stage output

```json
{{previous}}
```

## Decision rules

**Default = HOLD.** Only emit `buy` / `sell` when an explicit rule fires below.

**Tier override = MODERATE.** Use the moderate tier values everywhere a tier is mentioned (`entryRsiThreshold = 42`, sizing as listed below). This caps the exposure on counter-trend entries vs the aggressive default.

### Position-already-open path (`previous.vault_position_token_amount > 0`)

Test exits in priority order. First match wins.

**Min-hold protection (counter-trend):** When `previous.open_position_entry_path ∈ {"B", "E"}` AND `previous.open_position_ticks_since_buy < 2`, the only exits allowed are `stop` (safety) and `tp` (full take-profit). Skip `scalp`, `trailing`, and `reversal` — counter-trend entries need at least 2 tick bars to let the rebound develop. If neither stop nor tp fires within this window → `hold`.

**Stop-loss:** `previous.price <= previous.open_position_stop_loss_usd` → `sell`, `path: "stop"`, full close.

**Full take-profit:** `previous.price >= previous.open_position_tp_target_usd` → `sell`, `path: "tp"`, full close.

**Quick scalp (33%):** `previous.price >= previous.open_position_scalp_target_usd` AND (`previous.rsi_1h >= scalpRsiThreshold` OR `previous.rsi_15m >= scalpRsiThreshold + 5`) → `sell`, `path: "scalp"`, `scalp_pct: 33`.

**Trailing exit:** the orchestrator does not have a way to compute "NET PnL" without arithmetic, so this path requires `previous.tf_15m` flipping to `SELL` AND `previous.macd_15m_histogram < 0` AND `previous.price > previous.open_position_cost_basis_usd / previous.vault_position_token_amount`. (The position is up vs cost basis AND momentum is rolling over.) → `sell`, `path: "trailing"`.

**Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` AND `previous.open_position_entry_path ∉ {"B", "E"}` → `sell`, `path: "reversal"`. **Excluded for B/E entries**: those paths enter deliberately counter-trend, so a still-bearish HTF is the entry premise, not a reversal — let stop/tp/scalp/trailing handle the exit.

If none fire → `hold`.

### No-position path (`previous.vault_position_token_amount == 0`)

**HARD GUARD — read before everything else in this section.** When `previous.vault_position_token_amount == 0` you hold zero of the trading token, so you have NOTHING to sell. Exits (`stop`, `tp`, `scalp`, `trailing`, `reversal`) are FORBIDDEN here regardless of how bearish the timeframes look — they exist ONLY in the Position-already-open path above. The only valid emissions when position is 0 are: `hold`, or `buy` with one of the entry paths A / B / C / D / E. Emitting `{"decision":"sell", ...}` with `vault_position_token_amount == 0` is a hard contract violation: there is no inventory to dispose of and the orchestrator will reject it.

Test in priority order. First match wins. Use **moderate tier**: `entryRsiThreshold = 42`.

#### Path A — Short-timeframe mean-reversion

LONG fires when ALL hold:
- `previous.rsi_1h < 42` (moderate threshold)
- `previous.rsi_15m_crossed_up_from_below_35 == true` (15m oversold reversal confirmed)
- `previous.macd_15m_flipped_positive == true` (15m momentum flipped within the last 2 bars)
- `previous.tf_daily ∉ {SELL, STRONG_SELL}` (1d not bearish — daily-flat-or-better)

Size: **35%** (moderate).

#### Path E — Capitulation oversold (BYPASS HTF wall, SPOT-ONLY)

LONG fires when ALL hold:
- `previous.rsi_1h < 27` (moderate threshold). DO NOT relax — this is the extreme-tail entry.
- `previous.rsi_15m > 30` (some recovery from the bottom)
- `previous.macd_15m_flipped_positive == true` (early momentum flip confirmed)
- `previous.close_above_low_12_pct >= 0.3` (proof the local bottom is in)

No HTF filter. Size: **20%** (moderate). 60-min anti-wash window after this entry's exit.

#### Path C — Trend continuation pullback

LONG fires when ALL hold:
- `previous.tf_buy_count >= 3` (3-of-4 timeframes BUY or STRONG_BUY)
- `previous.rsi_1h < 60` (not yet overbought)
- `previous.macd_15m_histogram > 0` (15m is going up)
- `previous.atr_pct >= 1.0`
- `previous.regime != "bear"`

Size: **25%** (moderate). 30-min anti-wash window.

#### Path B — Deep-value counter-trend

LONG fires when ALL hold:
- `previous.rsi_daily < 30` AND `previous.rsi_weekly < 35`
- `previous.tf_4h ∈ {BUY, STRONG_BUY, NEUTRAL}` (4h reversing up)
- `previous.tf_1h ∈ {BUY, STRONG_BUY}` AND `previous.rsi_15m >= 50`
- `previous.macd_15m_flipped_positive == true` (15m momentum confirms — required to avoid catching a falling knife)

Size: **50%** (moderate, down from 65% aggressive).

#### Path D — Confirmed momentum

LONG fires when ALL hold:
- `previous.tf_buy_count >= 3` (moderate alignment, looser than aggressive 4/4)
- `previous.breakout_last_24_periods == true`
- `previous.volume_confirm_15m == true`
- `previous.atr_pct >= 1.5`

Size: **50%** (moderate).

### Default

If no path fires → `hold`.

## Anti-wash trade rule

After a full take-profit / final scalp / stop / trailing / reversal exit, the next 30 min ONLY allows Path A (oversold dip) or Path E (capitulation). Path B / Path C / Path D are forbidden in that window regardless of signal.

## Output schema (your last message MUST be a single-line JSON object — no markdown fences, just one line)

```json
{"decision":"<buy|sell|hold>","path":"<A|B|C|D|E|stop|tp|scalp|trailing|reversal|null>","size_pct":<number 0-100 or null>,"scalp_pct":<33|null>,"reasoning":"<one short sentence>"}
```

The orchestrator parses your LAST line as JSON. Emit it on a single line, no code fence, no trailing prose.

If `previous.unavailable == true` → `{"decision":"hold","path":null,"size_pct":null,"scalp_pct":null,"reasoning":"indicators unavailable"}`.
reversal-guard overrides 1 stage: 02-decide
02-decide.md  diff vs base
You are the **decide** stage of the trading workflow.
… 24 unchanged lines …
**Trailing exit:** the orchestrator does not have a way to compute "NET PnL" without arithmetic, so this path requires `previous.tf_15m` flipping to `SELL` AND `previous.macd_15m_histogram < 0` AND `previous.price > previous.open_position_cost_basis_usd / previous.vault_position_token_amount`. (The position is up vs cost basis AND momentum is rolling over.) → `sell`, `path: "trailing"`.
- **Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` → `sell`, `path: "reversal"`.
+ **Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` AND `previous.open_position_entry_path ∉ {"B", "E"}` → `sell`, `path: "reversal"`. **Excluded for B/E entries**: those paths enter deliberately counter-trend, so a still-bearish HTF is the entry premise, not a reversal — let stop/tp/scalp/trailing handle the exit.
If none fire → `hold`.
… 75 unchanged lines …
show full prompt (variant)
You are the **decide** stage of the trading workflow.

Apply the strict v30 rules to research's output and pick exactly one action. **NO arithmetic.** Compare values directly with the listed thresholds. Do not derive flags, do not recompute MACD/RSI/EMA, do not interpolate.

## Previous stage output

```json
{{previous}}
```

## Decision rules

**Default = HOLD.** Only emit `buy` / `sell` when an explicit rule fires below.

Risk thresholds come from `strategy.config` in the system prompt: `entryRsiThreshold`, `fullAlignmentBars`, `spotEntryPct`, `maxExposurePct`, `scalpRsiThreshold`. Defaults below assume the aggressive tier; moderate / conservative override via the config knobs.

### Position-already-open path (`previous.vault_position_token_amount > 0`)

Test exits in priority order. First match wins.

**Stop-loss:** `previous.price <= previous.open_position_stop_loss_usd` → `sell`, `path: "stop"`, full close.

**Full take-profit:** `previous.price >= previous.open_position_tp_target_usd` → `sell`, `path: "tp"`, full close.

**Quick scalp (33%):** `previous.price >= previous.open_position_scalp_target_usd` AND (`previous.rsi_1h >= scalpRsiThreshold` OR `previous.rsi_15m >= scalpRsiThreshold + 5`) → `sell`, `path: "scalp"`, `scalp_pct: 33`.

**Trailing exit:** the orchestrator does not have a way to compute "NET PnL" without arithmetic, so this path requires `previous.tf_15m` flipping to `SELL` AND `previous.macd_15m_histogram < 0` AND `previous.price > previous.open_position_cost_basis_usd / previous.vault_position_token_amount`. (The position is up vs cost basis AND momentum is rolling over.) → `sell`, `path: "trailing"`.

**Trend reversal:** `previous.tf_4h ∈ {SELL, STRONG_SELL}` AND `previous.tf_daily ∈ {SELL, STRONG_SELL}` AND `previous.open_position_entry_path ∉ {"B", "E"}` → `sell`, `path: "reversal"`. **Excluded for B/E entries**: those paths enter deliberately counter-trend, so a still-bearish HTF is the entry premise, not a reversal — let stop/tp/scalp/trailing handle the exit.

If none fire → `hold`.

### No-position path (`previous.vault_position_token_amount == 0`)

**HARD GUARD — read before everything else in this section.** When `previous.vault_position_token_amount == 0` you hold zero of the trading token, so you have NOTHING to sell. Exits (`stop`, `tp`, `scalp`, `trailing`, `reversal`) are FORBIDDEN here regardless of how bearish the timeframes look — they exist ONLY in the Position-already-open path above. The only valid emissions when position is 0 are: `hold`, or `buy` with one of the entry paths A / B / C / D / E. Emitting `{"decision":"sell", ...}` with `vault_position_token_amount == 0` is a hard contract violation: there is no inventory to dispose of and the orchestrator will reject it.

Test in priority order. First match wins. Use `config.entryRsiThreshold` (default 45 aggressive / 42 moderate / 40 conservative) where shown.

#### Path A — Short-timeframe mean-reversion

LONG fires when ALL hold:
- `previous.rsi_1h < config.entryRsiThreshold`
- `previous.rsi_15m_crossed_up_from_below_35 == true` (15m oversold reversal confirmed)
- `previous.macd_15m_flipped_positive == true` (15m momentum flipped within the last 2 bars)
- `previous.tf_daily ∉ {SELL, STRONG_SELL}` (1d not bearish — daily-flat-or-better)

Size: `config.spotEntryPct.A` (default 50% aggressive / 35% moderate / 20% conservative).

#### Path E — Capitulation oversold (BYPASS HTF wall, SPOT-ONLY)

LONG fires when ALL hold:
- `previous.rsi_1h < 22` (aggressive), `< 27` (moderate), `< 18` (conservative). DO NOT relax — this is the extreme-tail entry.
- `previous.rsi_15m > 30` (some recovery from the bottom)
- `previous.macd_15m_flipped_positive == true` (early momentum flip confirmed)
- `previous.close_above_low_12_pct >= 0.3` (proof the local bottom is in)

No HTF filter. Size: 30% aggressive / 20% moderate / 12% conservative. 60-min anti-wash window after this entry's exit (no Path A re-entry inside that window).

#### Path C — Trend continuation pullback

LONG fires when ALL hold:
- `previous.tf_buy_count >= 3` (3-of-4 timeframes BUY or STRONG_BUY)
- `previous.rsi_1h < 60` (not yet overbought — leaves room)
- `previous.macd_15m_histogram > 0` (15m is going up)
- `previous.atr_pct >= 1.0` (enough volatility for a meaningful continuation)
- `previous.regime != "bear"`

Catches the **mid-trend pullback** that Path A (oversold) and Path D (4/4 + breakout) both miss. Size: 35% aggressive / 25% moderate / 15% conservative. 30-min anti-wash window.

#### Path B — Deep-value counter-trend

LONG fires when ALL hold:
- `previous.rsi_daily < 30` AND `previous.rsi_weekly < 35`
- `previous.tf_4h ∈ {BUY, STRONG_BUY, NEUTRAL}` (4h reversing up)
- `previous.tf_1h ∈ {BUY, STRONG_BUY}` AND `previous.rsi_15m >= 50`

Size: 65% aggressive / 50% moderate / 30% conservative.

#### Path D — Confirmed momentum

LONG fires when ALL hold:
- `previous.tf_buy_count >= config.fullAlignmentBars` (default 4 = strict, 3 = looser)
- `previous.breakout_last_24_periods == true` (15m close above the 24-bar high)
- `previous.volume_confirm_15m == true` (15m vol_ratio ≥ 1.3)
- `previous.atr_pct >= 1.5`

Size: 65% aggressive / 50% moderate / 30% conservative.

### Default

If no path fires → `hold`.

## Anti-wash trade rule

After a full take-profit / final scalp / stop / trailing / reversal exit, the next 30 min ONLY allows Path A (oversold dip) or Path E (capitulation). Path B / Path C / Path D are forbidden in that window regardless of signal. The runtime SELL GUARD + 2h BUY cooldown back this up at the code level — your job is to not even propose a forbidden re-entry.

## Output schema (your last message MUST be a single-line JSON object — no markdown fences, just one line)

```json
{"decision":"<buy|sell|hold>","path":"<A|B|C|D|E|stop|tp|scalp|trailing|reversal|null>","size_pct":<number 0-100 or null>,"scalp_pct":<33|null>,"reasoning":"<one short sentence>"}
```

The orchestrator parses your LAST line as JSON. Emit it on a single line, no code fence, no trailing prose. The skip_condition `previous.decision == "hold"` requires a parseable JSON; if you wrap the line in markdown the orchestrator falls back to a string and execute spawns wastefully.

If `previous.unavailable == true` → `{"decision":"hold","path":null,"size_pct":null,"scalp_pct":null,"reasoning":"indicators unavailable"}`.

Trade-by-trade detail

Click any run to expand its trade list.

base  btcusdc 2026-05-05_base_btcusdc_gemma4-31b-cloud_196936bd   open ↗ 2 BUY · 2 SELL   -0.24%
sim_tssidepathamount $price $cost %realized $realized %
2026-02-06 01:00:00 BUY E $3000.00 $63509.39 0.53%
2026-02-06 02:00:00 SELL reversal $3071.34 $65714.96 0.53% +$71.34 +2.38%
2026-02-09 23:00:00 BUY B $6546.37 $70372.96 0.57%
2026-02-10 00:00:00 SELL reversal $6450.97 $70138.00 0.56% $-95.40 -1.46%
base  wethusdc 2026-05-05_base_wethusdc_gemma4-31b-cloud_83e7374d   open ↗ 4 BUY · 3 SELL   -5.94%
sim_tssidepathamount $price $cost %realized $realized %
2026-02-06 21:00:00 BUY B $6500.00 $2054.23 0.56%
2026-02-06 22:00:00 SELL reversal $6425.97 $2053.97 0.56% $-74.03 -1.14%
2026-02-06 23:00:00 BUY B $6451.88 $2075.10 0.56%
2026-02-07 00:00:00 SELL reversal $6343.25 $2063.38 0.56% $-108.62 -1.68%
2026-02-07 03:00:00 BUY B $6381.28 $2059.39 0.56%
2026-02-07 04:00:00 SELL reversal $6375.13 $2080.81 0.56% $-6.15 -0.10%
2026-02-07 18:00:00 BUY B $6377.28 $2061.16 0.56%
full-counter-trend  btcusdc 2026-05-05_full-counter-trend_btcusdc_gemma4-31b-cloud_2da7d   open ↗ 1 BUY · 1 SELL   +1.87%
sim_tssidepathamount $price $cost %realized $realized %
2026-02-06 01:00:00 BUY E $3000.00 $63509.39 0.53%
2026-02-06 15:00:00 SELL tp $3187.21 $68194.89 0.53% +$187.21 +6.24%
full-counter-trend  wethusdc 2026-05-05_full-counter-trend_wethusdc_gemma4-31b-cloud_5e61   open ↗ 0 BUY · 0 SELL   +0.00%
sim_tssidepathamount $price $cost %realized $realized %
No trades — entry conditions never fired.
full-plus-sizing  btcusdc 2026-05-05_full-plus-sizing_btcusdc_gemma4-31b-cloud_c79b69d   open ↗ 1 BUY · 5 SELL   +0.86%
sim_tssidepathamount $price $cost %realized $realized %
2026-02-06 01:00:00 BUY E $2000.00 $63509.39 0.52%
2026-02-06 06:00:00 SELL scalp $683.06 $66408.11 0.51% +$23.06 +3.49%
2026-02-06 12:00:00 SELL scalp $459.20 $66631.32 0.50% +$17.00 +3.84%
2026-02-06 13:00:00 SELL scalp $307.33 $66557.93 0.50% +$11.05 +3.73%
2026-02-06 14:00:00 SELL scalp $208.26 $67316.82 0.50% +$9.76 +4.91%
2026-02-06 15:00:00 SELL tp $428.33 $68194.89 0.50% +$25.31 +6.28%
full-plus-sizing  wethusdc 2026-05-05_full-plus-sizing_wethusdc_gemma4-31b-cloud_1c242d   open ↗ 2 BUY · 10 SELL   +0.57%
sim_tssidepathamount $price $cost %realized $realized %
2026-02-06 10:00:00 BUY E $2000.00 $1919.00 0.52%
2026-02-06 15:00:00 SELL scalp $673.62 $1978.88 0.51% +$13.62 +2.06%
2026-02-06 16:00:00 SELL scalp $451.78 $1980.81 0.50% +$9.58 +2.17%
2026-02-06 17:00:00 SELL scalp $311.16 $2036.17 0.50% +$14.88 +5.02%
2026-02-06 18:00:00 SELL scalp $211.63 $2067.01 0.50% +$13.13 +6.61%
2026-02-06 20:00:00 SELL scalp $141.70 $2065.63 0.50% +$8.70 +6.54%
2026-02-06 21:00:00 SELL scalp $94.42 $2054.23 0.50% +$5.31 +5.96%
2026-02-06 23:00:00 SELL scalp $63.90 $2075.10 0.50% +$4.20 +7.03%
2026-02-07 04:00:00 SELL scalp $42.93 $2080.81 0.50% +$2.93 +7.33%
2026-02-07 05:00:00 SELL scalp $28.86 $2087.40 0.50% +$2.06 +7.67%
2026-02-07 10:00:00 SELL tp $56.54 $2014.45 0.50% +$2.13 +3.91%
2026-02-11 09:00:00 BUY E $2015.31 $1950.12 0.52%
reversal-guard  btcusdc 2026-05-05_reversal-guard_btcusdc_gemma4-31b-cloud_b4afc4ce   open ↗ 2 BUY · 6 SELL   -2.61%
sim_tssidepathamount $price $cost %realized $realized %
2026-02-06 01:00:00 BUY E $3000.00 $63509.39 0.53%
2026-02-06 06:00:00 SELL scalp $1024.44 $66408.11 0.51% +$34.44 +3.48%
2026-02-06 12:00:00 SELL scalp $688.71 $66631.32 0.51% +$25.41 +3.83%
2026-02-06 13:00:00 SELL scalp $460.94 $66557.93 0.50% +$16.53 +3.72%
2026-02-06 14:00:00 SELL scalp $312.35 $67316.82 0.50% +$14.60 +4.90%
2026-02-07 12:00:00 SELL scalp $211.32 $67972.65 0.50% +$11.82 +5.93%
2026-02-07 13:00:00 SELL tp $435.67 $69024.98 0.50% +$30.63 +7.56%
2026-02-09 20:00:00 BUY B $6586.73 $70957.01 0.57%
reversal-guard  wethusdc 2026-05-05_reversal-guard_wethusdc_gemma4-31b-cloud_d97bd534   open ↗ 1 BUY · 6 SELL   +0.94%
sim_tssidepathamount $price $cost %realized $realized %
2026-02-06 20:00:00 BUY B $6500.00 $2065.63 0.56%
2026-02-08 12:00:00 SELL scalp $2190.28 $2132.35 0.52% +$45.28 +2.11%
2026-02-08 13:00:00 SELL scalp $1466.96 $2131.43 0.51% +$29.81 +2.07%
2026-02-08 14:00:00 SELL scalp $980.68 $2126.59 0.51% +$17.79 +1.85%
2026-02-08 15:00:00 SELL scalp $657.70 $2128.62 0.51% +$12.57 +1.95%
2026-02-08 20:00:00 SELL scalp $440.29 $2126.77 0.50% +$8.05 +1.86%
2026-02-09 10:00:00 SELL stop $858.37 $2042.27 0.51% $-19.21 -2.19%

Run config

VariantPairRun IDPrompts FPStartedFinished
base btcusdc 2026-05-05_base_btcusdc_gemma4-31b-cloud_196936bd 5f80dcb4d5d69586 2026-05-05 19:01:29 2026-05-05 21:48:29
base wethusdc 2026-05-05_base_wethusdc_gemma4-31b-cloud_83e7374d 5f80dcb4d5d69586 2026-05-05 19:01:29 2026-05-05 21:56:13
full-counter-trend btcusdc 2026-05-05_full-counter-trend_btcusdc_gemma4-31b-cloud_2da7d621 7a098dc44f79d94b 2026-05-05 19:01:29 2026-05-05 21:46:41
full-counter-trend wethusdc 2026-05-05_full-counter-trend_wethusdc_gemma4-31b-cloud_5e618bed 7a098dc44f79d94b 2026-05-05 19:01:29 2026-05-05 21:49:24
full-plus-sizing btcusdc 2026-05-05_full-plus-sizing_btcusdc_gemma4-31b-cloud_c79b69d8 c27d60d41e3a943f 2026-05-05 19:01:29 2026-05-05 21:47:02
full-plus-sizing wethusdc 2026-05-05_full-plus-sizing_wethusdc_gemma4-31b-cloud_1c242d89 c27d60d41e3a943f 2026-05-05 19:01:29 2026-05-05 21:50:43
reversal-guard btcusdc 2026-05-05_reversal-guard_btcusdc_gemma4-31b-cloud_b4afc4ce f963f4aa2f563223 2026-05-05 19:01:29 2026-05-05 21:55:21
reversal-guard wethusdc 2026-05-05_reversal-guard_wethusdc_gemma4-31b-cloud_d97bd534 f963f4aa2f563223 2026-05-05 19:01:29 2026-05-05 21:50:51

Generated by src/04-build-report.mjs · 8 runs · 2026-05-06 14:41:48 UTC