Skip to content

victorywwong/GameTrader

Repository files navigation

Blind Chart Trader (React Native + Expo)

Getting Started

  • Prereqs: Node 20+, pnpm 9+, Expo CLI.
  • Install deps: make setup
  • Configure API env: copy services/api/.env.example to services/api/.env and fill keys.
  • Run API: make dev-api (listens on :4000).
  • Run Mobile (separate terminal): make dev-mobile then open in iOS/Android or web.
  • Useful: make dev runs both via Turbo; make test/make lint/make fmt placeholders.

Networking tip

  • Android emulator uses 10.0.2.2 for host machine. The app auto-targets http://10.0.2.2:4000 on Android and http://localhost:4000 on iOS/web. If using a real device via LAN, set a tunnel or adjust BASE_URL in apps/mobile/src/api/client.ts.

This repository tracks the requirements for a mobile app where players plan a trade on a hidden future chart, reveal bars, and score P/L. The PRD below is adapted for a React Native + Expo stack with a Node/TypeScript backend, TradingView Lightweight Charts via WebView, and yfinance/CCXT data sources.


Product Requirements Document (PRD)

Working Title

Blind Chart Trader — plan a trade on a hidden future chart, reveal bars, and score P/L.

Objective

Deliver a mobile app where players: 1. opens a game with chosen market universe (equities, indices, forex, crypto, or a mix), 2. view a historical chart slice (future hidden), 3. switch timeframes safely, 4. place entry, stop-loss, position size, and expiry, 5. reveal future bars, 6. get profit/loss (P/L) as the score, see the outcome chart, and immediately play the next round.

1) Scope & Decisions (fixed)

•	Charting: TradingView Lightweight Charts (open-source renderer; we control the data feed & reveal) via React Native WebView.
•	Data sources:
•	Equities & Indices & (optionally) some FX: yfinance (Yahoo Finance) for OHLCV.
•	Crypto (major coins): CCXT (exchange APIs, e.g., Binance, Kraken, Coinbase).
•	Game fairness: No “time travel” leakage. We only send bars up to the reveal cursor.
•	Score = P/L: The score for a round is the monetary P/L derived from user inputs (entry, stop, size, expiry). No extra multipliers in v1 (keep it transparent).
•	Multi-timeframe (MTF) switching: Allowed without future leakage (see §4.3).

2) Personas & Use Cases

Personas

•	Solo Player: Practices trade planning and risk control.
•	Coach/Streamer (later): Runs rooms where everyone sees the same round (out of scope for v1, keep data model ready).

Core Use Cases

1.	Start a game with chosen universe & TF.
2.	Inspect context bars (future hidden).
3.	Switch TFs (e.g., 5m ↔ 15m ↔ 1h) without revealing future aggregates.
4.	Place entry, stop, position size, and expiry (time budget until the trade auto-exits).
5.	Hit Reveal to simulate forward bars to TP/SL/Expiry.
6.	Receive P/L, see outcome, save/share, Play Next.

3) Functional Requirements

3.1 Game Creation

•	Player selects:
•	Universe: Equities, Indices, Forex, Crypto, or Mixed (random across chosen classes).
•	Timeframes available: e.g., 1m (crypto), 5m, 15m, 1h, 4h, 1D (configurable per asset class/data depth).
•	Lookback bars (context): default 150 (configurable).
•	Forward window (max future bars engine will simulate): default 300 (configurable).
•	System randomizes symbol, start index/time, base timeframe (see §4), ensuring:
•	Sufficient historical depth before and after start.
•	Forward window fully exists in the past (no near-real-time bars).
•	Liquidity/session sanity (skip illiquid gaps, out-of-session equities bars).

3.2 Chart Display

•	Render only lookback bars at first; future hidden.
•	Show OHLCV candles with volume (optional toggle).
•	Disable panning beyond the right-edge “now”; clamp zoom to not skip beyond.
•	Provide TF switcher UI (hotkeys & dropdown).

3.3 Orders & Inputs

•	Players can set:
•	Side: long/short.
•	Entry: price level (limit) or use “market at next bar open” (toggle).
•	Stop-loss: price level.
•	Position size: units (default), or notional; allow a simple “risk % of account” calculator (optional v1.1).
•	Expiry: max bars until the trade closes at last price if neither SL/TP hit (default e.g. 100 bars).
•	Take-profit (optional): If absent, P/L at SL or expiry only.
•	Orders are anchored to price, not pixels. UX: draggable horizontal lines with numeric input.

3.4 Reveal & Simulation

•	On Reveal:
•	Engine advances bars from the canonical base series, checking:
•	Entry fill logic (see §4.5).
•	SL/TP hit logic with deterministic intrabar ordering.
•	Expiry (trade exits at bar close when expiry counter hits zero).
•	When trade closes:
•	Compute P/L = (exit_price − entry_fill) × signed_size (fees/slippage optional v1.1).
•	Show result with summary (see §3.5).

