168 Commits (4e2d2c0d13ac4f28736e9c538e8b7ce388123d70)
 

Author SHA1 Message Date
I Luk Kim 4e2d2c0d13 Add V45 sector ETF diagnostic script; document exhausted signal axes
diag_orb_sector_etf.py tests sector ETF gap/momentum as ORB quality signals.
Finding: sector ETF signals null (best G2=0.122R vs threshold 0.30R); QQQ regime
filter already captures all market-level information.

Also documents exhausted axes in lineage memory:
- Momentum curve 60-252d (best G2=0.259R, 252d)
- Calendar effects (period-specific artifact)
- Event catalyst (n=39, below G1 n≥120 threshold)
- CMF 20d (G2=0.046R)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 16f49411cb Add V34-V44 ORB diagnostic scripts; wire obv_slope_5 + min_obv_slope_20d infra
Signal axes tested (V34-V44, all failed G2 ≥ 0.30R gate):
- V34 obv_slope_5 (5d): G2=0.083R (null)
- V35 obv_slope composite (5d+20d): regime artifact (200d +18pp, 400d -12pp)
- V36 RSI-14: G2=0.148R, G5a=0.742 (redundant with OBV)
- V37 BB %B / BB width: G2=0.186R
- V38 dollar_vol_trend / sleep_streak / prior_day / vol_trend: all fail G2
- V39 premarket acceleration + hold ratio: G2=0.013R (null)
- V40 prior-day market breadth: G2=0.008R (null)
- V41 min_obv_slope_20d=0.0 hard filter: -15pp (OBV as gate too aggressive)
- V42 52w-high proximity + range position: G2=0.200R (best near-miss, fails)
- V43 30-min ORB window: -14.79% (catastrophic)
- V44 trailing multiplier sweep 0.6-1.0: 0.80 confirmed global optimum

Infrastructure added (backward-compatible, V24 parity preserved):
- features.py: obv_slope_5 enrichment key
- domain.py: weight_obv_slope_5=0.0, min_obv_slope_20d=None
- orb_simulator.py: 5 wiring sites for obv_slope_5; min_obv_slope_20d gate

V24 remains live champion. 20 signal axes exhausted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 8bd4dba89c V32 exit sweep FAILED; V33 QQQ ORB quality FAILED — V24 absolute terminal
V32 parametric sweep on V24 base (4 variants — all failed):
- risk6 (0.05→0.06): -1.93pp 200d FAIL
- trail_loose (0.8→1.0): +7.69pp 200d but -6.72pp 400d FAIL (regime-specific)
- breakeven_early (1.0→0.75R): -7.39pp 200d FAIL
- trail_09 (0.8→0.9): -14.83pp 400d FAIL (non-monotonic; 0.8 is global optimum)

V33 QQQ ORB candle quality diagnostic (new script):
- qqq_orb_body_pct/return/close_loc: Pearson ~0.001–0.022, day-level ρ ≈ 0
- QQQ daily gap filter already captures all market-level regime signal
- All 3 features fail G1 and G2 completely

All improvement axes now exhausted: 7 signal axes + exit sweep + market intraday.
V24 (OBV-slope w=0.05, 200d +95% / 400d +162%) is the absolute final champion.
Next R&D cycle requires new data source: sector ETF ORB / options flow / architecture.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 557d54921a V31 gap-zscore signal test: FAILED on both hard gate and negative weight
V31 research findings (2026-04-22):
- Hard gate (max_gap_zscore_20d=1.0): 45.2% vs V24 95.3% — catastrophically bad.
  All three terciles are profitable; hard rejection removes positive-EV trades.
- Negative weight (weight_gap_zscore=-0.05): 90.6% DD-12.33% Sh=2.649.
  Signal too weak (G2 failed at 0.181R < 0.30R threshold). G2 ≥ 0.30R
  validated as reliable promotion gate: OBV-slope (G2=0.394R) passed; all
  signals below 0.30R failed in backtest.

All 7 signal axes exhausted — V24 is the peak for current feature library.
domain.py: add max_gap_zscore_20d param (no-op at None default)
orb_simulator.py: add gainers_leader hard-gate (no-op at None default)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 5c6950af9d Fix gap_vs_market computation in diag_orb_trending_features.py
Was using non-existent gap_pct key in enrichment dict; now computes from
today_open and prev_close fields. V30 results: hurst INVERTED+G2 FAIL,
ou_theta G1 FAIL (near-zero Pearson). gap_vs_market re-running as V30b.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 733d8dabbd Add V29/V30 ORB diagnostic scripts; document V29 structural axis failure
V29 (diag_orb_structural_features.py): grav_pull G2 FAIL (+0.203R), market_temp G1 FAIL,
momentum_20d near-miss G2 FAIL (+0.291R). All 3 pass G1+G3 but miss G2 threshold.

