Strategy Trading & Backtesting
Introduction to Backtesting
The BacktestX Script engine includes a built-in strategy object that allows you to simulate trades, calculate win rates, and draw entry/exit markers directly on the chart.
The Strategy API
Use the following methods to record simulated trades. When you pass boolean arrays as the condArray, the engine will automatically draw Execution Arrows on the corresponding candles.
strategy.entry(id, direction, condArray)
strategy.close(id, condArray)
- id: A string identifier for the trade (e.g., "MyLong").
- direction: "Long" or "Short".
- condArray: A boolean array representing the trigger condition (e.g., from
ta.crossover()).
Strategy Tester UI
Whenever a script containing strategy.entry or strategy.close is successfully evaluated, a Strategy Tester panel will automatically slide up at the bottom of your terminal. It displays detailed statistics such as Net Profit, Win Rate, and Max Drawdown, alongside a fully formatted chronological ledger of all executed trades!
Advanced Strategy API
0. Capital & Account Settings
ctx.strategy.initial_capital(amount, currency): Programmatically sets the starting capital for the strategy, which automatically updates the Strategy Tester UI dropdown.
1. Advanced Exits
ctx.strategy.exit(id, condArray, profit, loss, limit, stop, trail_points, trail_offset): Advanced exit logic with trailing stops and brackets. Allows you to set absolute profit/loss targets and dynamic trailing stops.
2. Risk Management
These functions enforce risk rules which the Strategy Tester will mathematically honor when generating your final Net Profit and Drawdown stats:
ctx.strategy.risk.max_drawdown(value, type): Stops trading if the strategy loses a certain amount. (type can be 'percent' or 'cash').ctx.strategy.risk.max_intraday_loss(value, type): Caps the maximum loss allowed per day.
3. Real-Time Tracking
You can read these live values inside your script to make dynamic sizing decisions (e.g. risking 1% of live equity per trade):
ctx.strategy.equity: Returns the live, updating equity balance (Initial Capital + Realized PnL).ctx.strategy.position_size: Returns the current open quantity (positive for Longs, negative for Shorts).ctx.strategy.position_avg_price: Returns the exact entry price of the current active trade.ctx.strategy.openprofit(): Returns the floating Unrealized PnL of the current trade.
4. Custom Strategy UI
You can customize the Strategy Tester UI directly from your scripts:
ctx.strategy.setMetric(label, value, color): Injects a custom stats block into the top Key Stats dashboard.- label: The title of the metric (e.g. "Sharpe Ratio").
- value: The text/number to display (e.g. "1.85").
- color: (Optional) Hex code for the value.
ctx.strategy.tagTrade(id, columnName, value, color): Appends a custom data column to the trade table for a specific trade.- id: The Trade ID (e.g. "MACD Long").
- columnName: The title of your custom column (e.g. "Confidence").
- value: The value for this specific trade's row (e.g. "High").
- color: (Optional) Hex color code for the text.
Exposing Technical Indicators & Volume
Your custom indicator scripts have access to standard technical indicator values in two distinct ways:
- Built-in Math Helpers: Call standard math functions directly from
ctx(such asctx.sma(closes, 20),ctx.rsi(closes, 14), orctx.macd(closes)) to calculate indicators dynamically. - Active Indicators Array: Inspect
ctx.indicatorsto read pre-calculated arrays for active indicators running on the chart. Every indicator object contains a populated.valuesproperty. - Accessing Volume: Retrieve raw bar volume using
ctx.bars[i].volume, or get the entire history array viactx.vol(ctx.bars).
Rendering Optimization & 60 FPS Guidelines
To ensure high-performance scripting (60 FPS rendering without lag or stutter):
- Clamp rendering loops: Restrict canvas rendering iterations from
Math.max(0, Math.floor(bounds.startIndex) - 1)toMath.ceil(bounds.endIndex) + 1. This padding ensures indicators pan smoothly without abruptly disappearing. Avoid looping through the entire historical dataset. - Function Hoisting (CRITICAL): Never declare helper functions inside loops or main rendering callbacks. Hoist all user-defined functions to the global scope to prevent heavy memory allocation.
- Local Scoping: Scope loop-local variables with block-level
letorconstto prevent global namespace lookups and scope leaks. - Map Callback Dereferencing: Avoid allocating new array references or parsing objects inside map callbacks. Dereference precalculated indicator arrays directly using index keys.
- Execution Limits: Scripts taking longer than 12ms to execute will trigger a performance warning in the console.
Mouse Interactions
You can query the real-time mouse position and action states using the ctx.mouse object. This allows you to build interactive hover overlays, highlight target coordinates, or reveal tooltip stats under the cursor.