3.5 Results & Next

•	Display:
•	Final P/L (score), % return relative to notional or account (if risk calc enabled).
•	Bars to outcome, RR snapshot if TP provided.
•	Outcome chart with full revealed bars up to exit/expiry.
•	Buttons: Play Next, Replay Round, Share Link (deep link with seed; replay is view-only).

3.6 Leaderboards (optional v1.1)

•	Daily/weekly aggregates by total P/L, # rounds, average risk, etc.

4) Game Engine & Data Rules

4.1 Canonical Base Timeframe

•	Each round runs on one base TF:
•	Crypto: 1m or 5m depending on data availability.
•	Equities/Indices/FX: 5m/15m/1h/1D based on chosen TF menu and source depth.
•	The base TF is the truth for simulation. All other TFs are views aggregated from base.

4.2 Data Acquisition

•	yfinance:
•	OHLCV download for equities/indices/FX (note FX availability varies).
•	Intraday limits: 1m history ~30–60 days; 5m/15m longer; daily: years.
•	Use adjusted prices for equities; normalize timezones to UTC.
•	CCXT:
•	Exchanges: Binance, Kraken, Coinbase (configurable).
•	Use exchange-specific OHLCV endpoints with rate limiting/backoff.
•	Normalize symbols and timezones to UTC.
•	Caching:
•	Pre-cache popular symbols & TFs.
•	Store canonical OHLC arrays per symbol/TF/day in Postgres or object storage to avoid repeated API calls.
•	Persist round slices by seed for perfect reproducibility.

4.3 Multi-Timeframe (MTF) Switching (no future leakage)

•	Let ratio = viewTF / baseTF.
•	Only show completed aggregate bars:
•	Visible aggregates = floor((revealed_base_bars) / ratio).
•	Do not render the partially forming aggregate; optionally show a ghost placeholder (no values).
•	If lower-than-base TF is requested, it must be backed by real data and aligned to base time; only display bars with timestamp ≤ current base “now”.

4.4 Reveal Cursor & Pan/Zoom Guardrails

•	Maintain reveal_cursor (index into base series).
•	All TF views read from this cursor; right edge is consistent.
•	Clamp pan/zoom so the user cannot move the right edge to expose unrevealed samples.

4.5 Deterministic Fill/Hit Logic

•	Entry (limit): first bar where price touches (H/L intrabar) the level after Reveal starts.
•	Market at next open: entry fills at next bar open after Reveal.
•	Intrabar priority on a bar crossing both SL & TP:
•	Order: Open → nearest level to open first (distance check) → then other level if still valid.
•	Gaps:
•	If price gaps through entry, fill at first tradable price (bar open).
•	If gap skips SL/TP, assume worst-case fill at first tradable price beyond the level (conservative).
•	Expiry:
•	Countdown in bars. On expiry, exit at bar close (or bar mid if configured).
•	Optional v1.1: Slippage & fees configs.

5) System Architecture

5.1 High-Level

•	Mobile App: React Native + Expo (TypeScript, expo-router) + TradingView Lightweight Charts via WebView; state via Zustand.
•	Backend: Node/TypeScript service for OHLCV, seeding, simulation, and persistence.
•	Data Layer: Postgres (users, rounds, seeds); Redis (rate limits, ephemeral rooms/cache).
•	Data Fetchers: yfinance for equities/indices/FX; CCXT for crypto; schedule pre-caching jobs.
•	Auth: Auth0 or Supabase Auth (mobile-friendly OAuth).
•	Hosting: Expo EAS for mobile builds/updates; Fly.io/Render/GCP/AWS for backend; object storage for cached OHLC blobs.

5.2 Services & Responsibilities

•	Round Service: symbol/TF randomization, seed creation, data slicing, rule validation.
•	Sim Engine: bar-by-bar reveal, fill/hit computation, P/L math.
•	Data Service: fetch/cache/normalize OHLCV, corporate actions adj., session filters.
•	Leaderboard Service (v1.1): aggregations and ranks.
•	Telemetry: event logs for UX funnels and auditing (see §9).

6) Data Model (relational)

users(
  id UUID PK,
  handle TEXT UNIQUE,
  email TEXT UNIQUE,
  created_at TIMESTAMP
)

rounds(
  id UUID PK,
  user_id UUID FK users,
  seed TEXT,               -- deterministic replay key
  asset_class TEXT,        -- equities|indices|forex|crypto|mixed
  symbol TEXT,
  base_tf TEXT,            -- e.g., "1m","5m","15m","1h","1d"
  start_ts TIMESTAMP,      -- first bar of lookback
  lookback INT,
  forward_max INT,
  created_at TIMESTAMP
)

