JSPM

@neural-trader/backtesting

2.1.1
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 47
  • Score
    100M100P100Q98996F
  • License MIT OR Apache-2.0

High-performance backtesting engine for Neural Trader - Rust-powered NAPI bindings

Package Exports

  • @neural-trader/backtesting
  • @neural-trader/backtesting/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@neural-trader/backtesting) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@neural-trader/backtesting

CI Status codecov License npm version

Lightning-fast backtesting engine powered by Rust with zero-overhead Node.js bindings. Test trading strategies against historical data with microsecond-level precision.

Introduction

Testing trading strategies on historical data is critical for validating performance before risking real capital. Traditional JavaScript-based backtesting engines are too slow for production use, often taking minutes or hours to process thousands of trades. @neural-trader/backtesting solves this with a native Rust implementation that delivers 8-19x faster performance than Python alternatives.

Built on the Rust nt-backtesting crate, this package provides comprehensive backtesting capabilities including commission modeling, slippage simulation, mark-to-market accounting, and detailed performance metrics. All calculations happen at native speed with automatic multi-threading for maximum performance.

The package seamlessly integrates with @neural-trader/strategies for signal generation, @neural-trader/neural for AI-powered predictions, and @neural-trader/risk for position sizing and risk management.

Features

  • Lightning-Fast Execution - Process 10,000+ trades in milliseconds with Rust's native performance
  • Multi-Threaded Processing - Automatic parallelization across CPU cores for walk-forward analysis
  • Realistic Simulation - Commission, slippage, and mark-to-market P&L calculations
  • Comprehensive Metrics - Sharpe ratio, Sortino ratio, max drawdown, win rate, profit factor, and more
  • Equity Curve Tracking - Full trade history with timestamp-synchronized equity curves
  • Walk-Forward Analysis - Built-in support for out-of-sample testing and parameter optimization
  • CSV Export - Export trade history and equity curves for external analysis
  • Zero-Copy NAPI - Efficient memory handling with minimal JavaScript overhead
  • Self-Learning Integration - Works with @neural-trader/neural for adaptive strategy optimization

Installation

Via npm (Node.js)

# Core package
npm install @neural-trader/backtesting

# With related packages
npm install @neural-trader/backtesting @neural-trader/strategies @neural-trader/risk

# Full platform (all features)
npm install neural-trader

Via Cargo (Rust)

# Add to Cargo.toml
[dependencies]
nt-backtesting = "1.0.0"

# Or install CLI tool
cargo install nt-backtesting-cli

Package Size: ~300 KB (compressed native binary)

See main packages documentation for all available packages.

Quick Start

30-second example showing basic backtesting:

const { BacktestEngine } = require('@neural-trader/backtesting');