V30 (diag_orb_trending_features.py): hurst_60d, ou_theta_60d, gap_vs_market (idiosyncratic
gap above QQQ). Running.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 5b7e17d50a Add V28/V29 ORB diagnostic scripts; V27/V28 axis verdicts documented
V28 (diag_orb_volatility_features.py): tests gap_zscore_20d, range_compression_10_60,
atr_ratio_10_60. At 400d: gap_zscore passes G1(n=176)+G3(+10.6pp WR)+G4+G5 but
fails G2 (avg_R gap 0.181R < 0.30R threshold). ABORT — V24 champion.

V29 (diag_orb_structural_features.py): tests grav_pull_20_50, market_temp_5_20,
momentum_20d — structural/regime axis orthogonal to OBV-slope.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim ab34c3ef1b Diagnose RSI-14/BB%B axis for V27: ABORT — redundant with OBV-slope
RSI-14: Pearson=+0.157, G2 passes (+0.316R gap, direction confirmed).
BUT ρ(RSI-14, obv_slope_20)=+0.726 — G5a FAIL. RSI captures same momentum
information as V24's OBV-slope. BB %B is ρ=0.889 with RSI — identical axis.
Both fail G1 (n=98 < 120 threshold). V24 remains champion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 137b413084 Diagnose ORB tape ignition (V26): NULL result, V24 remains champion
5 1-min microstructure features tested on V24 200d trade set (n=101).
range_coil_orb shows directional signal (Pearson=-0.128, WR gap +9.9pp)
but fails G1 (n=101 < 120) and G2 (avg_R gap 0.195R < 0.30R threshold).
p-value ~0.10 — insufficient for promotion. V24 remains champion.

Script fetches 1-min bars from Oracle and caches to data/cache/intraday_1min/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 1e7fcde14d Diagnose FINRA short-volume axis for V25: NULL result, V24 remains champion
Phase 1 diagnostic (diag_orb_short_volume.py) tests 3 short-ratio features
(prior-day, 20d avg, 20d z-score) on V24 200d trade set via FINRA CDN data.
All features fail all gates (|Pearson| ≤ 0.062, avg_R gap < 0.30R, WR gap < 5pp).

Direction inverts Boehmer 2020 hypothesis: high short ratio correlates positively
with ORB r_multiple (short-squeeze dynamics dominate at intraday ORB timescale).
V25 short-volume overlay not wired. V24 remains live champion.

Also adds scripts/audit_short_volume_coverage.py (Phase 0 DB coverage audit).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 4b8a157a67 Promote V24 ORB Gainers: add OBV-slope(20d) accumulation quality weight
Phase 1 diagnostic (diag_orb_quality_features.py) on V23 200d trade set found
obv_slope_20 passes all edge gates: Pearson=+0.2349 with r_multiple, top-tercile
WR 75% vs bottom 59.4% (+15.6pp), avg_R gap +0.394R. Hurst_60 and OU-θ_60 failed.

Weight sweep: 0.05 is Pareto-dominant (0.10/0.15 blow DD).

200d (same window): V24 +94.8% DD-11.3% Sharpe 2.83 vs V23 +85.0% DD-11.6% Sharpe 2.66
400d (same window): V24 +162.1% DD-13.7% Sharpe 2.47 vs V23 +149.4% DD-13.7% Sharpe 2.36
V24 Pareto-dominates V23 on both windows. V23 marked superseded.

Code changes:
- libs/intraday/features.py: add compute_obv_slope_approx() + enrich_daily_bars field
- libs/intraday/domain.py: add weight_obv_slope field to ORBStrategyParams
- libs/intraday/orb_simulator.py: wire obv_slope_20 read/store/score in gainers_leader branch
- configs: orb_gainers_v24_quality_overlay.yaml (new champion, live_readiness: experimental)
- configs: orb_gainers_v23.yaml status → superseded

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 9e622c6614 Investigate compound mode: V23 is absolute champion in all modes
- V23 pure compound (live-equivalent): 200d +148.13% DD-14.23%, 400d +209.41% DD-17.35%
- Hybrid V2 compound tested: 200d +175.41% looks promising but 400d +181.71% DD-23.72%
  loses to V23 by -27.7pp return AND -6.4pp worse DD → rejected