plans(
  id UUID PK,
  round_id UUID FK rounds,
  side TEXT,               -- long|short
  entry_type TEXT,         -- limit|market_next_open
  entry_price NUMERIC,     -- nullable if market_next_open
  stop_price NUMERIC,
  take_profit NUMERIC NULL,
  size NUMERIC,            -- positive number; sign implied by side
  expiry_bars INT
)

executions(
  id UUID PK,
  round_id UUID FK rounds,
  plan_id UUID FK plans,
  entry_fill NUMERIC,
  exit_price NUMERIC,
  exit_reason TEXT,        -- tp|sl|expiry|invalid
  bars_elapsed INT,
  pl NUMERIC,
  rr NUMERIC NULL,
  completed_at TIMESTAMP
)

ohlc_blobs(
  id UUID PK,
  symbol TEXT,
  tf TEXT,
  session_date DATE NULL,
  data_json JSONB,         -- compressed array [{time,open,high,low,close,volume}]
  source TEXT,             -- yfinance|ccxt:binance...
  created_at TIMESTAMP
)

7) API Contracts (v1)

All responses return { ok: boolean, data?: any, error?: {code, message} }

7.1 POST /round/new

Body

{
  "universe": ["equities","indices","forex","crypto"],
  "view_tfs": ["5m","15m","1h","1d"],
  "lookback": 150,
  "forward_max": 300
}

Response

{
  "ok": true,
  "data": {
    "round_id": "UUID",
    "seed": "string",
    "asset_class": "crypto",
    "symbol": "BTC/USDT",
    "base_tf": "1m",
    "lookback": 150,
    "forward_max": 300,
    "ohlcv_pre": [ { "time": 1685577600, "open":..., "high":..., "low":..., "close":..., "volume":... }, ... ],
    "rules": { "fill": "open-then-nearest", "gap": "first-tradable", "expiry_exit": "close" }
  }
}

7.2 POST /round/plan

Body

{
  "round_id": "UUID",
  "side": "long",
  "entry_type": "limit",
  "entry_price": 42350.0,
  "stop_price": 42050.0,
  "take_profit": 43150.0,
  "size": 0.5,
  "expiry_bars": 100
}

Response

{ "ok": true, "data": { "plan_id": "UUID" } }

7.3 POST /round/play

Starts simulation for this plan, returns either a stream or a single result + optional steps.

Body

{ "round_id": "UUID", "plan_id": "UUID" }

Response (non-stream)

{
  "ok": true,
  "data": {
    "revealed_bars": [ ],
    "execution": {
      "entry_fill": 42352.0,
      "exit_price": 43150.0,
      "exit_reason": "tp",
      "bars_elapsed": 37,
      "pl": 399.0,
      "rr": 3.0
    }
  }
}

7.4 GET /round/:id

Returns replay info + bars to visualize final state.

{
  "ok": true,
  "data": {
    "meta": { ... },
    "plan": { ... },
    "execution": { ... },
    "ohlcv_full": [ ]
  }
}

7.5 GET /symbols/catalog

Return curated symbol list per asset class for the randomizer (to avoid illiquid instruments).

{
  "ok": true,
  "data": {
     "equities": ["AAPL","MSFT","NVDA"],
     "indices": ["^GSPC","^NDX","^DJI","^FTSE"],
     "forex": ["EURUSD","GBPUSD","USDJPY","XAUUSD"],
     "crypto": ["BTC/USDT","ETH/USDT","SOL/USDT"]
  }
}

8) Mobile Requirements

8.1 UI Components

•	Header: logo, Profile, Settings.
•	Config panel (drawer or screen):
•	Universe selector (multi-select).
•	TF switcher (buttons: 1m/5m/15m/1h/4h/1D depending on asset).
•	Lookback and Expiry (advanced).
•	Chart area (Lightweight Charts in WebView):
•	Candle + optional Volume.
•	Price-level handles for Entry/Stop/TP (draggable; numeric inputs).
•	Right-edge lock icon + tooltip “future hidden.”
•	Trade controls:
•	Side toggle (Long/Short).
•	Entry type (Limit / Market next open).
•	Inputs: Entry, Stop, TP (optional), Size, Expiry.
•	CTA: Reveal (disabled until plan valid).
•	Results modal/panel:
•	Big P/L number, exit reason (TP/SL/Expiry), bars elapsed.
•	RR snapshot if TP was set.
•	Buttons: Play Next, Replay (read-only), Share.

8.2 UX Rules

•	Validation: Side-aware constraints (for long: TP > Entry > SL; for short: TP < Entry < SL).
•	Error states: Clear, inline errors on invalid prices/size/expiry.
•	Keyboard/gesture shortcuts: TF hotkeys where available, reveal after valid plan.
•	Loading/Empty: Skeleton chart states; friendly copy.

