qkt — backlog¶
Single source of truth for what's done, in progress, and queued. Update the status marker (done, progress, tbd) as items move.
Status legend:
- done — shipped and merged
- progress — actively in flight (spec/plan/branch in progress, or partial implementation merged)
- tbd — queued, not started
- dropped — closed without building (not planned); kept for the record
Issue tracking. Every open item is mirrored as a GitHub issue, linked at the end of its line. The working flow: find a bug or pick up an item → the issue holds the problem statement and proposed solution → solve it → close the issue. This file stays the tiered roadmap; issues are the per-item tracker. When an item ships, flip its marker to done here and close its issue.
Done¶
done— Phase 1: core engine MVP (tick → strategy → signal → order → broker → trade)done— Phase 2: event bus, candle aggregator, multi-strategy support, SLF4Jdone— Phase 3: risk engine, position tracking, P&L, BigDecimal for pricesdone— Phase 4: deterministic backtest replaydone— Phase 5: internal Kotlin DSL, then external SQL-like parserdone— Phase 6: on-disk content-addressable data store, Dukascopy auto-fetch, BYO CSVdone— Phase 7c: TradingView live vendor (anonymous, free-tier) for paper tradingdone— Phase 7e–7h: Bybit Spot + Linear (USDT) live trading with reconciliation, rate limiting, connection resiliencedone— Phase 8: per-strategy P&L attributiondone— Phase 9: risk engine — equity tracking, DD halts, daily loss halts, halt-as-state with operator-driven resumedone— Phase 10: backtest reporting — equity curves, Sharpe, Calmar, profit factor, win/loss statsdone— Phase 10b: parameter sweep harness with sequential or fixed-pool parallel executiondone— Phase 10c: walk-forward analysisdone— Phase 11: DSL master design and parser maturitydone— Phase 11a: OSS baselinedone— Phase 12a: CLI surfacedone— Phase 12b: observability (status/logs/metrics endpoints)done— Phase 12c: daemon (deploy/list/status/stop)done— Phase 13a: STACK pyramiding (one BUY/SELL → N price-triggered entries with optional time fence)done— Phase 13b: CANCEL/CANCEL_ALL action + PORTFOLIO file format with regime-gated child activationdone— Phase 14: portfolio v2 daemon fan-out — per-child LiveSession + ports + logs + PnL;qkt startverb; cascade stopdone— Phase 15: DSLLOGactiondone— Phase 16: backtest fidelity + HTML reportdone— Phase 17: MT5 broker via mt5-gatewaydone— Phase 18: LiveSession typed-broker dispatchdone— Phase 19: pre-live confidence pack — parity test, audit-ticks, logging guide, memory leak auditdone— Phase 20: top-level QUICKSTART + docker-compose stackdone— Phase 21: documentation site — MkDocs Material, Mermaid, Dokka, GitHub Pagesdone— Phase 22: KDoc the public API — every Tier 1 type, style guide, SKILL rule for future workdone— Phase 23: DSL catalog expansion — register SMA/WMA/MACD/Bollinger, add HIGHEST/LOWEST, position dot accessors,#commentsdone— Phase 24: risk-sizing primitives —SIZING N PCT RISK,WARMUP N BARS,IS NULL/IS NOT NULL,FLATTENDSL action (#52)done— Phase 25: operator tooling —qkt fetchCLI,TRAILING_STOPwiring,per_strategy:risk config block, VWAP DSL registration (#53)
Immediate (blocks going live with real money)¶
2026-07-02 backtest/live parity audit¶
Full-code parity audit (7 pillars, findings verified against source before filing). P0 = live-money correctness; P2/P3 = backtest-side parity and research-tier fidelity.
done— Live DSL warmup credits the gate but leaves every indicator/DSL state cold (#614)done— Live fill events book unquantized/partial quantity (#615)done— Live engine-initiated closes are commission/swap-blind (#616)done— Armed-trail orphaned after venue-side close on attached brackets (#617)done— Plain-bracket armed-trail close has no ticket → counter position on hedging (#618)done— RESIZE live semantics: netting shrink, stale qty, no min-lot deadband (#619)done— Book-risk layer never wired live (#620)done— MT5 time_msc convention contradiction across feed/broker/warmup (#621)done— Live CompositeBroker silently paper-fills unrouted symbols (#622)done— Session/day-latching indicators latch partial windows at deploy (#623)done— tick-fills classifier mid-based vs side-aware triggers (#624)done— Backtest brokers fill orders cancelled in the same pass (#625)done— Halt kill-switch live-only; backtest fills post-halt (#626)done— Portfolio backtest ≠ live: capital/gates/topology/caps (#627)done— Portfolio backtest silently ignores --bars flags, skips validation (#628)done— sweep --scenarios downgrades --bars --tick-fills silently (#629)done— --bars tier has no completeness validation (#630)done— Live warmup bars bid-based vs backtest mid (#631)done— Bar-close rules read NOW at flush time (#632)done— SCHEDULE over gaps: per-occurrence live vs coalesced backtest (#633)done— Heartbeat early bar close duplicates windows (#634)done— Sim StopLimit instant-fill + slippage on limit fills (#635)done— GTD deadline==touch tie: fill vs cancel by mode (#636)done— fireFallbackTrigger submits after refused transition (#637)done— Stops-level halves + freeze-level unmodeled (#638) — freeze-level stays live-only, catalogued residualdone— Crossed stored tick crashes backtests forever (#639)done— Volume feed inert: fetcher writes empty volume (#640)done— Non-dukascopy symbols: no validation, silent empty feeds (#641)done— tick-fills contract unproven for latency/mixed-tf (#642) — latency/mixed-tf now rejected; synthetic-marks residual catalogueddone— --bars gap-through stops filled at level not gap (#643)done— Restart recovery double-books executions already in the leg book (#1096) — position-ledger stage Bdone— Persisted leg books keep legs for positions the venue already closed (#1097) — consequence of #1096; periodic venue-vs-book reconcile in stage Cdone— Straddle whipsaw: sibling cancel drops leg B's open intent so its fill nets (#1098) — position-ledger stage Btbd— StartupPositionReconciledcarries an unprefixed symbol so the venue correction never matches a book (#1103) — position-ledger follow-updone—POSITION.<stream>.mfe/maestay 0 on hedging venues: no PRIMARY leg to track (#1152) — 2026-09-15 position matrix on Exness demodone— Unrealized P&L marked at mid, half a spread optimistic per leg (#1153) — 2026-09-15 position matrixdone— Opposite-side entry on a hedging venue nets to 0 in qkt while the venue holds both tickets (#1154) — 2026-09-15 position matrixdone— PlainORD-Nids collide across strategies under one magic; resolver misattributes fills (#1155) — 2026-09-15 position matrixdone—daemon stoplets later sessions keep trading while earlier ones drain (#1157) — 2026-09-15 position matrix round 2done—POSITION.mfe/maestay 0 after a daemon restart over an open position (#1158) — 2026-09-15 position matrix round 3tbd— Model swap in backtest cost model (#644)tbd— Cross-mode parity test program epic (#645)
2026-07-02 performance audit¶
Hot-path audit per the hedge-fund checklist (allocation-minimal, lock-free, no blocking I/O on the engine thread). All proposed fixes are byte-identical restructuring; measured dead-ends (symbol→int, query-time columnar, setScale removal) were excluded up front.
done— Live persistence defaults to sync DSYNC: ~7 fsyncs per fill on engine thread (#646)done— MT5 close/cancel/modify are sync HTTP on engine thread (#647)done— OrderJournal per-event open+DSYNC+close, submit written twice (#648)done— Per-tick equity recompute: map copies, FX churn, 4x duplicate work (#649)done— epochDay java.time chain allocated every tick (#650)done— Hot-path allocation batch: broker filter, empty-loop iterators, merge feed (#651)done— DSL eval batch: value() recompute per read, duplicate instances, boxing (#652)done— Serial symbol polling staleness + unbounded trades list (#653)-
done— PortfolioStrategy dead code with per-tick alloc landmines (#654) -
done— DSLLOGaction with levels, placeholders, structured fields; stdout[strategy]prefix; child file slash-safe names (see phase 15) done— Backtest fidelity audit: equity curve, DD-days, Monte Carlo, per-trade risk in HTML report (slippage/spread/regime deferred) (see phase 16)done— Backtest vs live execution parity: identical trades (orderId/symbol/side/qty/price/timestamp) between Backtest and LiveSession given same compiled strategy and tick sequence (src/test/kotlin/com/qkt/parity/BacktestLiveParityTest.kt)done— Backtest report HTML output: single self-containedreport.html(see phase 16)progress— Tick-feed accuracy audit:qkt audit-ticksframework shipped (TV vs MT5 drift); operator-driven runs against live feeds (see phase 19) (#54)done— End-to-end portfolio daemon test (deferred from Phase 14 — seedocs/phases/phase-14.mdknown limitations) (#55)done— Pristine test sweep + memory leak audit: code-review audit complete, two leaks fixed (Observability executor, OrderManager risk map); CandleHub.unregister and Broker.shutdown lifecycle now both clean. (see phase 19) (#56)done— Documentation MVP: MkDocs Material site with Diátaxis IA, Mermaid diagrams, Dokka API reference, GitHub Pages deploy via Actions (see phase 21)
Sequence-after-immediate (still pre-live, days not weeks)¶
done— MT5 broker (multi-profile via mt5-gateway) + LiveSession typed-broker dispatch (see phase 17, phase 18)done— Standardized logging guide: MDC keys documented, console + file patterns specified, conventions for strategy authors + engine contributors (see docs/logging.md)progress— Packaging and one-shot install: full docker-compose stack (qkt + mt5-gateway) shipped (Phase 20); single-binary install pending (#57)done— CI/CD: docs build + GitHub Pages deploy shipped (Phase 21); build/test/ktlint CI green viacheck.yml; release-artifact CI shipped viarelease.yml—distTarattached to the GitHub release on eachv*tag (scripts/install.shconsumes it). (#58)done— Tier 2 KDoc backfill — backtest reporting types, risk types, portfolio supervisor, indicator catalog. Phase 22 covered Tier 1; Tier 2 shipped across #191/#192/#193/#194 with the indicator-catalog block rewritten for the new accessibility rule in CLAUDE.md. (#59)
Performance and hardening (post-go-live)¶
tbd— Speed and latency improvements (profiling-driven) (#60)tbd— Memory and GC tuning (#61)tbd— Virtual threads where applicable (#62)tbd— GraalVM native image for the CLI (#63)tbd— JNI for hot paths if profiles show wins (#64)tbd— Stress tests, soak tests, chaos tests (#65)tbd— Bundle/binary size reduction (#66)
Future¶
tbd— News pipeline: Twitter, Yahoo, economic calendar, per-symbol curation; integrates into DSL (#67)tbd— AI strategy-tuning pipeline: train on a strategy, derive best configs, agent layer for buy/sell decisions, continuous retraining (#68)progress— Portfolio v3 (#69):WEIGHTcapital allocation shipped (#224); import-time overrides split to #223; nested-portfolio allocation deferred (blocked byPortfolioLoaderrejecting nesting)dropped— Symbol watch dynamic extension: closed as not-planned (#70) — no concrete need, and the "arbitrary new symbol at runtime" framing fights backtest=live determinism. If revived, the tractable path is lazy activation of a known universe (see the issue's closing note).done— Editor tooling for.qktfiles — parser/AST/linter, syntax highlighting, language server, VSCode + Neovim extensions. Shipped under epic #71 with children #82–#86.done— Landing page — shipped via mkdocs hero section on the documentation site. (#72)
Post-v0.28 backlog — ranked easy → hard¶
Captured 2026-05-17 during the prod-readiness audit. The current focus is getting hedge-straddle running cleanly on Dokploy in demo, then real money. Everything below is either supportive of that focus or queued for after.
Tier 0 — current focus¶
progress— Observe hedge-straddle on prod for 1 week before flipping the broker login from demo to real. Items needed to call this complete:- 19:55 UTC verification fires correctly (Phase 30 contractSize math + v0.26.6 OCO fix proven under live conditions).
- 1 week of placement windows complete without engine-side errors.
- Daily PnL roughly matches manually-computed expectation.
- (#33)
progress— Gateway-sideBUY_STOP price must be above current askrejection on hedge-straddle: diagnostic logs landed in #200 (submit-time INFO with computed prices +priceTracker.lastPrice). Waiting on 1–2 prod rejections to confirm stale-quote hypothesis; fix path (wider offsets vs re-quote at submission) decides on the evidence. (#185)progress— Production-readiness umbrella ties together the deploy/observability/risk loose ends needed before flipping to real money. Parent meta-issue, no direct work item. (#142)
Tier 1 — staged work¶
Both items below have shipped.
-
done— Gate Bybit market-source routes onBYBIT_API_KEYenv presence so pure-MT5 deployments don't construct two idleOkHttpClientinstances at boot.MarketSourceFactory.compositegained anenableBybitflag defaulting to theBYBIT_API_KEYenv check. Shipped in v0.28.3 (commit6591d7e, mergedd7a815). (#34) Superseded by the connector contracts (2026-09-18): Bybit routes now come fromtype: bybitaccount entries inbrokers:, never from the environment alone. Superseded again (2026-10): the in-process Bybit connector is gone; Bybit routes come fromtype: gatewayentries on a qkt-venue-gateway running its Bybit adapter. -
done— v0.28.6:MT5StateRecoverynow correlates venue-side orphan positions back to the owning strategy via comment-prefix match and seedspositionMetaByTicketso a server-side close firesOrderFilledwith the correctstrategyId. MT5 truncates comments to 16 chars, so the matcher tolerates truncation (AmbiguousTruncation→ seed + WARN) and rejects prefix-overlap collisions (AmbiguousOverlap→ skip + WARN). Constraint: strategies sharing one MT5 magic must be prefix-disjoint.
Tier 2 — operational / config (small, no engine code)¶
done— Wire Telegram alerts in qkt-prod. Needed three pieces, not just env vars: theTELEGRAM_*passthrough in qkt-prodcompose.yml, the env values (postgres +.env), and engine fix #89 wiring the daemon notifier intoLiveSession. Shipped in v0.28.9;strategy_startedalerts confirmed delivered. (#35)done— Docker daemon json-file log rotation for the qkt service inqkt-prodcompose.yml(logging.driver: json-filewithmax-size+max-file). Separate from logback's bind-mount rotation (already done in v0.28.1). (#36)done— Backup story forqkt-prod/state/. Documented indocs/operations/state-backup.md: back up the whole state directory hourly, off-host, retaining ~2 days of snapshots. (#37)
Tier 3 — Phase 31.1 (telegram alerts completion, hours)¶
Items I deferred when shipping Phase 31. Documented in
docs/phases/phase-31-telegram-alerts.md under
"Known limitations".
done— WireBrokerEvent.OrderRejectedto the notifier viaOrderManager(orderDetailsFor) so the alert names symbol/side/quantity. (#38)done— FireNotificationEvent.DaemonStartedfromDaemonCommandat daemon boot.NotifierFactory.fromConfigbuilds the daemon notifier; the event fires whendaemon_startedis opted in. (#39)done— Strategy-error alerts:DaemonCommandfiresNotificationEvent.StrategyErrorwhen a--load-dirauto-deploy fails to parse/compile/start. (#40)done— Daily-rolling tracker forequityDeltaPct,tradesToday,haltsToday—DailyRollingTrackerfeeds the daily summary real numbers instead of placeholder zeros. (#41)done— Consolidate to oneDailySummarySchedulerper daemon instead of one perLiveSession, so multi-strategy operators get one summary message at the UTC tick instead of N. (#42)
Tier 4 — Single-phase engine work (~1-3 days each)¶
Ranked by leverage for FX/commodities quant research, highest first.
-
done— walkforward--json+ null-sharpe sentinel fix — machine-readable walk-forward output for downstream tooling (qkt-forge G4); null scores print asnull.--jsonfold rows now carrytestTotalPnL,testMaxDrawdown,testTrades;--report-dirwrites the full per-fold bundle. (#417) -
done— Phase 32 — bid/ask DSL exposure.bid/askcarried ontoCandle,<stream>.bid/.ask/.spreadexposed to the DSL and the KotlinStreamRef. Merged3a17386. See phase 32. done— Phase 33 —MT5BrokerSimulatorfor backtest fidelity. Closes the 5 remaining backtest-vs-live divergences documented indocs/parity/backtest-vs-live.md(rows 1, 2, 3, 4-6). Turns "backtest result is directional only" into "backtest matches live within spread/slippage budget". (#43)tbd— Phase 34 — second-broker proof of life. Add a second MT5 profile (e.g. ICMARKETS) to qkt-prod, deploy a trivial no-op strategy on it, observe both run on the same daemon. Proves multi-broker routing in production. Engine code already supports; this is mostly config + ops. (#44)done— Phase 35 — bar-level synchronized publish for paired symbols.SYNCHRONIZEDSL clause inSYMBOLSdeclares N-member sync groups;CandleHubatomic-fires when every member closes the same window;AstCompiler.bindToHubruns a two-pass evaluate so cross-stream indicators are also same-window. Shipped across #195/#196/#197/#198/#199. See phase 35. (#45)done— OCO restart-linkage gap.OrderManager.siblingsrehydrated duringMT5StateRecoveryso a leg rejected across a restart boundary unwinds its sibling instead of leaving a one-legged straddle. (#46)done—MT5Broker.submitCompositenon-atomicity. Half-placed-OCO bug closed insubmitCompositeto match the fix insubmitOco. (#47)
Tier 5 — Hedge-straddle parity gaps (Phase 36+, ~1 day each)¶
Strategy-side gaps documented in the strategy header. Each is a DSL/engine primitive addition. None block deploy — they keep hedge-straddle from being bit-identical to pa-quant.
done— Phase 36 — armed trailing stop (STOP LOSS TRAILING <distance> AFTER MFE >= <threshold>). Closes hedge-straddle GAP 1. Live on prod inhedge-straddle.qktv2. See phase 36. (#48)done— Phase 37 — proportional stack sizing (STACK_AT SIZING <expr>instead of literal). Closes GAP 2 — stacks scale with the main leg's hour-varying size. See phase 37. (#49)done— Phase 38 — GTD time-in-force for pending orders. Closes GAP 5 — the:10sweep rule workaround removed. See phase 38. (#50)done— Phase 39 —INSTRUMENT_METADSL accessor.gold.tick_size,gold.contract_size, etc. exposed for portable strategies. See phase 39. (#51)
Tier 6 — Asset-class expansion (multi-phase)¶
tbd— Crypto exercised end-to-end on Bybit. Bybit is reached through the qkt-venue-gateway's Bybit adapter (type: gateway). Never run in qkt-prod. First Bybit strategy will find latent bugs. (#73)tbd— Equity / stocks broker adapter. No equity broker exists. Needs new broker likeMT5Broker(Interactive Brokers / Alpaca / TradeStation) plus stock-specific concepts: corporate actions, dividend adjustment, pre/post-market sessions, halts. Substantial — multi-phase work. (#74)tbd— Futures broker adapter (e.g. Tradovate, IBKR futures). Similar scope to equities — distinct order types, session calendars, expiry roll logic. (#75)
Tier 7 — DSL surface expansion (as needed)¶
The DSL has 28+ phases of primitives but most are exercised only by hedge-straddle. The following are likely to surface as the second/third strategy gets written:
tbd— Cross-strategy state sharing (one strategy reads another's positions or equity). Currently strategies are isolated viaStrategyPositionTrackernamespacing; cross-reads would need an explicit query primitive. (#76)dropped— Symbol watch dynamic extension (closed as not-planned; tracked in the Future section above, #70).tbd— DSL action:SCHEDULEfor time-of-day non-tick-driven actions (currently done viaWHEN NOW.minute_utc = N, which works but is awkward). (#77)
Tier 8 — Platform maturity (post-research-platform)¶
tbd— Inbound Telegram bot commands (/status,/halt,/resumefrom phone) — needs long-polling or webhook receiver. (#78)done— HTTP/metricsendpoint (Prometheus-compatible) forNotifierMetrics+ engine internals. (#79)tbd— Multi-host deployment (active-passive failover for the qkt daemon). (#80)done—qkt researchREPL — playback v1 shipped (#225): session core + Playback mode (steppable event tape over a historical replay, bit-identical to backtest). Watch mode, expression REPL, and DSL parameters deferred as #81 epic follow-ups. (#81)
How to maintain this file¶
- Update the status marker in place (
done↔progress↔tbd). - Every open item carries a GitHub issue link. When you open a new item, create its issue
(problem statement + proposed solution) and link it here. When an item ships, flip it to
doneand close the issue. - When an item ships, leave it in its current section but flip to
done. Move to the Done section only at the next major housekeeping pass. - New items go into the section that matches their priority. If unsure between immediate and future, default to future.
- Keep entries one line each. If an item needs more detail, link to its spec/plan/changelog.