<!-- Version: v1.1.0 | Updated: 2026-04-13 | Project: 20260412_TWM_exit_optimization -->

# Stop Loss Workflow

> **Version:** v1.1.0 | **Updated:** 2026-04-13 | **Project:** 20260412_TWM_exit_optimization  
> **Supersedes:** v1.0 (2026-03-23, 20260319_refactor_strategy)

---

## Overview

`stop_loss` is a single tracked value. It is set once at trade entry and may only be tightened (raised for longs) thereafter.

- Only tightening is permitted: `stop_loss = max(stop_loss, candidate)`.
- Stop types are classified as **Hard** or **Soft** — this determines whether a violation causes an **immediate broker-executed exit** or merely increments the `exit_counter`.

---

## Hard Stop vs Soft Stop — Classification

| Stop | Classification | Behaviour on Violation |
|------|----------------|------------------------|
| **Type 1 — Initial** (lookback low, clamped at max distance) | **Hard** | Broker stop order executes immediately; position closes at `stop_loss` price |
| **Type 2 — Break-Even +1 pt** (ratchet after sufficient profit) | **Hard** | Broker stop order moved to `entry + 1`; closes if price reverses below it |
| **Type 3 — LWR Trailing** (`lohb − sl_type_3_offset`) | **Soft** | Increments `exit_counter` only; never moves broker stop order |
| **Exit MA signal** | **Soft** | Increments `exit_counter` only |
| **Premarket limits** | **Soft** | Increments `exit_counter` only |

**Rule:** Hard stops are the only stops that modify or execute the resting broker stop order.  
**Rule:** Soft stops feed only into `exit_counter` — they never move the broker stop and never directly close the position.  
**Rule:** The `exit_counter` logic is entirely separate from hard stop logic. Hard stops must be evaluated BEFORE any counter logic and cause an immediate return from `evaluate()`.

---

## Stop Loss Lifecycle

### Trade Entry — Type 1 (Initial Hard Stop)

Set **once** when the position is entered. This is the **only** initial stop value — there is no distinction between "clamped" and "base level" sub-types. The initial stop is always a Hard Stop.

| Attribute | Value |
|-----------|-------|
| **Transition** | **t_110** — trade_entry_submitted (State07 → State09) |
| **Transition** | **t_120** — entry_block_cleared (State08 → State09) |
| **Formula** | `raw = shift_event_low − sl_type_1_offset` |
| | `floor = entry_price − sl_max_distance` (ES: 10 pts, NQ: 30 pts) |
| | `stop_loss = max(raw, floor)` ← **one value; always the hard stop** |
| **Condition** | Always on entry |
| **Broker action** | Submit resting stop order at `stop_loss` |
| **JSON record** | `stop_loss`, `stop_type = 'Type_1_Hard'` |
| **Exit transition** | `t_210_exit_hard_stop` / `t_211` / `t_212` (per active state) — immediate exit |

`shift_event_low` is the bar low captured at the Bull_Shift bar (State02 → State03 transition).

> **Critical rule:** Whether or not the `max()` clamp was binding at entry, the resulting `stop_loss` is the hard stop. A violation (`bar_low < stop_loss`) always fires `EXIT_HARD_STOP` immediately. The `exit_counter` is **never** involved in Type 1 stop enforcement.

---

### Per-Bar Updates — Types 2, 3, 5

Evaluated each bar while in active states 09 (Yellow), 10 (Green), or 11 (Red).
**None of these currently has a dedicated FSM transition** — see Gaps section.

#### Type 2 — Break-Even

| Attribute | Value |
|-----------|-------|
| **FSM Transition** | **None defined** ⚠ gap |
| **Active States** | 09 (Yellow), 10 (Green), 11 (Red) |
| **Formula** | `stop_loss = max(stop_loss, entry_price + sl_type_2_offset)` |
| **Condition** | `bar_high > entry_price + profit_limit` (one-time trigger per trade) |
| **Broker action** | Modify resting stop order to new `stop_loss` |
| **JSON record** | `stop_loss`, `stop_type = Type_2_BreakEven` |

#### Type 3 — LWR Trailing

| Attribute | Value |
|-----------|-------|
| **FSM Transition** | **None defined** ⚠ gap |
| **Active States** | 11 (Red only) |
| **Formula** | `stop_loss = max(stop_loss, lohb + 1.0 − sl_type_3_offset)` |
| **Condition** | Each bar while in state 11 |
| **Broker action** | Modify resting stop order to new `stop_loss` if changed |
| **JSON record** | `stop_loss`, `stop_type = Type_3_LWR_Trailing` |
| **⚠ Discrepancy** | Soft_Stop (50) comment uses `lohb − sl_type_3_offset`; Stop Loss Types Reference (state machine footer) uses `lohb + 1.0 − sl_type_3_offset`. **Resolve before implementation.** |

#### Type 4 — Session Limit (Disabled)