async function quickStart() {
  // Initialize backtest engine
  const engine = new BacktestEngine({
    initialCapital: 100000,
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,        // 0.1% per trade
    slippage: 0.0005,         // 0.05% slippage
    useMarkToMarket: true
  });

  // Generate signals from your strategy
  const signals = [
    {
      id: '1',
      strategyId: 'momentum-strategy',
      symbol: 'AAPL',
      direction: 'long',
      confidence: 0.85,
      entryPrice: 150.00,
      stopLoss: 145.00,
      takeProfit: 160.00,
      reasoning: 'Strong momentum breakout',
      timestampNs: Date.now() * 1_000_000
    }
  ];

  // Run backtest
  const result = await engine.run(signals, 'data/market-data.csv');

  console.log('Performance Metrics:', result.metrics);
  console.log(`Total Return: ${(result.metrics.totalReturn * 100).toFixed(2)}%`);
  console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio.toFixed(2)}`);
  console.log(`Max Drawdown: ${(result.metrics.maxDrawdown * 100).toFixed(2)}%`);
}

quickStart().catch(console.error);

Expected Output:

Performance Metrics: {
  totalReturn: 0.127,
  sharpeRatio: 1.84,
  sortinoRatio: 2.31,
  maxDrawdown: 0.082,
  winRate: 0.58,
  profitFactor: 2.15,
  totalTrades: 142
}
Total Return: 12.70%
Sharpe Ratio: 1.84
Max Drawdown: 8.20%

Core Concepts

Signal-Based Backtesting

@neural-trader/backtesting uses a signal-based approach where your strategy generates trade signals that the engine executes against historical market data.

// Signals define entry/exit intentions
const signal = {
  id: 'unique-id',
  strategyId: 'your-strategy',
  symbol: 'AAPL',
  direction: 'long',          // 'long' or 'short'
  confidence: 0.75,           // 0.0 to 1.0
  entryPrice: 150.00,
  stopLoss: 145.00,           // Risk management
  takeProfit: 160.00,         // Profit target
  reasoning: 'Why this trade',
  timestampNs: 1234567890000000n  // Nanosecond precision
};

Realistic Trade Execution

The engine simulates realistic market conditions with commission and slippage:

const config = {
  initialCapital: 100000,
  commission: 0.001,      // 0.1% per trade side
  slippage: 0.0005,       // 0.05% average slippage
  useMarkToMarket: true   // Daily P&L calculation
};

// Actual entry price includes slippage and commission
// Entry: $150.00 * (1 + 0.0005) * (1 + 0.001) = $150.23
// Commission: $150.23 * 0.001 = $0.15

Performance Metrics

Comprehensive metrics automatically calculated after each backtest:

const metrics = {
  totalReturn: 0.15,        // 15% total return
  annualReturn: 0.125,      // Annualized
  sharpeRatio: 1.8,         // Risk-adjusted return
  sortinoRatio: 2.3,        // Downside risk-adjusted
  maxDrawdown: 0.12,        // Maximum peak-to-trough decline
  winRate: 0.58,            // 58% winning trades
  profitFactor: 2.1,        // Gross profit / gross loss
  totalTrades: 150,
  winningTrades: 87,
  losingTrades: 63,
  avgWin: 0.025,            // 2.5% average win
  avgLoss: 0.015,           // 1.5% average loss
  largestWin: 0.08,
  largestLoss: 0.05,
  finalEquity: 115000
};

Key Terminology

  • Signal: A trading intention generated by your strategy with entry/exit parameters
  • Equity Curve: Portfolio value over time, tracking all P&L and positions
  • Mark-to-Market: Daily portfolio valuation using current market prices
  • Walk-Forward Analysis: Testing strategy on rolling out-of-sample periods
  • Slippage: The difference between expected and actual execution prices
  • Commission: Transaction costs per trade side (entry and exit)

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                    @neural-trader/backtesting                │
│                                                               │
│  ┌────────────────────┐         ┌─────────────────────────┐ │
│  │  BacktestEngine    │────────▶│  Rust nt-backtesting    │ │
│  │  (Node.js API)     │  NAPI   │  (Native Performance)    │ │
│  └────────────────────┘         └─────────────────────────┘ │
│           │                               │                  │
│           │ Signals                       │ Market Data      │
│           ▼                               ▼                  │
│  ┌────────────────────┐         ┌─────────────────────────┐ │
│  │ Strategy Generator │         │ Multi-threaded Executor │ │
│  └────────────────────┘         └─────────────────────────┘ │
│                                           │                  │
│                                           ▼                  │
│                                  ┌─────────────────────────┐ │
│                                  │  Metrics Calculator     │ │
│                                  │  - Sharpe/Sortino       │ │
│                                  │  - Drawdown Analysis    │ │
│                                  │  - Trade Statistics     │ │
│                                  └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

API Reference

BacktestEngine

High-performance backtesting engine for executing strategy signals against historical market data.

Constructor

new BacktestEngine(options: BacktestConfig)

Parameters:

Parameter Type Required Default Description
initialCapital number Yes - Starting portfolio value in dollars
startDate string Yes - Backtest start date (YYYY-MM-DD)
endDate string Yes - Backtest end date (YYYY-MM-DD)
commission number No 0.001 Commission per trade side (0.001 = 0.1%)
slippage number No 0.0005 Average slippage per trade (0.0005 = 0.05%)
useMarkToMarket boolean No true Enable daily mark-to-market P&L calculation

Example:

const engine = new BacktestEngine({
  initialCapital: 100000,
  startDate: '2024-01-01',
  endDate: '2024-12-31',
  commission: 0.001,
  slippage: 0.0005,
  useMarkToMarket: true
});

Methods

run(signals: Signal[], marketDataPath: string): Promise<BacktestResult>

Execute backtest with strategy signals against historical market data.

Parameters:

Parameter Type Required Description
signals Signal[] Yes Array of trading signals from your strategy
marketDataPath string Yes Path to CSV file with historical OHLCV data

Returns: Promise resolving to BacktestResult with metrics, trades, and equity curve

Example:

const result = await engine.run(signals, 'data/AAPL-2024.csv');
console.log(result.metrics);
// Output: { totalReturn: 0.15, sharpeRatio: 1.8, maxDrawdown: 0.12, ... }
calculateMetrics(equityCurve: number[]): BacktestMetrics

Calculate performance metrics from an equity curve.

Parameters:

Parameter Type Required Description
equityCurve number[] Yes Array of portfolio values over time

Returns: BacktestMetrics object with all performance statistics

Example:

const metrics = engine.calculateMetrics([100000, 102000, 101500, 105000]);
console.log(`Sharpe: ${metrics.sharpeRatio.toFixed(2)}`);
exportTradesCsv(trades: Trade[]): string

Export trade history to CSV format for external analysis.

Example:

const csv = engine.exportTradesCsv(result.trades);
require('fs').writeFileSync('trades.csv', csv);

compareBacktests

Compare multiple backtest results side-by-side.

Signature:

function compareBacktests(results: BacktestResult[]): string

Example:

const { compareBacktests } = require('@neural-trader/backtesting');

const comparison = compareBacktests([result1, result2, result3]);
console.log(comparison);

Type Definitions

BacktestResult

interface BacktestResult {
  metrics: BacktestMetrics;  // Performance statistics
  trades: Trade[];           // All executed trades with P&L
  equityCurve: number[];     // Portfolio value over time
  dates: string[];           // Corresponding timestamps
}

BacktestMetrics

interface BacktestMetrics {
  totalReturn: number;       // Total return (0.15 = 15%)
  annualReturn: number;      // Annualized return
  sharpeRatio: number;       // Risk-adjusted return
  sortinoRatio: number;      // Downside risk-adjusted return
  maxDrawdown: number;       // Maximum drawdown
  winRate: number;           // Winning trades / total trades
  profitFactor: number;      // Gross profit / gross loss
  totalTrades: number;       // Total number of trades
  winningTrades: number;     // Number of winning trades
  losingTrades: number;      // Number of losing trades
  avgWin: number;            // Average winning trade return
  avgLoss: number;           // Average losing trade return
  largestWin: number;        // Largest winning trade
  largestLoss: number;       // Largest losing trade
  finalEquity: number;       // Final portfolio value
}

Detailed Tutorials

Tutorial 1: Backtest a Momentum Strategy

Goal: Test a simple momentum breakout strategy and analyze performance metrics

Prerequisites:

  • Basic understanding of trading signals
  • Historical market data in CSV format (OHLCV)

Step 1: Generate Momentum Signals

Create signals when price breaks above 20-day high:

const { BacktestEngine } = require('@neural-trader/backtesting');

function generateMomentumSignals(marketData) {
  const signals = [];
  const lookback = 20;

  for (let i = lookback; i < marketData.length; i++) {
    const recentPrices = marketData.slice(i - lookback, i).map(b => b.high);
    const maxHigh = Math.max(...recentPrices);
    const currentBar = marketData[i];

    // Breakout signal
    if (currentBar.close > maxHigh) {
      signals.push({
        id: `signal-${i}`,
        strategyId: 'momentum-breakout',
        symbol: currentBar.symbol,
        direction: 'long',
        confidence: 0.8,
        entryPrice: currentBar.close,
        stopLoss: currentBar.close * 0.95,    // 5% stop loss
        takeProfit: currentBar.close * 1.10,  // 10% take profit
        reasoning: `Breakout above ${lookback}-day high`,
        timestampNs: BigInt(currentBar.timestamp) * 1_000_000n
      });
    }
  }

  return signals;
}

Step 2: Run Backtest

Execute the backtest with realistic parameters:

async function backtestMomentum() {
  const engine = new BacktestEngine({
    initialCapital: 100000,
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,        // 0.1% commission
    slippage: 0.0005,         // 0.05% slippage
    useMarkToMarket: true
  });

  // Load market data
  const marketData = loadMarketData('data/AAPL-2024.csv');
  const signals = generateMomentumSignals(marketData);

  console.log(`Generated ${signals.length} signals`);

  // Run backtest
  const result = await engine.run(signals, 'data/AAPL-2024.csv');
  return result;
}

Step 3: Analyze Results

Review performance metrics and equity curve:

async function analyzeResults() {
  const result = await backtestMomentum();
  const m = result.metrics;

  console.log('=== Backtest Results ===');
  console.log(`Total Return: ${(m.totalReturn * 100).toFixed(2)}%`);
  console.log(`Annual Return: ${(m.annualReturn * 100).toFixed(2)}%`);
  console.log(`Sharpe Ratio: ${m.sharpeRatio.toFixed(2)}`);
  console.log(`Sortino Ratio: ${m.sortinoRatio.toFixed(2)}`);
  console.log(`Max Drawdown: ${(m.maxDrawdown * 100).toFixed(2)}%`);
  console.log('');
  console.log(`Total Trades: ${m.totalTrades}`);
  console.log(`Win Rate: ${(m.winRate * 100).toFixed(1)}%`);
  console.log(`Profit Factor: ${m.profitFactor.toFixed(2)}`);
  console.log(`Avg Win: ${(m.avgWin * 100).toFixed(2)}%`);
  console.log(`Avg Loss: ${(m.avgLoss * 100).toFixed(2)}%`);
  console.log('');
  console.log(`Final Equity: $${m.finalEquity.toLocaleString()}`);

  // Export trades for analysis
  const csv = engine.exportTradesCsv(result.trades);
  require('fs').writeFileSync('momentum-trades.csv', csv);
  console.log('\nTrades exported to momentum-trades.csv');
}

Expected Output:

=== Backtest Results ===
Total Return: 15.30%
Annual Return: 15.30%
Sharpe Ratio: 1.84
Sortino Ratio: 2.31
Max Drawdown: 8.20%

Total Trades: 42
Win Rate: 61.9%
Profit Factor: 2.15
Avg Win: 4.20%
Avg Loss: 2.30%

Final Equity: $115,300

Trades exported to momentum-trades.csv

Complete Example:

const { BacktestEngine } = require('@neural-trader/backtesting');
const fs = require('fs');

async function completeMomentumBacktest() {
  // 1. Load market data
  const marketData = loadMarketData('data/AAPL-2024.csv');

  // 2. Generate signals
  const signals = generateMomentumSignals(marketData);

  // 3. Configure engine
  const engine = new BacktestEngine({
    initialCapital: 100000,
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,
    slippage: 0.0005,
    useMarkToMarket: true
  });

  // 4. Run backtest
  const result = await engine.run(signals, 'data/AAPL-2024.csv');

  // 5. Analyze and export
  console.log('Performance Metrics:', result.metrics);
  fs.writeFileSync('trades.csv', engine.exportTradesCsv(result.trades));

  return result;
}

completeMomentumBacktest().catch(console.error);

Tutorial 2: Multi-Symbol Portfolio Backtest

Goal: Test a diversified portfolio strategy across multiple symbols

Prerequisites:

  • Market data for multiple symbols
  • Understanding of portfolio allocation

Step 1: Configure Multi-Symbol Backtest

const symbols = ['AAPL', 'MSFT', 'GOOGL', 'AMZN'];

async function multiSymbolBacktest() {
  const engine = new BacktestEngine({
    initialCapital: 500000,  // Larger capital for diversification
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,
    slippage: 0.0005,
    useMarkToMarket: true
  });

  // Generate signals for each symbol
  const allSignals = [];
  for (const symbol of symbols) {
    const data = loadMarketData(`data/${symbol}-2024.csv`);
    const signals = generateMomentumSignals(data);
    allSignals.push(...signals);
  }

  // Sort signals by timestamp
  allSignals.sort((a, b) => Number(a.timestampNs - b.timestampNs));

  return engine.run(allSignals, 'data/combined-2024.csv');
}

Step 2: Risk-Adjusted Position Sizing

const { RiskManager } = require('@neural-trader/risk');

function generateRiskAdjustedSignals(marketData, portfolioValue) {
  const riskManager = new RiskManager({
    confidenceLevel: 0.95,
    lookbackPeriods: 252,
    method: 'historical'
  });

  const signals = [];

  for (let i = 60; i < marketData.length; i++) {
    const bar = marketData[i];

    // Calculate position size based on 2% risk per trade
    const stopLoss = bar.close * 0.95;  // 5% stop
    const stopDistance = Math.abs(bar.close - stopLoss) / bar.close;

    const positionSize = riskManager.calculatePositionSize(
      portfolioValue,
      bar.close,
      0.02,  // Risk 2% per trade
      stopDistance
    );

    signals.push({
      id: `signal-${i}`,
      strategyId: 'risk-adjusted-momentum',
      symbol: bar.symbol,
      direction: 'long',
      confidence: 0.75,
      entryPrice: bar.close,
      stopLoss: stopLoss,
      takeProfit: bar.close * 1.10,
      positionSize: positionSize.shares,  // Number of shares
      reasoning: `Risk-adjusted position: ${positionSize.shares} shares`,
      timestampNs: BigInt(bar.timestamp) * 1_000_000n
    });
  }

  return signals;
}

Step 3: Compare Strategies

const { compareBacktests } = require('@neural-trader/backtesting');

async function compareMultipleStrategies() {
  // Test different parameter sets
  const results = [];

  // Strategy 1: Aggressive (10% stop, 20% target)
  results.push(await backtestStrategy(0.90, 1.20));

  // Strategy 2: Moderate (5% stop, 10% target)
  results.push(await backtestStrategy(0.95, 1.10));

  // Strategy 3: Conservative (3% stop, 6% target)
  results.push(await backtestStrategy(0.97, 1.06));

  // Compare all strategies
  const comparison = compareBacktests(results);
  console.log(comparison);

  // Find best strategy
  const best = results.reduce((a, b) =>
    a.metrics.sharpeRatio > b.metrics.sharpeRatio ? a : b
  );

  console.log('\nBest Strategy:');
  console.log(`Sharpe Ratio: ${best.metrics.sharpeRatio.toFixed(2)}`);
  console.log(`Total Return: ${(best.metrics.totalReturn * 100).toFixed(2)}%`);
}

Complete Example:

async function completeMultiSymbolBacktest() {
  const symbols = ['AAPL', 'MSFT', 'GOOGL', 'AMZN'];
  const engine = new BacktestEngine({
    initialCapital: 500000,
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,
    slippage: 0.0005,
    useMarkToMarket: true
  });

  // Generate and combine signals
  const allSignals = symbols.flatMap(symbol =>
    generateRiskAdjustedSignals(
      loadMarketData(`data/${symbol}-2024.csv`),
      500000 / symbols.length  // Equal allocation
    )
  ).sort((a, b) => Number(a.timestampNs - b.timestampNs));

  // Run backtest
  const result = await engine.run(allSignals, 'data/combined-2024.csv');

  console.log('Multi-Symbol Portfolio Results:');
  console.log(`Total Return: ${(result.metrics.totalReturn * 100).toFixed(2)}%`);
  console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio.toFixed(2)}`);
  console.log(`Max Drawdown: ${(result.metrics.maxDrawdown * 100).toFixed(2)}%`);

  return result;
}

