# Trading bot session summary: Wednesday 2026-09-23

Everything discussed, changed and tested on 2026-09-23, in the order it happened, so it can be reviewed later. Paper-trading account. All times are ET.

## At a glance

| Item | Result |
|---|---|
| Live P/L today | **−$379.57** over 68 trades (20 winners, 48 losers). Equity at close $8,931.70 |
| Session 1 (9:30–11:04) | 36 trades, 11 winners, **−$165.40**. Old rules with 6 slots; 5th and 6th entries often rejected for buying power |
| Session 2 (11:04–11:10) | 6 trades, 5 winners, **+$5.68**. 5 slots; liquidated to switch on the slope rule |
| Session 3 (11:10–15:55) | 26 trades, 4 winners, **−$219.85**. Slope rule live. 21 of 26 exits were hard stops (−$269) |
| Live changes made today | 5-bar slope rule ON; max positions 6→5; per-position cap 20%→19% (from tomorrow) |
| Built today, switched OFF | 30-min rescan (**ON from tomorrow**), resistance-stall exit, per-tick trade plan, volatility-based minimum stop |
| Bugs fixed | Stream never subscribed symbols added mid-session; reconnect resubscribed only the morning list; simulator reset the stop to 1.2× when `--min-entry-score` was passed |

**After-close testing in one line:** the exit isn't the main leak (tighter profit protection cut big winners more than it saved). The entry is. Blocking re-entries after a loss and the new trade plan both picked clearly better signals. Best 5-slot result: trade plan + re-entry rule, **+$153 over 4 days** (65% winners), against **−$34** for the current rules. Nothing new was switched on live.

## 1. Morning review: was yesterday's design working?

### 3× ATR stop and 1/4 giveback
- **3× ATR stop:** working exactly as coded. Every entry's stop was exactly 3.0× the 1-minute ATR. That put stops 1–6.5% below entry on volatile names, but only 3¢ on quiet ones.
- **1/4 giveback from the peak:** running every poll as coded, but it never switched on in the first hour. It only activates after a +15¢ peak **and** a downward slope, and no morning position peaked above +11¢. In a fast drop, price can fall well past the 1/4 line before the slope turns negative. On 09-21 in the backtest, SECZ and RUN were sold through this rule at −3% and −4%.
- **None of the morning losses came from either setting.** All 6 early losers were sold by the "deterioration" exit (2 of 4 signals) within 1–4 minutes of entry.

### Buying power: the 6th slot could never fill
- The account has no margin (multiplier 1). Six positions at a 20% cap each would need 120% of equity.
- Result: dozens of "insufficient buying power" rejections every few seconds (MARA, NWL, XHLD, GENI, LTRX…).

### SLS: why the bot tried to buy back 35 seconds after selling
| Time | Event |
|---|---|
| 9:32:24 | BUY at $12.11 (trend positive, imbalance +86%) |
| 9:33:49 | SELL at $11.985: imbalance fell 5 reads in a row (−87% → −97%) and slope −0.013% |
| 9:34:05 | Back above VWAP by 2¢; 18-second hold starts |
| 9:34:25 | BUY signal again (imbalance **+97%**, score 88), blocked only by buying power |

Why it happened:
1. **Stage 1's "flat but constructive" branch** let it through. Price was going sideways within about ±6¢ of VWAP. It passed on 1–5¢ margins above VWAP and a 0.7¢ EMA9-over-EMA20 gap.
2. **The 20-second imbalance number was noise.** It went −97% → +97% → −100% within 2 minutes on thin trading.
3. **The entry score rose from 78 to 88**, because it rewards calm, flat stocks.
4. **Nothing remembers an exit.** There's no cooldown. The `allow_multiple_entries_same_symbol` and `same_symbol_reentry_cooldown_minutes` settings exist in `config.json`, but **no code reads them**.
5. **The slope thresholds don't match between entry and exit.** The exit treated −0.013% as "sloping down". The entry treated −0.078% as "flat" and let it in.

