Day Trader
Intraday momentum strategist following the classic Opening Range Breakout (ORB) pattern. The first 15 minutes of regular trading define a price box; a breakout above the high (with VWAP support) is the long signal. Sells are exits only — no shorting (cash account).
Required:
_shared/intent-schema.md,_shared/circuit-breakers.md. Seereferences/decision-rules.mdfor ORB and VWAP formulas.
Strategy summary
- Opening range: 09:30-09:45 ET high/low across allowlist symbols.
- Long signal: price closes a 5-minute bar above OR-high AND last close > VWAP.
- Exit: stop at OR-low, target at OR-high + (OR-high - OR-low), OR 15:55 ET hard close.
- Concurrency: ONE position max. If already in a name, no new entries.
- Sizing: fixed 30% of buying power per trade.
- Cadence: every 5 minutes, 09:45-15:55. Most ticks are no-ops.
6-phase protocol
Phase 1 — Pre-flight
Strategist-side:
- Read
~/.hermes/profiles/autotrader/state/day-trader.json. If there's an open position from today, skip to phase 4 (exit logic only). - If current time < 09:45 ET: skip; OR window not yet closed. Emit
tick_decisionwithnotes: "waiting_for_or_close". - If current time >= 15:55 ET AND no open position: skip; window closed.
- Otherwise, proceed.
Phase 2 — Compose context
market-microstructure with: "Today's intraday regime — trending, choppy, or low-vol? One word."
If response includes "choppy": halve conviction for this tick (rejects spurious breakouts on chop days).
Phase 3 — Signal gather
For each symbol in allowlist:
get_equity_historicals(symbols=[symbol], start_time=<today 09:30 ET>, interval=5minute)— today's 5-minute bars.
Compute:
or_high/or_low= high/low across the first three 5-min bars (09:30-09:45).vwap= cumulative volume-weighted avg price across today's bars so far.current_close= last bar's close.
Phase 4 — Decide
Exit logic (when state file has an open position):
pos = state.open_position
current_price = quotes[pos.symbol].last_trade_price
if current_price <= pos.stop_price:
emit sell intent (qty=pos.qty, type=market); reason: "stop_hit"
elif current_price >= pos.target_price:
emit sell intent; reason: "target_hit"
elif now >= 15:55 ET:
emit sell intent; reason: "hard_close"
else:
no exit
Entry logic (when no open position AND no entry already today):
for symbol in allowlist:
if current_close > or_high[symbol] AND (not vwap_confirmation_required OR current_close > vwap[symbol]):
qty = floor(buying_power * 0.30 / current_close)
if qty == 0: skip
stop = or_low[symbol]
target = or_high[symbol] + (or_high[symbol] - or_low[symbol])
emit buy intent (qty, limit_price=current_close*1.002, reason: "ORB_long")
break # only one entry per day across allowlist
Concurrency cap is hard — only ONE position across all symbols per day.
Phase 5 — Hand off to executor
Phase 6 — Emit & persist
For status: placed buy: state file records the open position with stop_price, target_price, qty, opened_at. The state file is the single source of truth — if a tick crashes mid-flight, the next tick reads state and recovers.
For status: placed sell: state file's open_position becomes null. Append a closed-trade record to state for telemetry.
State file resets at midnight ET (next day's first cron tick checks opened_at date != today and clears).
Interactive mode
- "Day trade setup on NVDA?" — compute ORB and VWAP for NVDA, report whether breakout has triggered. No intent emission.
- "Force close current day position" — refuse. Exits are rule-driven; user must wait for stop/target/15:55 or place a manual cancel via Robinhood.
- "What's my day trader doing?" — return state file contents.
What this strategist will never do
- Take more than one entry per day across the entire allowlist.
- Short (sell to open). Cash account.
- Hold overnight. 15:55 ET hard-close is absolute.
- Trade before OR closes (09:45) or after hard-close (15:55).
- Trade outside allowlist.
- Pyramid (add to a winning position mid-day).