Tutorial 3: Walk-Forward Analysis

Goal: Validate strategy robustness with rolling out-of-sample testing

Complete Implementation:

const { BacktestEngine } = require('@neural-trader/backtesting');

async function walkForwardAnalysis(marketData, windowDays = 252, stepDays = 63) {
  const results = [];

  for (let i = 0; i < marketData.length - windowDays; i += stepDays) {
    // In-sample training window
    const trainData = marketData.slice(i, i + windowDays * 0.7);

    // Out-of-sample testing window
    const testData = marketData.slice(
      i + windowDays * 0.7,
      i + windowDays
    );

    // Optimize parameters on training data
    const params = optimizeParameters(trainData);

    // Test on out-of-sample data
    const engine = new BacktestEngine({
      initialCapital: 100000,
      startDate: testData[0].date,
      endDate: testData[testData.length - 1].date,
      commission: 0.001,
      slippage: 0.0005,
      useMarkToMarket: true
    });

    const signals = generateSignalsWithParams(testData, params);
    const result = await engine.run(signals, `data/test-${i}.csv`);

    results.push({
      period: `${testData[0].date} to ${testData[testData.length - 1].date}`,
      metrics: result.metrics,
      params: params
    });

    console.log(`Period ${results.length}: Return ${(result.metrics.totalReturn * 100).toFixed(2)}%`);
  }

  // Aggregate results
  const avgReturn = results.reduce((sum, r) => sum + r.metrics.totalReturn, 0) / results.length;
  const avgSharpe = results.reduce((sum, r) => sum + r.metrics.sharpeRatio, 0) / results.length;

  console.log('\nWalk-Forward Analysis Complete:');
  console.log(`Average Return: ${(avgReturn * 100).toFixed(2)}%`);
  console.log(`Average Sharpe: ${avgSharpe.toFixed(2)}`);
  console.log(`Consistency: ${results.filter(r => r.metrics.totalReturn > 0).length}/${results.length} periods profitable`);

  return results;
}