The earliest a sold stock can be re-bought is about 20 seconds after the exit. There's no "5 reads × 5 s" confirmation on entries. That rule belongs to the **exit** (`imbalance_exit_confirm_reads: 5`).

## 2. 5-bar slope rule (ON since 11:10)
- **Rule:** the slope of the last 5 one-minute bars must be **above the stock's flat band** (up, not flat) on **every** read. Otherwise Stage 1 fails and the 18-second hold restarts. The hold is about 5 reads, so that's about 5 consecutive "sloping up" reads for every entry and re-entry.
- **Why:** Stage 1's own trend uses a regression over every bar since the open, and its flat branch allowed gently falling stocks.
- **Backtest before enabling** (6 slots, 1/4 giveback, 3× ATR, score 55):

| Day | Old rules | 5-bar slope rule | "Any slope above zero" |
|---|---|---|---|
| 09-18 | +$322 | **+$467** | +$298 |
| 09-21 | −$439 | −$476 | −$589 |
| 09-22 (to 10:49) | −$195 | **−$146** | −$234 |
| **Total** | **−$311** | **−$155** | −$525 |
| Re-buys within 2 min of an exit | 21 | **4** | 7 |

- **Live check at 11:47:** 1,270 entry checks; 1,088 rejected by the rule (86%); 0 entries passed Stage 1 without an up slope.
- Config: `smart_engine.entry_slope_rule {enabled: true, lookback_bars: 5, mode: "positive"}`.

## 3. Slots, liquidations and restarts
| Time | Action | P/L of liquidated positions |
|---|---|---|
| ~11:03 | `max_positions` 6 → 5 | — |
| 11:04 | Bot stopped (SIGTERM → its own EOD liquidation), sold LTRX, QUBT, BTG, VNCE; restarted | +$34.23 (LTRX +27.55, QUBT +11.82, BTG −8.60, VNCE +3.46) |
| 11:10 | Stopped again to switch on the slope rule; sold FLNC, AMPL, MBC, NOMD, BLMN; restarted | +$12.94 |

- Each restart re-ran the scanner, and the **morning candidate file was overwritten** by the 11:10 list.
- With 5 slots at 20% each, 5 positions still used about 100% of equity. TAL was rejected at 11:05 with $17.89 left. **Per-position cap lowered 20% → 19%**, effective from the next start: 5 positions ≈ 95% of equity.

## 4. Why entries go negative right away
Every one of the 10 afternoon entries dipped below its entry price within 1–2 reads, **winners included**. FIRY fell 12¢ below entry, then ran +36¢.
1. **Spread:** market orders pay the ask, and the position is then marked near the bid. Fills were 0–2.5¢ above the signal price.
2. **Timing:** it buys after 5 rising bars plus the 18-second hold plus a buying burst, so at the top of a short move. A small pullback comes first.
3. **Scale:** the slope is per minute (e.g. +1.4¢/min) while the price moves ±2–3¢ every few seconds.
4. **The real damage was tight stops on quiet stocks.** 3× a tiny 1-minute ATR gave 3–7¢ stops (BLMN, LTRX 3¢), inside the normal dip. That's why the afternoon had 21 hard-stop exits.

## 5. 30-minute rescan (ON from tomorrow)
- After the 9:28 opening scan, the bot **rescans for a new top 30 every 30 minutes** (about 9:58, 10:28 …) until the 15:15 no-new-entries cutoff. The scan runs in a background thread, so exits keep being checked every 5 seconds.
- New symbols are backfilled with the day's bars, then subscribed. Dropped symbols are unsubscribed **unless a position is open** in them. Resistance levels are kept from the first scan a symbol appeared in.
- Rescans are saved as `data/candidates/<date>_scanner_HHMM.json`. The opening file isn't overwritten.
- **Two stream bugs fixed (`stream.py`):**
  1. `add_symbols()` sent its subscribe to an event loop that never runs, so symbols added mid-session were **never subscribed**. It now calls alpaca-py's thread-safe subscribe directly.
  2. After a reconnect, the stream resubscribed the original morning list only. It now resubscribes whatever is currently watched.