- Safe v9 compound 400d: +128.49% DD-14.43% — better DD but -81pp return vs V23 → rejected
- V23 tight governor compound 400d: +192.54% DD-17.32% — marginal gain, not worth config
- Live paper trader uses compound mode (engine.py:1816 session_equity = initial_equity + P&L)
- All improvement axes exhausted; V23 daily_reset declared TERMINAL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim cccbf88067 Document V23 TRUE 400d result and fix Safe v9 framing
V23 400d TRUE (correct pipeline, 2026-04-21): +146.09%, DD -13.66%, Sharpe 2.33.
Prior result (+120.87%, DD -23.97%) was from buggy AH-close pipeline; data fix
improved DD by 10.31pp. V23 now strictly dominates Safe v9 on ALL 400d metrics
(+45pp return, +3.5pp DD, +0.34 Sharpe). Updated Safe v9 status to
validated_200d_only and clarified Korean framing to remove the misleading
"최종 검증 전략" without qualification.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 2560556c72 Fix: NameError 'sym' undefined in parking overlay gate check
Should be actual_sym (defined in _parking_evaluate_gate scope),
not sym (which is only defined in _parking_buy).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 04bb11f9bb Add Oracle health pre-check in run_pre_screen to warn before bar-fetch timeout
If Oracle is unreachable at 09:20 ET, without this check the pre-screen silently
waits through 5 chunks × 15s timeout (75s) before logging the empty-bars warning.
The new 3s probe logs a CRITICAL warning immediately so the operator can restart
Oracle before the market opens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 65afc95c7e Clean up: reduce Oracle timeout, fix company endpoint, archive old v7/v15/v16 experiments
- libs/oracle_client/alpaca.py: reduce bar-fetch timeout 90s→15s (fail fast on Oracle outage)
- libs/oracle_client/client.py: add health_check_fast() for cheap liveness probe; fix health path
- libs/oracle_client/company.py + financial.py: use /api/v1/company/{symbol} (newer endpoint)
- libs/oracle_client/__init__.py: re-export AlpacaSnapshot/get_snapshot/get_snapshots at package level
- configs/experiments: delete archived v15.x, v16.x, v7.119–v7.358 experiment configs (superseded)
- README.md: fix absolute path → relative path for ORB docs link

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim ee2f1f6f84 Fix zombie daemon blocking ORB restart in ORBDaemonController
os.kill(pid, 0) returns success for zombie (defunct) processes.
Added ps stat check — if process is in Z state, treat as dead and
clean up PID file so subsequent start() calls work correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim b98442b28a Add paper trader improvements, web GUI updates, and experiment registry cleanup
- Paper trader: Alpaca broker fixes, catchup-thread state improvements
- Web GUI: intraday backtest duplicate run button, paper trading fixes
- Experiment registry: cleanup old v15/v16 experiments, update index
- Tests: Oracle client test additions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim d7bfda039b Add expanded ORB simulator features and metrics
- orb_simulator.py: min_abs_gap_pct filter, premarket dollar vol filter,
  rolling_loss circuit breaker, drawdown_governor, streak_sizing,
  trailing_tighten_at_r, allow_doji/red_to_green breakout, abs_gap scoring
  for gainers_leader, ORBSimulationState, run_orb_simulation_with_state API
- metrics.py: loss_containment_score and related metrics
- features.py: enrich_daily_bars with gap_zscore, ATR ratio, range compression
- domain.py: extended ORBStrategyParams with new fields
- cache.py: DailyBarCache with merged parquet storage and coverage metadata
- simulator.py: base simulator updates for new entry/exit mechanics
- configs/intraday: updated orb_gainers_v23.yaml with canonical params
- Added BLD to midlarge symbol snapshot

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 8f0f99bdda Fix daily bar rebuild to use market-hours close; clean ORB simulator debug code
Two fixes:
1. _rebuild_daily_from_intraday_cache now filters to regular market hours
   (9:30–16:00 ET) before computing OHLCV. Previously used bars[-1] which
   included after-hours data, distorting prev_close for gap calculations.
   Root cause of V23 regression: HIMS Aug-4 after-hours drop to $54.81
   made it appear as a +0.89% gap on Aug 5 instead of the correct -12.85%
   gap (from $63.45 market close), causing it to fail min_abs_gap_pct filter.
   V23 with fix: +109.32%, WR 58.1%, Sharpe 3.01, DD -12.91%

