Interactive Brokers Client Services
Jun 17 12:40 AM
Message Center Notification
Interactive Brokers ticket response regarding Kanex account messaging.
Joaquín Medina
Jun 17 12:34 AM
RE: Re:[## 708 ##] RE: RMA for EXT-4KHD70M
AVIT Vision requests credit memo for destroyed equipment per RMA 708.
Microsoft Outlook
Jun 16 10:36 PM
Undeliverable: FW: TIER 3 Trending Stocks Part 2 (1 New Red Candle): $DELL, $OSCR, $ONDS, $ZETA, $LMND and $TMC (June 17, 2026-daily)
Microsoft Outlook: Undeliverable: FW: TIER 3 Trending Stocks Part 2 (1 New Red
Interactive Brokers Client Services
Jun 16 9:59 PM
Security Notice for User k******8: Verify Log In
Fake Interactive Brokers security alert requesting account verification.
Microsoft Outlook
Jun 16 9:38 PM
Undeliverable: FW: $QCOM (June 17, 2026-daily)
Microsoft Outlook: Undeliverable: FW: $QCOM (June 17, 2026-daily)
TDhruv Sharma
Jun 16 9:05 PM
[Teams oneOnOne] (Teams DM)
Dhruv Sharma: [Teams oneOnOne] (Teams DM)
Fabiola Hernandez
Jun 16 6:55 PM
Tomorrow is Spirit Day – Souvenir T-Shirt Day
Spirit Day reminder: kids invited to wear souvenir t-shirt tomorrow at camp.
Derrick
Jun 16 6:19 PM
Request for More Info: EXT-USBC2XI-100M - Dual-Host USB 3.2 Gen 1 Extender over CAT6a — USB-C & USB-B Inputs, 100m/328ft
Product inquiry for USB extender; requesting pricing, specs, availability.
Sydnee Agent (AI)
Jun 16 6:00 PM
[Spread Cal] 2026-06-17 — per-stock max_spread_bps results
Sydnee Agent (AI): [Spread Cal] 2026-06-17 — per-stock max_spread_bps results
Sydnee Agent (AI)
Jun 16 5:40 PM
[Calibration Daily] 2026-06-17
Sydnee Agent (AI): [Calibration Daily] 2026-06-17
Sydnee Agent (AI)
Jun 16 5:30 PM
Sydnee algo daily — dev $-2,699 · prod $+0 · 6d window
Sydnee Agent (AI): Sydnee algo daily — dev $-2,699 · prod $+0 · 6d window
Find My
Jun 16 5:24 PM
A sound was played on Kelvin’s iPad mini.
Find My: A sound was played on Kelvin’s iPad mini.
Sammy Cemo, Matt Pourcho and Anthony DeLorenzo
Jun 16 4:04 PM
New Pricing | Fortune 40 Credit | STNL Industrial | 11 Yr. WALT | SoCal
⚠ PHISHING: employee impersonation: display name matches 'anthony' but sender is cbre.com
Microsoft Store
Jun 16 3:23 PM
Meet the new Surface lineup—with limited-time offers
Microsoft Store: Meet the new Surface lineup—with limited-time offers
[email protected]
Jun 16 2:34 PM
New Funding Program
Funding broker offering working capital solutions and consolidation services.
Sammy Cemo and Anthony DeLorenzo
Jun 16 2:03 PM
Single-Story Owner-User Offering in Newport Beach
⚠ PHISHING: employee impersonation: display name matches 'anthony' but sender is cbre.com
Aarti Gupta
Jun 16 1:53 PM
Re: CR-TOUCH6R 6" Widescreen Touch Panel with Knob, RS232/RS485 & PoE
Aarti Gupta: Re: CR-TOUCH6R 6" Widescreen Touch Panel with Knob, RS232/RS
[email protected]
Jun 16 1:43 PM
Action required: Your June booking bonuses expire soon
⚠ PHISHING: phishing subject pattern: 'Action required' from external sender vacationoffer.com
TAnthony Patino
Jun 16 1:30 PM
[Teams oneOnOne] (Teams DM)
LK account overdrawn; bank fee applied, needs replenishment before QB charge.
TAnthony Patino
Jun 16 1:27 PM
[Teams oneOnOne] (Teams DM)
Anthony Patino sent a brief Teams DM referencing 'LK'.
TAnthony Patino
Jun 16 1:27 PM
[Teams oneOnOne] (Teams DM)
Anthony Patino reports insufficient funds issue.
Amazon Payments
Jun 16 12:44 PM
Action requise sur le compte Amazon Payments
Fake Amazon Payments suspension notice in French requesting account verification.
Nick Daniel
Jun 16 11:04 AM
Quick question
TriNet HR solution sales inquiry.
Aarti Gupta
Jun 16 10:04 AM
Re: Order help #1227
Aarti Gupta: Re: Order help #1227
Aarti Gupta
Jun 16 10:03 AM
Re: Order help #1227
Aarti Gupta: Re: Order help #1227
Aarti Gupta
Jun 16 9:59 AM
EXT-USBCPD4K-70M 18Gbps USB-C 4K60 HDBaseT 3.0 Extender with 100W PD (70m)
Aarti Gupta: EXT-USBCPD4K-70M 18Gbps USB-C 4K60 HDBaseT 3.0 Extender with
Sean McGinley
Jun 16 9:58 AM
Order help #1227
Customer inquiry about HDMI extender transmitter compatibility for order #1227.
IBKR FYI
Jun 16 9:51 AM
FYI: Upcoming Exchange Holidays
Exchange holiday notice: MIAX, NASDAQ, NYSE closed June 19.
IBKR FYI
Jun 16 9:27 AM
FYI: Upcoming Exchange Holidays
NASDAQ/MIAX exchange holiday June 19, 2026 — no trading.
Hims
Jun 16 9:02 AM
Kelvin - action required on your account
⚠ PHISHING: phishing subject pattern: 'action required' from external sender icloud.com
[email protected]
Jun 16 9:02 AM
You have a new estimate
Suspicious medical estimate link from Providence—verify legitimacy before clicking.
Mail Delivery System
Jun 16 8:20 AM
Mail delivery failed [Invoice #36077 PO: SH260526762J]
Mail delivery failed for invoice #36077 to Mike Vanderkamp; recipient address rejected.
Mail Delivery System
Jun 16 8:19 AM
Mail delivery failed [Invoice #36078 PO: SH260430677J]
Mail delivery failed: [email protected] → [email protected] for invoice #36078.
Mail Delivery System
Jun 16 8:19 AM
Mail delivery failed [Invoice #36079 PO: SH2606101007J]
Mail delivery failure: invoice to [email protected] rejected by recipient server.
TDhruv Sharma
Jun 16 8:16 AM
[Teams oneOnOne] (Teams DM)
Dhruv Sharma: [Teams oneOnOne] (Teams DM)
Zoho Campaigns
Jun 16 7:55 AM
Campaign "NEW USB-C + USB-B Dual-Host Extender · 100m" has been successfully Sent - Zoho Campaigns
Zoho Campaigns notification: USB-C/USB-B extender product campaign sent successfully.
Ali Pacheco
Jun 16 7:53 AM
Request for More Info: EXT-USBC2XI-100M - Dual-Host USB 3.2 Gen 1 Extender over CAT6a — USB-C & USB-B Inputs, 100m/328ft
Product inquiry for USB 3.2 extender from external vendor.
KanexPro
Jun 16 7:51 AM
NEW USB-C + USB-BDual-Host Extender · 100m
KanexPro: NEW USB-C + USB-BDual-Host Extender · 100m
KanexPro
Jun 16 7:50 AM
NEW USB-C + USB-BDual-Host Extender · 100m
KanexPro: NEW USB-C + USB-BDual-Host Extender · 100m
KanexPro
Jun 16 7:50 AM
NEW USB-C + USB-BDual-Host Extender · 100m
KanexPro: NEW USB-C + USB-BDual-Host Extender · 100m
KanexPro
Jun 16 7:49 AM
NEW USB-C + USB-BDual-Host Extender · 100m
KanexPro: NEW USB-C + USB-BDual-Host Extender · 100m
TDhruv Sharma
Jun 16 7:33 AM
[Teams oneOnOne] (Teams DM)
Dhruv Sharma: [Teams oneOnOne] (Teams DM)
TDhruv Sharma
Jun 16 7:32 AM
[Teams oneOnOne] (Teams DM)
Dhruv Sharma: [Teams oneOnOne] (Teams DM)
Bank of America
Jun 16 6:16 AM
Your available account balance is low
Bank of America: Your available account balance is low
Let's Talk Supply Chain
Jun 16 6:01 AM
Are you ready?
Suspicious meeting confirmation from unknown sender with obfuscation.
Interactive Brokers Client Services
Jun 16 5:18 AM
Message Center Notification
Interactive Brokers ticket response regarding Kanex account notification.
Benjamin & Williams
Jun 16 5:03 AM
Commercial Claim Discovery Documents Our file:D-8222 Debtor: VICTORIA ROPA ELEGANTE
Fake debt collector demanding payment on unknown commercial claim within 24h.
IBKR FYI
Jun 16 5:01 AM
FYI: Option Expiration Notification
Oracle options expiring 18JUN2026 — immediate action required.
IBKR FYI
Jun 16 5:00 AM
FYI: Option Expiration Notification
MSTR call option expiring 18JUN2026; action needed if extending position.
Sydnee Agent (AI)
Jun 16 4:25 AM
Sydnee nightly — exit_flow audit 2026-06-16 — 0P0 8P1 6R
Sydnee Agent (AI): Sydnee nightly — exit_flow audit 2026-06-16 — 0P0 8P1 6R
Sydnee nightly — exit_flow audit 2026-06-02 — 0P0 5P1 5R
AI verdict
employee
high
· confidence: high
· by internal-exempt
“Sydnee Agent (AI): Sydnee nightly — exit_flow audit 2026-06-02 — 0P0 5P1 5R”
Reasoning: @sydnee.ai is a protected domain — hard exemption
Sydnee nightly — exit_flow audit — 2026-06-02
P0 findings: 0 P1 findings: 5 Risks: 5
- Area: Exit flow (how and when open positions are closed)
- Branch: `dev` (6528ac2)
- Files scanned: `bot.py` (~18 225 lines), `docs/strategy_decisions.md`, prior exit-flow audits (2026-05-26, 2026-05-27), `git log --oneline -30`
- Bugs found (P0 / P1): 0 / 5 (2 new, 3 carried)
- Risks noted: 5 (2 new, 3 carried)
Cross-check: `git log --oneline -30` shows no commits since `6528ac2` that touch exit flow, stop logic, or trim ladder. Both carried P1s from 2026-05-26 and the carried P1 from 2026-05-31 remain unfixed. Two new P1s found via direct code inspection.
---
Full report (dev branch): https://github.com/kanex1/sydnee.signals/blob/dev/docs/audit_2026-06-02_exit_flow.md
Reply FROM [email protected] to [email protected] to request fixes, e.g.:
"code_task on sydnee-signals-dev: apply fix for the P0 about RVOL threshold in bot.py"
Sydnee Agent will propose + you APPROVE (or plain 'approve') + auto-push to dev.
--- Full audit below (first 12 KB) ---
# Nightly Audit 2026-06-02 — EXIT FLOW
## Summary
- Area: Exit flow (how and when open positions are closed)
- Branch: `dev` (6528ac2)
- Files scanned: `bot.py` (~18 225 lines), `docs/strategy_decisions.md`, prior exit-flow audits (2026-05-26, 2026-05-27), `git log --oneline -30`
- Bugs found (P0 / P1): 0 / 5 (2 new, 3 carried)
- Risks noted: 5 (2 new, 3 carried)
Cross-check: `git log --oneline -30` shows no commits since `6528ac2` that touch exit flow, stop logic, or trim ladder. Both carried P1s from 2026-05-26 and the carried P1 from 2026-05-31 remain unfixed. Two new P1s found via direct code inspection.
---
## Findings
### BUG [P1] (new): `profit_per_share` uses stale bar close — RSI/BXt exits misrouted to trim path when intrabar price is at a loss
**File:** `bot.py:4595` (`profit_per_share` assignment) + `bot.py:4862` (`_in_profit` gate)
**Evidence:**
```python
# bot.py:4594-4595 — profit uses BAR CLOSE, not live tick
live_price = float(ss.last_price) if ss.last_price else close_price
profit_per_share = (close_price - t.entry_price) * t.direction # ← stale close
# bot.py:4862 — _in_profit gates trim vs full-close routing
_in_profit = profit_per_share > 0
# bot.py:4864-4919 — RSI exit path uses _in_profit to decide route
if not _in_profit:
...full close...
elif _is_trimmed_2_now:
...runner close...
elif is_trimmed:
t._rsi_force_trim2 = True # ← trim-ladder path
else:
t._rsi_force_trim = True # ← trim-ladder path
# Same _in_profit routing at bot.py:5009-5025 (BXt reversal exit)
```
`_evaluate_symbol` is triggered at each 5m bar close. `close_price` is the just-closed bar's price. `live_price` (used for trim level checks) is the WebSocket tick, which can diverge in fast-moving markets.
**Concrete scenario (LONG position):**
1. Entry at $100.00; bar N closes at $100.10 → `profit_per_share = +$0.10 > 0`, `_in_profit = True`
2. Bar N+1 starts; price drops intrabar to $99.80 before `_evaluate_symbol` runs
3. RSI(9) remains ≥ 70 (carried from bar N's close)
4. `_in_profit = True` (bar N close, stale) → **trim path**: `_rsi_force_trim = True`
5. EXIT 4 fires: TRIM1 at `live_price = $99.80` (loss of $0.20/sh on the trim child)
6. `profit_per_share > 0` → profit guard does NOT activate → `new_stop = $100.00` (BE above current price)
7. Next bar: `close_price ≤ $100.00` → stop fires → runner sold at ~$99.80 (another loss fill)
**vs. correct (using `live_price` for `_in_profit`):**
- `_in_profit = False` → single clean full-close at $99.80
**Impact:** When RSI/BXt reversal fires while intrabar price is below entry after a profitable bar close: (a) two fills instead of one, (b) extra commission, (c) BE stop set above current price guaranteeing immediate stop-out on runner, (d) activity log says "TRIM1" + "Stop-loss" masking the actual in-loss exit. Frequency: any RSI/BXt reversal bar where price has moved below entry since the last 5m close.
**Fix:** Use `live_price` for the profit gate:
```python
# bot.py:4862 — replace:
_in_profit = profit_per_share > 0
# with:
_in_profit = (live_price - float(t.entry_price)) * t.direction > 0
```
Same fix applies to the BXt reversal `_in_profit` check at `bot.py:5009` (same variable, same scope).
---
### BUG [P1] (new): `_check_stops` defined but never called — intrabar bar-high/low stop check is dead code
**File:** `bot.py:6323–6341` (function definition); absent from all callers
**Evidence:**
```python
# bot.py:6323 — defined:
def _check_stops(self, trade: Trade, bar) -> None:
hit, reason = False, ""
if trade.stop_price:
if trade.direction == 1 and bar.low <= trade.stop_price: # ← correct: checks bar LOW
hit, reason = True, f"Stop-loss hit at ${trade.stop_price:.2f}"
elif trade.direction == -1 and bar.high >= trade.stop_price:
hit, reason = True, f"Stop-loss hit at ${trade.stop_price:.2f}"
if not hit and trade.target_price:
if trade.direction == 1 and bar.high >= trade.target_price:
hit, reason = True, f"Profit target hit at ${trade.target_price:.2f}"
elif trade.direction == -1 and bar.low <= trade.target_price:
hit, reason = True, f"Profit target hit at ${trade.target_price:.2f}"
if hit:
...
self._deferred_closes.append((trade, reason))
# grep result: ZERO callers in all .py files
```
Meanwhile, the 5m exit loop at `bot.py:4730–4734` only uses `close_price`:
```python
if t.direction == 1 and close_price <= t.stop_price:
_stop_hit_pending = True
```
**Impact:** When `WS_TICK_EXITS=false` (the default), stops fire ONLY on bar-close price. A bar that trades below the stop but closes above it never triggers the stop. Example: LONG with stop=$99.50, bar range $99.00–$101.00, close=$100.50 → stop not hit → loss of $0.50/share vs $0.50 stop. Frequency: any volatile bar with an intrabar wick through the stop level. Mitigated only when `WS_TICK_EXITS=true` (opt-in, default off).
The bar data needed for the check is already in scope at `_evaluate_symbol`: `signal_df["low"].iloc[-1]` and `signal_df["high"].iloc[-1]` (defined at `bot.py:4578`).
**Fix:** Replace the dead `_check_stops` call pattern with inline checks using signal_df in `_evaluate_symbol`, right next to the existing `_stop_hit_pending` block:
```python
# bot.py:4730–4734 — replace:
if t.direction == 1 and close_price <= t.stop_price:
_stop_hit_pending = True
elif t.direction == -1 and close_price >= t.stop_price:
_stop_hit_pending = True
# with:
_bar_low = float(signal_df["low"].iloc[-1])
_bar_high = float(signal_df["high"].iloc[-1])
if t.direction == 1 and _bar_low <= t.stop_price:
_stop_hit_pending = True
elif t.direction == -1 and _bar_high >= t.stop_price:
_stop_hit_pending = True
```
Same check for `target_price` at the bottom of the same block.
---
### BUG [P1] (carried from 2026-05-26 + 2026-05-27): OBV Rule F permanently disabled after in-loss skip
**File:** `bot.py:4662–4695` (in-loss profit-guard branch); outer guard at `bot.py:4614`
**Evidence:**
```python
# bot.py:4614 — one-shot outer guard (confirmed present in HEAD):
if os.environ.get("OBV_BE_STOP", "").lower() in ("1", "true", "yes") \
and not getattr(t, '_obv_be_applied', False):
...
if _profit_guard and profit_per_share < 0:
...
elif not getattr(t, '_obv_be_applied', False):
self._log_activity(...)
t._obv_be_applied = True # ← line 4687: consumed in in-loss path
...
else:
...
t._obv_be_applied = True # line 4694: correct (stop moved)
```
In-loss path sets `_obv_be_applied = True` (line 4687) without moving the stop. Subsequent bars skip Rule F entirely — the wide entry stop defends alone.
**Impact:** Trades underwater before OBV turns adverse, then recovering to profit, lose Rule F's stop-tighten. The −$774→−$217 bxt_reversal damage reduction only applies to trades profitable when Rule F first fires. Two audit cycles unfixed.
**Fix:** Remove `t._obv_be_applied = True` from the in-loss path (lines 4687-4688); keep it only in the profit path (line 4694) and in the `OBV_LOSS_EXIT` hit path (trade is closing anyway). See 2026-05-26 audit for full diff.
---
### BUG [P1] (carried from 2026-05-26 + 2026-05-27): TRIM2 `_rsi_force_trim2` flag never cleared for 1-share parents
**File:** `bot.py:5077–5112`
**Evidence:**
```python
if not hit and is_trimmed and not is_trimmed_2 and (_trim2_hit or _force_trim2):
trim = True
trim2_shares = t.shares // 2
if trim2_shares > 0: # ← guard
t._trimmed_2 = True # ← inside guard
t._rsi_force_trim2 = False # ← inside guard — never clears when shares=1
self._update_trade_field(...)
# no else branch
```
TRIM1 on an odd-share position (e.g., 1 share) leaves `trim2_shares = 0`. The `_rsi_force_trim2` flag stays `True` in memory and in DB (`force_trim2_pending=True`). Every subsequent bar re-enters the TRIM2 block with `trim = True`, suppressing the normal hold-log (`elif not trim:`).
**Impact:** Per-bar wasted evaluation and silent activity log every bar until exit. DB column `force_trim2_pending` stays stale through restarts. No incorrect close — cosmetic + CPU waste. Two audit cycles unfixed.
**Fix:** Add an `else` after the `if trim2_shares > 0:` block:
```python
else:
t._trimmed_2 = True
t._rsi_force_trim2 = False
self._update_trade_field(t.trade_id, trimmed_2=True,
force_trim2_pending=False, force_trim_reason=None)
```
---
### BUG [P1] (carried from 2026-05-31): `TV_BXT_TRAIL_AGAINST` default mismatch — live `1.0` vs history endpoint `1.5`
**File:** `bot.py:3750` (live OBV trail); `bot.py:14080` (history replay / stop-analysis endpoint)
**Evidence:**
```python
# bot.py:3750 — live _obv_trail_stop_hit:
agnst = float(os.environ.get("TV_BXT_TRAIL_AGAINST", "1.0"))
# bot.py:14080 — history replay used by dashboard stop-analysis:
agnst = float(os.environ.get("TV_BXT_TRAIL_AGAINST", "1.5"))
```
When env var is unset (default), live trail uses `1.0×ATR` while history replay uses `1.5×ATR`. Dashboard stop-analysis shows a 50% wider trail than what actually ran.
**Impact:** Dashboard /api/trade_obv_trail misleads the operator about live trail width; backtest comparison of OBV-trail performance is biased toward the wider trail. Three audit cycles unfixed.
**Fix:** Change `bot.py:14080` default `"1.5"` → `"1.0"`.
---
### RISK (new): `_stop_hit_pending` overwrites earlier `hit=True` reason with no guard
**File:** `bot.py:4848–4849`
**Evidence:**
```python
# HOLD_CAP (EXIT 0B) may set hit=True at bot.py:4723:
hit = True
reason = f"Hold cap {int(_held_min)}min ≥ ..."
# Later, _stop_hit_pending fires with NO `not hit` guard:
if _stop_hit_pending: # ← line 4848: no `not hit` check
hit, reason = True, f"Stop-loss ${t.stop_price:.2f} · ..." # ← overwrites HOLD_CAP reason
```
If HOLD_CAP fires (because trade exceeded cap duration) AND the same bar's close is also ≤ stop (common: the trade is at a loss, stop = BE at $100, close = $99.80), `_stop_hit_pending=True` overwrites the reason. Trade closes correctly; but DB `exit_reason` says "Stop-loss" instead of "Hold cap."
Same issue if `OBV_LOSS_EXIT` sets `hit=True` — its reason can also be overwritten by `_stop_hit_pending` on the same bar.
**Impact:** P&L attribution by exit type misclassifies HOLD_CAP and OBV_LOSS_EXIT exits as stop-outs. No trading error.
**Fix:** Add `not hit` guard at `bot.py:4848`:
```python
if _stop_hit_pending and not hit:
hit, reason = True, f"Stop-loss ${t.stop_price:.2f} · {_state_snap()}"
```
---
### RISK (new): Tick exit path has no TRIM2 check — `WS_TICK_EXITS=true` skips trim2 level
**File:** `bot.py:16484–16551` (`_tick_exit_step`)
**Evidence:**
```python
# _tick_exit_step checks:
# 1. TICK STOP — closes full remaining position
# 2. TICK TARGET — closes full remaining position
# 3. TICK T1 — 50% trim at trim1_price, then exits
# 4. PROFIT EXIT — signed_vol flip
# No TICK T2 check.
```
When `WS_TICK_EXITS=true`: after tick T1 fires (50% trim), the remaining 50% is managed by the next 5m bar. If price rises to trim2 level intrabar (above trim1, below target), tick T2 never fires because there is no check. The 5m bar must close above trim2 for it to fire.
If price reaches target intrabar after trim1 but before the bar close, TICK TARGET fires → closes the remaining 50% at target, skipping trim2. The 5m path would have done: trim2 at trim2 level (50%), trim3 at target (50%), then run the final runner. The tick path closes the remaining 50% at target directly, which is actually a better outcome (exits more shares at the target), but diverges from the expected 4-level ladder.
**Impact:** Behavioral divergence between `WS_TICK_EXITS=true` and `WS_TICK_EXITS=false` runs. Ops may see unexpected trim ladder shortcutting when comparing live sessions.
**Mitigation:** Document in env v