function optimizeParameters(trainData) {
  // Simple parameter optimization
  const lookbacks = [10, 20, 30, 50];
  const results = lookbacks.map(lookback => ({
    lookback,
    return: calculateReturn(trainData, lookback)
  }));

  return results.sort((a, b) => b.return - a.return)[0];
}

Tutorial 4: Neural Strategy Integration

Goal: Integrate AI-powered predictions with backtesting

Implementation:

const { BacktestEngine } = require('@neural-trader/backtesting');
const { NeuralModel } = require('@neural-trader/neural');

async function neuralStrategyBacktest() {
  // 1. Train neural model
  const model = new NeuralModel({
    modelType: 'LSTMAttention',
    inputSize: 50,
    horizon: 5,
    hiddenSize: 256,
    numLayers: 3,
    dropout: 0.2,
    learningRate: 0.001
  });

  const trainData = prepareTrainingData('data/AAPL-train.csv');
  await model.train(trainData.features, trainData.targets, {
    epochs: 100,
    batchSize: 32,
    validationSplit: 0.2,
    earlyStoppingPatience: 10,
    useGpu: true
  });

  // 2. Generate AI-powered signals
  async function generateNeuralSignals(marketData) {
    const signals = [];

    for (let i = 60; i < marketData.length; i++) {
      const features = extractFeatures(marketData.slice(i - 60, i));
      const prediction = await model.predict(features);

      // Only trade on high-confidence predictions
      if (Math.abs(prediction.predictions[0]) > 0.01) {
        const direction = prediction.predictions[0] > 0 ? 'long' : 'short';
        const confidence = Math.abs(prediction.predictions[0]);

        signals.push({
          id: `neural-${i}`,
          strategyId: 'lstm-momentum',
          symbol: marketData[i].symbol,
          direction: direction,
          confidence: confidence,
          entryPrice: marketData[i].close,
          stopLoss: marketData[i].close * (direction === 'long' ? 0.97 : 1.03),
          takeProfit: marketData[i].close * (direction === 'long' ? 1.06 : 0.94),
          reasoning: `AI predicted ${(prediction.predictions[0] * 100).toFixed(2)}% return`,
          timestampNs: BigInt(marketData[i].timestamp) * 1_000_000n
        });
      }
    }

    return signals;
  }

  // 3. Backtest neural strategy
  const engine = new BacktestEngine({
    initialCapital: 100000,
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,
    slippage: 0.0005,
    useMarkToMarket: true
  });

  const testData = loadMarketData('data/AAPL-test.csv');
  const signals = await generateNeuralSignals(testData);
  const result = await engine.run(signals, 'data/AAPL-test.csv');

  console.log('Neural Strategy Results:');
  console.log(`Total Return: ${(result.metrics.totalReturn * 100).toFixed(2)}%`);
  console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio.toFixed(2)}`);
  console.log(`Win Rate: ${(result.metrics.winRate * 100).toFixed(1)}%`);

  return result;
}

Tutorial 5: Live Trading Simulation

Goal: Simulate real-time trading with delayed data feeds

Advanced Example:

const { BacktestEngine } = require('@neural-trader/backtesting');

class LiveTradingSimulator {
  constructor(config) {
    this.engine = new BacktestEngine(config);
    this.signals = [];
    this.positions = new Map();
  }

  async onBar(bar) {
    // Generate signal based on current bar
    const signal = await this.analyzeBar(bar);

    if (signal) {
      this.signals.push(signal);
      console.log(`Signal generated: ${signal.direction} at $${signal.entryPrice}`);
    }

    // Check for stop loss / take profit
    for (const [id, position] of this.positions) {
      if (bar.low <= position.stopLoss) {
        console.log(`Stop loss hit for position ${id}`);
        this.closePosition(id, position.stopLoss);
      } else if (bar.high >= position.takeProfit) {
        console.log(`Take profit hit for position ${id}`);
        this.closePosition(id, position.takeProfit);
      }
    }
  }

  async analyzeBar(bar) {
    // Your strategy logic here
    // Return signal or null
  }

  async runSimulation(marketDataPath) {
    // Simulate live trading bar-by-bar
    const data = loadMarketData(marketDataPath);

    for (const bar of data) {
      await this.onBar(bar);
      await sleep(100);  // Simulate real-time delay
    }

    // Final backtest with all signals
    return this.engine.run(this.signals, marketDataPath);
  }
}

// Usage
const simulator = new LiveTradingSimulator({
  initialCapital: 100000,
  startDate: '2024-01-01',
  endDate: '2024-12-31',
  commission: 0.001,
  slippage: 0.0005,
  useMarkToMarket: true
});

const result = await simulator.runSimulation('data/AAPL-2024.csv');

Integration Examples

Integration with @neural-trader/strategies

Combine backtesting with pre-built trading strategies:

const { BacktestEngine } = require('@neural-trader/backtesting');
const { MomentumStrategy } = require('@neural-trader/strategies');

async function backtestStrategy() {
  const strategy = new MomentumStrategy({
    lookbackPeriod: 20,
    stopLossPercent: 0.05,
    takeProfitPercent: 0.10
  });

  // Generate signals from strategy
  const marketData = loadMarketData('data/AAPL-2024.csv');
  const signals = [];

  for (const bar of marketData) {
    const signal = await strategy.analyze(bar);
    if (signal) signals.push(signal);
  }

  // Backtest signals
  const engine = new BacktestEngine({
    initialCapital: 100000,
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,
    slippage: 0.0005,
    useMarkToMarket: true
  });

  return engine.run(signals, 'data/AAPL-2024.csv');
}

Integration with @neural-trader/risk

Add risk management to your backtesting:

const { BacktestEngine } = require('@neural-trader/backtesting');
const { RiskManager } = require('@neural-trader/risk');

async function riskManagedBacktest() {
  const riskManager = new RiskManager({
    confidenceLevel: 0.95,
    lookbackPeriods: 252,
    method: 'historical'
  });

  // Calculate position sizes with risk management
  function generateRiskAdjustedSignals(marketData, portfolioValue) {
    const signals = [];

    for (let i = 20; i < marketData.length; i++) {
      const bar = marketData[i];
      const stopLoss = bar.close * 0.95;
      const stopDistance = Math.abs(bar.close - stopLoss) / bar.close;

      // Calculate position size for 2% risk per trade
      const position = riskManager.calculatePositionSize(
        portfolioValue,
        bar.close,
        0.02,
        stopDistance
      );

      signals.push({
        id: `signal-${i}`,
        strategyId: 'risk-managed',
        symbol: bar.symbol,
        direction: 'long',
        confidence: 0.8,
        entryPrice: bar.close,
        stopLoss: stopLoss,
        takeProfit: bar.close * 1.10,
        positionSize: position.shares,
        reasoning: position.reasoning,
        timestampNs: BigInt(bar.timestamp) * 1_000_000n
      });
    }

    return signals;
  }

  const marketData = loadMarketData('data/AAPL-2024.csv');
  const signals = generateRiskAdjustedSignals(marketData, 100000);

  const engine = new BacktestEngine({
    initialCapital: 100000,
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,
    slippage: 0.0005,
    useMarkToMarket: true
  });

  const result = await engine.run(signals, 'data/AAPL-2024.csv');

  // Analyze risk metrics
  const returns = calculateReturns(result.equityCurve);
  const var95 = riskManager.calculateVar(returns, 100000);
  const drawdown = riskManager.calculateDrawdown(result.equityCurve);

  console.log(`VaR (95%): $${var95.varAmount.toLocaleString()}`);
  console.log(`Max Drawdown: ${(drawdown.maxDrawdown * 100).toFixed(2)}%`);

  return result;
}

Integration with @neural-trader/neural

Combine neural networks with backtesting for AI-driven strategies:

const { BacktestEngine } = require('@neural-trader/backtesting');
const { NeuralModel } = require('@neural-trader/neural');
const { RiskManager } = require('@neural-trader/risk');

async function neuralBacktestWithRisk() {
  // 1. Train neural model
  const model = new NeuralModel({
    modelType: 'LSTMAttention',
    inputSize: 50,
    horizon: 5,
    hiddenSize: 256,
    numLayers: 3,
    dropout: 0.2,
    learningRate: 0.001
  });

  const trainData = prepareTrainingData('data/train.csv');
  await model.train(trainData.features, trainData.targets, {
    epochs: 100,
    batchSize: 32,
    validationSplit: 0.2,
    earlyStoppingPatience: 10,
    useGpu: true
  });

  // 2. Generate signals with AI predictions and risk management
  const riskManager = new RiskManager({
    confidenceLevel: 0.95,
    lookbackPeriods: 252,
    method: 'historical'
  });

  async function generateSmartSignals(marketData, portfolioValue) {
    const signals = [];

    for (let i = 60; i < marketData.length; i++) {
      const features = extractFeatures(marketData.slice(i - 60, i));
      const prediction = await model.predict(features);
      const expectedReturn = prediction.predictions[0];

      // Only trade on confident predictions
      if (Math.abs(expectedReturn) > 0.01) {
        const bar = marketData[i];
        const direction = expectedReturn > 0 ? 'long' : 'short';

        // Calculate risk-adjusted position size
        const stopLoss = bar.close * (direction === 'long' ? 0.97 : 1.03);
        const stopDistance = Math.abs(bar.close - stopLoss) / bar.close;

        const position = riskManager.calculatePositionSize(
          portfolioValue,
          bar.close,
          0.02,  // Risk 2% per trade
          stopDistance
        );

        signals.push({
          id: `ai-signal-${i}`,
          strategyId: 'neural-risk-managed',
          symbol: bar.symbol,
          direction: direction,
          confidence: Math.abs(expectedReturn),
          entryPrice: bar.close,
          stopLoss: stopLoss,
          takeProfit: bar.close * (direction === 'long' ? 1.06 : 0.94),
          positionSize: position.shares,
          reasoning: `AI: ${(expectedReturn * 100).toFixed(2)}% expected, ${position.shares} shares`,
          timestampNs: BigInt(bar.timestamp) * 1_000_000n
        });
      }
    }

    return signals;
  }

  // 3. Backtest with full integration
  const engine = new BacktestEngine({
    initialCapital: 100000,
    startDate: '2024-01-01',
    endDate: '2024-12-31',
    commission: 0.001,
    slippage: 0.0005,
    useMarkToMarket: true
  });

  const testData = loadMarketData('data/test.csv');
  const signals = await generateSmartSignals(testData, 100000);
  const result = await engine.run(signals, 'data/test.csv');

  console.log('AI + Risk-Managed Strategy Results:');
  console.log(`Total Return: ${(result.metrics.totalReturn * 100).toFixed(2)}%`);
  console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio.toFixed(2)}`);
  console.log(`Win Rate: ${(result.metrics.winRate * 100).toFixed(1)}%`);
  console.log(`Max Drawdown: ${(result.metrics.maxDrawdown * 100).toFixed(2)}%`);

  return result;
}