2. Remove temporary debug instrumentation (HIMS/2025-08-05 trace blocks)
   that was left in orb_simulator.py during regression investigation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 6489b22c89 Fix: paper trader missing TQQQ overlay evaluation in parking gate
_parking_evaluate_gate() was returning only QQQM or SGOV, never TQQQ,
because the low-vol overlay logic (_evaluate_low_vol_overlay_target in
backtester) was not implemented in the live engine. Add overlay check
at the end of the gate: vol threshold, temperature, entropy, and Hurst
R/S analysis — matching the backtester's conditions exactly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim cbeb463685 Fix stale hardcoded schedule references in run_breakout_check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 2d6da31bd5 Fix module-level docstring: run_stop_check schedule description
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 11d1bf6bfe Add live_pre_screen unit tests including min/max_atr_pct filters
12 tests covering all screener filters: min_price, min_atr_14,
min_avg_dollar_volume, date selection (latest-before, future excluded),
and the V23 quality filters min_atr_pct / max_atr_pct added last session
but previously untested.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim c5fa1394ed Add run_stop_check unit tests covering stop_loss, breakeven, and tighten
Tests the stop evaluation loop that mirrors orb_simulator.py:477-580:
- Long/short stop_loss hit
- Breakeven promotion (stop moves to entry at 1R)
- trailing_tighten_at_r: verifies tight ATR multiplier fires at 2R vs
  normal multiplier, exercising the tighten logic added in V23 port

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim d4daf7a951 Fix stale chunk_checkpoint test; add _record_trade and run_post_close tests
- Fix pre-existing test failure: fake_run_sim mock was missing **kwargs for
  the vix_by_day argument added to run_orb_simulation_with_state

- Add TestRecordTrade (7 tests): verifies long/short PnL sign, R-multiple,
  DB close call, and exit_reason preservation — the direction sign bug would
  silently invert short-trade PnL

- Add TestRunPostClose (4 tests): equity accumulation, stops_hit counter,
  today-only trade filter, snapshot persistence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim ba491b2a0d Fix EOD DB sweep bug and add regression test
Bug: pending candidate DB records were only swept inside the "has open
positions" branch of run_eod_exit, so a server restart mid-day (ORB
detection ran, no breakouts, no positions) left candidates as "pending"
forever.

Fix: move the in-memory and DB pending sweep to run unconditionally before
the positions check.

Test: TestEodDbSweep verifies both code paths (no-position + in-memory).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim a0732a9589 Add unit tests for run_orb_detection and run_breakout_check guards
Tests the three structural guards that were previously untested:
- Rolling loss filter: skip logic, boundary, window slicing, date exclusion
- Circuit breaker: 25% drawdown halts session
- max_simultaneous_entries: blocks new entries when at cap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim ecbff65ea4 Update run_stop_check docstring to reflect dynamic sim_bar_minutes schedule
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 1f1fd4299f Move function-scope library imports to module top in orb engine
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 713d04deef Fix EOD exit: sweep DB for stale pending candidates after restart; remove misleading compound_returns override
- run_eod_exit now queries DB for any pending candidates not in-memory
  (guards against server restart mid-day leaving zombie pending records)
- Remove compound_returns=True force-override; live engine doesn't use it
  and V23 config has compound_returns=false

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 6ae4588a62 Move inline stdlib imports (copy, time) to module top in orb engine
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 91efa04d4e Add unit tests for ORBTradingEngine._compute_sizing_capital
14 tests covering daily_budget_reset, drawdown governor (no-op, partial, full),
and streak sizing (win/loss/capped/floored/direction correctness).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 190f7a47fa Fix V23 live engine: regime filter, sizing fidelity, trailing tighten
- screener.py: add min_atr_pct/max_atr_pct filters to live_pre_screen
- engine.py: prepend regime ticker (QQQ) to bar fetch so regime filter works
- engine.py: add rolling loss + account circuit breaker at run_orb_detection
- engine.py: patch today_open from first 1-min bar so regime gap is real
- engine.py: explicit regime + breadth filter before compute_orb_candidates
- engine.py: max_simultaneous_entries guard in run_breakout_check
- engine.py: _compute_sizing_capital with daily_budget_reset (fixed $10k base),
  drawdown governor, and streak sizing (win bonus / loss penalty)
- engine.py: trailing_tighten_at_r in run_stop_check (tight multiplier at 2R)