- Setting: `scanner.rescan_interval_minutes: 30` (0 = off). The simulator does **not** replay rescans yet.
- **Watch tomorrow at about 9:58** for `[RESCAN]` log lines. This is its first live run.

## 6. Resistance-stall exit (built, OFF)
Designed from the OPTX walk-through: bought at $7.61, then tested a $7.70–7.72 ceiling about 10 times in 50 minutes on thin volume without breaking out.

**Your five answers:**
1. The clock starts at the **first touch of the ceiling after entry**.
2. If **rising lows or rising volume on the tests** is confirmed, give it **10 more minutes**.
3. Sell at the **bottom** of the ceiling zone.
4. Sell **even if the position is below entry**.
5. Use a **market order** for now.

**Rules as built (`exit_resistance_stall.py`):**
- **Ceiling:** the highest cluster of at least 3 one-minute highs within max(2¢, 0.3%), with at most one wick above it.
- **A real breakout:** a completed bar closing above the ceiling + 1¢ on at least 1.5× average volume. That resets the clock.
- **At 60 minutes:** +10 minutes once if building; otherwise the rule arms and sells the first time price reaches the ceiling bottom.
- It runs after the giveback check and before the other exits.

**OPTX replay:** first touch 11:24 → ceiling confirmed 11:26 → the $7.7199 wick at 11:34 isn't a breakout → armed 12:24 (no rising lows, no rising volume) → **sold at $7.70 at 12:30** after 11 touches.

## 7. AMPL: manual "is this worth buying?" evaluation (14:57)
**Verdict: pass at $13.71; buy only on a confirmed breakout.**
- **Good:** steady uptrend from the $12.84 low with rising lows ($13.20 → $13.63); 1.5% above VWAP; liquid (2¢ spread, about 2,500 shares/min); test volume rising (5.9k–8.5k/min against 2.5k average).
- **Against:** a $13.70–13.71 ceiling that held for about 3 hours; volume faded right at the ceiling; the previous day's high ($13.80) was only 9¢ away; stop about 8¢ below → R:R about 1:1; about 1 hour left.
- **What would change it:** a 1-minute close above $13.72 on 5,000+ shares (better still, through $13.80); or a pullback that holds $13.63–13.65 (stop $13.58).
- The bot was also rejecting it, because of the slope rule. Its 3× ATR stop would have been only 4¢.

## 8. Per-tick trade plan (built, OFF)
Built so the bot runs the AMPL-style analysis itself, for every candidate, every 5 seconds (`setup_analyzer.py`).

**Your three answers:**
1. The plan **replaces** the final checks (+50% imbalance and the entry score).
2. Minimum **reward-to-risk is 1.5**.
3. **The plan's stop replaces the 3× ATR stop.**

Stage 1 (including the slope rule) and the 18-second hold still come first.

| Step | What it computes |
|---|---|
| Levels | VWAP, high of day, premarket high, previous day's high, 20-day high, current ceiling |
| Structure | Pivot lows and whether the last 3 are rising |
| Stop | Under the last pivot low, with a minimum floor (0.5% placeholder → volatility floor) |
| Target | Next level above; clear air = the stock's typical 60-minute move |
| R:R | Must be at least 1.5 |
| Time | Target must be reachable before 15:55 given how far the stock typically moves |
| Liquidity | At least 500 shares/min |

- **Output:** PASS (with reasons), WATCH (with exact triggers), or BUY on a **breakout** (first close through a level never closed above before, on at least 1.5× volume) or a **pullback** (rising lows, price in the zone above the last pivot low, green bar).
- **Logging:** a `[PLAN]` line whenever a stock's plan changes. It takes about 0.09 s per poll for 30 symbols.
- **Replays:** OPTX → BUY (breakout) at 11:19, the same moment as the real entry, then WATCH once the ceiling formed (R:R 1.24). AMPL → PASS from 14:52 (target not reachable in the time left), matching the manual read.
- **Two bugs fixed during testing:** plans were always PASS before 10:00 (needed 30 minutes of history), and re-crossing an old level counted as a breakout.

