# Web PRD (Source of Truth) ## 1. Scope This document defines the product behavior for the Streamlit web app in `web/src/`. This PRD is intentionally web-only: - Data fetch and analysis logic - Classification/trend rules - Filters, chart behavior, exports, and persisted settings Out of scope: - macOS shell/wrapper architecture and packaging ## 2. Product Goal Provide an analysis-only charting tool that classifies OHLC bars as real/fake, tracks trend state using only real bars, and exposes clear visual, training-oriented guidance, and exportable outputs. ## 3. Inputs and Data Pipeline 1. User configures: - `symbol` - optional `watchlist` (per-profile) - `interval` - `period` - `max_bars` - optional `market_preset` - filter/toggle settings - optional advanced controls (alerts, replay, compare symbols, backtest controls, regime filter) 2. App fetches OHLCV via Yahoo Finance (`yfinance`). - For day-based periods (for example `1d`, `5d`), fetch widens calendar lookback as needed, then trims to the latest N trading days that actually contain bars. 3. Optional last-bar drop (live-bar guard) for intraday intervals. 4. Bars are classified (`real_bull`, `real_bear`, `fake`, `unclassified` for first bar). 5. Trend state is derived from classification sequence. 6. UI renders metrics, chart, events, and export artifacts. ## 4. Settings Contract Persisted settings path: - Primary: `~/.web_local_shell/settings.json` - Legacy fallback read: `~/.manesh_trader/settings.json` Storage format: - Current format stores per-profile settings: - `last_profile`: most recently used profile id - `profiles`: object map of `profile_id -> profile record` - profile record fields: - `settings`: normalized settings payload - `pin_hash`: optional SHA-256 hash for 4-6 digit PIN - `audit`: metadata (`created_at`, `updated_at`, `last_login_at`, `last_symbol`) - Legacy single-profile payloads are read as profile `default` and migrated to current format on next save. Profile behavior: - App enforces a profile login gate before data/settings UI is shown. - Login requires typing an existing profile name. - Login checks PIN when profile has one configured. - Login includes `Remember me on this browser`. - Create Profile requires typing a new profile name. - Create Profile accepts optional 4-6 digit PIN. - Profile-name uniqueness is case-insensitive (for example `Matt` and `matt` are treated as duplicates). - Sidebar shows active profile with a `Switch profile` control. - Sidebar shows profile audit stamps (created/updated/last login/last symbol). - Query param `profile` selects active profile. - Save/load are scoped to active profile to avoid cross-user overwrites. - If profile has no saved settings, defaults are used. - Session activity is tracked in-memory; after 30 minutes of inactivity the app clears active profile and returns to login screen. - If `remember=1` is present with a known non-PIN profile, app auto-restores that profile without showing login. - PIN-protected profiles always require PIN entry after session timeout/reopen. Watchlist and preset behavior: - `watchlist` is saved per profile and supports comma/newline input. - Watchlist supports one-click symbol quick-select buttons. - `market_preset` applies tuned defaults for common workflows (`Custom`, `Stocks Swing`, `Crypto Intraday`, `Crypto Swing`). - Preset application affects defaults for timeframe/period/max bars and related monitoring/gap options. Advanced feature behavior: - Multi-timeframe confirmation (`1h`, `4h`, `1d`) can show consensus trend and agreement percent. - Alert rules can trigger on bullish/bearish trend events and optionally POST JSON payloads to a webhook URL. - Session stats track since-login wins/losses, average move after signal, and fake-bar rate for visible data. - Backtest controls include slippage/fees (bps), optional stop-loss/take-profit %, and min/max hold bars. - Signal quality score combines trend state, volume-filter usage, and recent fake-bar density. - Replay mode limits visible bars to first N rows to simulate no-hindsight review. - Compare symbols panel can summarize trend/regime/fake-ratio for a small basket. - Regime filter flags choppy periods and can suppress directional bias. Normalization constraints: - `symbol`: uppercase, non-empty fallback `AAPL` - `interval`: must be one of `INTERVAL_OPTIONS`, fallback `1d` - `period`: must be one of `PERIOD_OPTIONS`, fallback `6mo` - `max_bars`: `[20, 5000]`, fallback `500` - `volume_sma_window`: `[2, 100]`, fallback `20` - `volume_multiplier`: `[0.1, 3.0]`, rounded to 0.1, fallback `1.0` - `refresh_sec`: `[10, 600]`, fallback `60` - `show_live_guide`: boolean, fallback `false` - `show_past_behavior`: boolean, fallback `false` - `show_trade_markers`: boolean, fallback `false` - `focus_chart_on_selected_example`: boolean, fallback `false` - `max_training_examples`: `[5, 100]`, fallback `20` - `watchlist`: uppercase de-duplicated symbol list, max 40 items - `market_preset`: one of `Custom`, `Stocks Swing`, `Crypto Intraday`, `Crypto Swing`, fallback `Custom` - `compare_symbols`: uppercase de-duplicated symbol list, max 12 items - `alert_webhook_url`: optional string - `backtest_slippage_bps`: `[0.0, 100.0]`, fallback `0.0` - `backtest_fee_bps`: `[0.0, 100.0]`, fallback `0.0` - `backtest_stop_loss_pct`: `[0.0, 25.0]`, fallback `0.0` (0 disables) - `backtest_take_profit_pct`: `[0.0, 25.0]`, fallback `0.0` (0 disables) - `backtest_min_hold_bars`: `[1, 20]`, fallback `1` - `backtest_max_hold_bars`: `[1, 40]`, fallback `1` and clamped to `>= min_hold` - `display_timezone`: one of `America/New_York`, `America/Chicago`, `America/Denver`, `America/Los_Angeles`, `America/Phoenix`, `America/Anchorage`, `Pacific/Honolulu`; fallback `America/Chicago` - `use_24h_time`: boolean, fallback `false` (`false` => `1:00 PM`, `true` => `13:00`) - booleans normalized from common truthy/falsy strings and numbers ## 5. Classification Rules For each bar `i` (starting at index 1): - Reference prior bar `i-1`. - If `use_body_range = false`: - `prev_high = prev.High` - `prev_low = prev.Low` - If `use_body_range = true`: - `prev_high = max(prev.Open, prev.Close)` - `prev_low = min(prev.Open, prev.Close)` Volume filter: - If enabled, `volume_ok = Volume >= SMA(Volume, volume_sma_window) * volume_multiplier` - If `volume_ok` is false, classification is `fake` regardless of price break. Price logic (when volume is OK): - `Close > prev_high` -> `real_bull` - `Close < prev_low` -> `real_bear` - otherwise -> `fake` First bar is always `unclassified`. ## 6. Trend-State Rules Trend states: - `No Active Trend` - `Bullish Trend Active` - `Bearish Trend Active` State machine: - From neutral: - 2 consecutive `real_bull` -> bullish trend started - 2 consecutive `real_bear` -> bearish trend started - From bullish: - 2 consecutive `real_bear` -> bearish reversal confirmed - From bearish: - 2 consecutive `real_bull` -> bullish reversal confirmed Important: - `fake` bars do not increment opposite-run counters enough to reverse trend. ## 7. Chart and Visualization Behavior - Main candlestick chart with bullish/bearish markers: - `real_bull`: green triangle-up - `real_bear`: red triangle-down - Optional fake-bar de-emphasis via gray candle layer (`gray_fake`). - Optional example-trade overlay markers (`show_trade_markers`): - long entry marker - short entry marker - winning exit marker - loss/flat exit marker - If a past-behavior row is selected, chart highlights that trade window and path. - Optional focused zoom around selected trade (`focus_chart_on_selected_example`). - Volume subplot colored by trend state. Gap handling (`hide_market_closed_gaps`): - Always removes weekend gaps (`sat` -> `mon`). - Removes full missing calendar days between first/last bar (for example market holidays with no bars). - For intraday intervals, uses contiguous bar-order x-axis (no closed-session spacing) and day-level tick labels. - For daily interval, weekend break removal is applied. ## 8. Help and Onboarding Behavior - Web-only help entry exists in sidebar: - `Help / Quick Start` - Help appears in a dialog with multiple navigable screens (screen picker + previous/next). - Help copy is intentionally beginner-friendly and explains each major sidebar control group, including detailed backtest controls and why each setting matters. - Main page includes a beginner training block: - `What This Tool Means (Beginner Training)` - Plain-English definitions for top metrics (`Current Trend`, real/fake bars, `Signal Quality`, `Regime`, `Recent Fake Ratio`). - Historical learning table with trailing windows (`1M`, `3M`, `6M`, `1Y`) computed from loaded data. - Per-window interpretation text that summarizes whether behavior was trend-dominant, bearish-dominant, or choppy/noisy. - The onboarding markdown remains project documentation; in-app help content is rendered from `web/src/web_core/ui/help_content.py`. ## 9. Outputs - Metrics: - current trend - real bullish count - real bearish count - fake count - beginner training guide (plain-English metric glossary) - historical learning snapshots (`1M`, `3M`, `6M`, `1Y`) including price change, bar-type counts, trend flips, and interpretation - Live decision guide (optional): - bias (long/short/neutral) - signal confirmation status - latest bar interpretation - action + invalidation guidance - Trend events table (latest events), rendered in selected US display timezone and 12h/24h format - Backtest snapshot: - signal at trend-change rows to active bull/bear states - advanced mode supports configurable costs/holds/stop/target - Past behavior examples (optional training panel): - historical examples using trend-confirmation entries and opposite-confirmation exits - per-example direction, entry/exit timestamps (rendered in selected US display timezone and 12h/24h format), bars held, P/L%, and outcome - aggregate example metrics (count, win/loss, win rate, average P/L) - selectable table rows that drive chart highlight of chosen example - plain-language explanation for selected example - Exports: - CSV always available - PDF via Plotly image export (requires Kaleido runtime) - Additional optional panels: - multi-timeframe confirmation - compare symbols snapshot - session stats ## 10. Validation Expectations Code-level checks: - `python -m py_compile web/src/app.py` - `PYTHONPATH=web/src pytest -q web/src/tests` Behavior checks: - No crash on missing/invalid persisted settings - Symbol/interval/period invalid combinations show actionable data error - Trend logic matches two-consecutive-real-bars contract - Exports include normalized timestamp column