Bug fixes in _compute_sizing_capital:
- streak direction: remove reversed() so outcomes[0] = newest trade
- daily reset: use initial_equity as base (not growing equity), matching V23

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim a59b71e46a Add V28 Stage A wiki signal probe script
Stage A for V28 (attention-axis second sleeve) exploration.
Probes existing orb_attention cache against V23 trade outcomes.
Result: ABORT — cache miss 35-43% on V23's traded (ticker, date) pairs;
only n=9 trades hit wiki>=1.5 across full 400d run (p=0.166, not significant).
Stage A inconclusive due to sparsity on V23's trading domain, not signal noise.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 41462c9e2c Fix: parking buy fill confirmation blocks event loop with 5s hard timeout
Make _parking_buy async (asyncio.sleep instead of time.sleep) and extend
confirmation from 5s to 30s per attempt with up to 3 retries on timeout.
On timeout, cancels the stale order before retrying with fresh price data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 0cae86aa87 Revert: remove daily_budget_reset from PEAD backtest
Feature was added to wrong system (PEAD backtester). Fully reverted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 189aa58343 Add daily_budget_reset mode for research backtesting
New mode (risk.daily_budget_reset=True) where cash_available and sizing
equity reset to initial_equity at the start of each day, regardless of
how many open positions or realized P&L exist. Unlike fixed_capital_sizing
(단리, sizing only), this also treats buying power as if no positions are
held — useful for evaluating signal quality independent of capital constraints.

- domain.py: daily_budget_reset field on RiskConfig
- run.py: _daily_budget_reset flag; _sizing_equity / _sleeve_equity_est /
  _build_portfolio_state all honor the new flag
- backtest_sim.py: daily_budget_reset param threaded through
- direct_runner.py: --daily-budget-reset CLI flag
- routers/backtest.py: BacktestRequest field + cmd arg
- client.ts: BacktestParams / BacktestTask types updated
- Backtest.tsx: checkbox in form + DBR badge in task list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 27b8a49d77 Fix: paper trader ignores per-engine overrides in build_planned_order
All five build_planned_order() calls in apps/paper_trader/engine.py were
missing execution_config, causing build_planned_order to fall back to
base config.execution and silently ignore per-engine target_1_r_override,
target_1_fraction_override, max_holding_days, tiered-target settings, etc.

The backtester has always passed execution_config=_build_effective_execution_config()
(run.py:2210). This divergence caused paper trading to compute wrong target
prices and partial-exit fractions — e.g. AVGO entered with target_r=1.5
(base) instead of 3.0 (engine override), triggering a premature partial
exit on 4/15 that the backtest never produced.

Fix: add execution_config=build_effective_execution_config(candidate, self._config)
to all five call sites and hoist the function to the module-level import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim fdd56ff683 Add duplicate run button and improve RunConfigPopup UX in Intraday ORB Backtest
- Add Copy button per run row in Run History table; opens pre-filled RunConfigPopup
  with original run's period/universe/compound_returns settings
- Make RunConfigPopup larger (500px wide) and more spacious with proper header/X button
- Prevent dialog from closing on backdrop click; only Cancel or X button closes it
- Range date inputs laid out side-by-side in 2-column grid

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim ebfada24cb Fix: don't permanently reject events when parking sell fails transiently
- When _parking_liquidate_for_event returns False but parking had shares
  (sell failed due to transient Alpaca error), skip without recording so
  event retries on next run_next_open instead of being permanently blocked

- Improve parking_sell_for_event_failed log: include exc_type, symbol, qty
  so we can see the actual exception (was silently swallowed with empty msg)

- Also deleted AVGO from processed_events so it retries tomorrow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 5ea8850ac2 Fix paper trader startup: run missed run_open if market still open; improve poll_error logging
- AutoScheduler._run_catchup: if server starts after 9:35 AM ET but before
  market close (16:00 ET), and run_open hasn't already run today
  (checked via processed_phases), run it immediately instead of silently
  skipping it — prevents AVGO/event entries being missed on late starts

- filing_poller: log exc_type alongside error so empty-string exceptions
  (e.g. HTTPError()) are still identifiable by their type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 86419beeb0 Fix ORB intraday data pipeline and consolidate strategy configs
- screener: switch from non-existent single-ticker endpoint to multi-ticker
  /alpaca/intraday batch calls (grouped by date, chunk ≤ 75); fixes 0-trades