## 9. Volatility-based minimum stop (built, OFF)
- **Volatility** = daily ATR(14) as a % of price, from the daily bars the scanner already downloads. Classes: **low** under 3%, **medium** 3–6%, **high** over 6%. The class and stop distance are logged on every entry.
- **Floor** = max(volatility floor, 2× spread). The volatility floor is either k × daily ATR, or tiers of 0.6% / 1.0% / 1.5% of price. It **only ever widens** a stop.
- It feeds both stop paths: the current 3× ATR stop and the trade plan's stop.
- **Position sizing does not shrink with a wider stop in practice.** The 19% cap (about $1,697) is always the binding limit until the stop is more than about 5.3% away. A wider stop means **more dollars at risk per trade** (3¢ → $5, 15¢ → $25 on a $10 stock), not fewer shares.

**Premise check (118 real trades, 09-18 → 09-23):**

| Volatility class | Trades | Median dip after entry | In daily-ATR units | Winners' largest dip before their peak |
|---|---|---|---|---|
| Low (<3%) | 2 | 2.7¢ (0.34%) | 0.12 | 0% |
| Medium (3–6%) | 69 | 4.7¢ (0.56%) | 0.13 | 1.36% |
| High (>6%) | 47 | 7.5¢ (0.88%) | 0.12 | 2.79% |

| Floor | Winners it would have stopped out before they ran | Median floor |
|---|---|---|
| 0.10 × daily ATR | 8 of 36 ($244 of wins) | 5.3¢ |
| 0.15 × daily ATR | 5 of 36 ($183) | 7.9¢ |
| 0.20 × daily ATR | 2 of 36 ($31) | 10.5¢ |
| 0.25 × daily ATR | 1 of 36 ($13) | 13.1¢ |
| Tiers 0.6 / 1.0 / 1.5% | 2 of 36 ($31) | 10.0¢ |
| Flat 0.5% (plan placeholder) | 10 of 36 ($407) | 4.5¢ |

The dip after entry scales with volatility, at about 0.12–0.13 of the daily ATR in every class, so a floor based on daily ATR fits the data.

## 10. Backtests after the close: testing exits and entries separately

