{"openapi":"3.1.0","info":{"title":"PRUVIQ Simulation API","description":"Run crypto strategy simulations with realistic costs.","version":"0.3.0"},"paths":{"/real-mode-checklist":{"get":{"tags":["OKX Broker"],"summary":"Real Mode Checklist","description":"Auth-required. Returns structured checklist for real mode activation.\nUsed by the dashboard RealModeReadiness component.","operationId":"real_mode_checklist_real_mode_checklist_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/metrics":{"get":{"summary":"Metrics Endpoint","description":"Prometheus exposition — local scrapers only.\n\nalloy reads 127.0.0.1:8080 directly (deploy/alloy/config.alloy:26), so\nnothing legitimate arrives through the public Cloudflare tunnel; a repo\ngrep for external consumers of api.pruviq.com/metrics returns zero.\nThe older \"no auth, values are non-sensitive\" note understated it:\nmeasured 2026-07-25, the public exposition disclosed per-endpoint\nrequest volume, process uptime/RSS, and pruviq_auto_sessions_enabled\n(how many real-money OKX auto-trading sessions are live).\n\nget_client_ip() resolves the tunnel's cf-connecting-ip, so an external\ncaller yields a public address while alloy stays on loopback (verified\nin the uvicorn access log: tunnelled requests appear as `14.52.126.36:0`,\nlocal ones as `127.0.0.1:<port>`). Answer 404 rather than 403 so the\nendpoint's existence is not confirmed to the internet.","operationId":"metrics_endpoint_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/coins":{"get":{"summary":"List Coins","description":"Backtest-able coins, market-cap ordered. Stablecoins are excluded by\ndefault (they carry a `stablecoin: true` flag) — the picker's default-on\n\"exclude stablecoins\" toggle flips include_stablecoins=true to show them.\nExcluding by default keeps the picker unchanged when the box is checked.\n\n2026-08-15 오너 결정(다 받고 분리): 비-크립토 무기한(주식·원자재·프리IPO)은\n기본 유니버스에서 제외하고 include_non_crypto=true 로만 노출 — 응답에\nasset_class 를 실어 프론트가 배지·토큰형 고지를 붙인다(#6690 동형).","operationId":"list_coins_coins_get","parameters":[{"name":"include_stablecoins","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Stablecoins"}},{"name":"include_non_crypto","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Non Crypto"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CoinInfo"},"title":"Response List Coins Coins Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/strategies":{"get":{"summary":"List Strategies","operationId":"list_strategies_strategies_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/StrategyInfo"},"type":"array","title":"Response List Strategies Strategies Get"}}}}}}},"/indicators":{"get":{"summary":"List Indicators Flat","description":"Return the full INDICATOR_REGISTRY for frontend field discovery.","operationId":"list_indicators_flat_indicators_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/signals/live":{"get":{"summary":"Signals Live","description":"Return currently active trading signals.\n\nScans verified strategies on top coins, returns active signals.\nCached for 5 minutes.\n\nResponse: [{\"strategy\": \"bb-squeeze-short\", \"strategy_name\": \"BB Squeeze SHORT\",\n            \"coin\": \"BTCUSDT\", \"direction\": \"short\", \"signal_time\": \"...\",\n            \"entry_price\": 87000.0, \"status\": \"verified\",\n            \"sl_pct\": 10, \"tp_pct\": 8}, ...]","operationId":"signals_live_signals_live_get","parameters":[{"name":"top_n","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Top N"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/signals/history":{"get":{"summary":"Signals History","description":"Return signal history for the last N hours (max 72).","operationId":"signals_history_signals_history_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","default":24,"title":"Hours"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/signals/realtime":{"get":{"summary":"Signals Realtime","description":"Enriched live signals filtered by verified 30d performance.\n\nCombines:\n    - `_signal_scanner.scan()` for the current 1H bar's active signals\n      (same data /signals/live serves; 5-min cache shared via the\n      scanner's single-flight lock)\n    - 30d top50 ranking entries from `RANKING_DIR/ranking_<date>.json`\n      for the PF / win_rate / n_trades trust metrics\n\nA signal is returned only when:\n    1. The scanner reports it on the last completed 1H candle, AND\n    2. The same (strategy, direction, timeframe) appears in the 30d\n       ranking with `profit_factor >= min_pf`.\n\nNote on timeframe coupling: the scanner runs on 1H candles regardless of\nthe strategy's preferred timeframe (this is a known limitation of the\ncurrent scanner, documented at api/signal_scanner.py:74). We join the\nranking by `timeframe == \"1H\"` first, then fall back to the most\nprofitable timeframe variant if no 1H entry exists for that strategy.\nThis intentionally returns *fewer* signals on cycles where strategies\nonly have higher-timeframe entries in the ranking — better to emit\nnothing than emit a signal whose backtest PF doesn't match the\ntimeframe the scanner actually fired on.\n\nResponse: list of enriched signal dicts (max `max_results` items).\nEmpty list when no qualifying signals exist OR scanner not yet warm.\n\nCaching: 5 minutes (scanner + ranking index both 5-min cached).\nResponse size: capped at ~50KB by max_results clamp.","operationId":"signals_realtime_signals_realtime_get","parameters":[{"name":"min_pf","in":"query","required":false,"schema":{"type":"number","default":2.0,"title":"Min Pf"}},{"name":"max_results","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"Max Results"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/signals/scored":{"get":{"summary":"Signals Scored","description":"Versioned model outcomes for previously recorded reference candle prices.\n\nReference timestamps may precede publication or Telegram delivery. These\nresults do not represent fills a recipient could obtain. New reference-\nengine-v2 rows use engine_fast; legacy rows retain paper-tracker-v1 and\nalready finalized results are never rewritten. Funding coverage and frozen\ncost inputs accompany new results.\n\nQuery:\n    days: only signals published within the last N days (1-90, default 14).\n    limit: max signals returned (1-500, default 200) — bounds response size.\n    signal_ids: optional comma-separated recorded IDs (max 500). Exact ID\n        lookup ignores the ordinary publication-age and global limit window.\n\nResponse:\n    {\"as_of\": \"<ISO>\", \"signals\": [\n        {\"strategy\",\"strategy_name\",\"coin\",\"direction\",\"entry_price\",\n         \"sl_pct\",\"tp_pct\",\"signal_time\",\n         \"status\": \"tp\"|\"sl\"|\"timeout\"|\"liquidation\"|\"open\"|\"unscoreable\",\n         \"pnl_pct\": <net reference model if closed; gross reference movement if open>,\n         \"exit_price\": <float|null>, \"exit_time\": <ISO|null>,\n         \"bars_held\": <int|null>}, ...]}","operationId":"signals_scored_signals_scored_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":14,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}},{"name":"signal_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signal Ids"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/paper-trading":{"get":{"summary":"Paper Trading Status","description":"Current PRUVIQ paper-trading portfolio state.\n\nReads the cycle file written by `backend/scripts/paper_trading_tracker.py`\n(run daily via `pruviq-paper-trading.timer`). No simulation runs inside\nthis request — it's a JSON read of the most recent state.\n\nQuery:\n    cycle: optional cycle id (e.g. 1). Defaults to the latest.\n\nResponse shape (when a cycle exists):\n    {\n        \"cycle_id\": 1,\n        \"cycle_status\": \"active\",\n        \"cycle_day\": 14,\n        \"cycle_length_days\": 30,\n        \"start_date\": \"2026-04-16\",\n        \"starting_capital\": 1000.0,\n        \"current_equity\": 1247.50,\n        \"total_return_pct\": 24.75,\n        \"yesterday_pnl\": 21.30,\n        \"open_positions\": [...],\n        \"closed_positions\": [...],     # most recent 20\n        \"history\": [{\"date\", \"equity\", \"open_count\", \"closed_count\"}, ...],\n        ...\n    }\n\nWhen no cycle exists, returns 404 — callers should treat that as \"not\ninitialized yet\" rather than \"feature off\".","operationId":"paper_trading_status_paper_trading_get","parameters":[{"name":"cycle","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cycle"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/hot-strategies":{"get":{"summary":"Hot Strategies","description":"Return top-performing strategies in the last 30 days.\n\nRuns lightweight simulation on BTC with each verified strategy,\nreturns sorted by recent PF. Used for \"Hot Now\" banner on frontend.\nCached for 1 hour.","operationId":"hot_strategies_hot_strategies_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/simulate":{"post":{"summary":"Simulate","description":"Offload the CPU-bound backtest to a worker thread so the single-worker\nevent loop keeps answering /health (prevents watchdog false-restarts).","operationId":"simulate_simulate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/share":{"get":{"summary":"Share Card","description":"공유 카드 랜딩 (P2-2, 2026-08-18) — per-result 동적 OG.\n\n설계(정직성이 곧 구조): 카드 수치를 URL 로 받지 않는다 — 받으면 경계 안에서\n위조 가능한 «브랜드 입힌 가짜 성과 카드» 표면이 된다. 대신 **설정만** 받아\n같은 /simulate 캐시 경로로 서버가 재계산한다(공유 직전 실행이라 대부분 캐시\n히트). 크롤러는 이 HTML 의 og 메타(+/og 이미지)를 읽고, 사람은 meta refresh\n로 설정이 실린 시뮬레이터 페이지로 이동해 같은 백테스트를 재현한다 —\n«공유 = 자기복제 검증 이벤트» (ShareResultButton 계보) 의 카드판.\nnoindex: 정본은 시뮬레이터 페이지(canonical) — 중복 색인 방지.","operationId":"share_card_share_get","parameters":[{"name":"preset","in":"query","required":true,"schema":{"type":"string","title":"Preset"}},{"name":"dir","in":"query","required":false,"schema":{"type":"string","default":"long","title":"Dir"}},{"name":"sl","in":"query","required":false,"schema":{"type":"number","default":10.0,"title":"Sl"}},{"name":"tp","in":"query","required":false,"schema":{"type":"number","default":8.0,"title":"Tp"}},{"name":"topN","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"Topn"}},{"name":"lev","in":"query","required":false,"schema":{"type":"number","default":5.0,"title":"Lev"}},{"name":"fee","in":"query","required":false,"schema":{"type":"number","default":0.05,"title":"Fee"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"en","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ohlcv/{symbol}":{"get":{"summary":"Get Ohlcv","description":"Get OHLCV + indicator data for a single coin.\n\nSupports multi-timeframe via the `timeframe` query parameter.\nFor non-1H timeframes, data is resampled from 1H and indicators are recomputed.\n\nPagination:\n- limit: number of bars to return (default 1000, max 5000; 0 or negative → 1000)\n- offset: number of bars to skip from the end (0 = most recent)","operationId":"get_ohlcv_ohlcv__symbol__get","parameters":[{"name":"symbol","in":"path","required":true,"schema":{"type":"string","title":"Symbol"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":1000,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"timeframe","in":"query","required":false,"schema":{"type":"string","default":"1H","title":"Timeframe"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OhlcvResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/simulate/coin":{"post":{"summary":"Simulate Coin","description":"Offload the single-coin backtest to a worker thread (event-loop safe).","operationId":"simulate_coin_simulate_coin_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoinSimRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoinSimResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/coins/stats":{"get":{"summary":"Get Coin Stats","description":"Get pre-computed stats for all coins.","operationId":"get_coin_stats_coins_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoinStatsResponse"}}}}}}},"/simulate/compare":{"post":{"summary":"Simulate Compare","description":"Run all strategies under identical SL/TP conditions for comparison.","operationId":"simulate_compare_simulate_compare_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareResponse"}}}},"400":{"description":"top_n above 5: detail = {error, max_top_n, requested, alternative}","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareLimitError"},"example":{"detail":{"error":"top_n 10 is above the /simulate/compare limit of 5 coins: ...","max_top_n":5,"requested":10,"alternative":"/simulate per strategy"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/simulate/validate":{"post":{"summary":"Simulate Validate","description":"Offload OOS/Monte-Carlo validation to a worker thread (event-loop safe).","operationId":"simulate_validate_simulate_validate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/simulate/score-session":{"post":{"summary":"Simulate Score Session","description":"리플레이(수동 백테스트) 세션의 손 거래 목록 → WR·PF·MDD·합산 수익률. 저장 0·계정 0.","operationId":"simulate_score_session_simulate_score_session_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScoreSessionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScoreSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/simulate/dca":{"post":{"summary":"Simulate Dca Public","description":"DCA 봇 백테스트 (무인증). 안전주문 사다리·TP·수수료 규약 = PRUVIQ DCA 엔진(okx/dca_backtest.py).","operationId":"simulate_dca_public_simulate_dca_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BotSimRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/simulate/grid":{"post":{"summary":"Simulate Grid Public","description":"그리드 봇 백테스트 (무인증). 결과 `accuracy: \"approx\"` — 페어 기반 근사(실행기 대비 ±10%).","operationId":"simulate_grid_public_simulate_grid_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BotSimRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/simulate/optimize":{"post":{"summary":"Simulate Optimize","description":"SL/TP grid search — runs up to 36 simulations with different SL/TP pairs.","operationId":"simulate_optimize_simulate_optimize_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OptimizeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/market":{"get":{"summary":"Get Market","description":"Get market overview with BTC/ETH prices, Fear & Greed, top movers, funding rates.\nData is refreshed every 5min by background task (Binance primary).\nIf cache is stale (>30min), forces a fresh fetch.","operationId":"get_market_market_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketOverview"}}}}}}},"/regime":{"get":{"summary":"Get Regime","description":"Current market regime based on Fear & Greed Index + recommended strategies.\n\nRegime boundaries (backtest-validated, 2026-05-28, 45 runs × OKX top-50 coins):\n  Extreme Fear (<25): ATR Breakout SHORT PF=2.81, BB Squeeze SHORT PF=2.29 — 8/9 pass\n  Fear (25-44):       ADX Trend SHORT PF=1.19 only — most strategies fail, thin edge\n  Neutral (45-59):    BB Squeeze SHORT PF=2.56, ATR Breakout SHORT PF=1.97\n  Greed (60-79):      BB Squeeze LONG PF=1.09 only — bear strategies fail\n  Extreme Greed (≥80): ATR Breakout SHORT PF=2.55, BB Squeeze LONG PF=1.10","operationId":"get_regime_regime_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegimeResponse"}}}}}}},"/performance/public":{"get":{"summary":"Performance Public","description":"No-auth public endpoint. Returns current regime + strategy pick +\nlive position summary. Used by SNS content pipeline.","operationId":"performance_public_performance_public_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/market/live":{"get":{"summary":"Market Live","description":"Real-time Binance prices (30s TTL cache).\nSpot (primary) + Futures (fallback for Spot-missing coins).\nWeight: 40 (Spot) + 40 (Futures) = 80/refresh × 2/min = 160 (6000 limit = 2.7%).","operationId":"market_live_market_live_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/news":{"get":{"summary":"Get News","description":"Get aggregated crypto news from RSS feeds.\nData is refreshed every 60s by background task.","operationId":"get_news_news_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsResponse"}}}}}}},"/macro":{"get":{"summary":"Get Macro","description":"Get macro economic indicators and derivatives data.","operationId":"get_macro_macro_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MacroResponse"}}}}}}},"/builder/indicators":{"get":{"summary":"List Indicators","description":"List all available indicators for Strategy Builder.","operationId":"list_indicators_builder_indicators_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/IndicatorInfo"},"type":"array","title":"Response List Indicators Builder Indicators Get"}}}}}}},"/builder/presets":{"get":{"summary":"List Presets","description":"List all preset strategy templates.","operationId":"list_presets_builder_presets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PresetListItem"},"type":"array","title":"Response List Presets Builder Presets Get"}}}}}}},"/builder/presets/{preset_id}":{"get":{"summary":"Get Preset","description":"Get full preset strategy JSON for editing.","operationId":"get_preset_builder_presets__preset_id__get","parameters":[{"name":"preset_id","in":"path","required":true,"schema":{"type":"string","title":"Preset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/backtest":{"post":{"summary":"Run Backtest","description":"Run a custom strategy backtest using the ConditionEngine.\nThis is the core Strategy Builder endpoint.","operationId":"run_backtest_backtest_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BacktestRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BacktestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/export/csv":{"get":{"summary":"Export Csv","description":"Download backtest results as CSV.","operationId":"export_csv_export_csv_get","parameters":[{"name":"hash","in":"query","required":true,"schema":{"type":"string","title":"Hash"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/rankings/daily":{"get":{"summary":"Get Daily Rankings","description":"Return daily strategy rankings from pre-computed JSON files.","operationId":"get_daily_rankings_rankings_daily_get","parameters":[{"name":"date","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^\\d{8}$"},{"type":"null"}],"description":"Calendar date YYYYMMDD. Set strict_date=true for exact citation lookup; omit date for latest.","title":"Date"},"description":"Calendar date YYYYMMDD. Set strict_date=true for exact citation lookup; omit date for latest."},{"name":"period","in":"query","required":false,"schema":{"type":"string","default":"30d","title":"Period"}},{"name":"group","in":"query","required":false,"schema":{"type":"string","default":"top50","title":"Group"}},{"name":"strict_date","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Strict Date"}},{"name":"selection","in":"query","required":false,"schema":{"type":"boolean","description":"Add `selection`: the ranked rows (raw values, rank order), the previous day's rank inputs and the day file's sha256 — for publications that pin their source.","default":false,"title":"Selection"},"description":"Add `selection`: the ranked rows (raw values, rank order), the previous day's rank inputs and the day file's sha256 — for publications that pin their source."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DailyRankingResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/og":{"get":{"summary":"Generate Og Image","description":"1200x630 OG card. 수치는 쿼리에서 받지 않고 서버가 설정으로 재계산한다 (Q-B68).\n\n종전엔 wr·pf·ret·trades·mdd 를 URL 로 받아 그대로 그렸다 — 범위 검사만 있어서\n`/og?strategy=ma-cross&pf=9.99` 가 PRUVIQ 로고 옆에 PF 9.99 를 찍었다(브랜드 박힌\n위조 성과 카드). /share 와 같은 원칙: 설정만 받고 같은 _gated_simulate 캐시 경로로\n계산한다. /share 가 방금 채운 요청과 같은 키라 공유 흐름은 캐시 히트다.","operationId":"generate_og_image_og_get","parameters":[{"name":"strategy","in":"query","required":false,"schema":{"type":"string","default":"bb-squeeze-short","title":"Strategy"}},{"name":"dir","in":"query","required":false,"schema":{"type":"string","default":"short","title":"Dir"}},{"name":"sl","in":"query","required":false,"schema":{"type":"number","default":10.0,"title":"Sl"}},{"name":"tp","in":"query","required":false,"schema":{"type":"number","default":8.0,"title":"Tp"}},{"name":"topN","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"Topn"}},{"name":"lev","in":"query","required":false,"schema":{"type":"number","default":5.0,"title":"Lev"}},{"name":"fee","in":"query","required":false,"schema":{"type":"number","default":0.05,"title":"Fee"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"wr","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wr"}},{"name":"pf","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pf"}},{"name":"ret","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ret"}},{"name":"trades","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trades"}},{"name":"mdd","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mdd"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/generate-bot":{"post":{"summary":"Generate Bot","description":"Generate a downloadable trading bot zip from strategy config.","operationId":"generate_bot_generate_bot_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateBotRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/subscribe":{"post":{"summary":"Subscribe Email","description":"Subscribe an email to weekly strategy alerts.","operationId":"subscribe_email_api_subscribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/unsubscribe":{"get":{"summary":"Unsubscribe Email","description":"Unsubscribe via signed link in emails.","operationId":"unsubscribe_email_api_unsubscribe_get","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","title":"Email"}},{"name":"token","in":"query","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/trust/metrics":{"get":{"summary":"Trust Metrics","description":"Public execution-quality metrics. Never exposes per-user data.","operationId":"trust_metrics_trust_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Trust Metrics Trust Metrics Get"}}}}}}},"/trust/real-track":{"get":{"summary":"Trust Real Track","description":"Internal real-money NAV track. Requires X-Admin-Key.\n\nThis was a public endpoint, built as \"the /trust honesty ledger\" before\nthe owner withheld real-money figures from the site (#6937). The two\ndecisions never met: the UI component stayed unmounted while this route\nkept serving nav_usdt, start_capital_usdt, per-symbol positions_usdt,\ndeposit history and the individual fill ledger to anyone who asked.\nOwner decision 2026-07-27: internal only.\n\nThe anonymization contract (no bot_id, no session_id) is unchanged and\nstill applies — it was never what kept the amounts private, because\nnothing did. Consumed by the Mac data pipeline, which now presents the\nkey. Re-opening this is a deliberate act: drop the header argument and\nthe guard together, and republish the static file in the same change,\nor the trust page will render a number nobody can fetch.","operationId":"trust_real_track_trust_real_track_get","parameters":[{"name":"X-Admin-Key","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Trust Real Track Trust Real Track Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/trust/merkle/{date}":{"get":{"summary":"Trust Merkle Root","description":"Return {date, leaf_count, root, algorithm} for YYYYMMDD UTC day.\n\nEmpty day returns root=null with leaf_count=0 — silence is not\nomission here, it's evidence the day had no trades.","operationId":"trust_merkle_root_trust_merkle__date__get","parameters":[{"name":"date","in":"path","required":true,"schema":{"type":"string","title":"Date"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Trust Merkle Root Trust Merkle  Date  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"BacktestRequest":{"properties":{"name":{"type":"string","maxLength":100,"title":"Name","default":"Custom Strategy"},"direction":{"type":"string","title":"Direction","description":"short | long. Omitted → SHORT (the documented /backtest default). Unlike /simulate, which resolves an omitted direction from the strategy registry, /backtest has no strategy id to resolve from — send direction explicitly. The response's direction_source says whether it was sent or defaulted (Q-B82).","default":"short"},"indicators":{"additionalProperties":true,"type":"object","title":"Indicators","description":"Indicator configs: {'bb': {'period': 20}, 'ema': {}, ...}","default":{"bb":{},"ema":{},"volume":{},"candle":{}}},"entry":{"additionalProperties":true,"type":"object","title":"Entry","description":"Entry conditions tree: {'type': 'AND', 'conditions': [...]}"},"exit_conditions":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Exit Conditions","description":"Optional exit-signal conditions tree (same shape as entry). When met during an open trade, exit early (exit_reason='signal'). null = no signal exit (TP/SL/trailing/timeout only)."},"avoid_hours":{"items":{"type":"integer"},"type":"array","title":"Avoid Hours","description":"UTC hours to avoid (0-23)","default":[]},"avoid_months":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Avoid Months","description":"Months to avoid entering trades (1-12). null = no month filter"},"min_vol_regime":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Vol Regime","description":"Minimum ATR ratio (current ATR / 14-period ATR MA) to allow entry. e.g., 0.7 = skip low-volatility periods. null = no filter"},"sl_pct":{"type":"number","maximum":50.0,"minimum":0.5,"title":"Sl Pct","description":"Stop Loss %","default":10.0},"tp_pct":{"type":"number","maximum":100.0,"minimum":0.5,"title":"Tp Pct","description":"Take Profit %","default":8.0},"tp_source":{"type":"string","enum":["custom_pct","trailing"],"title":"Tp Source","description":"Exit mode: custom_pct = fixed TP/SL; trailing = trailing stop (tp_pct is the trail distance)","default":"custom_pct"},"trailing_pct":{"anyOf":[{"type":"number","maximum":50.0,"minimum":0.5},{"type":"null"}],"title":"Trailing Pct","description":"Trailing stop distance %. If null and tp_source=trailing, uses tp_pct."},"max_bars":{"type":"integer","maximum":168.0,"minimum":1.0,"title":"Max Bars","description":"Max holding period (bars)","default":48},"top_n":{"anyOf":[{"type":"integer","maximum":535.0,"minimum":1.0},{"type":"null"}],"title":"Top N","description":"Number of coins (null = top 50)"},"symbols":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Symbols","description":"Specific symbols"},"include_stablecoins":{"type":"boolean","title":"Include Stablecoins","description":"Include stablecoins (USDC, DAI…) in the top_n universe. Default false — ~0 volatility → empty backtests. Ignored when `symbols` is set (explicit picks always honored).","default":false},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Symbol","description":"Single-symbol alias for `symbols`. Auto-mapped (prevents silent ignore)."},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date","description":"Backtest start date (YYYY-MM-DD)"},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Date","description":"Backtest end date (YYYY-MM-DD)"},"timeframe":{"type":"string","enum":["1H","2H","4H","6H","12H","1D","1W"],"title":"Timeframe","description":"Candle timeframe: 1H, 2H, 4H, 6H, 12H, 1D, 1W","default":"1H"},"per_coin_usd":{"type":"number","maximum":1000000.0,"minimum":1.0,"title":"Per Coin Usd","description":"USD per coin position (compounding=True: total portfolio capital)","default":60.0},"leverage":{"type":"integer","maximum":125.0,"minimum":1.0,"title":"Leverage","description":"Leverage multiplier","default":1},"max_concurrent_positions":{"type":"integer","maximum":1000.0,"minimum":1.0,"title":"Max Concurrent Positions","description":"Max simultaneous open positions","default":100},"compounding":{"type":"boolean","title":"Compounding","description":"True = reinvest profits (compound), False = fixed position size (simple)","default":false}},"type":"object","required":["entry"],"title":"BacktestRequest","description":"Custom strategy backtest request from Strategy Builder."},"BacktestResponse":{"properties":{"name":{"type":"string","title":"Name"},"direction":{"type":"string","title":"Direction"},"executed":{"type":"boolean","title":"Executed","description":"False when the strategy failed validation and nothing was run — every metric is a placeholder (0), NOT a 0-trade result. validation_errors says why. HTTP stays 200 (documented contract).","default":true},"direction_source":{"type":"string","enum":["request","default_short"],"title":"Direction Source","description":"«request» = the request sent direction; «default_short» = it was omitted and this run is SHORT (the /backtest default — /simulate would use the strategy registry's direction instead).","default":"request"},"sl_pct":{"type":"number","title":"Sl Pct"},"tp_pct":{"type":"number","title":"Tp Pct"},"max_bars":{"type":"integer","title":"Max Bars"},"indicators_used":{"items":{"type":"string"},"type":"array","title":"Indicators Used"},"conditions_count":{"type":"integer","title":"Conditions Count"},"total_trades":{"type":"integer","title":"Total Trades"},"wins":{"type":"integer","title":"Wins"},"losses":{"type":"integer","title":"Losses"},"win_rate":{"type":"number","title":"Win Rate"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"profit_factor":{"type":"number","title":"Profit Factor"},"avg_win_pct":{"type":"number","title":"Avg Win Pct"},"avg_loss_pct":{"type":"number","title":"Avg Loss Pct"},"max_drawdown_pct":{"type":"number","title":"Max Drawdown Pct"},"max_consecutive_losses":{"type":"integer","title":"Max Consecutive Losses"},"tp_count":{"type":"integer","title":"Tp Count"},"sl_count":{"type":"integer","title":"Sl Count"},"timeout_count":{"type":"integer","title":"Timeout Count"},"total_fees_pct":{"type":"number","title":"Total Fees Pct","default":0.0},"total_funding_pct":{"type":"number","title":"Total Funding Pct","default":0.0},"sharpe_ratio":{"type":"number","title":"Sharpe Ratio","default":0.0},"sortino_ratio":{"type":"number","title":"Sortino Ratio","default":0.0},"calmar_ratio":{"type":"number","title":"Calmar Ratio","default":0.0},"coins_used":{"type":"integer","title":"Coins Used"},"top_n_requested":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top N Requested","description":"The top_n this run resolved to. null for explicit symbols= requests (no top-N universe)."},"eligible_universe":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Eligible Universe","description":"Coins eligible for a top-N universe at run time (stablecoins unless include_stablecoins, non-crypto and liquidity-dead markets excluded), read in the same selection as the coins run. null for symbols= requests (and on /backtest when the strategy is invalid, is_valid=false)."},"universe_capped":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Universe Capped","description":"eligible_universe < top_n_requested: the request asked for more coins than exist, so the whole eligible universe ran. A cap only — coins lacking data are reported in coins_missing_data. null for symbols= requests."},"coins_missing_data":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Coins Missing Data","description":"min(top_n_requested, eligible_universe) - (selected coins with at least one candle inside start_date..end_date). Counts selected coins with no complete candle up to the cutoff AND coins whose candles all fall outside the requested window (those stay in coins_used, so this can exceed min(top_n_requested, eligible_universe) - coins_used). null for symbols= requests."},"data_range":{"type":"string","title":"Data Range"},"equity_curve":{"items":{"$ref":"#/components/schemas/EquityPoint"},"type":"array","title":"Equity Curve"},"coin_results":{"items":{"$ref":"#/components/schemas/CoinResult"},"type":"array","title":"Coin Results","default":[]},"trades":{"items":{"$ref":"#/components/schemas/TradeItem"},"type":"array","title":"Trades","default":[]},"compounding":{"type":"boolean","title":"Compounding","default":false},"ruin_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ruin Index"},"per_coin_usd":{"type":"number","title":"Per Coin Usd","default":60.0},"leverage":{"type":"integer","title":"Leverage","default":5},"initial_capital_usd":{"type":"number","title":"Initial Capital Usd","default":0.0},"total_return_usd":{"type":"number","title":"Total Return Usd","default":0.0},"total_return_pct_portfolio":{"type":"number","title":"Total Return Pct Portfolio","default":0.0},"max_drawdown_usd":{"type":"number","title":"Max Drawdown Usd","default":0.0},"expectancy":{"type":"number","title":"Expectancy","default":0.0},"recovery_factor":{"type":"number","title":"Recovery Factor","default":0.0},"payoff_ratio":{"type":"number","title":"Payoff Ratio","default":0.0},"btc_hold_return_pct":{"type":"number","title":"Btc Hold Return Pct","default":0.0},"eth_hold_return_pct":{"type":"number","title":"Eth Hold Return Pct","default":0.0},"btc_hold_curve":{"items":{"$ref":"#/components/schemas/EquityPoint"},"type":"array","title":"Btc Hold Curve","default":[]},"eth_hold_curve":{"items":{"$ref":"#/components/schemas/EquityPoint"},"type":"array","title":"Eth Hold Curve","default":[]},"var_95":{"type":"number","title":"Var 95","default":0.0},"cvar_95":{"type":"number","title":"Cvar 95","default":0.0},"strategy_grade":{"type":"string","title":"Strategy Grade","default":""},"grade_details":{"type":"string","title":"Grade Details","default":""},"edge_p_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Edge P Value"},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings","default":[]},"walk_forward_consistency":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Walk Forward Consistency"},"walk_forward_details":{"type":"string","title":"Walk Forward Details","default":""},"profit_factor_ci":{"anyOf":[{"$ref":"#/components/schemas/MetricCI"},{"type":"null"}]},"sharpe_ci":{"anyOf":[{"$ref":"#/components/schemas/MetricCI"},{"type":"null"}]},"deflated_sharpe":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Deflated Sharpe"},"dsr_haircut_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Dsr Haircut Pct"},"mc_p_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mc P Value"},"mc_percentile":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mc Percentile"},"jensens_alpha":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Jensens Alpha"},"avg_bars_held":{"type":"number","title":"Avg Bars Held","default":0.0},"median_bars_held":{"type":"number","title":"Median Bars Held","default":0.0},"positions_skipped":{"type":"integer","title":"Positions Skipped","default":0},"pnl_distribution":{"items":{"type":"integer"},"type":"array","title":"Pnl Distribution","default":[]},"pnl_buckets":{"items":{"type":"string"},"type":"array","title":"Pnl Buckets","default":[]},"regime_performance":{"anyOf":[{"$ref":"#/components/schemas/RegimePerformance"},{"type":"null"}]},"is_valid":{"type":"boolean","title":"Is Valid"},"validation_errors":{"items":{"type":"string"},"type":"array","title":"Validation Errors","default":[]},"yearly_stats":{"items":{"$ref":"#/components/schemas/YearlyStat"},"type":"array","title":"Yearly Stats","default":[]},"monthly_stats":{"items":{"$ref":"#/components/schemas/MonthlyStat"},"type":"array","title":"Monthly Stats","default":[]},"compute_time_ms":{"type":"integer","title":"Compute Time Ms","default":0},"reliability_checks":{"items":{"$ref":"#/components/schemas/ReliabilityCheck"},"type":"array","title":"Reliability Checks","description":"축별 판정 레코드 — 이 응답의 «판정 SSoT». reliability_warning 은 파생물.\n\n⚠ `verdict` 는 세 값이다. `not_evaluated` 를 «통과»로 세면 0거래 응답이\n「4개 축 통과」로 읽힌다 — 그 축들은 실행조차 안 됐다.","readOnly":true},"reliability_warning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reliability Warning","description":"계약은 build_reliability_warning 한 곳이 소유한다(룰3).","readOnly":true}},"type":"object","required":["name","direction","sl_pct","tp_pct","max_bars","indicators_used","conditions_count","total_trades","wins","losses","win_rate","total_return_pct","profit_factor","avg_win_pct","avg_loss_pct","max_drawdown_pct","max_consecutive_losses","tp_count","sl_count","timeout_count","coins_used","data_range","equity_curve","is_valid","reliability_checks","reliability_warning"],"title":"BacktestResponse","description":"Custom strategy backtest result."},"BotSimRequest":{"properties":{"symbol":{"type":"string","maxLength":16,"minLength":5,"title":"Symbol","description":"OHLCV symbol, e.g. BTCUSDT"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"start":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start","description":"ISO8601 window start (inclusive)"},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End","description":"ISO8601 window end (inclusive)"},"taker_fee_pct":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Taker Fee Pct","description":"% per fill, default 0.05"}},"type":"object","required":["symbol"],"title":"BotSimRequest","description":"DCA/그리드 백테스트 요청. `params` 키·범위는 봇 설정과 동일(okx/dca_bots.py·grid_bots.py `_BOUNDS`)."},"CoinInfo":{"properties":{"symbol":{"type":"string","title":"Symbol"},"rows":{"type":"integer","title":"Rows"},"date_from":{"type":"string","title":"Date From"},"date_to":{"type":"string","title":"Date To"},"stablecoin":{"type":"boolean","title":"Stablecoin","default":false},"asset_class":{"type":"string","title":"Asset Class","default":"crypto"},"change_7d":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change 7D"},"sparkline_7d":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Sparkline 7D"}},"type":"object","required":["symbol","rows","date_from","date_to"],"title":"CoinInfo"},"CoinResult":{"properties":{"symbol":{"type":"string","title":"Symbol"},"trades":{"type":"integer","title":"Trades"},"wins":{"type":"integer","title":"Wins"},"losses":{"type":"integer","title":"Losses"},"win_rate":{"type":"number","title":"Win Rate"},"profit_factor":{"type":"number","title":"Profit Factor"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"avg_pnl_pct":{"type":"number","title":"Avg Pnl Pct"},"tp_count":{"type":"integer","title":"Tp Count"},"sl_count":{"type":"integer","title":"Sl Count"},"timeout_count":{"type":"integer","title":"Timeout Count"}},"type":"object","required":["symbol","trades","wins","losses","win_rate","profit_factor","total_return_pct","avg_pnl_pct","tp_count","sl_count","timeout_count"],"title":"CoinResult","description":"Per-coin simulation result in portfolio backtest."},"CoinSimRequest":{"properties":{"symbol":{"type":"string","title":"Symbol"},"fee_pct":{"anyOf":[{"type":"number","maximum":0.01,"minimum":0.0},{"type":"null"}],"title":"Fee Pct","description":"Fee per side (0.0005 = 0.05%). None = use market_type default"},"sl_pct":{"type":"number","maximum":50.0,"minimum":1.0,"title":"Sl Pct","default":10.0},"tp_pct":{"type":"number","maximum":50.0,"minimum":1.0,"title":"Tp Pct","default":8.0},"max_bars":{"type":"integer","maximum":168.0,"minimum":1.0,"title":"Max Bars","default":48},"direction":{"type":"string","title":"Direction","default":"short"},"market_type":{"type":"string","enum":["futures","spot"],"title":"Market Type","default":"futures"},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date","description":"Backtest start date (YYYY-MM-DD)"},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Date","description":"Backtest end date (YYYY-MM-DD)"},"timeframe":{"type":"string","enum":["1H","2H","4H","6H","12H","1D","1W"],"title":"Timeframe","description":"Candle timeframe: 1H, 2H, 4H, 6H, 12H, 1D, 1W","default":"1H"},"strategy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Strategy","description":"Strategy id (registry). Omitted = legacy bb-squeeze-{direction}."},"leverage":{"type":"number","maximum":125.0,"minimum":1.0,"title":"Leverage","default":1.0}},"type":"object","required":["symbol"],"title":"CoinSimRequest"},"CoinSimResponse":{"properties":{"symbol":{"type":"string","title":"Symbol"},"total_trades":{"type":"integer","title":"Total Trades"},"win_rate":{"type":"number","title":"Win Rate"},"profit_factor":{"type":"number","title":"Profit Factor"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"max_drawdown_pct":{"type":"number","title":"Max Drawdown Pct"},"tp_count":{"type":"integer","title":"Tp Count"},"sl_count":{"type":"integer","title":"Sl Count"},"timeout_count":{"type":"integer","title":"Timeout Count"},"sharpe_ratio":{"type":"number","title":"Sharpe Ratio","default":0.0},"sortino_ratio":{"type":"number","title":"Sortino Ratio","default":0.0},"calmar_ratio":{"type":"number","title":"Calmar Ratio","default":0.0},"trades":{"items":{"$ref":"#/components/schemas/TradeDetail"},"type":"array","title":"Trades"}},"type":"object","required":["symbol","total_trades","win_rate","profit_factor","total_return_pct","max_drawdown_pct","tp_count","sl_count","timeout_count","trades"],"title":"CoinSimResponse"},"CoinStats":{"properties":{"symbol":{"type":"string","title":"Symbol"},"price":{"type":"number","title":"Price"},"change_24h":{"type":"number","title":"Change 24H"},"volume_24h":{"type":"number","title":"Volume 24H"},"trades":{"type":"integer","title":"Trades","default":0},"win_rate":{"type":"number","title":"Win Rate","default":0.0},"profit_factor":{"type":"number","title":"Profit Factor","default":0.0},"total_return_pct":{"type":"number","title":"Total Return Pct","default":0.0},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"image":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image"},"change_1h":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change 1H"},"change_7d":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change 7D"},"market_cap":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Market Cap"},"market_cap_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Market Cap Rank"},"sparkline_7d":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Sparkline 7D"},"change_7d_carried":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Change 7D Carried"},"cg_carried":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cg Carried"},"cg_as_of":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cg As Of"}},"type":"object","required":["symbol","price","change_24h","volume_24h"],"title":"CoinStats"},"CoinStatsResponse":{"properties":{"generated":{"type":"string","title":"Generated"},"strategy":{"type":"string","title":"Strategy"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"coins":{"items":{"$ref":"#/components/schemas/CoinStats"},"type":"array","title":"Coins"}},"type":"object","required":["generated","strategy","params","coins"],"title":"CoinStatsResponse"},"CompareLimitDetail":{"properties":{"error":{"type":"string","title":"Error"},"max_top_n":{"type":"integer","title":"Max Top N"},"requested":{"type":"integer","title":"Requested"},"alternative":{"type":"string","title":"Alternative"}},"type":"object","required":["error","max_top_n","requested","alternative"],"title":"CompareLimitDetail","description":"detail of the /simulate/compare 400 when top_n is above COMPARE_MAX_COINS (Q-B55) — typed for generated clients."},"CompareLimitError":{"properties":{"detail":{"$ref":"#/components/schemas/CompareLimitDetail"}},"type":"object","required":["detail"],"title":"CompareLimitError"},"CompareRequest":{"properties":{"sl_pct":{"type":"number","maximum":50.0,"minimum":1.0,"title":"Sl Pct","description":"Stop Loss %","default":10.0},"tp_pct":{"type":"number","maximum":50.0,"minimum":1.0,"title":"Tp Pct","description":"Take Profit %","default":8.0},"max_bars":{"type":"integer","maximum":168.0,"minimum":1.0,"title":"Max Bars","description":"Max holding period (bars)","default":48},"top_n":{"anyOf":[{"type":"integer","maximum":535.0,"minimum":1.0},{"type":"null"}],"title":"Top N","description":"Number of coins, at most 5 (null = 5). 6..535 → HTTP 400 with detail {error, max_top_n: 5, requested, alternative: \"/simulate per strategy\"}; above 535 → the generic 422 (detail is a list). Every call runs all strategies and more coins do not finish inside the 45 s gateway limit (Q-B55)."}},"type":"object","title":"CompareRequest","description":"Compare all strategies under identical conditions."},"CompareResponse":{"properties":{"sl_pct":{"type":"number","title":"Sl Pct"},"tp_pct":{"type":"number","title":"Tp Pct"},"max_bars":{"type":"integer","title":"Max Bars"},"coins_used":{"type":"integer","title":"Coins Used"},"top_n_requested":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top N Requested","description":"The top_n this run resolved to. null for explicit symbols= requests (no top-N universe)."},"eligible_universe":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Eligible Universe","description":"Coins eligible for a top-N universe at run time (stablecoins unless include_stablecoins, non-crypto and liquidity-dead markets excluded), read in the same selection as the coins run. null for symbols= requests (and on /backtest when the strategy is invalid, is_valid=false)."},"universe_capped":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Universe Capped","description":"eligible_universe < top_n_requested: the request asked for more coins than exist, so the whole eligible universe ran. A cap only — coins lacking data are reported in coins_missing_data. null for symbols= requests."},"run_cap":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Run Cap","description":"Q-B131: the per-request limit that actually stopped this run before min(top_n_requested, eligible_universe) coins, or null when none did (coins_used then reaches that number, data gaps aside). See run_cap_reason for which limit."},"run_cap_reason":{"anyOf":[{"type":"string","enum":["indicator_cache","compare_max_coins"]},{"type":"null"}],"title":"Run Cap Reason","description":"Q-B131: which limit run_cap is. «indicator_cache»: the cached path of /simulate/compare, /simulate/validate and /simulate/optimize computes at most the indicator-cache size per request (no all-coin hold; larger runs are a separate async path, Q-B132). «compare_max_coins»: kept for compatibility — since Q-B55 /simulate/compare rejects a top_n above its limit (COMPARE_MAX_COINS) with HTTP 400, so this cut no longer binds. When both apply, the smaller one — the one that bound — is reported. null when no limit bound."},"coins_not_computed":{"items":{"type":"string"},"type":"array","title":"Coins Not Computed","description":"Q-B131: explicitly requested symbols= that were not run because the per-request compute limit (the indicator-cache size) was reached. Empty when every requested symbol ran. Distinct from coins_missing_data (coins without candles in the window)."},"data_range":{"type":"string","title":"Data Range"},"strategies":{"items":{"$ref":"#/components/schemas/StrategyResult"},"type":"array","title":"Strategies"}},"type":"object","required":["sl_pct","tp_pct","max_bars","coins_used","data_range","strategies"],"title":"CompareResponse","description":"Comparison across all strategies."},"DailyRankingResponse":{"properties":{"schema_version":{"type":"string","title":"Schema Version"},"date":{"type":"string","format":"date","title":"Date"},"generated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Generated At"},"period":{"type":"string","title":"Period"},"group":{"type":"string","title":"Group"},"top3":{"items":{"$ref":"#/components/schemas/RankingRow"},"type":"array","title":"Top3"},"worst3":{"items":{"$ref":"#/components/schemas/RankingRow"},"type":"array","title":"Worst3"},"weekly_best3":{"items":{"$ref":"#/components/schemas/RankingRow"},"type":"array","title":"Weekly Best3"},"citation":{"$ref":"#/components/schemas/RankingCitation"},"how_to_reverify":{"$ref":"#/components/schemas/RankingReverification"},"research_status_definitions":{"additionalProperties":{"$ref":"#/components/schemas/ResearchDefinition"},"type":"object","title":"Research Status Definitions"},"criteria_url":{"type":"string","title":"Criteria Url"},"rc_scope":{"type":"string","title":"Rc Scope"},"headline_has_verified":{"type":"boolean","title":"Headline Has Verified","description":"True if a configuration whose research label is verified (rule C, configuration scope) is in top3. Rule: criteria headline."},"verified_in_ranking":{"items":{"$ref":"#/components/schemas/VerifiedInRanking"},"type":"array","title":"Verified In Ranking","description":"Every verified configuration in this ranked population, with its rank and shown PF."},"headline_note":{"anyOf":[{"$ref":"#/components/schemas/LocalizedText"},{"type":"null"}],"description":"Computed, never fixed. See headline_note_kind and criteria headline."},"headline_note_kind":{"anyOf":[{"type":"string","enum":["verified_below","verified_ranked_lower","no_verified_in_group","unknown"]},{"type":"null"}],"title":"Headline Note Kind","description":"verified_below = top3 has no verified configuration, verified ones are ranked below and all have PF < 1; verified_ranked_lower = top3 has none, verified ones are ranked below and not all have PF < 1 (ranks and shown PF only, no comparison); no_verified_in_group = top3 has none and this group's ranking has none; unknown = the group is not a published universe (legacy file / unmapped title) so labels cannot be judged — no sentence; null = no sentence (a verified configuration is in top3, or nothing is ranked for this period/group — empty top3; headline_has_verified is then false too)."}},"additionalProperties":true,"type":"object","required":["schema_version","date","generated_at","period","group","top3","worst3","weekly_best3","citation","how_to_reverify","research_status_definitions","criteria_url","rc_scope","headline_has_verified","verified_in_ranking","headline_note","headline_note_kind"],"title":"DailyRankingResponse"},"DeflatedSharpeInfo":{"properties":{"dsr":{"type":"number","title":"Dsr","description":"N=grid 셀 수(전 시도 공개) 기준 DSR — 보수적 기본"},"sharpe_annualized":{"type":"number","title":"Sharpe Annualized","description":"승자 셀의 연율 Sharpe (표시용 — 계산은 per-period)"},"n_trials":{"type":"integer","title":"N Trials","description":"이 그리드에서 노출된 시도 수. 개발 중 폐기된 시도는 포함되지 않음(file-drawer)"},"n_obs":{"type":"integer","title":"N Obs","description":"승자 셀의 일별 수익률 관측 수 T"},"skew":{"type":"number","title":"Skew"},"kurtosis_raw":{"type":"number","title":"Kurtosis Raw","description":"raw 첨도 (정규분포=3)"},"sensitivity":{"additionalProperties":true,"type":"object","title":"Sensitivity","description":"{N: dsr} — N 불확실성 3점 공시"},"caveat":{"type":"string","title":"Caveat","default":"DSR corrects for the number of trials shown here only; trials discarded during development are not counted. It does not validate the backtest itself (fees, look-ahead)."}},"type":"object","required":["dsr","sharpe_annualized","n_trials","n_obs","skew","kurtosis_raw","sensitivity"],"title":"DeflatedSharpeInfo","description":"그리드 승자의 Deflated Sharpe — 다중검정(선택 편향) 보정 (Bailey & LdP 2014).\n\ndsr > 0.95 = 시도 횟수를 고백한 뒤에도 5% 유의수준에서 우연 최댓값이 아니라는\n뜻. sensitivity 는 «독립 시도 수 N 을 정확히 알 수 없다»는 논문 자신의 한계\n(부록 A.3)를 제품이 스스로 공시하는 3점이다."},"DerivativesData":{"properties":{"btc_open_interest_b":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Btc Open Interest B","default":0},"eth_open_interest_b":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eth Open Interest B","default":0},"btc_ls_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Btc Ls Ratio","default":0},"eth_ls_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eth Ls Ratio","default":0},"btc_oi_change_24h":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Btc Oi Change 24H","default":0},"eth_oi_change_24h":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eth Oi Change 24H","default":0},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"}},"type":"object","title":"DerivativesData","description":"Crypto derivatives market data."},"EconomicEvent":{"properties":{"date":{"type":"string","title":"Date"},"time_utc":{"type":"string","title":"Time Utc","default":""},"country":{"type":"string","title":"Country","default":""},"event":{"type":"string","title":"Event"},"impact":{"type":"string","title":"Impact","default":""},"forecast":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Forecast"},"previous":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previous"}},"type":"object","required":["date","event"],"title":"EconomicEvent","description":"Upcoming economic calendar event."},"EngineRun":{"properties":{"parameters":{"additionalProperties":true,"type":"object","title":"Parameters","description":"Bound run_fast arguments, including defaults. Fee/slippage are per-side fractions; SL/TP are fractions."},"strategy_parameters":{"additionalProperties":true,"type":"object","title":"Strategy Parameters"},"data":{"$ref":"#/components/schemas/FrameSnapshot"}},"type":"object","required":["parameters","strategy_parameters","data"],"title":"EngineRun"},"EquityPoint":{"properties":{"time":{"type":"string","title":"Time"},"value":{"type":"number","title":"Value"}},"type":"object","required":["time","value"],"title":"EquityPoint"},"ExecutionProvenance":{"properties":{"schema_version":{"type":"string","const":"1.0.0","title":"Schema Version","default":"1.0.0"},"engine_commit":{"type":"string","pattern":"^[0-9a-f]{40}$","title":"Engine Commit"},"started_at":{"type":"string","format":"date-time","title":"Started At"},"measured_at":{"type":"string","format":"date-time","title":"Measured At"},"request":{"additionalProperties":true,"type":"object","title":"Request","description":"Validated request with defaults before engine normalization"},"coins":{"items":{"type":"string"},"type":"array","title":"Coins"},"data_snapshot_id":{"type":"string","pattern":"^sha256:[0-9a-f]{64}$","title":"Data Snapshot Id"},"selection":{"items":{"$ref":"#/components/schemas/SelectedFrame"},"type":"array","title":"Selection"},"runs":{"items":{"$ref":"#/components/schemas/EngineRun"},"type":"array","title":"Runs"},"funding":{"items":{"$ref":"#/components/schemas/FundingSnapshot"},"type":"array","title":"Funding"}},"type":"object","required":["engine_commit","started_at","measured_at","request","coins","data_snapshot_id","selection","runs","funding"],"title":"ExecutionProvenance"},"FrameColumn":{"properties":{"name":{"type":"string","title":"Name"},"dtype":{"type":"string","title":"Dtype"}},"type":"object","required":["name","dtype"],"title":"FrameColumn"},"FramePeriod":{"properties":{"start":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start"},"end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End"}},"type":"object","required":["start","end"],"title":"FramePeriod"},"FrameSnapshot":{"properties":{"snapshot_id":{"type":"string","pattern":"^sha256:[0-9a-f]{64}$","title":"Snapshot Id"},"rows":{"type":"integer","minimum":0.0,"title":"Rows"},"columns":{"items":{"$ref":"#/components/schemas/FrameColumn"},"type":"array","title":"Columns"},"row_hash":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Row Hash"},"pandas_version":{"type":"string","title":"Pandas Version"},"period":{"$ref":"#/components/schemas/FramePeriod"}},"type":"object","required":["snapshot_id","rows","columns","row_hash","pandas_version","period"],"title":"FrameSnapshot"},"FundingRate":{"properties":{"symbol":{"type":"string","title":"Symbol"},"rate":{"type":"number","title":"Rate"},"annual_pct":{"type":"number","title":"Annual Pct"}},"type":"object","required":["symbol","rate","annual_pct"],"title":"FundingRate"},"FundingSnapshot":{"properties":{"symbol":{"type":"string","title":"Symbol"},"available":{"type":"boolean","title":"Available"},"rows":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rows"},"snapshot_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Snapshot Id"}},"type":"object","required":["symbol","available"],"title":"FundingSnapshot"},"GenerateBotRequest":{"properties":{"strategy_id":{"type":"string","pattern":"^[\\w-]{1,64}$","title":"Strategy Id","default":"bb-squeeze-short"},"direction":{"type":"string","title":"Direction","default":"short"},"sl_pct":{"type":"number","maximum":50.0,"minimum":0.5,"title":"Sl Pct","default":10.0},"tp_pct":{"type":"number","maximum":100.0,"minimum":0.5,"title":"Tp Pct","default":8.0},"max_bars":{"type":"integer","maximum":168.0,"minimum":1.0,"title":"Max Bars","default":48},"leverage":{"type":"integer","maximum":125.0,"minimum":1.0,"title":"Leverage","default":5},"position_size_usd":{"type":"number","maximum":10000.0,"minimum":1.0,"title":"Position Size Usd","default":60.0},"coins":{"items":{"type":"string"},"type":"array","title":"Coins","default":["BTC-USDT-SWAP","ETH-USDT-SWAP"]},"avoid_hours":{"items":{"type":"integer"},"type":"array","title":"Avoid Hours","default":[]},"backtest_win_rate":{"type":"number","title":"Backtest Win Rate","default":0},"backtest_profit_factor":{"type":"number","title":"Backtest Profit Factor","default":0}},"type":"object","title":"GenerateBotRequest","description":"Request to generate a trading bot zip."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthResponse":{"properties":{"status":{"type":"string","title":"Status"},"version":{"type":"string","title":"Version"},"coins_loaded":{"type":"integer","title":"Coins Loaded"},"universe_order":{"type":"string","enum":["market_cap","data_size"],"title":"Universe Order","default":"data_size"},"uptime_seconds":{"type":"number","title":"Uptime Seconds"},"db_ok":{"type":"boolean","title":"Db Ok","default":true},"db_age_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Db Age S"}},"type":"object","required":["status","version","coins_loaded","uptime_seconds"],"title":"HealthResponse"},"IndicatorInfo":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"fields":{"items":{"type":"string"},"type":"array","title":"Fields"},"default_params":{"additionalProperties":true,"type":"object","title":"Default Params"}},"type":"object","required":["id","name","fields","default_params"],"title":"IndicatorInfo","description":"Available indicator for Strategy Builder."},"LocalizedText":{"properties":{"en":{"type":"string","title":"En"},"ko":{"type":"string","title":"Ko"}},"type":"object","required":["en","ko"],"title":"LocalizedText"},"MCEquityBand":{"properties":{"trade_idx":{"type":"integer","title":"Trade Idx"},"p5":{"type":"number","title":"P5"},"p25":{"type":"number","title":"P25"},"p50":{"type":"number","title":"P50"},"p75":{"type":"number","title":"P75"},"p95":{"type":"number","title":"P95"}},"type":"object","required":["trade_idx","p5","p25","p50","p75","p95"],"title":"MCEquityBand","description":"Equity percentile at a trade index."},"MacroIndicator":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"value":{"type":"number","title":"Value"},"change":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change"},"previous":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Previous"},"unit":{"type":"string","title":"Unit","default":""},"updated":{"type":"string","title":"Updated","default":""},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"},"source":{"type":"string","title":"Source","default":""}},"type":"object","required":["id","name","value"],"title":"MacroIndicator","description":"A single macro economic indicator."},"MacroResponse":{"properties":{"indicators":{"items":{"$ref":"#/components/schemas/MacroIndicator"},"type":"array","title":"Indicators","default":[]},"derivatives":{"anyOf":[{"$ref":"#/components/schemas/DerivativesData"},{"type":"null"}]},"events":{"items":{"$ref":"#/components/schemas/EconomicEvent"},"type":"array","title":"Events","default":[]},"generated":{"type":"string","title":"Generated","default":""}},"type":"object","title":"MacroResponse","description":"Macro economic dashboard response."},"MarketMover":{"properties":{"symbol":{"type":"string","title":"Symbol"},"price":{"type":"number","title":"Price"},"change_24h":{"type":"number","title":"Change 24H"},"volume_24h":{"type":"number","title":"Volume 24H"}},"type":"object","required":["symbol","price","change_24h","volume_24h"],"title":"MarketMover"},"MarketOverview":{"properties":{"btc_price":{"type":"number","title":"Btc Price","default":0},"btc_change_24h":{"type":"number","title":"Btc Change 24H","default":0},"eth_price":{"type":"number","title":"Eth Price","default":0},"eth_change_24h":{"type":"number","title":"Eth Change 24H","default":0},"fear_greed_index":{"type":"integer","title":"Fear Greed Index","default":0},"fear_greed_label":{"type":"string","title":"Fear Greed Label","default":"N/A"},"total_market_cap_b":{"type":"number","title":"Total Market Cap B","default":0},"btc_dominance":{"type":"number","title":"Btc Dominance","default":0},"total_volume_24h_b":{"type":"number","title":"Total Volume 24H B","default":0},"cg_global_unknown":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cg Global Unknown"},"cg_global_carried":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cg Global Carried"},"cg_global_as_of":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cg Global As Of"},"top_gainers":{"items":{"$ref":"#/components/schemas/MarketMover"},"type":"array","title":"Top Gainers","default":[]},"top_losers":{"items":{"$ref":"#/components/schemas/MarketMover"},"type":"array","title":"Top Losers","default":[]},"extreme_funding":{"items":{"$ref":"#/components/schemas/FundingRate"},"type":"array","title":"Extreme Funding","default":[]},"generated":{"type":"string","title":"Generated","default":""}},"type":"object","title":"MarketOverview"},"MetricCI":{"properties":{"unit":{"type":"string","title":"Unit"},"point":{"type":"number","title":"Point"},"lo":{"type":"number","title":"Lo"},"hi":{"type":"number","title":"Hi"},"ci_pct":{"type":"number","title":"Ci Pct"},"n_input":{"type":"integer","title":"N Input"},"n_resamples":{"type":"integer","title":"N Resamples"},"n_used":{"type":"integer","title":"N Used"},"no_loss_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"No Loss Pct"}},"type":"object","required":["unit","point","lo","hi","ci_pct","n_input","n_resamples","n_used"],"title":"MetricCI","description":"지표 하나의 부트스트랩 신뢰구간.\n\n★ `unit` 이 **값으로** 있는 이유 (Q-B29 A, 2026-08-29):\n각 지표의 CI 는 «그 헤드라인이 실제로 쓰는 입력» 을 재표집해야 한다.\n    profit_factor  ← 거래별 gross P/L        → unit=\"trades\"\n    sharpe_ratio   ← 일별 수익률 × √365      → unit=\"daily_returns\"\n거래를 재표집해 Sharpe CI 를 내면 **화면의 그 Sharpe 가 아니다.** 그런데\n틀려 보이지 않는다 — 실측(BTCUSDT rsi<30 long, 176거래): 헤드라인 −0.91,\n거래 축 CI −4.78~0.29 로 **헤드라인이 구간 안에 들어간다.** 라벨도 «Sharpe\nCI», 숫자 모양도 맞고 점추정도 구간 안이다. 축만 다르다.\n⇒ 라벨이 스스로 축을 말하게 한다. 소비자는 이 값을 «무엇을 몇 번 재표집한\n  CI 인가» 문구에 그대로 쓴다(룰4 스코프 라벨)."},"MonteCarloResult":{"properties":{"mean_return":{"type":"number","title":"Mean Return"},"median_return":{"type":"number","title":"Median Return"},"std_return":{"type":"number","title":"Std Return"},"percentile_5":{"type":"number","title":"Percentile 5"},"percentile_25":{"type":"number","title":"Percentile 25"},"percentile_75":{"type":"number","title":"Percentile 75"},"percentile_95":{"type":"number","title":"Percentile 95"},"worst_case_return":{"type":"number","title":"Worst Case Return"},"best_case_return":{"type":"number","title":"Best Case Return"},"worst_case_mdd":{"type":"number","title":"Worst Case Mdd"},"positive_pct":{"type":"number","title":"Positive Pct"},"n_simulations":{"type":"integer","title":"N Simulations"},"n_trades":{"type":"integer","title":"N Trades"},"equity_bands":{"items":{"$ref":"#/components/schemas/MCEquityBand"},"type":"array","title":"Equity Bands"}},"type":"object","required":["mean_return","median_return","std_return","percentile_5","percentile_25","percentile_75","percentile_95","worst_case_return","best_case_return","worst_case_mdd","positive_pct","n_simulations","n_trades","equity_bands"],"title":"MonteCarloResult","description":"Monte Carlo simulation result."},"MonthlyStat":{"properties":{"month":{"type":"string","title":"Month"},"trades":{"type":"integer","title":"Trades"},"wins":{"type":"integer","title":"Wins"},"win_rate":{"type":"number","title":"Win Rate"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"profit_factor":{"type":"number","title":"Profit Factor"}},"type":"object","required":["month","trades","wins","win_rate","total_return_pct","profit_factor"],"title":"MonthlyStat","description":"Per-month performance breakdown."},"NewsItem":{"properties":{"title":{"type":"string","title":"Title"},"link":{"type":"string","title":"Link"},"source":{"type":"string","title":"Source"},"published":{"type":"string","title":"Published"},"summary":{"type":"string","title":"Summary","default":""},"category":{"type":"string","title":"Category","default":"crypto"}},"type":"object","required":["title","link","source","published"],"title":"NewsItem"},"NewsResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/NewsItem"},"type":"array","title":"Items"},"generated":{"type":"string","title":"Generated"}},"type":"object","required":["items","generated"],"title":"NewsResponse"},"OOSPeriodMetrics":{"properties":{"trades":{"type":"integer","title":"Trades"},"win_rate":{"type":"number","title":"Win Rate"},"total_return":{"type":"number","title":"Total Return"},"profit_factor":{"type":"number","title":"Profit Factor"},"max_dd":{"type":"number","title":"Max Dd"},"avg_win":{"type":"number","title":"Avg Win"},"avg_loss":{"type":"number","title":"Avg Loss"}},"type":"object","required":["trades","win_rate","total_return","profit_factor","max_dd","avg_win","avg_loss"],"title":"OOSPeriodMetrics","description":"Metrics for one period (IS or OOS)."},"OOSResult":{"properties":{"is_metrics":{"$ref":"#/components/schemas/OOSPeriodMetrics"},"oos_metrics":{"$ref":"#/components/schemas/OOSPeriodMetrics"},"degradation_ratio":{"type":"number","title":"Degradation Ratio"},"overfit_risk":{"type":"string","title":"Overfit Risk"}},"type":"object","required":["is_metrics","oos_metrics","degradation_ratio","overfit_risk"],"title":"OOSResult","description":"IS vs OOS comparison."},"OhlcvBar":{"properties":{"t":{"type":"integer","title":"T"},"o":{"type":"number","title":"O"},"h":{"type":"number","title":"H"},"l":{"type":"number","title":"L"},"c":{"type":"number","title":"C"},"v":{"type":"number","title":"V"},"bb_upper":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Bb Upper"},"bb_lower":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Bb Lower"},"bb_mid":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Bb Mid"},"ema20":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ema20"},"ema50":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ema50"},"vol_ratio":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Vol Ratio"}},"type":"object","required":["t","o","h","l","c","v"],"title":"OhlcvBar"},"OhlcvResponse":{"properties":{"symbol":{"type":"string","title":"Symbol"},"timeframe":{"type":"string","title":"Timeframe","default":"1H"},"total_bars":{"type":"integer","title":"Total Bars"},"data":{"items":{"$ref":"#/components/schemas/OhlcvBar"},"type":"array","title":"Data"}},"type":"object","required":["symbol","total_bars","data"],"title":"OhlcvResponse"},"OptimizeCell":{"properties":{"sl_pct":{"type":"number","title":"Sl Pct"},"tp_pct":{"type":"number","title":"Tp Pct"},"total_trades":{"type":"integer","title":"Total Trades"},"win_rate":{"type":"number","title":"Win Rate"},"profit_factor":{"type":"number","title":"Profit Factor"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"max_drawdown_pct":{"type":"number","title":"Max Drawdown Pct"},"sharpe_ratio":{"type":"number","title":"Sharpe Ratio","default":0.0}},"type":"object","required":["sl_pct","tp_pct","total_trades","win_rate","profit_factor","total_return_pct","max_drawdown_pct"],"title":"OptimizeCell","description":"Single cell in the SL/TP optimization grid."},"OptimizeRequest":{"properties":{"strategy":{"type":"string","title":"Strategy","description":"Strategy ID","default":"bb-squeeze"},"direction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Direction","description":"long | short | both"},"sl_steps":{"items":{"type":"number"},"type":"array","title":"Sl Steps","description":"Stop Loss values to sweep (max 6)","default":[5.0,8.0,10.0,15.0,20.0]},"tp_steps":{"items":{"type":"number"},"type":"array","title":"Tp Steps","description":"Take Profit values to sweep (max 6)","default":[5.0,8.0,10.0,15.0,20.0]},"max_bars":{"type":"integer","maximum":168.0,"minimum":1.0,"title":"Max Bars","default":48},"market_type":{"type":"string","enum":["futures","spot"],"title":"Market Type","default":"futures"},"symbols":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Symbols"},"top_n":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":1.0},{"type":"null"}],"title":"Top N","description":"Limit coins for speed (default 20)","default":20},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date"},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Date"},"timeframe":{"type":"string","enum":["1H","2H","4H","6H","12H","1D","1W"],"title":"Timeframe","default":"1H"},"metric":{"type":"string","title":"Metric","description":"Primary metric: total_return_pct | win_rate | profit_factor | sharpe_ratio","default":"total_return_pct"}},"type":"object","title":"OptimizeRequest","description":"SL/TP grid search request."},"OptimizeResponse":{"properties":{"strategy":{"type":"string","title":"Strategy"},"direction":{"type":"string","title":"Direction"},"metric":{"type":"string","title":"Metric"},"sl_steps":{"items":{"type":"number"},"type":"array","title":"Sl Steps"},"tp_steps":{"items":{"type":"number"},"type":"array","title":"Tp Steps"},"grid":{"items":{"$ref":"#/components/schemas/OptimizeCell"},"type":"array","title":"Grid"},"coins_used":{"type":"integer","title":"Coins Used"},"top_n_requested":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top N Requested","description":"The top_n this run resolved to. null for explicit symbols= requests (no top-N universe)."},"eligible_universe":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Eligible Universe","description":"Coins eligible for a top-N universe at run time (stablecoins unless include_stablecoins, non-crypto and liquidity-dead markets excluded), read in the same selection as the coins run. null for symbols= requests (and on /backtest when the strategy is invalid, is_valid=false)."},"universe_capped":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Universe Capped","description":"eligible_universe < top_n_requested: the request asked for more coins than exist, so the whole eligible universe ran. A cap only — coins lacking data are reported in coins_missing_data. null for symbols= requests."},"run_cap":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Run Cap","description":"Q-B131: the per-request limit that actually stopped this run before min(top_n_requested, eligible_universe) coins, or null when none did (coins_used then reaches that number, data gaps aside). See run_cap_reason for which limit."},"run_cap_reason":{"anyOf":[{"type":"string","enum":["indicator_cache","compare_max_coins"]},{"type":"null"}],"title":"Run Cap Reason","description":"Q-B131: which limit run_cap is. «indicator_cache»: the cached path of /simulate/compare, /simulate/validate and /simulate/optimize computes at most the indicator-cache size per request (no all-coin hold; larger runs are a separate async path, Q-B132). «compare_max_coins»: kept for compatibility — since Q-B55 /simulate/compare rejects a top_n above its limit (COMPARE_MAX_COINS) with HTTP 400, so this cut no longer binds. When both apply, the smaller one — the one that bound — is reported. null when no limit bound."},"coins_not_computed":{"items":{"type":"string"},"type":"array","title":"Coins Not Computed","description":"Q-B131: explicitly requested symbols= that were not run because the per-request compute limit (the indicator-cache size) was reached. Empty when every requested symbol ran. Distinct from coins_missing_data (coins without candles in the window)."},"data_range":{"type":"string","title":"Data Range"},"compute_time_ms":{"type":"integer","title":"Compute Time Ms"},"deflated_sharpe":{"anyOf":[{"$ref":"#/components/schemas/DeflatedSharpeInfo"},{"type":"null"}]}},"type":"object","required":["strategy","direction","metric","sl_steps","tp_steps","grid","coins_used","data_range","compute_time_ms"],"title":"OptimizeResponse","description":"SL/TP optimization grid results."},"PresetListItem":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"direction":{"type":"string","title":"Direction"},"indicators":{"items":{"type":"string"},"type":"array","title":"Indicators"},"conditions_count":{"type":"integer","title":"Conditions Count"},"sl_pct":{"type":"number","title":"Sl Pct"},"tp_pct":{"type":"number","title":"Tp Pct"}},"type":"object","required":["id","name","direction","indicators","conditions_count","sl_pct","tp_pct"],"title":"PresetListItem","description":"Preset strategy summary for listing."},"RankingCitation":{"properties":{"url":{"type":"string","title":"Url"},"generated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Generated At"},"criteria_version":{"type":"string","title":"Criteria Version"},"research_source_digest":{"type":"string","title":"Research Source Digest"},"note":{"type":"string","title":"Note"}},"type":"object","required":["url","generated_at","criteria_version","research_source_digest","note"],"title":"RankingCitation"},"RankingReverification":{"properties":{"url":{"type":"string","title":"Url"},"command":{"type":"string","title":"Command"},"criteria_url":{"type":"string","title":"Criteria Url"},"scope":{"type":"string","title":"Scope"}},"type":"object","required":["url","command","criteria_url","scope"],"title":"RankingReverification"},"RankingRow":{"properties":{"rank":{"type":"integer","title":"Rank"},"configuration_id":{"type":"string","title":"Configuration Id"},"configuration_identity_version":{"type":"string","title":"Configuration Identity Version"},"strategy":{"type":"string","title":"Strategy"},"direction":{"type":"string","title":"Direction"},"name_en":{"type":"string","title":"Name En"},"name_ko":{"type":"string","title":"Name Ko"},"win_rate":{"type":"number","title":"Win Rate"},"profit_factor":{"type":"number","title":"Profit Factor"},"pf_capped":{"type":"boolean","title":"Pf Capped","description":"True = profit_factor is a lower bound, not a measurement (daily: reached pf_clip; weekly: any contributing day exceeded pf_clip before averaging). Rule: criteria pf_caps."},"pf_clip":{"type":"number","title":"Pf Clip","description":"The cap applied to this row's profit_factor: 99.99 for daily rows (display), 20.0 per day for weekly means."},"total_trades":{"type":"integer","title":"Total Trades"},"timeframe":{"type":"string","title":"Timeframe"},"low_sample":{"type":"boolean","title":"Low Sample"},"research_status":{"type":"string","enum":["verified","conditional","live","testing","killed","shelved","unrated"],"title":"Research Status"},"status_scope":{"anyOf":[{"type":"string","enum":["configuration","record"]},{"type":"null"}],"title":"Status Scope","description":"What research_status describes: configuration = measured for this exact configuration; record = the whole strategy record (retirement); null = unrated. Rule: criteria research_label."},"research_record":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Research Record","description":"Research record the row resolved to (may carry a status that does not apply to this configuration)."},"reason_url":{"type":"string","title":"Reason Url"},"criteria_version":{"type":"string","title":"Criteria Version"},"measured_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Measured At","description":"Timestamp from the retained ranking generation record, not an exact simulation completion time; null if only a date was retained."},"sample":{"$ref":"#/components/schemas/RankingSample"},"rc":{"type":"integer","enum":[0,1,2],"title":"Rc","description":"Existing research lifecycle projection. Not a verdict on this ranking configuration; see rc_scope."}},"additionalProperties":true,"type":"object","required":["rank","configuration_id","configuration_identity_version","strategy","direction","name_en","name_ko","win_rate","profit_factor","pf_capped","pf_clip","total_trades","timeframe","low_sample","research_status","status_scope","research_record","reason_url","criteria_version","measured_at","sample","rc"],"title":"RankingRow"},"RankingSample":{"properties":{"coins":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Coins","description":"Source-retained coins_used aggregation universe count. May include failed/skipped coins; not a count of successful simulations. Null when not retained."},"coins_scope":{"type":"string","enum":["aggregation_universe","not_retained"],"title":"Coins Scope"},"requested_coins":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Requested Coins","description":"Requested universe limit; distinct from the retained aggregation count."},"timeframe":{"type":"string","title":"Timeframe"},"period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period","description":"Retained period bucket; null for unlabelled legacy rows."},"start_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Start Date","description":"Recorded input start date, not inferred from publication time."},"end_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"End Date","description":"Recorded input end date."},"aggregation":{"type":"string","enum":["single_window","weekly_mean"],"title":"Aggregation","default":"single_window"}},"type":"object","required":["coins","coins_scope","requested_coins","timeframe","period"],"title":"RankingSample"},"RegimeMetrics":{"properties":{"trades":{"type":"integer","title":"Trades"},"win_rate":{"type":"number","title":"Win Rate"},"total_return":{"type":"number","title":"Total Return"},"profit_factor":{"type":"number","title":"Profit Factor"},"avg_pnl":{"type":"number","title":"Avg Pnl"}},"type":"object","required":["trades","win_rate","total_return","profit_factor","avg_pnl"],"title":"RegimeMetrics"},"RegimePerformance":{"properties":{"bull":{"$ref":"#/components/schemas/RegimeMetrics"},"bear":{"$ref":"#/components/schemas/RegimeMetrics"},"sideways":{"$ref":"#/components/schemas/RegimeMetrics"}},"type":"object","required":["bull","bear","sideways"],"title":"RegimePerformance"},"RegimeResponse":{"properties":{"regime":{"type":"string","title":"Regime"},"regime_label_en":{"type":"string","title":"Regime Label En"},"regime_label_ko":{"type":"string","title":"Regime Label Ko"},"fng_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fng Index"},"fng_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fng Label"},"description_en":{"type":"string","title":"Description En"},"description_ko":{"type":"string","title":"Description Ko"},"recommended":{"items":{"$ref":"#/components/schemas/RegimeStrategy"},"type":"array","title":"Recommended"},"generated":{"type":"string","title":"Generated"}},"type":"object","required":["regime","regime_label_en","regime_label_ko","description_en","description_ko","recommended","generated"],"title":"RegimeResponse"},"RegimeStrategy":{"properties":{"id":{"type":"string","title":"Id"},"name_en":{"type":"string","title":"Name En"},"name_ko":{"type":"string","title":"Name Ko"},"direction":{"type":"string","title":"Direction"},"timeframe":{"type":"string","title":"Timeframe"},"sl_pct":{"type":"number","title":"Sl Pct"},"tp_pct":{"type":"number","title":"Tp Pct"},"profit_factor":{"type":"number","title":"Profit Factor"},"win_rate":{"type":"number","title":"Win Rate","default":0.0},"max_drawdown_pct":{"type":"number","title":"Max Drawdown Pct","default":0.0},"trades":{"type":"integer","title":"Trades","default":0},"simulate_url_en":{"type":"string","title":"Simulate Url En"},"simulate_url_ko":{"type":"string","title":"Simulate Url Ko"}},"type":"object","required":["id","name_en","name_ko","direction","timeframe","sl_pct","tp_pct","profit_factor","simulate_url_en","simulate_url_ko"],"title":"RegimeStrategy"},"ReliabilityCheck":{"properties":{"axis_id":{"type":"string","enum":["trades","ruin","sample","leverage","diversification"],"title":"Axis Id"},"verdict":{"type":"string","enum":["pass","fail","not_evaluated"],"title":"Verdict"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Threshold"},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"}},"type":"object","required":["axis_id","verdict"],"title":"ReliabilityCheck","description":"신뢰 판정 **한 축의 레코드**. 판정은 여기 «데이터»로 산다.\n\n2026-08-31 온리원 토론: 판정 결과가 데이터가 아니라 **문장**으로 살아서\n① 통과·미평가가 응답에 **존재하지 않고**(실패만 join 하니 나머지는 `None`)\n② 프론트가 그 문자열을 `startsWith(\"Small sample\")` · `!includes(\" · \")` 로\n   **파싱**하고 ③ 화면에서 「전부 통과」·「필드 안 옴」·「이 경로에 컴포넌트\n없음」이 **한 픽셀**이 됐다. 세 결함의 공통 뿌리는 «판정의 표현»이다.\n\n`verdict` 가 **세 값**인 것이 이 모델의 핵심이다 — `not_evaluated` 가 없으면\n0거래 응답에서 나머지 4축이 «통과»로 읽힌다(실제로는 실행조차 안 된다)."},"ResearchDefinition":{"properties":{"rc":{"type":"integer","enum":[0,1,2],"title":"Rc"},"label":{"$ref":"#/components/schemas/LocalizedText"},"reason":{"$ref":"#/components/schemas/LocalizedText"}},"type":"object","required":["rc","label","reason"],"title":"ResearchDefinition"},"ScoreSessionRequest":{"properties":{"symbol":{"type":"string","maxLength":16,"minLength":5,"title":"Symbol"},"timeframe":{"type":"string","title":"Timeframe","default":"1H"},"trades":{"items":{"$ref":"#/components/schemas/ScoreTrade"},"type":"array","maxItems":500,"minItems":1,"title":"Trades"},"fee_pct_per_side":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Fee Pct Per Side","description":"% of notional per side (taker default)","default":0.05}},"type":"object","required":["symbol","trades"],"title":"ScoreSessionRequest"},"ScoreSessionResponse":{"properties":{"symbol":{"type":"string","title":"Symbol"},"timeframe":{"type":"string","title":"Timeframe"},"trades":{"type":"integer","title":"Trades"},"wins":{"type":"integer","title":"Wins"},"losses":{"type":"integer","title":"Losses"},"win_rate":{"type":"number","title":"Win Rate"},"profit_factor":{"type":"number","title":"Profit Factor"},"gross_profit_pct":{"type":"number","title":"Gross Profit Pct"},"gross_loss_pct":{"type":"number","title":"Gross Loss Pct"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"max_drawdown_pct":{"type":"number","title":"Max Drawdown Pct"},"avg_win_pct":{"type":"number","title":"Avg Win Pct"},"avg_loss_pct":{"type":"number","title":"Avg Loss Pct"},"per_trade_pct":{"items":{"type":"number"},"type":"array","title":"Per Trade Pct"},"convention":{"type":"string","title":"Convention"}},"type":"object","required":["symbol","timeframe","trades","wins","losses","win_rate","profit_factor","gross_profit_pct","gross_loss_pct","total_return_pct","max_drawdown_pct","avg_win_pct","avg_loss_pct","per_trade_pct","convention"],"title":"ScoreSessionResponse"},"ScoreTrade":{"properties":{"direction":{"type":"string","enum":["long","short"],"title":"Direction"},"entry_price":{"type":"number","exclusiveMinimum":0.0,"title":"Entry Price"},"exit_price":{"type":"number","exclusiveMinimum":0.0,"title":"Exit Price"},"entry_time":{"type":"integer","minimum":0.0,"title":"Entry Time","description":"Unix seconds"},"exit_time":{"type":"integer","minimum":0.0,"title":"Exit Time","description":"Unix seconds"}},"type":"object","required":["direction","entry_price","exit_price","entry_time","exit_time"],"title":"ScoreTrade","description":"리플레이에서 손으로 낸 거래 하나. 가격은 사용자가 본 봉의 종가(클라이언트가 채움)."},"SelectedFrame":{"properties":{"snapshot_id":{"type":"string","pattern":"^sha256:[0-9a-f]{64}$","title":"Snapshot Id"},"rows":{"type":"integer","minimum":0.0,"title":"Rows"},"columns":{"items":{"$ref":"#/components/schemas/FrameColumn"},"type":"array","title":"Columns"},"row_hash":{"type":"string","pattern":"^[0-9a-f]{64}$","title":"Row Hash"},"pandas_version":{"type":"string","title":"Pandas Version"},"period":{"$ref":"#/components/schemas/FramePeriod"},"symbol":{"type":"string","title":"Symbol"}},"type":"object","required":["snapshot_id","rows","columns","row_hash","pandas_version","period","symbol"],"title":"SelectedFrame"},"SimulationRequest":{"properties":{"record_provenance":{"type":"boolean","title":"Record Provenance","description":"Capture actual engine/input hashes for a fresh registry-strategy execution; bypass result cache, retain compute limits","default":false},"strategy":{"type":"string","title":"Strategy","description":"Strategy ID","default":"bb-squeeze"},"direction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Direction","description":"long | short | both (null = use strategy default)"},"sl_pct":{"type":"number","maximum":50.0,"minimum":1.0,"title":"Sl Pct","description":"Stop Loss %","default":10.0},"tp_pct":{"type":"number","maximum":50.0,"minimum":1.0,"title":"Tp Pct","description":"Take Profit %","default":8.0},"max_bars":{"type":"integer","maximum":168.0,"minimum":1.0,"title":"Max Bars","description":"Max holding period (bars)","default":48},"market_type":{"type":"string","enum":["futures","spot"],"title":"Market Type","description":"spot | futures","default":"futures"},"symbols":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Symbols","description":"Specific symbols (null = use top_n)"},"symbol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Symbol","description":"Single-symbol alias for `symbols`. Auto-mapped (prevents silent ignore of a singular field)."},"top_n":{"anyOf":[{"type":"integer","maximum":535.0,"minimum":1.0},{"type":"null"}],"title":"Top N","description":"Number of coins (null = top 50)"},"include_stablecoins":{"type":"boolean","title":"Include Stablecoins","description":"Include stablecoins (USDC, DAI…) in the top_n universe. Default false — ~0 volatility → empty backtests. Ignored when `symbols` is set (explicit picks always honored).","default":false},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date","description":"Backtest start date (YYYY-MM-DD)"},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Date","description":"Backtest end date (YYYY-MM-DD)"},"cutoff_utc":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Cutoff Utc","description":"Only candles closed by this UTC instant; null = current closed hour. Does not freeze historical source revisions."},"timeframe":{"type":"string","enum":["1H","2H","4H","6H","12H","1D","1W"],"title":"Timeframe","description":"Candle timeframe: 1H, 2H, 4H, 6H, 12H, 1D, 1W","default":"1H"},"compounding":{"type":"boolean","title":"Compounding","description":"True = reinvest profits (compound), False = fixed position size (simple)","default":false},"avoid_hours":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Avoid Hours","description":"UTC hours to avoid entering trades (0-23). null = use strategy default"},"avoid_months":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Avoid Months","description":"Months to avoid entering trades (1-12). null = no month filter"},"min_vol_regime":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Vol Regime","description":"Minimum ATR ratio (current ATR / 14-period ATR MA) to allow entry. e.g., 0.7 = skip low-volatility periods. null = no filter"},"btc_trend_filter":{"type":"boolean","title":"Btc Trend Filter","description":"If true, only allow LONG entries when BTC is above its 50-period SMA. Improves LONG edge in bull regimes.","default":false},"fee_pct":{"anyOf":[{"type":"number","maximum":0.01,"minimum":0.0},{"type":"null"}],"title":"Fee Pct","description":"Fee per side (0.0005 = 0.05%). None = use market_type default"},"leverage":{"type":"number","maximum":125.0,"minimum":1.0,"title":"Leverage","description":"Leverage multiplier for PnL calculation","default":1.0}},"additionalProperties":false,"type":"object","title":"SimulationRequest","description":"시뮬레이션 요청\n\n`extra=\"forbid\"` — 모르는 필드는 **거부**한다(2026-09-20, Q-B97).\n\n왜: 이 파일에 `extra` 선언이 한 줄도 없어서 Pydantic v2 기본값 `ignore` 가\n적용돼 있었다. 그래서 `{\"params\": {...}}` 처럼 한 겹 감싸 보내면 **전 필드가\n기본값으로 떨어지고 HTTP 200 에 전혀 다른 답**이 나갔다(실측 27배 차이).\n호출자는 자기 입력이 버려진 걸 알 길이 없다 — 오답이 성공처럼 보인다.\n사람에게도 나쁘지만 **에이전트에게 특히 나쁘다**: 사람은 화면 숫자가 이상하면\n멈추지만, 프로그램은 200 을 받으면 그대로 인용한다.\n\n회귀 위험은 켜기 전에 실측했다 — `/simulate` 를 부르는 프론트 4곳의 전송 키\n합집합 13개가 **전부 이 모델의 필드**다(모델에만 있는 8개는 무관):\n  SimulatorPage(자동실행) 13 · StrategyDemo 5 · TrustGapPanel 9 · simRequest 10\n빌더의 커스텀 전략 본문(`...customSnapshot`)은 이 엔드포인트가 아니라\n`/backtest` 로 간다 — 그쪽 모델은 이 변경의 범위가 아니다."},"SimulationResponse":{"properties":{"provenance":{"anyOf":[{"$ref":"#/components/schemas/ExecutionProvenance"},{"type":"null"}]},"strategy":{"type":"string","title":"Strategy"},"direction":{"type":"string","title":"Direction"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"market_type":{"type":"string","title":"Market Type"},"total_trades":{"type":"integer","title":"Total Trades"},"wins":{"type":"integer","title":"Wins"},"losses":{"type":"integer","title":"Losses"},"win_rate":{"type":"number","title":"Win Rate"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"profit_factor":{"type":"number","title":"Profit Factor"},"avg_win_pct":{"type":"number","title":"Avg Win Pct"},"avg_loss_pct":{"type":"number","title":"Avg Loss Pct"},"max_drawdown_pct":{"type":"number","title":"Max Drawdown Pct"},"max_consecutive_losses":{"type":"integer","title":"Max Consecutive Losses"},"total_fees_pct":{"type":"number","title":"Total Fees Pct"},"profit_factor_ci":{"anyOf":[{"$ref":"#/components/schemas/MetricCI"},{"type":"null"}]},"sharpe_ci":{"anyOf":[{"$ref":"#/components/schemas/MetricCI"},{"type":"null"}]},"sharpe_window_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Sharpe Window Days"},"sharpe_annualized_below_one_year":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Sharpe Annualized Below One Year"},"mc_p_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mc P Value"},"mc_percentile":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mc Percentile"},"total_funding_pct":{"type":"number","title":"Total Funding Pct","default":0.0},"funding_uncovered":{"items":{"type":"string"},"type":"array","title":"Funding Uncovered","default":[]},"funding_missing":{"items":{"type":"string"},"type":"array","title":"Funding Missing","default":[]},"tp_count":{"type":"integer","title":"Tp Count"},"sl_count":{"type":"integer","title":"Sl Count"},"timeout_count":{"type":"integer","title":"Timeout Count"},"sharpe_ratio":{"type":"number","title":"Sharpe Ratio","default":0.0},"sortino_ratio":{"type":"number","title":"Sortino Ratio","default":0.0},"calmar_ratio":{"type":"number","title":"Calmar Ratio","default":0.0},"coins_used":{"type":"integer","title":"Coins Used"},"top_n_requested":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top N Requested","description":"The top_n this run resolved to. null for explicit symbols= requests (no top-N universe)."},"eligible_universe":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Eligible Universe","description":"Coins eligible for a top-N universe at run time (stablecoins unless include_stablecoins, non-crypto and liquidity-dead markets excluded), read in the same selection as the coins run. null for symbols= requests (and on /backtest when the strategy is invalid, is_valid=false)."},"universe_capped":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Universe Capped","description":"eligible_universe < top_n_requested: the request asked for more coins than exist, so the whole eligible universe ran. A cap only — coins lacking data are reported in coins_missing_data. null for symbols= requests."},"coins_missing_data":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Coins Missing Data","description":"min(top_n_requested, eligible_universe) - (selected coins with at least one candle inside start_date..end_date). Counts selected coins with no complete candle up to the cutoff AND coins whose candles all fall outside the requested window (those stay in coins_used, so this can exceed min(top_n_requested, eligible_universe) - coins_used). null for symbols= requests."},"data_range":{"type":"string","title":"Data Range"},"equity_curve":{"items":{"$ref":"#/components/schemas/EquityPoint"},"type":"array","title":"Equity Curve"},"btc_hold_return_pct":{"type":"number","title":"Btc Hold Return Pct","default":0.0},"btc_hold_curve":{"items":{"$ref":"#/components/schemas/EquityPoint"},"type":"array","title":"Btc Hold Curve","default":[]},"coin_results":{"items":{"$ref":"#/components/schemas/CoinResult"},"type":"array","title":"Coin Results","default":[]},"yearly_stats":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Yearly Stats","default":[]},"rolling_sharpe":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Rolling Sharpe","default":[]},"best_trade_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Best Trade Pct"},"worst_trade_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Worst Trade Pct"},"exposure_time_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Exposure Time Pct"},"direction_breakdown":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Direction Breakdown"},"monthly_stats":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Monthly Stats","default":[]},"start_sensitivity":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Start Sensitivity","default":[]},"regime_performance":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Regime Performance"},"trades":{"items":{"$ref":"#/components/schemas/TradeItem"},"type":"array","title":"Trades","default":[]},"trades_total":{"type":"integer","title":"Trades Total","default":0},"trades_truncated":{"type":"integer","title":"Trades Truncated","default":0},"ruin_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ruin Index"},"reliability_checks":{"items":{"$ref":"#/components/schemas/ReliabilityCheck"},"type":"array","title":"Reliability Checks","description":"축별 판정 레코드 — 이 응답의 «판정 SSoT». reliability_warning 은 파생물.\n\n⚠ `verdict` 는 세 값이다. `not_evaluated` 를 «통과»로 세면 0거래 응답이\n「4개 축 통과」로 읽힌다 — 그 축들은 실행조차 안 됐다.","readOnly":true},"reliability_warning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reliability Warning","description":"계약은 build_reliability_warning 한 곳이 소유한다(룰3).","readOnly":true}},"type":"object","required":["strategy","direction","params","market_type","total_trades","wins","losses","win_rate","total_return_pct","profit_factor","avg_win_pct","avg_loss_pct","max_drawdown_pct","max_consecutive_losses","total_fees_pct","tp_count","sl_count","timeout_count","coins_used","data_range","equity_curve","reliability_checks","reliability_warning"],"title":"SimulationResponse","description":"시뮬레이션 결과"},"StrategyInfo":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"default_params":{"additionalProperties":true,"type":"object","title":"Default Params"},"verdict3":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verdict3"}},"type":"object","required":["id","name","description","default_params"],"title":"StrategyInfo"},"StrategyResult":{"properties":{"strategy_id":{"type":"string","title":"Strategy Id"},"name":{"type":"string","title":"Name"},"direction":{"type":"string","title":"Direction"},"status":{"type":"string","title":"Status"},"total_trades":{"type":"integer","title":"Total Trades"},"wins":{"type":"integer","title":"Wins"},"losses":{"type":"integer","title":"Losses"},"win_rate":{"type":"number","title":"Win Rate"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"profit_factor":{"type":"number","title":"Profit Factor"},"max_drawdown_pct":{"type":"number","title":"Max Drawdown Pct"},"tp_count":{"type":"integer","title":"Tp Count"},"sl_count":{"type":"integer","title":"Sl Count"},"timeout_count":{"type":"integer","title":"Timeout Count"},"equity_curve":{"items":{"$ref":"#/components/schemas/EquityPoint"},"type":"array","title":"Equity Curve"}},"type":"object","required":["strategy_id","name","direction","status","total_trades","wins","losses","win_rate","total_return_pct","profit_factor","max_drawdown_pct","tp_count","sl_count","timeout_count","equity_curve"],"title":"StrategyResult","description":"Result for a single strategy in comparison."},"SubscribeRequest":{"properties":{"email":{"type":"string","maxLength":254,"title":"Email"},"lang":{"type":"string","title":"Lang","default":"en"}},"type":"object","required":["email"],"title":"SubscribeRequest","description":"Email subscription request."},"TradeDetail":{"properties":{"direction":{"type":"string","enum":["long","short"],"title":"Direction"},"entry_time":{"type":"integer","title":"Entry Time"},"entry_price":{"type":"number","title":"Entry Price"},"exit_time":{"type":"integer","title":"Exit Time"},"exit_price":{"type":"number","title":"Exit Price"},"pnl_pct":{"type":"number","title":"Pnl Pct"},"exit_reason":{"type":"string","title":"Exit Reason"},"bars_held":{"type":"integer","title":"Bars Held"},"mfe_pct":{"type":"number","title":"Mfe Pct","default":0.0},"mae_pct":{"type":"number","title":"Mae Pct","default":0.0}},"type":"object","required":["direction","entry_time","entry_price","exit_time","exit_price","pnl_pct","exit_reason","bars_held"],"title":"TradeDetail"},"TradeItem":{"properties":{"symbol":{"type":"string","title":"Symbol"},"direction":{"type":"string","title":"Direction"},"entry_time":{"type":"string","title":"Entry Time"},"exit_time":{"type":"string","title":"Exit Time"},"entry_price":{"type":"number","title":"Entry Price","default":0.0},"exit_price":{"type":"number","title":"Exit Price","default":0.0},"pnl_pct":{"type":"number","title":"Pnl Pct"},"pnl_usd":{"type":"number","title":"Pnl Usd","default":0.0},"exit_reason":{"type":"string","title":"Exit Reason"},"bars_held":{"type":"integer","title":"Bars Held"},"mfe_pct":{"type":"number","title":"Mfe Pct","default":0.0},"mae_pct":{"type":"number","title":"Mae Pct","default":0.0}},"type":"object","required":["symbol","direction","entry_time","exit_time","pnl_pct","exit_reason","bars_held"],"title":"TradeItem"},"ValidateRequest":{"properties":{"record_provenance":{"type":"boolean","title":"Record Provenance","description":"Capture actual engine/input hashes for a fresh registry-strategy execution; bypass result cache, retain compute limits","default":false},"strategy":{"type":"string","title":"Strategy","description":"Strategy ID (ignored when `entry` is provided — custom-conditions mode)","default":"bb-squeeze"},"direction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Direction"},"sl_pct":{"type":"number","maximum":50.0,"minimum":1.0,"title":"Sl Pct","default":10.0},"tp_pct":{"type":"number","maximum":50.0,"minimum":1.0,"title":"Tp Pct","default":8.0},"max_bars":{"type":"integer","maximum":168.0,"minimum":1.0,"title":"Max Bars","default":48},"market_type":{"type":"string","enum":["futures","spot"],"title":"Market Type","default":"futures"},"top_n":{"anyOf":[{"type":"integer","maximum":535.0,"minimum":1.0},{"type":"null"}],"title":"Top N","description":"Number of coins (null = top 50)"},"symbols":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Symbols"},"oos_pct":{"type":"number","maximum":50.0,"minimum":10.0,"title":"Oos Pct","description":"OOS split %","default":30.0},"mc_runs":{"type":"integer","maximum":5000.0,"minimum":100.0,"title":"Mc Runs","description":"Monte Carlo runs","default":1000},"start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start Date","description":"Backtest start date (YYYY-MM-DD)"},"end_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End Date","description":"Backtest end date (YYYY-MM-DD)"},"timeframe":{"type":"string","enum":["1H","2H","4H","6H","12H","1D","1W"],"title":"Timeframe","description":"Candle timeframe: 1H, 2H, 4H, 6H, 12H, 1D, 1W","default":"1H"},"avoid_hours":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Avoid Hours","description":"UTC hours to avoid entering trades (0-23). null = use strategy default"},"avoid_months":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Avoid Months","description":"Months to avoid entering trades (1-12). null = no month filter"},"min_vol_regime":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Min Vol Regime","description":"Minimum ATR ratio (current ATR / 14-period ATR MA) to allow entry. e.g., 0.7 = skip low-volatility periods. null = no filter"},"name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Name","description":"Custom strategy display name (custom-conditions mode only)"},"indicators":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Indicators","description":"Indicator configs for custom-conditions mode: {'bb': {'period': 20}, 'ema': {}, ...}"},"entry":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Entry","description":"Entry conditions tree: {'type': 'AND', 'conditions': [...]}. Presence switches validation to custom-conditions mode (strategy field ignored)."},"exit_conditions":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Exit Conditions","description":"Optional exit-signal conditions tree (custom-conditions mode only), same shape as entry."},"tp_source":{"type":"string","enum":["custom_pct","trailing"],"title":"Tp Source","description":"Exit mode (custom-conditions mode only): custom_pct = fixed TP/SL; trailing = trailing stop (tp_pct is the trail distance)","default":"custom_pct"},"trailing_pct":{"anyOf":[{"type":"number","maximum":50.0,"minimum":0.5},{"type":"null"}],"title":"Trailing Pct","description":"Trailing stop distance % (custom-conditions mode only). If null and tp_source=trailing, uses tp_pct."}},"type":"object","title":"ValidateRequest","description":"OOS validation + Monte Carlo request."},"ValidateResponse":{"properties":{"provenance":{"anyOf":[{"$ref":"#/components/schemas/ExecutionProvenance"},{"type":"null"}]},"strategy":{"type":"string","title":"Strategy"},"direction":{"type":"string","title":"Direction"},"coins_used":{"type":"integer","title":"Coins Used"},"top_n_requested":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Top N Requested","description":"The top_n this run resolved to. null for explicit symbols= requests (no top-N universe)."},"eligible_universe":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Eligible Universe","description":"Coins eligible for a top-N universe at run time (stablecoins unless include_stablecoins, non-crypto and liquidity-dead markets excluded), read in the same selection as the coins run. null for symbols= requests (and on /backtest when the strategy is invalid, is_valid=false)."},"universe_capped":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Universe Capped","description":"eligible_universe < top_n_requested: the request asked for more coins than exist, so the whole eligible universe ran. A cap only — coins lacking data are reported in coins_missing_data. null for symbols= requests."},"run_cap":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Run Cap","description":"Q-B131: the per-request limit that actually stopped this run before min(top_n_requested, eligible_universe) coins, or null when none did (coins_used then reaches that number, data gaps aside). See run_cap_reason for which limit."},"run_cap_reason":{"anyOf":[{"type":"string","enum":["indicator_cache","compare_max_coins"]},{"type":"null"}],"title":"Run Cap Reason","description":"Q-B131: which limit run_cap is. «indicator_cache»: the cached path of /simulate/compare, /simulate/validate and /simulate/optimize computes at most the indicator-cache size per request (no all-coin hold; larger runs are a separate async path, Q-B132). «compare_max_coins»: kept for compatibility — since Q-B55 /simulate/compare rejects a top_n above its limit (COMPARE_MAX_COINS) with HTTP 400, so this cut no longer binds. When both apply, the smaller one — the one that bound — is reported. null when no limit bound."},"coins_not_computed":{"items":{"type":"string"},"type":"array","title":"Coins Not Computed","description":"Q-B131: explicitly requested symbols= that were not run because the per-request compute limit (the indicator-cache size) was reached. Empty when every requested symbol ran. Distinct from coins_missing_data (coins without candles in the window)."},"data_range":{"type":"string","title":"Data Range"},"oos_pct":{"type":"number","title":"Oos Pct"},"oos":{"$ref":"#/components/schemas/OOSResult"},"monte_carlo":{"$ref":"#/components/schemas/MonteCarloResult"}},"type":"object","required":["strategy","direction","coins_used","data_range","oos_pct","oos","monte_carlo"],"title":"ValidateResponse","description":"OOS validation + Monte Carlo response."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifiedInRanking":{"properties":{"configuration_id":{"type":"string","title":"Configuration Id"},"rank":{"type":"integer","title":"Rank"},"profit_factor":{"type":"number","title":"Profit Factor"},"pf_capped":{"type":"boolean","title":"Pf Capped"}},"type":"object","required":["configuration_id","rank","profit_factor","pf_capped"],"title":"VerifiedInRanking"},"YearlyStat":{"properties":{"year":{"type":"integer","title":"Year"},"trades":{"type":"integer","title":"Trades"},"wins":{"type":"integer","title":"Wins"},"win_rate":{"type":"number","title":"Win Rate"},"total_return_pct":{"type":"number","title":"Total Return Pct"},"profit_factor":{"type":"number","title":"Profit Factor"}},"type":"object","required":["year","trades","wins","win_rate","total_return_pct","profit_factor"],"title":"YearlyStat","description":"Per-year performance breakdown."}}}}