Full Platform Integration

Complete workflow with all packages:

const { BacktestEngine, compareBacktests } = require('@neural-trader/backtesting');
const { MomentumStrategy, MeanReversionStrategy } = require('@neural-trader/strategies');
const { NeuralModel } = require('@neural-trader/neural');
const { RiskManager } = require('@neural-trader/risk');

async function fullPlatformBacktest() {
  // Initialize all components
  const riskManager = new RiskManager({
    confidenceLevel: 0.95,
    lookbackPeriods: 252,
    method: 'historical'
  });

  const neuralModel = new NeuralModel({
    modelType: 'LSTMAttention',
    inputSize: 50,
    horizon: 5,
    hiddenSize: 256,
    numLayers: 3,
    dropout: 0.2,
    learningRate: 0.001
  });

  // Train neural model
  const trainData = prepareTrainingData('data/train.csv');
  await neuralModel.train(trainData.features, trainData.targets, {
    epochs: 100,
    batchSize: 32,
    validationSplit: 0.2,
    earlyStoppingPatience: 10,
    useGpu: true
  });

  // Test multiple strategies
  const strategies = [
    new MomentumStrategy({ lookbackPeriod: 20 }),
    new MeanReversionStrategy({ lookbackPeriod: 20, threshold: 2.0 }),
    { name: 'neural', model: neuralModel }
  ];

  const results = [];

  for (const strategy of strategies) {
    const engine = new BacktestEngine({
      initialCapital: 100000,
      startDate: '2024-01-01',
      endDate: '2024-12-31',
      commission: 0.001,
      slippage: 0.0005,
      useMarkToMarket: true
    });

    const marketData = loadMarketData('data/test.csv');
    const signals = await generateSignalsWithRisk(strategy, marketData, riskManager);
    const result = await engine.run(signals, 'data/test.csv');

    results.push(result);
  }

  // Compare all strategies
  const comparison = compareBacktests(results);
  console.log(comparison);

  // Select best strategy
  const best = results.reduce((a, b) =>
    a.metrics.sharpeRatio > b.metrics.sharpeRatio ? a : b
  );

  console.log('\n=== Best Strategy ===');
  console.log(`Sharpe Ratio: ${best.metrics.sharpeRatio.toFixed(2)}`);
  console.log(`Total Return: ${(best.metrics.totalReturn * 100).toFixed(2)}%`);
  console.log(`Max Drawdown: ${(best.metrics.maxDrawdown * 100).toFixed(2)}%`);

  return best;
}