**Method.** The first round judged every change by total portfolio P/L. That mixes the two problems: a better exit frees a slot, and whatever the bot buys next is then charged to the exit. At your direction, exits and entries were tested **separately**:
- **Exit tests:** the same 144 entries (the baseline's, 4 days) were replayed under each exit rule, with no refills. Checked first: replaying the baseline's own entries with its own exits reproduced the baseline to the cent.
- **Entry tests:** every buy signal taken (no slot limit) with the same standard exit, scored **per signal**.
- All runs use live settings: 1/4 giveback (15¢ minimum), 3× ATR stop, entry score 55, 5-bar slope rule, 19% cap. Days: 09-18, 09-21, 09-22 (replay stops at 10:49, when the live bot crashed that day), 09-23 (candidate list is the 11:10 restart list, so the morning isn't faithful).

### 10a. First round (portfolio level, 5 slots)
| Variant | 09-18 | 09-21 | 09-22 | 09-23 | Total | Trades | Win % | Hard-stop losses |
|---|---|---|---|---|---|---|---|---|
| A: current live rules | +$449 | −$438 | −$125 | +$80 | **−$34** | 144 | 41.7 | −$619 |
| B: floor 0.20× daily ATR | +$449 | −$509 | −$125 | +$66 | −$119 | 140 | 40.0 | −$630 |
| B: floor tiers | +$449 | −$399 | −$125 | +$15 | −$60 | 137 | 41.6 | −$584 |
| B: floor 0.25× daily ATR | +$449 | −$409 | −$125 | +$39 | −$46 | 136 | 41.9 | −$511 |
| C: stall exit 60 min | +$303 | −$389 | −$125 | +$101 | −$109 | 161 | 43.5 | −$706 |
| D: trade plan (with slope rule) | +$6 | −$32 | +$65 | −$87 | −$50 | 16 | 43.8 | −$172 |

The stall exit's **own 15 sales were profitable** (about +$130; 9 of the 15 stocks did close above their ceiling later, mostly by only a few cents, and holding all 15 to 15:55 would have made about +$33 more). The variant lost overall because every freed slot was **refilled with a weaker trade**: 161 trades against 144. That led to the separate tests.

### 10b. Exit tests: same 144 entries, different exits
| Exit variant | P/L | Win % | Given back from peaks | Green (up 5¢+) → loss | Big wins ($25+) | Hard-stop losses |
|---|---|---|---|---|---|---|
| **Current live exits** | −$34 | 41.7 | $3,177 | 33 trades, −$547 | $1,069 | −$619 |
| **+ stall exit 45 min** | **+$41** | 45.1 | $2,965 | 28, −$490 | $1,016 | −$586 |
| + stall exit 60 min | +$23 | 44.4 | $3,009 | — | — | −$586 |
| + stall exit 90 min | −$53 | 41.7 | $3,150 | — | — | −$619 |
| Giveback activates at 10¢ | −$253 | 45.1 | $2,933 | — | — | −$593 |
| Giveback activates at 5¢ | −$193 | 51.4 | $2,498 | 19, −$178 | $427 | −$361 |
| Giveback ratio 1/2 | −$288 | 40.3 | $3,581 | — | — | −$589 |
| Breakeven lock at 5¢ | −$260 | 46.5 | $2,512 | 26, −$101 | $547 | −$361 |
| Breakeven lock at 8¢ | −$283 | 44.4 | $2,861 | 29, −$329 | $657 | −$548 |
| Breakeven lock at 10¢ | −$226 | 41.0 | $3,060 | 34, −$433 | $822 | −$593 |
| Giveback without waiting for slope | −$209 | 43.8 | $2,832 | 30, −$476 | $539 | −$619 |
| Stop floor 0.20× / 0.25× / tiers | −$46 / −$56 / −$41 | 43 | about the same | — | — | −$565 to −$602 |

What the exit tests show:
- The 144 entries reached **$3,143 of combined peak profit, and the current exits kept none of it.** Most of the giveback (about $2,300) is on trades that went green by a few cents and then ended as losses. They never reached the 15¢ that switches the 1/4 rule on.
- **Tighter profit protection (breakeven lock, earlier giveback) saves those trades but cuts the big winners roughly in half.** In this data, most big winners dropped back to their entry price before running. With these entries, protecting small gains costs more than it saves.
- **The only exit change that helped is the stall exit at 45 minutes (+$75 over 4 days).** It was better on 2 of the 3 days where it fired, so the evidence is thin.
- **Volatility stop floors made no real difference** once entries are held fixed.
- **Conclusion: the exit isn't where most of the money leaks.** Too many entries only get a few cents of gain, and no exit can bank much from that.

### 10c. Entry tests: every signal taken, same exit
| Entry rule | Signals | P/L | Per-signal avg | Win % | Median run-up | Median dip | Reached +10¢ | Reached +20¢ |
|---|---|---|---|---|---|---|---|---|
| Current (slope rule on) | 281 | −$83 | −$0.29 | 42.0 | 6.2¢ | 5.5¢ | 40% | 19% |
| Without the slope rule | 466 | −$264 | −$0.57 | 40.6 | 4.0¢ | 4.0¢ | 32% | 14% |
| **Re-entry after a loss must be above that entry** | 219 | **+$402** | +$1.84 | 45.7 | 8.2¢ | 6.0¢ | 46% | 22% |
| Re-entry after a loss blocked | 148 | +$300 | +$2.03 | 48.0 | 8.0¢ | 5.9¢ | 45% | 24% |
| Trade plan, with the slope rule | 11 | +$83 | +$7.51 | 63.6 | 15.9¢ | 9.5¢ | 82% | 27% |
| **Trade plan, without the slope rule** | 25 | **+$164** | **+$6.54** | **64.0** | **16.5¢** | 6.0¢ | **80%** | **32%** |

By day, "re-entry must be above that entry" beat the current rules on **all 4 days**: +$733 against +$526, −$380 against −$550, −$166 against −$193, +$215 against +$134.

What the entry tests show:
- **The slope rule does improve signal quality.** Without it, the average signal is worse (−$0.57 against −$0.29), and there are 66% more signals.
- **Re-entry after a loss is the biggest single leak.** Requiring price to be back above the losing trade's entry turned the entry side from −$83 to +$402.
- **The trade plan picks far better signals:** 64% winners, and 80% of them reach +10¢, against 40% for the current rules. But it's very selective (about 6 a day), and 25 signals is a small sample.
- **The trade plan and the slope rule conflict.** The plan's pullback buy needs a dip, and the slope rule needs 5 rising bars, so together they allow only 11 signals.

### 10d. Final combinations (real 5 slots, portfolio P/L)
| Combination | 09-18 | 09-21 | 09-22 | 09-23 | Total | Trades | Win % | Hard-stop losses |
|---|---|---|---|---|---|---|---|---|
| A: current live rules | +$449 | −$438 | −$125 | +$80 | −$34 | 144 | 41.7 | −$619 |
| + re-entry must be above the losing trade's entry | +$287 | −$264 | −$128 | +$100 | −$4 | 129 | 42.6 | −$525 |
| + re-entry rule + stall exit 45 min | +$362 | −$315 | −$128 | +$82 | +$1 | 155 | 43.2 | −$782 |
| **Trade plan (no slope rule) + re-entry rule** | +$63 | −$7 | +$60 | +$36 | **+$153** | 23 | **65.2** | **−$115** |

- **The trade plan combination is the only one positive in total, and it's the steadiest.** It was up on 3 of 4 days, with the smallest losses and a 65% win rate. But it traded only about 6 times a day, and it made only +$63 on the strong 09-18 day, where the current rules made +$449.
- **The re-entry rule on its own** mainly cut losses on the bad days (09-21: −$438 → −$264) and gave up part of the good day.
- **Caveats:** only 4 days of data, one of them partial and one with a non-faithful candidate list. The trade plan was designed today and tested on these same days. **None of this is proof yet.**

### Recommendation
1. **Entries (the bigger problem):** turn on the **re-entry-after-loss rule (`above_entry`)**. It was consistent on all 4 days in the entry test. Then run the **trade plan in shadow mode** for a few live days: it logs its `[PLAN]` decisions without trading, so its picks can be checked against the current rules before it replaces them. If the shadow results hold, switch it on, with the slope rule off while the plan is on, because the two conflict.
2. **Exits:** keep the current exits. **Don't** add a breakeven lock or an earlier giveback; both cost more on big winners than they saved. The stall exit at 45 minutes is a small maybe (+$75 in the exit test); it's worth another week of data before switching it on.
3. **Stop floor:** no measurable benefit in these tests, so leave it off. It's ready if later data points the other way.



## 11. Files created and changed today
| File | Change | Backup |
|---|---|---|
| `smart_engine.py` | 5-bar slope rule; trade-plan hook (`use_setup_plan`); volatility floor + class logging; `daily_atr` excluded from levels | `.bak-2026-09-23`, `.bak-2026-09-23-volfloor` |
| `monitor.py` | 30-min background rescan; resistance-stall exit wiring; `[PLAN]` logging; daily ATR per symbol; re-entry rule | `.bak-2026-09-23`, `-volfloor`, `-reentry` |
| `stream.py` | `add_symbols` fix, new `remove_symbols`, reconnect fix | `.bak-2026-09-23` |
| `scanner.py` | Rescan file suffix; daily ATR from the existing daily-bar fetch | `.bak-2026-09-23`, `.bak-2026-09-23-volfloor` |
| `data_store.py` | `write_candidates(suffix=)` so rescans don't overwrite the opening scan | `.bak-2026-09-23` |
| `simulate.py` | Flags `--entry-slope-bars/-mode` (0 = off), `--resistance-stall-exit`, `--stall-minutes`, `--setup-plan`, `--min-stop-style/-k`, `--reentry-after-loss`, `--breakeven-lock`, `--giveback-no-slope`, **`--fixed-entries`** (exit-isolation mode); peak/low/giveback metrics per trade; settings-override fix; daily ATR per replayed date | `.bak-2026-09-23`, `-volfloor`, `-reentry`, `-isolation` |
| `setup_analyzer.py` | **New**: per-tick trade plan | `.bak-2026-09-23-volfloor` |
| `exit_resistance_stall.py` | **New**: stall-at-resistance exit | — |
| `volatility.py` | **New**: daily ATR, class, stop floor | — |
| `reentry.py` | **New**: re-entry-after-loss rule (off / block / above_entry), used by monitor and simulator | — |
| `exit_giveback_room.py` | New options `breakeven_lock_cents` and `require_slope` (defaults keep live behavior) | `.bak-2026-09-23` |
| `position_manager.py` | Unchanged (backups taken before edits that weren't needed) | `.bak-2026-09-23-volfloor`, `-reentry` |
| `config.json` | Slope rule ON; max positions 5; cap 19%; rescan 30; new sections `resistance_stall`, `setup_plan`, `smart_engine.min_stop`, `use_setup_plan`, `trading.reentry_after_loss` (all OFF) | `.bak-2026-09-23`, `-notional`, `-rescan`, `-stall`, `-plan`, `-volfloor`, `-reentry` |
| `logs/trade_bot_2026-09-23.log` | Removed 5 fake test lines (11:38:28, AAA/CCC) | `.bak-before-cleanup` |

## 12. What is live vs switched off (for the 2026-09-24 start at 9:25)
| Feature | Status |
|---|---|
| 3× ATR entry stop | Live |
| 1/4 giveback (15¢ minimum peak) | Live |
| Entry score ≥ 55, +50% imbalance final check | Live |
| 5-bar slope rule | **Live** |
| Max positions 5, per-position cap 19% | **Live** |
| 30-minute rescan + stream fixes | **Live** (first real run tomorrow) |
| Resistance-stall exit | OFF (`resistance_stall.enabled`) |
| Per-tick trade plan | OFF (`smart_engine.use_setup_plan`) |
| Volatility minimum stop | OFF (`smart_engine.min_stop.enabled`) |
| Re-entry-after-loss rule | OFF (`trading.reentry_after_loss.mode`) |
| Breakeven lock / giveback without slope | OFF (`giveback_room.breakeven_lock_cents`, `require_slope`) |

## 13. Open items and next steps
1. **Your decision:** turn on `trading.reentry_after_loss.mode = "above_entry"` for 09-24? (Built and tested; currently off.)
2. **Your decision:** add a **shadow mode** for the trade plan (log `[PLAN]` BUY decisions without trading) and run it for several days before letting it replace the current checks.
3. **Tomorrow at about 9:58:** confirm the first live 30-minute rescan in the log (`[RESCAN] applied ...`).
4. The simulator doesn't replay intraday rescans yet. Worth adding so future backtests match live behavior.
5. A **limit order at the bid or mid** for entries (instead of market orders) was discussed, to stop paying the spread, but not built.
6. The unused config settings `allow_multiple_entries_same_symbol` and `same_symbol_reentry_cooldown_minutes` still do nothing. Remove them, or wire them to the new re-entry rule.
7. More days of data are needed before trusting any of today's tuning. Rerun the exit and entry isolation tests weekly (`simulate.py --fixed-entries` for exits, `--max-positions 99` for entries).


## 14. Evening update: afternoon rules switched ON for 2026-09-24
At your request, the rules built this afternoon are switched on for tomorrow, so they can be compared with this morning's setup (backup: `config.json.bak-2026-09-23-evening`).

| Setting | This morning (live 9/23) | Tomorrow (9/24) |
|---|---|---|
| Final entry check | +50% imbalance + entry score ≥ 55 | **Trade plan** (breakout or pullback, R:R ≥ 1.5, time-fit) |
| 5-bar slope rule | On | **Off** (it blocks the plan's pullback buys) |
| Entry stop | 3× 1-min ATR | **Plan stop** (under the last higher low), at least **0.25× daily ATR** |
| Re-entry after a loss | Allowed | **Only above the losing trade's entry** |
| Stall-at-resistance exit | Off | **On, 45 min** (+10 if lows/test volume rising) |
| 1/4 giveback (15¢), hard stop, deterioration, imbalance exits | On | On (unchanged) |
| Slots / cap / rescan | 5 / 19% / 30 min | 5 / 19% / 30 min (unchanged) |

**Backtest of tomorrow's exact config** (5 slots): 09-18 **+$63** (7 trades) · 09-21 **+$48** (6) · 09-22 **+$60** (2, partial day) · 09-23 **+$119** (8) = **+$290 on 23 trades, 17 winners (74%)**. That compares with −$34 on 144 trades for this morning's rules on the same days, and −$379.57 live today.

Caveats: the trade plan was designed today and tested on these same 4 days, so this isn't proof. It trades only about 6 times a day. The live logs will show `[PLAN]` lines for every change in each stock's plan, which is the real comparison to watch.

## 15. Late additions (night of 9/23)

### Context-dependent entry rules (built, OFF)
`setup_plan.context_rules`, your design:
- **Breakout:** the last 5 bars must slope up.
- **Pullback:** may slope down temporarily if the higher low holds, the pullback low holds support (VWAP or the broken level), red-bar volume is at most 0.7× the leg up, the 20-second imbalance is at least −30%, R:R is at least 1.5, and the last bar **reclaims** the prior bar's high.
- Stage 1's 4-bar lower-highs reject is waived while a pullback is live.

| Version | Trades | Total | Per trade | Win % |
|---|---|---|---|---|
| Plan, every signal, context OFF | 25 | +$164 | +$6.54 | 64% |
| Plan, every signal, context ON | 9 | +$147 | +$16.30 | 67% |
| Tomorrow's config (5 slots), context OFF | 23 | +$290 | +$12.62 | 74% |
| Tomorrow's config (5 slots), context ON | 9 | +$205 | +$22.73 | 78% |

Better trades, but only about 2 a day, because pullbacks drop from 20 to 5. **Reminder for 9/24 at about 11:45:** decide whether to switch it on mid-day. The restart liquidates open positions.

### Reward/risk review
- **sip_bot** has no real R:R, only a "room to run" check: the next level must be at least 0.75% away unless a breakout is in progress, and the session high counts as a level. In its logs, it alone blocked 67 of 499 otherwise-passing checks (13%).
- **Our plan's R:R ≥ 1.5 is its biggest filter** (77% of raw signals, 57 of 61 breakouts). But the full simulator shows those blocked signals lose money:

| R:R minimum / breakout stop | Trades | Total | Per trade | Win % |
|---|---|---|---|---|
| **1.5 / pivot (current)** | 25 | **+$164** | **+$6.54** | 64% |
| 1.5 / under broken level | 26 | +$121 | +$4.67 | 62% |
| 1.0 / pivot | 38 | +$49 | +$1.29 | 55% |
| 1.0 / under broken level | 42 | +$81 | +$1.93 | 55% |
| none / under broken level | 106 | **−$285** | −$2.69 | 44% |

- **Conclusion:** the R:R gate protects the plan rather than over-limiting it. Every step looser was worse. A tighter stop under the broken level let more breakouts through, but those extra breakouts lost money. **Keep R:R 1.5 with the pivot stop.** The fixed-target replay hinted that R:R ≥ 2 signals are the strongest, so a 2.0 minimum is worth testing once there's more data.
- New option `setup_plan.breakout_stop` ("pivot" or "level", default pivot) and simulator flags `--plan-min-rr`, `--plan-breakout-stop`, `--plan-context`.
