AI Generated Documentation
This document provides a comprehensive overview of the OpenBackTest project structure. It is intended to help developers and AI agents navigate the codebase efficiently.
OpenBackTest is a high-performance trading backtesting utility built with React and Vite.
- Charting Engine: KlineCharts is used for high-performance financial charting.
- State Management: Zustand handles global application state, split into backtest playback and trading simulation.
- Styling: Modern, dark-themed UI built with custom CSS utilities and
lucide-reacticons.
The codebase follows a Decoupled Bridge Architecture:
- State (Pure): Stores handle raw data and math (PnL, aggregation). They are chart-agnostic.
- View (Declarative): React components manage layout and user input.
- Hooks (The Bridge): These "watch" the State and imperatively update the Chart Engine (
chart.applyNewData(),chart.createOverlay()). - Engine (Imperative): KlineCharts handles high-performance Canvas rendering via extensions in
lib/chart/. - Data Connections (Provider-neutral): Market-data providers implement a shared connection contract and feed normalized candles into the backtest store.
UI components categorized by functional area.
ChartGrid.tsx: Dynamic, resizable grid layout usingreact-resizable-panelsto display up to 3 charts simultaneously.TradingChart/: All components related to the chart interface (overlays, menus, legends, individual chart containers).Controls.tsx: Top navigation, data loading controls, and session import/export management.PlaybackBar.tsx: The bottom timeline and playback controls.TradingPanel.tsx: The right-side panel for trade execution and account status.ActualAccountPanel.tsx: Broker account snapshot, live statistics, and guarded Rithmic market-order controls.StatsModal.tsx: Performance analysis dashboard with equity curve and export features.
Custom React hooks encapsulating complex logic.
useChart.ts: Lifecycle management for the KlineCharts instance.useIndicators.ts: Logic for adding, removing, and managing technical indicators.useTradeOverlays.ts: Rendering logic for TP/SL lines and trade entry areas.useContextMenu.ts: Logic for the chart's right-click interaction.
Zustand stores defining the global state and actions.
useBacktestStore.ts: Controls data playback (Play/Pause/Step), symbol selection, and multi-chart state management (array ofChartConfig).useTradeStore.ts: Core trading engine. Manages positions, orders, PnL calculations, trade history, and session statistics.useMarketDataStore.ts: Manages provider-neutral connection state, normalized symbols, historical data, and live candle subscriptions.useExecutionStore.ts: Owns the selected broker account, live account snapshot, execution subscriptions, and order actions without touching simulation state.useBinanceStore.ts: Deprecated compatibility alias foruseMarketDataStore.useChartStyleStore.ts: Manages styling properties for the chart, such as bullish/bearish candle colors, and persists user settings in localStorage.
Low-level extensions for KlineCharts.
customIndicators.ts: Registry for custom indicators and their default parameters.indicators/: One implementation file per custom indicator (ATR, anchored VWAP, anchored Volume Profile, and VPVR).overlays.ts: Registration of custom visual elements (e.g., TP/SL lines and anchored indicator range selectors).constants.ts: Shared IDs and configuration constants for the chart.
index.ts: Shared TypeScript interfaces for Candles, Trades, and Timeframes.indicatorTypes.ts: Types specific to indicator configurations.
| File | Responsibility |
|---|---|
src/App.tsx |
Main application shell and layout. Hosts the ChartGrid. |
src/components/ChartGrid.tsx |
Manages the resizable split-pane layout for multiple charts. |
src/hooks/useChart.ts |
Initializes chart, handles data updates, and manages responsive resizing with isolated container IDs. |
src/store/useBacktestStore.ts |
Centralizes data state; includes stepForward, togglePlayback, loadData, updateLiveCandle, and multi-chart configurations. |
src/store/useTradeStore.ts |
Executes trades; tracks account equity, leverage, and aggregates positions for statistics. |
src/store/useMarketDataStore.ts |
Owns the active market-data connection and maps provider events into normalized candles. |
src/store/useExecutionStore.ts |
Owns actual-account state and routes provider-neutral orders through the active provider's execution adapter. |
src/store/useBinanceStore.ts |
Compatibility alias for the provider-neutral market-data store. |
src/store/useChartStyleStore.ts |
Central store managing persistent chart styles and styling properties. |
src/components/TradingChart/CandleStyleEditor.tsx |
Floating overlay editor for bullish/bearish candle, border, and wick colors. |
src/components/StatsModal.tsx |
Calculates and displays Win Rate, Profit Factor, R/R, and Equity Curve; handles CSV exports. |
src/lib/chart/customIndicators.ts |
Registry and defaults for indicators not natively supported by KlineCharts. |
src/lib/chart/indicators/*.ts |
One file per custom indicator implementation; anchored VWAP and anchored Volume Profile receive their selected time range from chart overlays. |
src/components/TradingChart/ContextMenu.tsx |
UI for the right-click menu (Set TP/SL, Reset View). |
src/components/TradingChart/DrawingToolbar.tsx |
Left-side sidebar for chart annotation tools (Lines, Measures). |
src/hooks/useIndicators.ts |
Bridges the store state to the KlineCharts indicator API. |
src/utils/aggregation.ts |
Logic to convert 1m raw data into higher timeframes (5m, 1h, etc.). |
src/services/binance.ts |
Handles Binance API interactions (fetching symbols, historical klines, live polling). |
src/services/rithmic.ts |
Browser-side WebSocket adapter for the local RAPI+ Rithmic market-data gateway. |
src/services/marketData.ts |
Shared MarketDataSource, MarketDataConnection, and subscription interfaces for provider adapters. |
src/services/marketDataRegistry.ts |
Registry used to select an available market-data provider. |
src/services/execution.ts |
Provider-neutral account, order, fill, position, and live-statistics contracts. |
- Adding a New Indicator:
- Define the indicator in its own file under
src/lib/chart/indicators/. - Register it and its defaults in
src/lib/chart/customIndicators.ts. - Add any required UI label or parameter metadata in
IndicatorMenu.tsxandIndicatorProperties.tsx.
- Define the indicator in its own file under
- Anchored VWAP / Volume Profile:
- Choose the indicator from the chart's Indicators menu, then draw the two-point range overlay on the chart.
- Drag either endpoint to recalculate the selected range. The range and indicator settings are persisted per symbol and chart screen.
- Modifying Trading Logic:
- Edit
src/store/useTradeStore.tsfor execution logic. - Edit
src/hooks/useTradeOverlays.tsto change how positions look on the chart.
- Edit
- Adjusting Statistics & Reporting:
- Statistics are calculated in
src/components/StatsModal.tsxusingfinishedPositionsfrom the trade store. - To add new metrics, update the
Positioninterface inuseTradeStore.tsand the calculation logic inStatsModal.tsx.
- Statistics are calculated in
KlineCharts: For chart API questions.Zustand: For state management patterns.VPVR: For Volume Profile logic.useBacktestStore: For playback control.StatsModal: For performance metrics and reporting.
When working on features, bug fixes, or enhancements, you MUST adhere to the following rules:
- Test Directory Structure: All unit and integration tests MUST be placed in the root
tests/directory (e.g.,tests/store,tests/components,tests/hooks). Do not place__tests__folders or.test.tsfiles alongside the source code in thesrc/directory. - Testing Stack: The project uses
vitest,jsdom, and@testing-library/react. - Mocking: When writing tests for complex React hooks and Zustand stores (especially those interacting with the canvas or browser APIs), actively use
@testing-library/react'srenderHookandvitest'svi.mock()/vi.spyOn(). - Coverage: When adding new UI components or data stores, ensure that you provide corresponding test coverage. Run
npm run coverageto verify your changes.
- Data Source: CSV/JSON loaded into
useBacktestStore. - Aggregation:
useBacktestStoreusesaggregation.tsto prepare data for the current timeframe. - Rendering:
useChartdetects data changes and callschart.applyNewData(). - Interaction: User actions trigger
useTradeStore, which updates overlays viauseTradeOverlays. - Completion: When a simulation is finished,
useTradeStoreaggregates all trades intofinishedPositionsand triggers theStatsModal.
graph TD
%% Layers
subgraph UI ["View Layer (React)"]
App["App.tsx"]
Controls["Controls.tsx"]
ChartGrid["ChartGrid.tsx"]
ChartUI["TradingChart/index.tsx"]
CandleEditor["TradingChart/CandleStyleEditor.tsx"]
Stats["StatsModal.tsx"]
end
subgraph Logic ["Logic & State (Zustand)"]
BS["useBacktestStore (Playback)"]
TS["useTradeStore (Execution & Stats)"]
CSS["useChartStyleStore (Styles)"]
BNS["useMarketDataStore (Live Data)"]
end
subgraph Bridge ["Bridge Hooks (Glue)"]
UC["useChart (Lifecycle)"]
UIH["useIndicators (Math)"]
UT["useTradeOverlays (Visuals)"]
end
subgraph Engine ["Engine Layer"]
KC["KlineCharts (Canvas)"]
Lib["lib/chart/* (Extensions)"]
end
%% Mapping
App --> Controls & ChartGrid & Stats
ChartGrid --> ChartUI
Controls --> BS & TS & BNS
BNS --> BS
ChartUI --> UC & UIH & UT & CandleEditor
CandleEditor --> CSS
Stats --> TS
UC & UIH & UT --> KC
UC --> CSS
KC <--> Lib
BS --> Agg["aggregation.ts"]
OpenBackTest consumes live data through a provider-neutral connection contract.
src/services/marketData.tsdefinesMarketDataSource,MarketDataConnection, andMarketDataSubscription.src/services/marketDataRegistry.tsregisters available providers.src/services/binance.tsimplements the current Binance Futures adapter: futures symbols, historical 1m klines, and REST-based live polling.src/services/rithmic.tsimplements the browser side of the Rithmic adapter. It speaks a small WebSocket protocol to the local .NET gateway and maps RAPI+ reference data, trade replay, and live trades into normalized symbols and candles.src/store/useMarketDataStore.tsowns the active connection, loads historical data, starts/stops subscriptions, and maps provider symbols to normalizedMarketSymbolvalues.src/store/useBinanceStore.tsremains as a compatibility alias while consumers migrate touseMarketDataStore.src/store/useBacktestStore.tsremains provider-agnostic and only receives normalized candles throughupdateLiveCandle(kline).
Rithmic market data and actual-account execution are available through the local gateway/ project. The gateway uses the Quantower-compatible RAPI+ runtime and the checked-in Chicago paper profile, while credentials and native library paths remain environment/browser configuration. The provider-neutral execution contract is separate from chart data, so future providers such as Binance can add account and order adapters without changing the simulation code. The account-wide flatten path cancels all working orders and exits every open account position before reporting completion.
The execution boundary is defined in src/services/execution.ts. It models broker accounts, orders, order updates, fills, positions, and live statistics without changing the current local simulation behavior. Rithmic is the first provider implementing it.
Import trades from another platform and analyze them using OpenBackTest's Statistics Modal. Construct a JSON file that mimics the internal session state. Load a CSV file into the application before importing the JSON session file.
JSON structure required to populate the statistics:
{
"backtest": {},
"trade": {
"initialBalance": 10000,
"isFinished": true,
"showStatsModal": true,
"tradeHistory": [
{
"id": "trade-1",
"type": "buy",
"price": 50000,
"time": 1704067200,
"quantity": 1,
"fee": 0,
"realizedPnL": 0,
"positionSize": 1,
"entryPrice": 50000,
"balance": 10000
},
{
"id": "trade-2",
"type": "sell",
"price": 51000,
"time": 1704070800,
"quantity": 1,
"fee": 10,
"realizedPnL": 1000,
"positionSize": 0,
"entryPrice": null,
"balance": 11000
}
],
"finishedPositions": [
{
"id": "pos-1",
"type": "long",
"entryPrice": 50000,
"exitPrice": 51000,
"quantity": 1,
"pnl": 1000,
"openTime": 1704067200,
"closeTime": 1704070800,
"trades": []
}
]
}
}
Key Fields to Map:
initialBalance: Your starting account equity.isFinished&showStatsModal: Set totrueto immediately open the dashboard.finishedPositions: Powers core stats (Win Rate, PnL, Drawdown, Profit Factor). Thepnlfield should be the gross profit/loss (before fees). Thetradesarray should be left empty ([]) for imported data.tradeHistory: Powers the "Trade Log" export, "Backtest from/to" dates, and fee calculations. Fees intradeHistoryentries are automatically subtracted from the gross PnL to compute the net profit displayed in the Statistics Modal.