Configuration Options

Basic Configuration

const config = {
  // Core settings
  initialCapital: 100000,      // Starting portfolio value
  startDate: '2024-01-01',     // Backtest start date (YYYY-MM-DD)
  endDate: '2024-12-31',       // Backtest end date (YYYY-MM-DD)

  // Optional settings
  commission: 0.001,           // Commission per trade side (0.1%)
  slippage: 0.0005,            // Average slippage (0.05%)
  useMarkToMarket: true        // Enable daily mark-to-market P&L
};

Advanced Configuration

const advancedConfig = {
  // Capital and dates
  initialCapital: 500000,
  startDate: '2023-01-01',
  endDate: '2024-12-31',

  // Transaction costs
  commission: 0.001,           // 0.1% commission
  slippage: 0.0005,            // 0.05% slippage

  // P&L calculation
  useMarkToMarket: true,       // Daily P&L updates

  // Position management
  maxPositionsPerSymbol: 1,    // One position per symbol
  allowShortSelling: true,     // Enable short positions

  // Execution settings
  fillOnOpen: false,           // Fill at close instead of open
  partialFills: true           // Allow partial position fills
};

Environment Variables

# Market data directory
NT_DATA_DIR=/path/to/market-data

# Performance tuning
NT_THREADS=8               # Number of threads for parallel processing