- cache: bump version 2→3 to invalidate stale IEX Parquet files
- oracle_client: add get_multi_intraday_bars_today() for IEX real-time feed
- paper_trader: use /alpaca/intraday/today for live sessions, /alpaca/intraday
  for historical (SIP)
- intraday.py: define _BUILTIN_STRATEGIES={} to fix /api/orb/strategies import
- delete orb_p1–p10_winner + variant configs; add strategies/orb_default.yaml
  (Phase 10 params) as the single registered web strategy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 564bcba27c Add ORB pre-market screening and fix Oracle/Alpaca reliability bugs
- Add run_pre_screen() at 9:20 ET: fetch daily bars + enrichment + quality filter
  before market open, narrowing universe for faster orb_detect intraday fetch
- run_orb_detection() uses cached pre-screen data when available; falls back to
  full pipeline if pre_screen missed (late start, failure)
- Add _last_trading_day() helper to skip weekends/holidays for bars_end,
  preventing Alpaca 502 on Mondays (today-1 = Sunday was causing failures)
- Fix Oracle client chunk_size 300→75: Alpaca rejects 100+ ticker URL requests
- Add pre_screen event to build_schedule() at 9:20 ET and dispatch in _run_trading()
- run_session_now() runs pre_screen before orb_detect for efficiency
- Add ORB daemon, engine, models, state, screener, and intraday strategy configs
- Add intraday library (libs/intraday/) and web routes for ORB/intraday trading

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim f93ed2cfb5 Fix paper engine: prevent permanent rejection on transient order failures
Three bugs fixed:

1. _verify_order_fill now distinguishes alpaca_rejected vs order_timeout:
   - alpaca_rejected → record processed_event permanently (real problem)
   - order_timeout → do NOT record, allows retry on next run_next_open

2. Add _is_market_open() guard before every market buy submission:
   skips without recording so event retries when market opens

3. _parking_liquidate_for_event: sleep 1s → 3s after SGOV sell to give
   Alpaca time to settle cash; if plan still shows insufficient_cash after
   parking freed (race condition), skip without recording instead of
   permanently rejecting the event

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 658a741017 Route ORB bar data through Oracle API instead of calling Alpaca SDK directly
- libs/oracle_client/alpaca.py: Added get_multi_daily_bars() and
  get_multi_intraday_bars() helpers that call Oracle's /api/v1/price/data
  and /api/v1/alpaca/intraday endpoints respectively. Oracle handles
  symbol normalization (e.g. BF-B → BF.B) internally, so symbols like
  BF-B no longer crash the screening chunk.
- apps/paper_trader/alpaca_broker.py: get_bars() and get_intraday_bars()
  now use the new Oracle client helpers instead of the Alpaca SDK
  StockBarsRequest, eliminating direct Alpaca bar API calls from broker.
- apps/orb_trader/engine.py: Removed per-symbol BF-B workaround (now
  unnecessary since Oracle normalizes the symbol server-side); kept outer
  try/except for chunk-level resilience.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim aaa960c556 Handle invalid symbols (e.g. BF-B) gracefully in ORB detection
Daily bars chunk loop: on failure, retry symbol-by-symbol to isolate
and skip the bad ticker rather than crashing the entire detection.
Intraday bars chunk loop: catch and log failures, continue with rest.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 84e80fca75 Fix run_session_now: log all exceptions, never silently drop errors
- First log call moved to very top of run_session_now() so user always
  sees the task started, even if subsequent DB/engine calls fail
- Entire function body wrapped in try/except: errors go to scheduler log
  instead of vanishing in asyncio's unhandled-exception machinery
- Endpoint wraps create_task() in a logging shim (_task()) for the same reason
- 'already ran' path now logs a visible warning instead of silent return

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 407238e5d5 Fix '지금 시작': immediately run breakout check after ORB detection
Previously run_session_now() only ran orb_detect and injected future
scheduled events, but scheduled breakout windows were already past so
no breakout check ever fired.

Now: after orb_detect, immediately run one breakout check with current
snapshot prices (the core of '지금 시작'). All scheduled breakout events
are marked completed. Only stop_check and eod_exit events are injected
into the live schedule going forward.

Also improve alert message to clarify background execution (~1-2 min).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago
I Luk Kim 55a9618b20 Add scheduler log clear button
- POST /orb/auto/clear-log: clears in-memory log lines and deletes
  the orb_scheduler.log file on disk
- ORBAutoScheduler.clear_log(): implements the wipe
- Log panel header now has an Eraser icon button on the right;
  disabled when log is empty

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4 months ago