Type 4 is currently disabled. No transition is required until re-enabled.
When active: closest adverse premarket level ± `sl_type_4_offset`, velocity-gated; applies in state 11 (Red).

#### Type 5 — Session Trailing

| Attribute | Value |
|-----------|-------|
| **FSM Transition** | **None defined** ⚠ gap |
| **Active States** | 10 (Green only) |
| **Formula** | Trail `stop_loss` behind session price levels crossed in the profit direction |
| **Condition** | Each bar in state 10 where price has crossed a new session level in profit direction |
| **Broker action** | Modify resting stop order to new `stop_loss` if changed |
| **JSON record** | `stop_loss`, `stop_type = Type_5_Session_Trailing` |
| **⚠ Note** | Exact formula not yet specified. Requires `sl_type_5_offset` or equivalent parameter. |

---

## Stop Loss Type Summary Table

| Type | Name | Class | Transition | Formula | Condition | Broker Action | State(s) |
|------|------|-------|-----------|---------|-----------|---------------|----------|
| 1 | Initial | **Hard** | t_110 / t_120 | `max(shift_event_low − sl_type_1_offset, entry_price − sl_max_distance)` | Trade entry | Submit stop order | Entry to 09 |
| 2 | Break-Even | **Hard** | t_283 (SL update) + t_210/211/212 on violation | `max(stop_loss, entry_price + sl_type_2_offset)` | `bar_high > entry_price + type_2_profit_limit` | Modify stop order | 09, 10, 11 |
| 3 | LWR Trailing | **Soft** | counter only | `lohb − sl_type_3_offset` | Each bar in State11 | None | 11 |
| 4 | Session Limit | Disabled | n/a | Closest adverse premarket level ± `sl_type_4_offset` | Velocity-gated | n/a | 11 |
| 5 | Session Trailing | **Soft** | counter only | Trail behind session levels in profit dir | Crossover in profit direction | None | 10 |

---

## Gaps and Recommended New Transitions

Three stop types (2, 3, 5) have no current FSM transition. Two approaches:

### Option A — Sub-Actions in Per-Bar Transitions (Recommended)

Add explicit `[SL_UPDATE: Type N]` sub-action comment blocks to the per-bar velocity transitions already in the state machine:

| Transition | State | SL Type to Add |
|-----------|-------|---------------|
| Y-G_ascending (38, 09→10) | Green entry | Type 5 begins: evaluate session trailing |
| G-Y_descending (44, 10→09) | Green exit | Type 5 ends |
| Y-R_descending (39, 09→11) | Red entry | Type 3 begins: evaluate LWR trailing |
| R-Y_ascending (54, 11→09) | Red exit | Type 3 ends |
| Per-bar evaluation (all active states 09/10/11) | All active | Type 2: evaluate break-even ratchet |

Type 2 requires a per-bar evaluation in all three active states — this has no existing "per-bar" transition. A [SL_UPDATE] shared transition may be required.

### Option B — New [SL_UPDATE] Shared Transition

Define a `[SL_UPDATE]` shared transition that fires on every bar in each active state, before exit checks:
- **Guard:** always (per-bar evaluation)
- **Action:** evaluate applicable ratchet types (2/3/5 based on current state); if `stop_loss` changes, modify broker stop order and update JSON

**Recommendation:** Implement Type 2/3/5 as [SL_UPDATE] sub-actions in the velocity entry/exit transitions for Type 3 and 5 (they activate/deactivate with state). For Type 2 (cross-state), add a [SL_UPDATE] shared transition to states 09, 10, and 11. This minimizes new transitions while keeping each stop type traceable to a specific event.

---

## Cross-References

- State machine: [long_entry_state_machine_v1_2_10.md](long_entry_state_machine_v1_2_10.md) — transitions 31, 36, 50
- Stop loss parameters: `config_2_indicators_v5_4_0.json` (`sl_type_1_offset`, `sl_type_2_offset`, `sl_type_3_offset`, `sl_type_4_offset`, `profit_limit`)
- Strategy source: `strategy_v7_0_2.py` — Stop Loss Types Reference section

---

## Change Log

| Date | Version | Project | Change Summary |
|------|---------|---------|----------------|
| 2026-04-13 | v1.1.0 | 20260412_TWM_exit_optimization | Clarify Type 1 initial stop: ONE value, ALWAYS Hard regardless of whether max-distance clamp was binding. Add Hard/Soft classification column to summary table. Add critical rule: exit_counter is never involved in Type 1 (Hard Stop) enforcement. Update entry transitions to t_110/t_120 (v9.5.x numbering). Add version control header. |
| 2026-03-23 | v1.0 | 20260319_refactor_strategy | Initial document — maps all stop loss transitions; flags gaps for Types 2, 3, 5; documents Type 3 formula discrepancy; recommends [SL_UPDATE] approach for per-bar ratchets |