# Logging
NT_LOG_LEVEL=info         # Logging level (debug, info, warn, error)

Configuration File

Create a configuration file backtest-config.json:

{
  "backtest": {
    "initialCapital": 100000,
    "commission": 0.001,
    "slippage": 0.0005
  },
  "dateRange": {
    "startDate": "2024-01-01",
    "endDate": "2024-12-31"
  },
  "execution": {
    "useMarkToMarket": true,
    "fillOnOpen": false
  }
}

Load configuration:

const fs = require('fs');
const config = JSON.parse(fs.readFileSync('backtest-config.json', 'utf8'));
const engine = new BacktestEngine(config.backtest);

Default Configuration Values

Option Type Default Description
initialCapital number required Starting portfolio value in dollars
startDate string required Backtest start date (YYYY-MM-DD format)
endDate string required Backtest end date (YYYY-MM-DD format)
commission number 0.001 Commission per trade side (0.001 = 0.1%)
slippage number 0.0005 Average slippage per trade (0.0005 = 0.05%)
useMarkToMarket boolean true Enable daily mark-to-market P&L calculation

Performance Tips

1. Use Multi-Threaded Processing

Leverage Rust's parallel processing for walk-forward analysis:

❌ Inefficient:

// Sequential backtesting
for (const period of periods) {
  const result = await engine.run(signals[period], data[period]);
  results.push(result);
}

✅ Optimized:

// Parallel backtesting with Promise.all
const results = await Promise.all(
  periods.map(period =>
    engine.run(signals[period], data[period])
  )
);

Performance Gain: 4-8x faster on multi-core systems

2. Batch Signal Generation

Generate all signals before backtesting:

❌ Inefficient:

// Generating signals during backtest
for (const bar of marketData) {
  const signal = await strategy.analyze(bar);
  if (signal) await engine.run([signal], dataPath);
}

✅ Optimized:

// Pre-generate all signals
const signals = [];
for (const bar of marketData) {
  const signal = await strategy.analyze(bar);
  if (signal) signals.push(signal);
}
const result = await engine.run(signals, dataPath);

Performance Gain: 10-20x faster

3. Efficient Market Data Loading

Use memory-mapped files for large datasets:

const { readFileSync } = require('fs');

// Load data once, reuse for multiple backtests
const marketData = readFileSync('data/large-dataset.csv', 'utf8');

// Run multiple backtests with same data
const results = await Promise.all([
  engine1.run(signals1, marketData),
  engine2.run(signals2, marketData),
  engine3.run(signals3, marketData)
]);

4. Minimize JavaScript-Rust Boundary Crossings

Batch operations to reduce NAPI overhead:

// ✅ Single backtest call with all signals
const result = await engine.run(allSignals, dataPath);

// ❌ Multiple calls for each signal
for (const signal of signals) {
  await engine.run([signal], dataPath);
}

5. Optimize Signal Timestamps

Pre-calculate timestamps to avoid conversion overhead:

Best Practices:

  • Use BigInt for nanosecond precision timestamps
  • Pre-sort signals by timestamp before backtesting
  • Cache timestamp calculations for recurring operations
// Pre-calculate and cache timestamps
const timestamps = marketData.map(bar =>
  BigInt(bar.timestamp) * 1_000_000n
);

signals.forEach((signal, i) => {
  signal.timestampNs = timestamps[i];
});

Performance Benchmarks

Operation Time Memory Throughput
10,000 trades backtest 45ms 12MB 222,000 trades/sec
100,000 trades backtest 380ms 95MB 263,000 trades/sec
Walk-forward (8 periods) 125ms 48MB 64 periods/sec (parallel)
Equity curve calculation 2ms 1MB 5,000,000 points/sec
CSV export (10K trades) 18ms 8MB 555,000 trades/sec

vs Python (pandas/numpy):

  • 8-19x faster trade execution
  • 12-24x faster metrics calculation
  • 4-8x lower memory usage

Troubleshooting

Common Issue 1: Market Data Format Errors

Problem: Backtest fails with "Invalid market data format" error

Symptoms:

Error: Invalid market data format at line 42
Expected: timestamp,open,high,low,close,volume

Cause: CSV file doesn't match expected OHLCV format

Solution:

// ✅ Correct CSV format
// timestamp,open,high,low,close,volume
// 2024-01-01 09:30:00,150.00,151.50,149.75,151.00,1000000
// 2024-01-01 09:31:00,151.00,152.00,150.50,151.75,950000

// Validate CSV format before backtesting
function validateMarketData(filePath) {
  const fs = require('fs');
  const lines = fs.readFileSync(filePath, 'utf8').split('\n');
  const header = lines[0].toLowerCase();

  if (!header.includes('timestamp') || !header.includes('close')) {
    throw new Error('Invalid CSV format. Required: timestamp,open,high,low,close,volume');
  }

  return true;
}

Prevention: Always validate market data format before running backtests


Common Issue 2: Signal Timestamp Mismatch

Problem: Trades not executing despite valid signals

Error:

Warning: Signal timestamp outside market data range
Signal: 2024-01-15 10:30:00
Market data: 2024-01-01 to 2024-01-14

Solution:

Step 1: Verify date ranges match

# Check market data date range
head -n 2 data/market.csv
tail -n 1 data/market.csv

Step 2: Align signal timestamps with market data