9) Non-Functional Requirements

•	Performance:
•	Initial load < 2s for cached rounds; chart FPS 30+ on mid devices.
•	Payloads: compress OHLC arrays (gzip/br).
•	Reliability: Gracefully degrade if a data source rate-limits; fall back to cached blobs.
•	Security:
•	Auth via OAuth; HTTPS everywhere; input validation server-side.
•	Anti-cheat: server is source of truth for outcome; client cannot override.
•	Privacy:
•	Store minimal PII; comply with GDPR (export/delete on request).
•	Licensing:
•	Lightweight Charts (MIT) OK for commercial.
•	yfinance/CCXT terms respected; do not redistribute vendor data in bulk.
•	Observability:
•	Structured logs, metrics: rounds_started, rounds_completed, avg_P/L, avg_bars_to_outcome, errors by type.
•	Client events for funnel analysis (config opened → plan valid → reveal → next).

10) Randomizer & Seeding

10.1 Symbol Universe

•	Maintain curated lists to avoid illiquid assets and broken sessions.
•	For Mixed, pick class with uniform probability or weighted (configurable).

10.2 Time Slice Selection

•	Enforce:
•	Lookback L_pre bars exist before t0.
•	Forward L_fwd bars exist after t0.
•	Exclude near-real-time windows (e.g., buffer ≥ 7 days from “today” for equities intraday).
•	Respect exchange sessions for equities; skip pre/post if configured.

10.3 Seed Format

•	seed = hash(symbol | base_tf | start_ts | L_pre | L_fwd | rule_version).
•	Deterministic reproduction of the round across users & devices.

11) Algorithms (deterministic)

11.1 Aggregation (base → higher TF)

Group every r base bars:

open  = first.open
high  = max(highs)
low   = min(lows)
close = last.close
vol   = sum(volumes)

Only show full groups ≤ reveal_cursor. Never render the forming bar.

11.2 Entry/SL/TP Resolution (per new bar)

•	Determine if entry is active:
•	If market_next_open and position not opened: fill at current bar open, first bar after Reveal.
•	If limit:
•	If (low ≤ entry ≤ high) after position not opened → fill at entry (or open if gap through).
•	If in position, check SL/TP on each new bar:
•	If bar crosses both, hit the closest level to bar open first.
•	Apply gap logic as per §4.5.

11.3 P/L

signed_size = size * (+1 for long, -1 for short)
P/L = (exit_price - entry_fill) * signed_size

(Optionally, scale by contract multiplier for indices/futures in v1.1)

12) Validation & Acceptance Criteria

•	A1: Switching TFs never reveals any future bar (QA: try edge zooms & pan).
•	A2: Given a fixed seed, two users produce identical outcomes with identical plans.
•	A3: Entry/SL/TP edge cases (gap through, both-hit bar) match rule spec across 50 curated tests.
•	A4: Expiry exits at bar close with correct bar count.
•	A5: P/L matches manual spreadsheet calc for 20 sample rounds across asset classes.
•	A6: “Play Next” produces a new seed; “Replay” loads same seed read-only.
•	A7: Rate limits from sources don’t crash the app; cached data used instead.

13) Testing Plan

•	Unit: aggregation, fill/hit, expiry, P/L.
•	Property tests: invariants under TF switches (no bar count mismatch; no future exposure).
•	Integration: end-to-end with mock OHLC feeds; then with yfinance/CCXT sandboxes.
•	Golden cases: JSON fixtures for rounds with known outcomes (gap up/down, wick-tap, tight stops).
•	Cross-platform: iOS and Android; WebView chart interactions.

14) Roadmap (post-v1 fast wins)

•	v1.1:
•	Leaderboards, shareable replays.
•	Fees & slippage model.
•	“Risk % of account” position sizing helper.
•	Multi-TP ladder, partial exits.
•	Rooms/head-to-head with same seed.
•	v1.2:
•	Basic indicators (MA/EMA/ATR) computed on base TF (legend shows TF).
•	Coaching notes overlay & export.

15) Glossary

•	Base TF: True simulation timeframe; all logic runs here.
•	Reveal Cursor: Index of last revealed base bar.
•	Expiry: Max bars allowed in position; auto-exit at close when reached.
•	P/L: Profit or loss in instrument units (or currency if sized as notional).

Handoff Notes for Teams

Design

•	Provide wireframes for: Config → Chart (MTF switcher, price handles) → Results modal.
•	States: invalid plan, pending reveal, outcome TP/SL/Expiry, no-volume overlays (indices).

Mobile (Expo)

•	Implement cursor-locked Lightweight Charts wrapper in WebView.
•	Price-line components with drag + numeric input.
•	Strict pan/zoom clamps; TF aggregation view.
•	Call backend API for rounds/seeds.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published