// Ensure signals are within data range
function alignSignalTimestamps(signals, startDate, endDate) {
  const start = new Date(startDate).getTime() * 1_000_000;
  const end = new Date(endDate).getTime() * 1_000_000;

  return signals.filter(s =>
    s.timestampNs >= start && s.timestampNs <= end
  );
}

const validSignals = alignSignalTimestamps(signals, '2024-01-01', '2024-12-31');

Common Issue 3: Performance Degradation

Problem: Backtest runs slowly with large datasets

Quick Fix:

// Enable parallel processing
process.env.NT_THREADS = '8';  // Use 8 threads

// Batch signals before backtesting
const batchSize = 1000;
const batches = [];
for (let i = 0; i < signals.length; i += batchSize) {
  batches.push(signals.slice(i, i + batchSize));
}

// Process batches in parallel
const results = await Promise.all(
  batches.map(batch => engine.run(batch, dataPath))
);

Common Issue 4: Memory Errors with Large Equity Curves

Problem: Out of memory error during equity curve calculation

Diagnosis:

  1. Check equity curve length: result.equityCurve.length
  2. Calculate memory usage: equityCurve.length * 8 bytes
  3. Verify available memory: process.memoryUsage()

Solution: Downsample equity curve for visualization

function downsampleEquityCurve(curve, targetPoints = 1000) {
  if (curve.length <= targetPoints) return curve;

  const step = Math.floor(curve.length / targetPoints);
  return curve.filter((_, i) => i % step === 0);
}

const downsampled = downsampleEquityCurve(result.equityCurve);

Common Issue 5: Inconsistent Backtest Results

Problem: Different results on repeated backtests with same data

Solution: Ensure deterministic signal ordering

// Sort signals by timestamp before backtesting
signals.sort((a, b) => Number(a.timestampNs - b.timestampNs));

// Use consistent random seed if using randomization
const deterministicSignals = signals.map(s => ({
  ...s,
  id: `${s.symbol}-${s.timestampNs}`  // Deterministic IDs
}));

Debugging Tips

Enable Debug Logging:

process.env.NT_LOG_LEVEL = 'debug';

const engine = new BacktestEngine({
  initialCapital: 100000,
  startDate: '2024-01-01',
  endDate: '2024-12-31',
  commission: 0.001,
  slippage: 0.0005,
  useMarkToMarket: true
});

Check Configuration:

console.log('Backtest Config:', {
  initialCapital: engine.initialCapital,
  commission: engine.commission,
  slippage: engine.slippage
});

Validate Signals:

function validateSignals(signals) {
  const errors = [];

  signals.forEach((signal, i) => {
    if (!signal.entryPrice || signal.entryPrice <= 0) {
      errors.push(`Signal ${i}: Invalid entry price`);
    }
    if (!signal.timestampNs) {
      errors.push(`Signal ${i}: Missing timestamp`);
    }
    if (!['long', 'short'].includes(signal.direction)) {
      errors.push(`Signal ${i}: Invalid direction`);
    }
  });

  if (errors.length > 0) {
    console.error('Signal validation errors:', errors);
    return false;
  }

  return true;
}

if (!validateSignals(signals)) {
  throw new Error('Invalid signals detected');
}

Getting Help

If you encounter issues not covered here:

  1. Check the main documentation
  2. Search GitHub Issues
  3. Join our Discord community
  4. Email support at support@neural-trader.io

Core Packages

For Strategy Development:

npm install @neural-trader/backtesting @neural-trader/strategies @neural-trader/risk

For AI-Powered Trading:

npm install @neural-trader/backtesting @neural-trader/neural @neural-trader/risk

For Production Trading:

npm install @neural-trader/backtesting @neural-trader/execution @neural-trader/risk

Complementary Packages

Full Package List

See packages/README.md for all 18 available packages.

Contributing

Contributions are welcome! We follow the main Neural Trader contribution guidelines.

Development Setup

# Clone repository
git clone https://github.com/ruvnet/neural-trader.git
cd neural-trader/neural-trader-rust

# Install dependencies
npm install

# Build package
cd packages/backtesting
npm run build

# Run tests
npm test

# Run linter
npm run lint

Running Tests

# Unit tests
npm test

# Integration tests
npm run test:integration

# E2E tests
npm run test:e2e

# With coverage
npm run test:coverage

# Watch mode
npm run test:watch

Code Style

This package follows the Neural Trader code style:

  • TypeScript: Strict mode enabled
  • Formatting: Prettier with 2-space indentation
  • Linting: ESLint with recommended rules
  • Testing: Jest with >80% coverage requirement
# Format code
npm run format

# Lint code
npm run lint

# Type check
npm run typecheck

Contribution Workflow

  1. Fork the repository
  2. Create a feature branch: git checkout -b feat/amazing-feature
  3. Make changes and add tests
  4. Run tests and linting: npm test && npm run lint
  5. Commit changes: git commit -m 'feat: add amazing feature'
  6. Push to branch: git push origin feat/amazing-feature
  7. Open a Pull Request

Pull Request Guidelines

  • Add tests for new features
  • Update documentation
  • Follow existing code style
  • Keep changes focused and atomic
  • Write clear commit messages
  • Update CHANGELOG.md if applicable

See CONTRIBUTING.md for detailed guidelines.

License

This project is dual-licensed under MIT OR Apache-2.0.

You may choose either license at your option:

Third-Party Licenses

This package includes dependencies with the following licenses:

  • Tokio: MIT
  • Serde: MIT OR Apache-2.0
  • Rayon: MIT OR Apache-2.0

See THIRD_PARTY_LICENSES.md for complete list.

Support

Documentation

Community

Professional Support

For enterprise support, training, or custom development:

Changelog

See CHANGELOG.md for version history and release notes.

Security

For security issues, please see SECURITY.md for our security policy and reporting process.

Do not report security vulnerabilities through public GitHub issues.

Acknowledgments

  • Built with Rust for performance
  • Node.js bindings via napi-rs
  • Multi-threading with Rayon
  • Neural Trader community contributors

Disclaimer: This software is for educational and research purposes only. Trading financial instruments carries risk. Past performance does not guarantee future results. Use at your own risk.