work on new engine

This commit is contained in:
Boki 2025-07-04 11:24:27 -04:00
parent 44476da13f
commit a1e5a21847
126 changed files with 3425 additions and 6695 deletions

View file

@ -1,149 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function debugPerformanceValues() {
console.log('Debugging Performance Calculation Values...\n');
// Create minimal service container with more logging
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => {
// Log everything related to P&L and portfolio
if (msg.includes('P&L') || msg.includes('portfolio') || msg.includes('Portfolio') ||
msg.includes('equity') || msg.includes('Total') || msg.includes('pnl')) {
console.log('[INFO]', msg, ...args);
}
},
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => {
if (msg.includes('P&L') || msg.includes('portfolio') || msg.includes('pnl')) {
console.log('[DEBUG]', msg, ...args);
}
},
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Initialize backtest mode
await modeManager.initializeMode({
mode: 'backtest',
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-15T00:00:00Z', // Just 15 days
speed: 'max',
symbols: ['TEST'],
initialCapital: 100000,
dataFrequency: '1d',
strategy: 'sma-crossover'
});
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
// Run backtest
const config = {
mode: 'backtest',
name: 'Debug Performance Values',
strategy: 'sma-crossover',
symbols: ['TEST'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-15T00:00:00Z',
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
console.log('Running backtest...');
const result = await backtestEngine.runBacktest(config);
// Debug values
console.log('\n=== RAW VALUES DEBUG ===');
console.log(`Initial Capital: $${config.initialCapital}`);
console.log(`Reported Metrics:`);
console.log(` - Total Return: ${result.metrics.totalReturn}%`);
console.log(` - Sharpe Ratio: ${result.metrics.sharpeRatio}`);
console.log(` - Max Drawdown: ${result.metrics.maxDrawdown}%`);
console.log(` - Win Rate: ${result.metrics.winRate}%`);
console.log(` - Total Trades: ${result.metrics.totalTrades}`);
console.log('\n=== EQUITY CURVE VALUES ===');
console.log(`Equity Points: ${result.equity.length}`);
if (result.equity.length > 0) {
const first = result.equity[0];
const last = result.equity[result.equity.length - 1];
console.log(`First: ${first.date} => $${first.value}`);
console.log(`Last: ${last.date} => $${last.value}`);
// Manual calculation
const manualReturn = ((last.value - first.value) / first.value) * 100;
console.log(`\nManual Total Return: ${manualReturn.toFixed(2)}%`);
console.log(`Difference from reported: ${Math.abs(manualReturn - result.metrics.totalReturn).toFixed(2)}%`);
}
console.log('\n=== TRADE ANALYSIS ===');
console.log(`Closed Trades: ${result.trades.length}`);
if (result.trades.length > 0) {
const wins = result.trades.filter(t => t.pnl > 0);
const losses = result.trades.filter(t => t.pnl < 0);
const manualWinRate = (wins.length / result.trades.length) * 100;
console.log(`Wins: ${wins.length}`);
console.log(`Losses: ${losses.length}`);
console.log(`Manual Win Rate: ${manualWinRate.toFixed(2)}%`);
// Show P&L values
const totalPnL = result.trades.reduce((sum, t) => sum + t.pnl, 0);
console.log(`\nTotal P&L from trades: $${totalPnL.toFixed(2)}`);
// Show first few trades
console.log('\nFirst 3 trades:');
result.trades.slice(0, 3).forEach((t, i) => {
console.log(` ${i+1}. ${t.side} ${t.quantity} @ ${t.exitPrice} | P&L: $${t.pnl.toFixed(2)}`);
});
}
// Check trading engine P&L
const tradingEngine = strategyManager.getTradingEngine();
if (tradingEngine) {
try {
const [realized, unrealized] = tradingEngine.getTotalPnl();
console.log('\n=== TRADING ENGINE P&L ===');
console.log(`Realized P&L: $${realized.toFixed(2)}`);
console.log(`Unrealized P&L: $${unrealized.toFixed(2)}`);
console.log(`Total P&L: $${(realized + unrealized).toFixed(2)}`);
console.log(`Portfolio Value: $${(config.initialCapital + realized + unrealized).toFixed(2)}`);
} catch (e) {
console.error('Failed to get P&L from trading engine:', e);
}
}
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
debugPerformanceValues().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -6,7 +6,7 @@ The stock-bot orchestrator includes a high-performance Technical Analysis (TA) l
The TA library consists of:
1. **Rust Core**: High-performance indicator calculations in `apps/stock/core/src/indicators/`
2. **NAPI Bindings**: TypeScript interfaces exposed through `@stock-bot/core`
2. **NAPI Bindings**: TypeScript interfaces exposed through `@stock-bot/engine`
3. **TypeScript Wrapper**: Convenient API in `orchestrator/src/indicators/TechnicalAnalysis.ts`
## Available Indicators

View file

@ -3,7 +3,7 @@
* Demonstrates orderbook analytics, portfolio risk, and bet sizing
*/
import { TradingEngine, RiskAnalyzer, OrderbookAnalyzer } from '@stock-bot/core';
import { OrderbookAnalyzer, RiskAnalyzer, TradingEngine } from '@stock-bot/engine';
import { getLogger } from '@stock-bot/logger';
const logger = getLogger('AdvancedRiskExample');

View file

@ -1,4 +1,4 @@
import { TradingEngine } from '@stock-bot/core';
import { TradingEngine } from '@stock-bot/engine';
async function debugRustShortTrades() {
// Create engine config for backtest mode

View file

@ -2,8 +2,7 @@
* Examples of using the Rust-based Technical Analysis library
*/
import { TechnicalIndicators, IncrementalSMA, IncrementalEMA, IncrementalRSI } from '@stock-bot/core';
import { TechnicalAnalysis, IncrementalIndicators, SignalGenerator } from '../src/indicators/TechnicalAnalysis';
import { IncrementalIndicators, SignalGenerator, TechnicalAnalysis } from '../src/indicators/TechnicalAnalysis';
// Example 1: Basic indicator calculations
async function basicIndicatorExample() {

View file

@ -1,9 +1,9 @@
import { EventEmitter } from 'events';
import { IServiceContainer } from '@stock-bot/di';
import { BacktestEngine as RustEngine } from '@stock-bot/core';
import { BacktestConfig, BacktestResult } from '../types';
import { BacktestEngine as RustEngine } from '@stock-bot/engine';
import { EventEmitter } from 'events';
import { StorageService } from '../services/StorageService';
import { StrategyExecutor, SMACrossoverStrategy } from '../strategies/StrategyExecutor';
import { SMACrossoverStrategy, StrategyExecutor } from '../strategies/StrategyExecutor';
import { BacktestConfig, BacktestResult } from '../types';
/**
* Adapter that bridges the orchestrator with the Rust backtest engine
@ -208,7 +208,7 @@ export class RustBacktestAdapter extends EventEmitter {
}
private registerStrategy(strategyName: string, parameters: any): void {
if (!this.currentEngine) return;
if (!this.currentEngine) {return;}
this.container.logger.info('Registering strategy', {
strategyName,

View file

@ -1,8 +1,8 @@
import { BacktestEngine as RustEngine } from '@stock-bot/core';
import { RustStrategy } from '../strategies/RustStrategy';
import { MarketData, BacktestConfig } from '../types';
import { StorageService } from '../services/StorageService';
import { IServiceContainer } from '@stock-bot/di';
import { BacktestEngine as RustEngine } from '@stock-bot/engine';
import { StorageService } from '../services/StorageService';
import { RustStrategy } from '../strategies/RustStrategy';
import { BacktestConfig } from '../types';
export interface RustBacktestConfig {
name: string;

View file

@ -1,10 +1,10 @@
import { TradingEngine } from '@stock-bot/core';
import { IServiceContainer } from '@stock-bot/di';
import { TradingMode, ModeConfig, BacktestConfigSchema, PaperConfigSchema, LiveConfigSchema } from '../types';
import { MarketDataService } from '../services/MarketDataService';
import { ExecutionService } from '../services/ExecutionService';
import { StorageService } from '../services/StorageService';
import { TradingEngine } from '@stock-bot/engine';
import { EventEmitter } from 'events';
import { ExecutionService } from '../services/ExecutionService';
import { MarketDataService } from '../services/MarketDataService';
import { StorageService } from '../services/StorageService';
import { BacktestConfigSchema, LiveConfigSchema, ModeConfig, PaperConfigSchema, TradingMode } from '../types';
export class ModeManager extends EventEmitter {
private mode: TradingMode = 'paper';
@ -148,7 +148,7 @@ export class ModeManager extends EventEmitter {
}
async shutdown(): Promise<void> {
if (!this.isInitialized) return;
if (!this.isInitialized) {return;}
this.container.logger.info(`Shutting down ${this.mode} mode...`);

View file

@ -1,4 +1,4 @@
import { TechnicalIndicators, IncrementalSMA, IncrementalEMA, IncrementalRSI, MacdResult, BollingerBandsResult, StochasticResult } from '@stock-bot/core';
import { BollingerBandsResult, IncrementalEMA, IncrementalRSI, IncrementalSMA, MacdResult, StochasticResult, TechnicalIndicators } from '@stock-bot/engine';
/**
* Wrapper class for the Rust TA library with TypeScript-friendly interfaces
@ -57,7 +57,7 @@ export class TechnicalAnalysis {
// Helper to check for crossovers
static crossover(series1: number[], series2: number[]): boolean {
if (series1.length < 2 || series2.length < 2) return false;
if (series1.length < 2 || series2.length < 2) {return false;}
const prev1 = series1[series1.length - 2];
const curr1 = series1[series1.length - 1];
const prev2 = series2[series2.length - 2];
@ -66,7 +66,7 @@ export class TechnicalAnalysis {
}
static crossunder(series1: number[], series2: number[]): boolean {
if (series1.length < 2 || series2.length < 2) return false;
if (series1.length < 2 || series2.length < 2) {return false;}
const prev1 = series1[series1.length - 2];
const curr1 = series1[series1.length - 1];
const prev2 = series2[series2.length - 2];

View file

@ -1,9 +1,8 @@
import { IServiceContainer } from '@stock-bot/di';
import { TradingEngine } from '@stock-bot/engine';
import { EventEmitter } from 'events';
import { v4 as uuidv4 } from 'uuid';
import { IServiceContainer } from '@stock-bot/di';
import { ModeConfig, OrderRequest, OrderRequestSchema } from '../types';
import { TradingEngine } from '@stock-bot/core';
import axios from 'axios';
import { StorageService } from './StorageService';
interface ExecutionReport {
@ -233,7 +232,7 @@ export class ExecutionService extends EventEmitter {
}
private async processFills(executionReport: ExecutionReport): Promise<void> {
if (!this.tradingEngine) return;
if (!this.tradingEngine) {return;}
for (const fill of executionReport.fills) {
// Update position in engine

View file

@ -1,4 +1,4 @@
import { BacktestEngine } from '@stock-bot/core';
import { BacktestEngine } from '@stock-bot/engine';
import { MarketData } from '../types';
export interface Signal {

View file

@ -1,8 +1,8 @@
import { EventEmitter } from 'events';
import { IServiceContainer } from '@stock-bot/di';
import { MarketData, StrategyConfig, OrderRequest } from '../types';
import { TradingEngine } from '@stock-bot/engine';
import { EventEmitter } from 'events';
import { MarketData, OrderRequest, StrategyConfig } from '../types';
import { BaseStrategy } from './BaseStrategy';
import { TradingEngine } from '@stock-bot/core';
export class StrategyManager extends EventEmitter {
private strategies = new Map<string, BaseStrategy>();

View file

@ -1,69 +0,0 @@
import { createContainer } from './src/simple-container';
import fetch from 'node-fetch';
async function testApiResponse() {
console.log('Testing API Response Values...\n');
// First, create the container and start the server
const container = await createContainer({
database: {
mongodb: { enabled: false, uri: '' },
postgres: { enabled: false, uri: '' },
questdb: { enabled: false, host: '', port: 0 },
dragonfly: { enabled: false }
}
});
// Run a simple backtest via API
const backtestRequest = {
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01',
endDate: '2023-02-01',
initialCapital: 100000,
config: {
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d'
}
};
try {
console.log('Sending backtest request...');
const response = await fetch('http://localhost:2003/api/backtest/run', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(backtestRequest)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('\n=== API RESPONSE ===');
console.log(JSON.stringify(result, null, 2));
if (result.metrics) {
console.log('\n=== METRICS VALUES ===');
console.log(`Total Return: ${result.metrics.totalReturn}`);
console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio}`);
console.log(`Max Drawdown: ${result.metrics.maxDrawdown}`);
console.log(`Win Rate: ${result.metrics.winRate}`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
}
} catch (error) {
console.error('API call failed:', error);
}
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
testApiResponse().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,70 +0,0 @@
#!/usr/bin/env bun
/**
* Simple backtest test without full container
*/
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { getLogger } from '@stock-bot/logger';
async function runSimpleBacktest() {
console.log('Running simple backtest test...\n');
// Create minimal container
const logger = getLogger('test');
const container = {
logger,
custom: {}
};
// Create services
const storageService = new StorageService(container as any);
const strategyManager = new StrategyManager(container as any);
// Initialize strategy
await strategyManager.initializeStrategies([{
id: 'test-sma',
name: 'sma-crossover',
enabled: true,
symbols: ['AAPL'],
allocation: 1.0
}]);
// Create backtest engine
const backtestEngine = new BacktestEngine(container as any, storageService, strategyManager);
const config = {
mode: 'backtest',
name: 'Simple SMA Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-03-01T00:00:00Z', // Just 2 months
initialCapital: 100000,
dataFrequency: '1d',
commission: 0.001,
slippage: 0.0001
};
try {
const result = await backtestEngine.runBacktest(config);
console.log('\nBacktest Results:');
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
console.log(`Trades in history: ${result.trades.length}`);
console.log(`Win Rate: ${result.metrics.winRate.toFixed(2)}%`);
console.log('\nTrade Details:');
result.trades.forEach((trade, i) => {
console.log(`Trade ${i + 1}: ${trade.side} ${trade.quantity} @ $${trade.entryPrice.toFixed(2)} -> $${trade.exitPrice.toFixed(2)} (P&L: $${trade.pnl.toFixed(2)})`);
});
} catch (error) {
console.error('Backtest failed:', error);
}
}
runSimpleBacktest().catch(console.error);

View file

@ -1,99 +0,0 @@
#!/usr/bin/env bun
import { createContainer } from './src/simple-container';
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { SimpleMovingAverageCrossover } from './src/strategies/examples/SimpleMovingAverageCrossover';
async function runBacktest() {
console.log('Starting backtest test...');
// Create container with minimal config
const config = {
port: 2004,
mode: 'paper',
enableWebSocket: false,
database: {
mongodb: { enabled: false },
postgres: { enabled: false },
questdb: { enabled: false }
},
redis: {
url: 'redis://localhost:6379'
},
backtesting: {
maxConcurrent: 1,
defaultSpeed: 'max',
dataResolutions: ['1d']
},
strategies: {
maxActive: 10,
defaultTimeout: 30000
}
};
const container = await createContainer(config);
// Initialize strategy manager
const strategyManager = new StrategyManager(container.executionService, container.modeManager);
// Create and add strategy
const strategyConfig = {
id: 'sma-test',
name: 'SMA Test',
type: 'sma-crossover',
symbols: ['AA'],
active: true,
allocation: 1.0,
riskLimit: 0.02,
maxPositions: 10
};
const strategy = new SimpleMovingAverageCrossover(strategyConfig, container.modeManager, container.executionService);
await strategyManager.addStrategy(strategy);
// Create backtest engine
const backtestEngine = new BacktestEngine(container, strategyManager);
// Run backtest
const backtestConfig = {
symbols: ['AA'],
strategy: 'sma-crossover',
startDate: '2024-01-01',
endDate: '2024-12-31',
initialCapital: 100000,
commission: 0.001,
slippage: 0.0005,
dataFrequency: '1d'
};
try {
console.log('Running backtest...');
const result = await backtestEngine.runBacktest(backtestConfig);
console.log('\n=== Backtest Results ===');
console.log(`Total trades: ${result.metrics.totalTrades}`);
console.log(`Win rate: ${result.metrics.winRate.toFixed(2)}%`);
console.log(`Total return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Sharpe ratio: ${result.metrics.sharpeRatio.toFixed(2)}`);
console.log(`Max drawdown: ${result.metrics.maxDrawdown.toFixed(2)}%`);
console.log('\n=== Trade History ===');
result.trades.forEach((trade, i) => {
console.log(`Trade ${i + 1}: ${trade.side} ${trade.quantity} ${trade.symbol} @ ${trade.entryPrice.toFixed(2)}`);
if (trade.exitDate) {
console.log(` Exit: ${trade.exitPrice.toFixed(2)}, P&L: ${trade.pnl.toFixed(2)} (${trade.pnlPercent.toFixed(2)}%)`);
}
});
console.log(`\nTotal trades in result: ${result.trades.length}`);
} catch (error) {
console.error('Backtest failed:', error);
} finally {
// Cleanup
await container.shutdownManager.shutdown();
process.exit(0);
}
}
runBacktest().catch(console.error);

View file

@ -1,138 +0,0 @@
#!/usr/bin/env bun
/**
* Test with very clear crossover patterns
*/
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { getLogger } from '@stock-bot/logger';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { DataManager } from './src/data/DataManager';
async function testClearCrossovers() {
console.log('=== Test with Clear Crossovers ===\n');
const logger = getLogger('test');
const container = {
logger,
custom: {}
};
const storageService = new StorageService(container as any);
const marketDataService = new MarketDataService(container as any);
const executionService = new ExecutionService(container as any);
const modeManager = new ModeManager(container as any, marketDataService, executionService, storageService);
container.custom = {
ModeManager: modeManager,
MarketDataService: marketDataService,
ExecutionService: executionService
};
const strategyManager = new StrategyManager(container as any);
const backtestEngine = new BacktestEngine(container as any, storageService, strategyManager);
// Override data loading to provide clear patterns
const dataManager = new DataManager(container as any, storageService);
(backtestEngine as any).dataManager = dataManager;
(dataManager as any).loadHistoricalData = async (symbols: string[], startDate: Date, endDate: Date) => {
const data = new Map();
const bars = [];
console.log('Generating clear crossover patterns...');
// Generate 100 days of data with 3 clear crossovers
// Pattern: Start high, go low (death cross), go high (golden cross), go low (death cross)
for (let i = 0; i < 100; i++) {
let price;
if (i < 20) {
// Start at 100, slight upward trend
price = 100 + i * 0.5;
} else if (i < 40) {
// Sharp downtrend from 110 to 70 (death cross around day 30)
price = 110 - (i - 20) * 2;
} else if (i < 60) {
// Sharp uptrend from 70 to 110 (golden cross around day 50)
price = 70 + (i - 40) * 2;
} else if (i < 80) {
// Sharp downtrend from 110 to 70 (death cross around day 70)
price = 110 - (i - 60) * 2;
} else {
// Stabilize around 70
price = 70 + Math.sin((i - 80) * 0.3) * 2;
}
const timestamp = startDate.getTime() + i * 86400000;
bars.push({
type: 'bar',
data: {
symbol: 'AAPL',
open: price - 0.5,
high: price + 1,
low: price - 1,
close: price,
volume: 1000000,
timestamp
}
});
if (i % 10 === 0) {
console.log(`Day ${i + 1}: Price = $${price.toFixed(2)}`);
}
}
console.log('\nExpected crossovers:');
console.log('- Death cross around day 30');
console.log('- Golden cross around day 50');
console.log('- Death cross around day 70\n');
data.set('AAPL', bars);
return data;
};
const config = {
mode: 'backtest' as const,
name: 'Clear Crossovers Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-04-10T00:00:00Z', // 100 days
initialCapital: 100000,
dataFrequency: '1d',
commission: 0.001,
slippage: 0.0001,
speed: 'max' as const
};
await modeManager.initializeMode(config);
try {
const result = await backtestEngine.runBacktest(config);
console.log('\n=== Backtest Results ===');
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
console.log(`Trades in history: ${result.trades.length}`);
console.log(`Win Rate: ${result.metrics.winRate.toFixed(2)}%`);
console.log('\nTrade Details:');
result.trades.forEach((trade, i) => {
const entry = new Date(trade.entryDate).toLocaleDateString();
const exit = trade.exitDate ? new Date(trade.exitDate).toLocaleDateString() : 'OPEN';
console.log(`Trade ${i + 1}: ${trade.side} ${trade.quantity} @ $${trade.entryPrice.toFixed(2)} (${entry}) -> ${exit === 'OPEN' ? 'OPEN' : `$${trade.exitPrice.toFixed(2)} (${exit})`} | P&L: ${trade.pnl.toFixed(2)}`);
});
} catch (error) {
console.error('Backtest failed:', error);
}
}
testClearCrossovers().catch(console.error);

View file

@ -1,120 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testCommissionDetailed() {
// Create service container with minimal logging
const container: IServiceContainer = {
logger: {
info: () => {},
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: () => {},
debug: () => {},
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Test with moderate commission and slippage
const config = {
mode: 'backtest',
name: 'Commission Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-02-28T00:00:00Z', // 2 months
initialCapital: 10000,
commission: 0.002, // 0.2% commission
slippage: 0.001, // 0.1% slippage
dataFrequency: '1d',
speed: 'max'
};
await modeManager.initializeMode(config);
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
console.log('\n=== COMMISSION & SLIPPAGE TEST ===');
console.log(`Initial Capital: $${config.initialCapital}`);
console.log(`Commission: ${(config.commission * 100).toFixed(2)}%`);
console.log(`Slippage: ${(config.slippage * 100).toFixed(2)}%`);
const result = await backtestEngine.runBacktest(config);
// Get P&L from Rust
const tradingEngine = strategyManager.getTradingEngine();
const [realized, unrealized] = tradingEngine.getTotalPnl();
console.log('\n=== RESULTS ===');
console.log(`Total Trades: ${result.trades.length}`);
console.log(`Final Portfolio Value: $${result.equity[result.equity.length - 1].value.toFixed(2)}`);
console.log(`Realized P&L: $${realized.toFixed(2)}`);
console.log(`Unrealized P&L: $${unrealized.toFixed(2)}`);
if (result.trades.length > 0) {
console.log('\n=== TRADE DETAILS ===');
let totalCommission = 0;
let totalSlippageCost = 0;
result.trades.slice(0, 5).forEach((trade, idx) => {
const entryValue = trade.quantity * trade.entryPrice;
const exitValue = trade.quantity * trade.exitPrice;
// Calculate expected slippage
// For a buy entry, we pay more (positive slippage)
// For a sell entry (short), we receive less (negative slippage)
const entrySlippage = trade.side === 'buy' ?
entryValue * config.slippage :
-entryValue * config.slippage;
// For exit, it's opposite
const exitSlippage = trade.side === 'buy' ?
-exitValue * config.slippage :
exitValue * config.slippage;
const expectedCommission = (entryValue + exitValue) * config.commission;
const slippageCost = entrySlippage + exitSlippage;
totalCommission += trade.commission;
totalSlippageCost += slippageCost;
console.log(`\nTrade ${idx + 1}: ${trade.symbol} ${trade.side}`);
console.log(` Quantity: ${trade.quantity} shares`);
console.log(` Entry: $${trade.entryPrice.toFixed(2)} (value: $${entryValue.toFixed(2)})`);
console.log(` Exit: $${trade.exitPrice.toFixed(2)} (value: $${exitValue.toFixed(2)})`);
console.log(` Commission: $${trade.commission.toFixed(2)} (expected: $${expectedCommission.toFixed(2)})`);
console.log(` Slippage Cost: $${slippageCost.toFixed(2)}`);
console.log(` Gross P&L: $${(exitValue - entryValue).toFixed(2)}`);
console.log(` Net P&L: $${trade.pnl.toFixed(2)}`);
});
console.log(`\n=== TOTALS ===`);
console.log(`Total Commission Paid: $${totalCommission.toFixed(2)}`);
console.log(`Total Slippage Cost: $${totalSlippageCost.toFixed(2)}`);
console.log(`Total Trading Costs: $${(totalCommission + totalSlippageCost).toFixed(2)}`);
}
process.exit(0);
}
testCommissionDetailed().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,123 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testCommissionSlippage() {
console.log('Testing Commission and Slippage...\n');
// Create service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => console.log('[INFO]', msg, ...args),
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Test with high commission and slippage
const config = {
mode: 'backtest',
name: 'Commission Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-31T00:00:00Z',
initialCapital: 10000,
commission: 0.01, // 1% commission (very high for testing)
slippage: 0.005, // 0.5% slippage (very high for testing)
dataFrequency: '1d',
speed: 'max'
};
// Initialize backtest mode
await modeManager.initializeMode(config);
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
console.log('Running backtest with:');
console.log(` Initial Capital: $${config.initialCapital}`);
console.log(` Commission: ${(config.commission * 100).toFixed(1)}%`);
console.log(` Slippage: ${(config.slippage * 100).toFixed(1)}%`);
try {
const result = await backtestEngine.runBacktest(config);
console.log('\n=== RESULTS ===');
console.log(`Initial Capital: $${config.initialCapital}`);
console.log(`Final Value: $${result.equity[result.equity.length - 1].value.toFixed(2)}`);
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
// Check trades for commission
if (result.trades.length > 0) {
console.log('\nFirst 3 trades with commission:');
result.trades.slice(0, 3).forEach((t, idx) => {
const tradeValue = t.quantity * t.entryPrice;
const expectedCommission = tradeValue * config.commission;
const totalCost = tradeValue + expectedCommission;
console.log(`\n${idx + 1}. ${t.symbol} ${t.side} ${t.quantity} shares`);
console.log(` Entry Price: $${t.entryPrice.toFixed(2)}`);
console.log(` Exit Price: $${t.exitPrice.toFixed(2)}`);
console.log(` Trade Value: $${tradeValue.toFixed(2)}`);
console.log(` Commission: $${t.commission.toFixed(2)} (expected: $${expectedCommission.toFixed(2)})`);
console.log(` P&L: $${t.pnl.toFixed(2)}`);
});
}
// Compare with zero commission/slippage
const zeroConfig = {
...config,
commission: 0,
slippage: 0
};
await modeManager.initializeMode(zeroConfig);
const zeroResult = await backtestEngine.runBacktest(zeroConfig);
console.log('\n=== COMPARISON ===');
console.log('With commission/slippage:');
console.log(` Final Value: $${result.equity[result.equity.length - 1].value.toFixed(2)}`);
console.log(` Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log('\nWithout commission/slippage:');
console.log(` Final Value: $${zeroResult.equity[zeroResult.equity.length - 1].value.toFixed(2)}`);
console.log(` Total Return: ${zeroResult.metrics.totalReturn.toFixed(2)}%`);
const difference = zeroResult.equity[zeroResult.equity.length - 1].value - result.equity[result.equity.length - 1].value;
console.log(`\nCost of commission/slippage: $${difference.toFixed(2)}`);
} catch (error) {
console.error('Backtest failed:', error);
}
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
testCommissionSlippage().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,41 +0,0 @@
import { PerformanceAnalyzer } from './src/analytics/PerformanceAnalyzer';
// Test with simple data
const analyzer = new PerformanceAnalyzer(100000);
// Add some equity points over 30 days
const startDate = new Date('2023-01-01');
const values = [
100000, 101000, 100500, 102000, 101500,
103000, 102500, 104000, 103500, 105000,
104500, 106000, 105500, 107000, 106500,
108000, 107500, 109000, 108500, 110000
];
for (let i = 0; i < values.length; i++) {
const date = new Date(startDate);
date.setDate(date.getDate() + i);
analyzer.addEquityPoint(date, values[i]);
console.log(`Day ${i + 1}: ${date.toISOString().split('T')[0]} => $${values[i]}`);
}
console.log('\n=== Analyzing Performance ===');
const metrics = analyzer.analyze();
console.log(`\nTotal Return: ${metrics.totalReturn.toFixed(2)}%`);
console.log(`Annualized Return: ${metrics.annualizedReturn.toFixed(2)}%`);
console.log(`Volatility: ${metrics.volatility.toFixed(2)}%`);
console.log(`Sharpe Ratio: ${metrics.sharpeRatio.toFixed(3)}`);
// Debug calculations
const finalValue = 110000;
const initialValue = 100000;
const totalReturn = ((finalValue - initialValue) / initialValue) * 100;
const days = 19;
const years = days / 365;
const annualizedReturn = (Math.pow(1 + totalReturn/100, 1/years) - 1) * 100;
console.log('\n=== Manual Calculations ===');
console.log(`Total Return: ${totalReturn.toFixed(2)}%`);
console.log(`Years: ${years.toFixed(4)}`);
console.log(`Annualized Return: ${annualizedReturn.toFixed(2)}%`);

View file

@ -1,73 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function debugEquityCurve() {
// Create service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => console.log('[INFO]', msg, ...args),
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Test with 5000 initial capital
const config = {
mode: 'backtest',
name: 'Debug',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-05T00:00:00Z', // Just 5 days
initialCapital: 5000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
await modeManager.initializeMode(config);
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
console.log('Before runBacktest - checking backtestEngine state...');
const result = await backtestEngine.runBacktest(config);
console.log('\n=== EQUITY CURVE DEBUG ===');
console.log(`Config Initial Capital: $${config.initialCapital}`);
console.log(`Number of equity points: ${result.equity.length}`);
// Show all equity points
result.equity.forEach((point, idx) => {
console.log(` ${idx}: ${point.date} -> $${point.value.toFixed(2)}`);
});
process.exit(0);
}
debugEquityCurve().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,95 +0,0 @@
import { createContainer } from './src/simple-container';
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
async function testEquityCurveSpikeFixture() {
console.log('Testing equity curve spike fix...\n');
// Create minimal container
const container = await createContainer({
database: {
mongodb: { enabled: false, uri: '' },
postgres: { enabled: false, uri: '' },
questdb: { enabled: false, host: '', port: 0 }
}
});
// Create services
const storageService = new StorageService(container);
const strategyManager = new StrategyManager(container);
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
// Run a quick backtest
const config = {
mode: 'backtest',
name: 'Equity Curve Spike Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-31T00:00:00Z', // Just one month
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
console.log('Running backtest...');
const result = await backtestEngine.runBacktest(config);
// Check the equity curve
console.log('\n=== Equity Curve Analysis ===');
console.log(`Initial Capital: $${config.initialCapital}`);
console.log(`Total equity points: ${result.equity.length}`);
if (result.equity.length > 0) {
// Check first few points
console.log('\nFirst 5 equity curve points:');
result.equity.slice(0, 5).forEach((point, index) => {
console.log(`${index + 1}. ${point.date}: $${point.value.toFixed(2)}`);
});
// Check for spike
const firstValue = result.equity[0].value;
const secondValue = result.equity.length > 1 ? result.equity[1].value : firstValue;
console.log(`\nFirst equity value: $${firstValue.toFixed(2)}`);
console.log(`Second equity value: $${secondValue.toFixed(2)}`);
// Check if there's a spike from 0 to initial capital
if (firstValue === 0 || firstValue < config.initialCapital * 0.5) {
console.log('\n❌ SPIKE DETECTED: First equity value is too low!');
} else if (Math.abs(firstValue - config.initialCapital) < 1) {
console.log('\n✅ NO SPIKE: First equity value correctly starts at initial capital!');
} else {
console.log(`\n⚠ First equity value differs from initial capital by $${Math.abs(firstValue - config.initialCapital).toFixed(2)}`);
}
// Check for duplicate timestamps
const timestamps = new Set();
let duplicates = 0;
result.equity.forEach(point => {
if (timestamps.has(point.date)) {
duplicates++;
}
timestamps.add(point.date);
});
if (duplicates > 0) {
console.log(`\n⚠ Found ${duplicates} duplicate timestamps in equity curve`);
} else {
console.log('\n✅ No duplicate timestamps found');
}
}
console.log('\n=== Test Complete ===');
process.exit(0);
}
testEquityCurveSpikeFixture().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,105 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testEquitySpike() {
console.log('Testing equity curve spike fix...\n');
// Create minimal service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => console.log('[INFO]', msg, ...args),
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Initialize backtest mode
await modeManager.initializeMode({
mode: 'backtest',
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-10T00:00:00Z', // Just 10 days
speed: 'max',
symbols: ['TEST'],
initialCapital: 100000,
dataFrequency: '1d',
strategy: 'sma-crossover'
});
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
// Run backtest
const config = {
mode: 'backtest',
name: 'Equity Spike Test',
strategy: 'sma-crossover',
symbols: ['TEST'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-10T00:00:00Z',
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
console.log('Running backtest...');
const result = await backtestEngine.runBacktest(config);
// Analyze equity curve
console.log('\n=== EQUITY CURVE ANALYSIS ===');
console.log(`Initial Capital: $${config.initialCapital.toLocaleString()}`);
console.log(`Equity points: ${result.equity.length}`);
if (result.equity.length > 0) {
console.log('\nFirst 3 equity points:');
result.equity.slice(0, 3).forEach((point, i) => {
console.log(` ${i + 1}. ${point.date} => $${point.value.toFixed(2)}`);
});
const firstValue = result.equity[0].value;
const hasSpike = firstValue === 0 || firstValue < config.initialCapital * 0.9;
console.log(`\nFirst value: $${firstValue.toFixed(2)}`);
console.log(`Expected: $${config.initialCapital.toFixed(2)}`);
console.log(`Difference: $${Math.abs(firstValue - config.initialCapital).toFixed(2)}`);
if (hasSpike) {
console.log('\n❌ SPIKE DETECTED! Portfolio value starts at 0 or too low.');
} else if (Math.abs(firstValue - config.initialCapital) < 1) {
console.log('\n✅ SUCCESS! Portfolio value correctly starts at initial capital.');
} else {
console.log('\n⚠ WARNING: Small difference detected, but no major spike.');
}
}
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
testEquitySpike().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,130 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testFullBacktest() {
console.log('Testing Full Backtest with Real Data...\n');
// Create service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => console.log('[INFO]', msg, ...args),
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Test configuration matching what frontend might send
const config = {
mode: 'backtest',
name: 'Full Test',
strategy: 'sma-crossover',
symbols: ['AAPL', 'MSFT', 'GOOGL'], // Multiple symbols
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-12-31T00:00:00Z', // Full year
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
// Initialize backtest mode
await modeManager.initializeMode(config);
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
console.log('Running full year backtest with multiple symbols...');
const startTime = Date.now();
try {
const result = await backtestEngine.runBacktest(config);
const duration = (Date.now() - startTime) / 1000;
console.log(`\nBacktest completed in ${duration.toFixed(2)} seconds`);
// Check for data anomalies
console.log('\n=== RESULT ANALYSIS ===');
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio.toFixed(3)}`);
console.log(`Max Drawdown: ${(result.metrics.maxDrawdown * 100).toFixed(2)}%`);
console.log(`Win Rate: ${result.metrics.winRate.toFixed(1)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
console.log(`Trades Array Length: ${result.trades.length}`);
// Check equity curve
console.log('\n=== EQUITY CURVE CHECK ===');
console.log(`Equity Points: ${result.equity.length}`);
if (result.equity.length > 0) {
const first = result.equity[0];
const last = result.equity[result.equity.length - 1];
const max = Math.max(...result.equity.map(e => e.value));
const min = Math.min(...result.equity.map(e => e.value));
console.log(`First: $${first.value.toFixed(2)}`);
console.log(`Last: $${last.value.toFixed(2)}`);
console.log(`Max: $${max.toFixed(2)}`);
console.log(`Min: $${min.toFixed(2)}`);
// Check for exponential growth
const growthRatio = last.value / first.value;
if (growthRatio > 10) {
console.log('\n⚠ WARNING: Detected possible exponential growth!');
console.log(`Growth ratio: ${growthRatio.toFixed(2)}x`);
}
}
// Sample some trades
console.log('\n=== TRADE SAMPLES ===');
if (result.trades.length > 0) {
console.log('First 3 trades:');
result.trades.slice(0, 3).forEach((t, i) => {
console.log(` ${i+1}. ${t.symbol} ${t.side} ${t.quantity} @ ${t.exitPrice.toFixed(2)} | P&L: $${t.pnl.toFixed(2)} (${t.pnlPercent.toFixed(2)}%)`);
});
if (result.trades.length > 3) {
console.log('\nLast 3 trades:');
result.trades.slice(-3).forEach((t, i) => {
console.log(` ${i+1}. ${t.symbol} ${t.side} ${t.quantity} @ ${t.exitPrice.toFixed(2)} | P&L: $${t.pnl.toFixed(2)} (${t.pnlPercent.toFixed(2)}%)`);
});
}
}
// Check raw metrics object
console.log('\n=== RAW METRICS ===');
console.log(JSON.stringify(result.metrics, null, 2));
} catch (error) {
console.error('Backtest failed:', error);
}
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
testFullBacktest().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,93 +0,0 @@
#!/usr/bin/env bun
/**
* Test the full flow from market data to trade execution
*/
import { SimpleMovingAverageCrossover } from './src/strategies/examples/SimpleMovingAverageCrossover';
import { BaseStrategy } from './src/strategies/BaseStrategy';
import { MarketData } from './src/types';
import { getLogger } from '@stock-bot/logger';
const logger = getLogger('test-flow');
async function testFullFlow() {
console.log('Testing full flow from market data to orders...\n');
// Create strategy
const config = {
id: 'test-sma',
name: 'Test SMA',
enabled: true,
symbols: ['AAPL'],
allocation: 1.0
};
const strategy = new SimpleMovingAverageCrossover(config, null, null);
let signalCount = 0;
let orderCount = 0;
// Listen for signals
strategy.on('signal', (signal) => {
signalCount++;
logger.info(`Signal #${signalCount}:`, signal);
});
// Listen for orders
strategy.on('order', (order) => {
orderCount++;
logger.info(`Order #${orderCount}:`, order);
});
await strategy.start();
// Generate 50 days of data with a clear uptrend after day 20
logger.info('Generating market data with uptrend...');
for (let day = 0; day < 50; day++) {
const basePrice = 100;
let price = basePrice;
// Create a clear uptrend after day 20
if (day > 20) {
price = basePrice + (day - 20) * 0.5; // 50 cents per day uptrend
} else {
price = basePrice + Math.sin(day * 0.3) * 2; // Sideways
}
const marketData: MarketData = {
type: 'bar',
data: {
symbol: 'AAPL',
open: price - 0.5,
high: price + 0.5,
low: price - 1,
close: price,
volume: 1000000,
timestamp: Date.now() + day * 86400000
}
};
// Process the data
await strategy.onMarketData(marketData);
if (day === 19) {
logger.info(`Day 19: Last day before uptrend, price = ${price}`);
}
if (day === 25) {
logger.info(`Day 25: Should see golden cross soon, price = ${price}`);
}
}
await strategy.stop();
console.log('\n=== Test Results ===');
console.log(`Total signals generated: ${signalCount}`);
console.log(`Total orders generated: ${orderCount}`);
const perf = strategy.getPerformance();
console.log('Strategy performance:', perf);
}
testFullFlow().catch(console.error);

View file

@ -1,122 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testInitialCapitalDebug() {
console.log('Debugging Initial Capital Issue...\n');
// Create service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => console.log('[INFO]', msg, ...args),
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Test with LOW initial capital
const config = {
mode: 'backtest',
name: 'Initial Capital Debug',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-31T00:00:00Z', // Just one month
initialCapital: 1000, // LOW CAPITAL
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
// Initialize backtest mode
await modeManager.initializeMode(config);
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
console.log('Running backtest with initial capital: $' + config.initialCapital);
try {
const result = await backtestEngine.runBacktest(config);
console.log('\n=== DEBUG INFO ===');
console.log(`Initial Capital: $${config.initialCapital}`);
// Check equity curve
console.log('\nEquity Curve:');
result.equity.forEach((point, idx) => {
if (idx < 3 || idx >= result.equity.length - 3) {
console.log(` ${new Date(point.timestamp).toISOString()}: $${point.value.toFixed(2)}`);
}
if (idx === 3 && result.equity.length > 6) {
console.log(' ...');
}
});
// Get trading engine to check P&L
const tradingEngine = strategyManager.getTradingEngine();
if (tradingEngine) {
const [realized, unrealized] = tradingEngine.getTotalPnl();
console.log(`\nRust Core P&L:`);
console.log(` Realized: $${realized.toFixed(2)}`);
console.log(` Unrealized: $${unrealized.toFixed(2)}`);
console.log(` Total P&L: $${(realized + unrealized).toFixed(2)}`);
console.log(` Expected Final Value: $${(config.initialCapital + realized + unrealized).toFixed(2)}`);
}
// Check trades
console.log('\nTrades:');
result.trades.forEach((t, idx) => {
console.log(` ${idx + 1}. ${t.symbol} ${t.side} ${t.quantity} @ $${t.entryPrice} -> $${t.exitPrice}`);
console.log(` P&L: $${t.pnl.toFixed(2)} (${t.pnlPercent.toFixed(2)}%)`);
});
// The issue calculation
const finalValue = result.equity[result.equity.length - 1].value;
console.log('\n=== ISSUE ANALYSIS ===');
console.log(`Final portfolio value: $${finalValue.toFixed(2)}`);
console.log(`Initial capital: $${config.initialCapital}`);
console.log(`Difference: $${(finalValue - config.initialCapital).toFixed(2)}`);
console.log(`Return %: ${((finalValue - config.initialCapital) / config.initialCapital * 100).toFixed(2)}%`);
// Check if it's using 100k
const assumedInitial = 100000;
const assumedReturn = (finalValue - assumedInitial) / assumedInitial * 100;
console.log(`\nIf initial was $100k:`);
console.log(` Return would be: ${assumedReturn.toFixed(2)}%`);
console.log(` P&L would be: $${(finalValue - assumedInitial).toFixed(2)}`);
} catch (error) {
console.error('Backtest failed:', error);
}
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
testInitialCapitalDebug().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,87 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testSimple() {
// Create service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => {},
error: (msg: string, ...args: any[]) => {},
warn: (msg: string, ...args: any[]) => {},
debug: (msg: string, ...args: any[]) => {},
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Test with 1000 initial capital
const config = {
mode: 'backtest',
name: 'Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-31T00:00:00Z',
initialCapital: 1000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
await modeManager.initializeMode(config);
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
const result = await backtestEngine.runBacktest(config);
// Get P&L from Rust
const tradingEngine = strategyManager.getTradingEngine();
const [realized, unrealized] = tradingEngine.getTotalPnl();
console.log('\n=== RESULTS ===');
console.log(`Config Initial Capital: $${config.initialCapital}`);
console.log(`First Equity Value: $${result.equity[0].value.toFixed(2)}`);
console.log(`Final Equity Value: $${result.equity[result.equity.length - 1].value.toFixed(2)}`);
console.log(`\nRust Core:`);
console.log(` Realized P&L: $${realized.toFixed(2)}`);
console.log(` Unrealized P&L: $${unrealized.toFixed(2)}`);
console.log(` Total P&L: $${(realized + unrealized).toFixed(2)}`);
console.log(`\nCalculated Final Value:`);
console.log(` $${config.initialCapital} + $${(realized + unrealized).toFixed(2)} = $${(config.initialCapital + realized + unrealized).toFixed(2)}`);
console.log(`\nActual vs Expected:`);
const actualFinal = result.equity[result.equity.length - 1].value;
const expectedFinal = config.initialCapital + realized + unrealized;
console.log(` Actual: $${actualFinal.toFixed(2)}`);
console.log(` Expected: $${expectedFinal.toFixed(2)}`);
console.log(` Difference: $${(actualFinal - expectedFinal).toFixed(2)}`);
// Check if it's using 100k base
if (Math.abs(actualFinal - (100000 + realized + unrealized)) < 1) {
console.log('\n⚠ BUG CONFIRMED: Using 100000 as base instead of ' + config.initialCapital);
}
process.exit(0);
}
testSimple().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,104 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testInitialCapital() {
console.log('Testing Initial Capital Issue...\n');
// Create service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => console.log('[INFO]', msg, ...args),
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Test with LOW initial capital
const config = {
mode: 'backtest',
name: 'Initial Capital Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-31T00:00:00Z', // Just one month
initialCapital: 1000, // LOW CAPITAL
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
// Initialize backtest mode
await modeManager.initializeMode(config);
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
console.log('Running backtest with initial capital: $' + config.initialCapital);
try {
const result = await backtestEngine.runBacktest(config);
console.log('\n=== RESULTS ===');
console.log(`Initial Capital: $${config.initialCapital}`);
console.log(`Final Value: $${result.equity[result.equity.length - 1].value.toFixed(2)}`);
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
// Check if portfolio grew from 1000
const finalValue = result.equity[result.equity.length - 1].value;
const expectedRange = config.initialCapital * 0.5; // Within 50% of initial
if (Math.abs(finalValue - config.initialCapital) > expectedRange &&
Math.abs(finalValue - 100000) < expectedRange) {
console.log('\n⚠ WARNING: Portfolio appears to be using 100000 as initial capital!');
} else {
console.log('\n✅ Portfolio appears to be using correct initial capital');
}
// Check first few trades
if (result.trades.length > 0) {
console.log('\nFirst trade:');
const t = result.trades[0];
console.log(` ${t.symbol} ${t.side} ${t.quantity} shares @ $${t.entryPrice}`);
console.log(` Trade value: $${(t.quantity * t.entryPrice).toFixed(2)}`);
if (t.quantity * t.entryPrice > config.initialCapital) {
console.log(' ⚠️ WARNING: Trade size exceeds initial capital!');
}
}
} catch (error) {
console.error('Backtest failed:', error);
}
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
testInitialCapital().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,187 +0,0 @@
import { RustBacktestAdapter } from './src/backtest/RustBacktestAdapter';
import { IServiceContainer } from '@stock-bot/di';
import { BacktestConfig } from './src/types';
// Mock container
const mockContainer: IServiceContainer = {
logger: {
info: console.log,
error: console.error,
warn: console.warn,
debug: console.log,
},
mongodb: {} as any,
postgres: {} as any,
redis: {} as any,
custom: {},
} as IServiceContainer;
// Mock storage service that returns test data
class MockStorageService {
async getHistoricalBars(symbol: string, startDate: Date, endDate: Date, frequency: string) {
console.log(`MockStorageService: Getting bars for ${symbol} from ${startDate} to ${endDate}`);
// Generate test data with mean reverting behavior
const bars = [];
const startTime = startDate.getTime();
const endTime = endDate.getTime();
const dayMs = 24 * 60 * 60 * 1000;
let time = startTime;
let dayIndex = 0;
// Base prices for different symbols
const basePrices = {
'AAPL': 150,
'GOOGL': 2800,
'MSFT': 400,
};
const basePrice = basePrices[symbol as keyof typeof basePrices] || 100;
while (time <= endTime) {
// Create mean reverting price movement
// Price oscillates around the base price with increasing then decreasing deviations
const cycleLength = 40; // 40 day cycle
const positionInCycle = dayIndex % cycleLength;
const halfCycle = cycleLength / 2;
let deviation;
if (positionInCycle < halfCycle) {
// First half: price moves away from mean
deviation = (positionInCycle / halfCycle) * 0.1; // Up to 10% deviation
} else {
// Second half: price reverts to mean
deviation = ((cycleLength - positionInCycle) / halfCycle) * 0.1;
}
// Alternate between above and below mean
const cycleNumber = Math.floor(dayIndex / cycleLength);
const multiplier = cycleNumber % 2 === 0 ? 1 : -1;
const price = basePrice * (1 + multiplier * deviation);
// Add some noise
const noise = (Math.random() - 0.5) * 0.02 * basePrice;
const finalPrice = price + noise;
bars.push({
timestamp: new Date(time),
open: finalPrice * 0.99,
high: finalPrice * 1.01,
low: finalPrice * 0.98,
close: finalPrice,
volume: 1000000,
vwap: finalPrice,
});
time += dayMs;
dayIndex++;
}
console.log(`Generated ${bars.length} bars for ${symbol}, first close: ${bars[0].close.toFixed(2)}, last close: ${bars[bars.length - 1].close.toFixed(2)}`);
return bars;
}
}
// Test the backtest
async function testMeanReversionBacktest() {
console.log('=== Testing Mean Reversion Backtest ===\n');
// Create adapter with mock storage
const adapter = new RustBacktestAdapter(mockContainer);
(adapter as any).storageService = new MockStorageService();
const config: BacktestConfig = {
name: 'Mean Reversion Test',
strategy: 'mean_reversion',
symbols: ['AAPL', 'GOOGL', 'MSFT'],
startDate: '2024-01-01T00:00:00Z',
endDate: '2024-06-01T00:00:00Z',
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
config: {
lookbackPeriod: 20,
entryThreshold: 2.0,
positionSize: 100,
},
};
try {
console.log('Starting backtest...\n');
const result = await adapter.runBacktest(config);
console.log('\n=== Backtest Results ===');
console.log(`Status: ${result.status}`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
console.log(`Profitable Trades: ${result.metrics.profitableTrades}`);
console.log(`Win Rate: ${result.metrics.winRate.toFixed(2)}%`);
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio.toFixed(2)}`);
console.log(`Max Drawdown: ${result.metrics.maxDrawdown.toFixed(2)}%`);
console.log('\n=== Trade Analysis ===');
console.log(`Number of completed trades: ${result.trades.length}`);
// Analyze trades by symbol
const tradesBySymbol: Record<string, any[]> = {};
result.trades.forEach(trade => {
if (!tradesBySymbol[trade.symbol]) {
tradesBySymbol[trade.symbol] = [];
}
tradesBySymbol[trade.symbol].push(trade);
});
Object.entries(tradesBySymbol).forEach(([symbol, trades]) => {
console.log(`\n${symbol}: ${trades.length} trades`);
const longTrades = trades.filter(t => t.side === 'long');
const shortTrades = trades.filter(t => t.side === 'short');
console.log(` - Long trades: ${longTrades.length}`);
console.log(` - Short trades: ${shortTrades.length}`);
// Count buy/sell pairs
const buyTrades = trades.filter(t => t.side === 'buy');
const sellTrades = trades.filter(t => t.side === 'sell');
console.log(` - Buy trades: ${buyTrades.length}`);
console.log(` - Sell trades: ${sellTrades.length}`);
// Show first few trades
console.log(` - First 3 trades:`);
trades.slice(0, 3).forEach((trade, idx) => {
console.log(` ${idx + 1}. Trade:`, JSON.stringify(trade, null, 2));
});
});
// Analyze trade pairing
console.log('\n=== Trade Pairing Analysis ===');
console.log(`Total fills: ${result.trades.length}`);
console.log(`Expected pairs: ${result.trades.length / 2}`);
// Look for patterns that show instant buy/sell
let instantPairs = 0;
for (let i = 1; i < result.trades.length; i++) {
const prev = result.trades[i-1];
const curr = result.trades[i];
if (prev.symbol === curr.symbol &&
prev.side === 'buy' && curr.side === 'sell' &&
new Date(curr.timestamp).getTime() - new Date(prev.timestamp).getTime() < 86400000) {
instantPairs++;
}
}
console.log(`Instant buy/sell pairs (< 1 day): ${instantPairs}`);
// Final positions
console.log('\n=== Final Positions ===');
Object.entries(result.finalPositions).forEach(([symbol, position]) => {
console.log(`${symbol}: ${position}`);
});
} catch (error) {
console.error('Backtest failed:', error);
}
}
// Run the test
testMeanReversionBacktest().catch(console.error);

View file

@ -1,80 +0,0 @@
#!/usr/bin/env bun
/**
* Minimal test to debug order flow
*/
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { getLogger } from '@stock-bot/logger';
import { TradingEngine } from '@stock-bot/core';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
async function testMinimalBacktest() {
console.log('=== Minimal Backtest Test ===\n');
const logger = getLogger('test');
const container = {
logger,
custom: {}
};
const storageService = new StorageService(container as any);
const marketDataService = new MarketDataService(container as any);
const executionService = new ExecutionService(container as any);
const modeManager = new ModeManager(container as any, marketDataService, executionService, storageService);
// Add services to container
container.custom = {
ModeManager: modeManager,
MarketDataService: marketDataService,
ExecutionService: executionService
};
const strategyManager = new StrategyManager(container as any);
// Add debug logging to strategy manager
const origHandleMarketData = (strategyManager as any).handleMarketData;
(strategyManager as any).handleMarketData = async function(data: any) {
console.log(`>>> StrategyManager.handleMarketData called for ${data.data.symbol} @ ${data.data.close}`);
console.log(` Active strategies: ${this.activeStrategies.size}`);
console.log(` Strategy IDs: ${Array.from(this.activeStrategies).join(', ')}`);
return origHandleMarketData.call(this, data);
};
const backtestEngine = new BacktestEngine(container as any, storageService, strategyManager);
const config = {
mode: 'backtest' as const,
name: 'Minimal Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-02-15T00:00:00Z', // 45 days to ensure we have enough data
initialCapital: 100000,
dataFrequency: '1d',
commission: 0.001,
slippage: 0.0001,
speed: 'max' as const
};
// Initialize mode manager with backtest config
await modeManager.initializeMode(config);
try {
const result = await backtestEngine.runBacktest(config);
console.log('\nResults:');
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
console.log(`Trades in history: ${result.trades.length}`);
} catch (error) {
console.error('Backtest failed:', error);
}
}
testMinimalBacktest().catch(console.error);

View file

@ -1,122 +0,0 @@
#!/usr/bin/env bun
/**
* Test order flow through the full backtest system
*/
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { getLogger } from '@stock-bot/logger';
import { SimpleMovingAverageCrossover } from './src/strategies/examples/SimpleMovingAverageCrossover';
async function testOrderFlow() {
console.log('Testing order flow in backtest...\n');
// Create minimal container
const logger = getLogger('test');
const container = {
logger,
custom: {}
};
// Create services
const storageService = new StorageService(container as any);
const strategyManager = new StrategyManager(container as any);
// First test the strategy directly
console.log('=== Testing Strategy Directly ===');
const testStrategy = new SimpleMovingAverageCrossover({
id: 'test-direct',
name: 'Direct Test',
enabled: true,
symbols: ['AAPL'],
allocation: 1.0
}, null, null);
let directSignals = 0;
let directOrders = 0;
testStrategy.on('signal', (signal) => {
directSignals++;
console.log(`Direct signal #${directSignals}:`, signal);
});
testStrategy.on('order', (order) => {
directOrders++;
console.log(`Direct order #${directOrders}:`, order);
});
await testStrategy.start();
// Generate test data with clear crossover
for (let i = 0; i < 30; i++) {
const basePrice = 100;
const price = i < 15 ? basePrice - i * 0.5 : basePrice + (i - 15) * 0.5;
await testStrategy.onMarketData({
type: 'bar',
data: {
symbol: 'AAPL',
open: price,
high: price + 1,
low: price - 1,
close: price,
volume: 1000000,
timestamp: Date.now() + i * 86400000
}
});
}
await testStrategy.stop();
console.log(`\nDirect test: ${directSignals} signals, ${directOrders} orders\n`);
// Now test through backtest engine
console.log('=== Testing Through Backtest Engine ===');
// Create backtest engine (it will initialize strategies)
const backtestEngine = new BacktestEngine(container as any, storageService, strategyManager);
// Hook into backtest engine to see what's happening
const origProcessMarketData = (backtestEngine as any).processMarketData;
(backtestEngine as any).processMarketData = async function(data: any) {
console.log(`Processing market data: ${data.data.symbol} @ ${data.data.close}`);
return origProcessMarketData.call(this, data);
};
const origCheckAndFillOrders = (backtestEngine as any).checkAndFillOrders;
(backtestEngine as any).checkAndFillOrders = async function(data: any) {
const pendingCount = this.pendingOrders.size;
if (pendingCount > 0) {
console.log(`Checking ${pendingCount} pending orders...`);
}
return origCheckAndFillOrders.call(this, data);
};
const config = {
mode: 'backtest',
name: 'Order Flow Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-02-01T00:00:00Z', // Just 1 month
initialCapital: 100000,
dataFrequency: '1d',
commission: 0.001,
slippage: 0.0001
};
try {
const result = await backtestEngine.runBacktest(config);
console.log('\nBacktest Results:');
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
console.log(`Trades in history: ${result.trades.length}`);
} catch (error) {
console.error('Backtest failed:', error);
}
}
testOrderFlow().catch(console.error);

View file

@ -1,134 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testPerformanceMetrics() {
console.log('Testing Performance Metrics Calculation...\n');
// Create minimal service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => console.log('[INFO]', msg, ...args),
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Initialize backtest mode
await modeManager.initializeMode({
mode: 'backtest',
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-03-31T00:00:00Z', // 3 months for more trades
speed: 'max',
symbols: ['AAPL'],
initialCapital: 100000,
dataFrequency: '1d',
strategy: 'sma-crossover'
});
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
// Run backtest
const config = {
mode: 'backtest',
name: 'Performance Metrics Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-03-31T00:00:00Z',
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
console.log('Running backtest...');
const result = await backtestEngine.runBacktest(config);
// Analyze metrics
console.log('\n=== PERFORMANCE METRICS ANALYSIS ===');
console.log('\n📊 Returns:');
console.log(` Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(` Sharpe Ratio: ${result.metrics.sharpeRatio.toFixed(3)}`);
console.log(` Max Drawdown: ${(result.metrics.maxDrawdown * 100).toFixed(2)}%`);
console.log('\n📈 Trading Statistics:');
console.log(` Total Trades: ${result.metrics.totalTrades}`);
console.log(` Win Rate: ${result.metrics.winRate.toFixed(2)}%`);
console.log(` Profit Factor: ${result.metrics.profitFactor.toFixed(2)}`);
console.log(` Average Win: $${result.metrics.avgWin.toFixed(2)}`);
console.log(` Average Loss: $${result.metrics.avgLoss.toFixed(2)}`);
console.log('\n🎯 Trade Details:');
console.log(` Closed Trades: ${result.trades.length}`);
if (result.trades.length > 0) {
const wins = result.trades.filter(t => t.pnl > 0);
const losses = result.trades.filter(t => t.pnl < 0);
console.log(` Winning Trades: ${wins.length}`);
console.log(` Losing Trades: ${losses.length}`);
console.log(` Calculated Win Rate: ${(wins.length / result.trades.length * 100).toFixed(2)}%`);
// Show first few trades
console.log('\n First 3 trades:');
result.trades.slice(0, 3).forEach((trade, i) => {
console.log(` ${i + 1}. ${trade.side} ${trade.quantity} @ ${trade.exitPrice.toFixed(2)} | P&L: $${trade.pnl.toFixed(2)} (${trade.pnlPercent.toFixed(2)}%)`);
});
}
console.log('\n💰 Equity Curve:');
console.log(` Starting Capital: $${config.initialCapital.toLocaleString()}`);
console.log(` Final Value: $${result.equity[result.equity.length - 1].value.toFixed(2)}`);
console.log(` Equity Points: ${result.equity.length}`);
// Show first and last few equity points
console.log('\n First 3 equity points:');
result.equity.slice(0, 3).forEach((point, i) => {
console.log(` ${i + 1}. ${point.date} => $${point.value.toFixed(2)}`);
});
console.log('\n Last 3 equity points:');
result.equity.slice(-3).forEach((point, i) => {
console.log(` ${i + 1}. ${point.date} => $${point.value.toFixed(2)}`);
});
// Diagnostic checks
console.log('\n🔍 Diagnostics:');
const sharpeOK = result.metrics.sharpeRatio !== 0;
const drawdownOK = result.metrics.maxDrawdown > 0 && result.metrics.maxDrawdown < 0.99;
const winRateOK = result.metrics.winRate > 0 && result.metrics.winRate < 100;
console.log(` ✅ Sharpe Ratio calculated: ${sharpeOK ? 'YES' : 'NO'}`);
console.log(` ✅ Max Drawdown reasonable: ${drawdownOK ? 'YES' : 'NO (suspicious value)'}`);
console.log(` ✅ Win Rate reasonable: ${winRateOK ? 'YES' : 'NO (check trade P&L)'}`);
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
testPerformanceMetrics().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,109 +0,0 @@
import { BacktestEngine } from './src/backtest/BacktestEngine';
import { StrategyManager } from './src/strategies/StrategyManager';
import { StorageService } from './src/services/StorageService';
import { ModeManager } from './src/core/ModeManager';
import { MarketDataService } from './src/services/MarketDataService';
import { ExecutionService } from './src/services/ExecutionService';
import { IServiceContainer } from '@stock-bot/di';
async function testPortfolioTracking() {
console.log('Testing Portfolio Value Tracking...\n');
// Create minimal service container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => {
// Filter for portfolio value messages
if (msg.includes('portfolio') || msg.includes('Portfolio') || msg.includes('equity')) {
console.log('[INFO]', msg, ...args);
}
},
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => {},
} as any,
custom: {}
};
// Initialize services
const storageService = new StorageService();
const marketDataService = new MarketDataService(container);
const executionService = new ExecutionService(container);
const modeManager = new ModeManager(container, marketDataService, executionService, storageService);
const strategyManager = new StrategyManager(container);
// Set services in container
container.custom = {
MarketDataService: marketDataService,
ExecutionService: executionService,
ModeManager: modeManager,
StorageService: storageService
};
// Initialize backtest mode
await modeManager.initializeMode({
mode: 'backtest',
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-10T00:00:00Z', // Just 10 days
speed: 'max',
symbols: ['TEST'],
initialCapital: 100000,
dataFrequency: '1d',
strategy: 'sma-crossover'
});
// Create backtest engine
const backtestEngine = new BacktestEngine(container, storageService, strategyManager);
// Run backtest
const config = {
mode: 'backtest',
name: 'Portfolio Tracking Test',
strategy: 'sma-crossover',
symbols: ['TEST'],
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-10T00:00:00Z',
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max'
};
console.log('Running backtest...');
const result = await backtestEngine.runBacktest(config);
// Analyze equity curve
console.log('\n=== EQUITY CURVE ANALYSIS ===');
console.log(`Initial Capital: $${config.initialCapital.toLocaleString()}`);
console.log(`Equity Points: ${result.equity.length}`);
// Show all equity points
console.log('\nAll equity points:');
result.equity.forEach((point, i) => {
console.log(` ${i + 1}. ${point.date} => $${point.value.toFixed(2)}`);
});
// Check for anomalies
const firstValue = result.equity[0].value;
const lastValue = result.equity[result.equity.length - 1].value;
const totalReturn = ((lastValue - firstValue) / firstValue) * 100;
console.log(`\nFirst Value: $${firstValue.toFixed(2)}`);
console.log(`Last Value: $${lastValue.toFixed(2)}`);
console.log(`Calculated Total Return: ${totalReturn.toFixed(2)}%`);
console.log(`Reported Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
// Check if values match
if (Math.abs(totalReturn - result.metrics.totalReturn) > 0.01) {
console.log('\n❌ WARNING: Calculated return does not match reported return!');
}
console.log('\n=== TEST COMPLETE ===');
process.exit(0);
}
testPortfolioTracking().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});

View file

@ -1,187 +0,0 @@
#!/usr/bin/env bun
/**
* Test with predictable data to ensure trades are generated
*/
import { TradingEngine } from '@stock-bot/core';
import { getLogger } from '@stock-bot/logger';
async function testPredictableBacktest() {
console.log('=== Predictable Backtest Test ===\n');
const logger = getLogger('test');
// Create trading engine directly
const tradingEngine = new TradingEngine('backtest', {
startTime: new Date('2023-01-01').getTime(),
endTime: new Date('2023-03-01').getTime(),
speedMultiplier: 0
});
// Set initial capital
await tradingEngine.setCapital(100000);
// Generate predictable price data that will cause crossovers
console.log('Generating predictable market data...');
// Phase 1: Downtrend (days 1-25) - prices fall from 100 to 75
for (let i = 0; i < 25; i++) {
const price = 100 - i;
const timestamp = new Date('2023-01-01').getTime() + i * 86400000;
await tradingEngine.advanceTime(timestamp);
await tradingEngine.updateQuote('AAPL', price - 0.01, price + 0.01, 10000, 10000);
if (i % 5 === 0) {
console.log(`Day ${i + 1}: Price = $${price}`);
}
}
// Phase 2: Uptrend (days 26-50) - prices rise from 76 to 100
for (let i = 25; i < 50; i++) {
const price = 76 + (i - 25);
const timestamp = new Date('2023-01-01').getTime() + i * 86400000;
await tradingEngine.advanceTime(timestamp);
await tradingEngine.updateQuote('AAPL', price - 0.01, price + 0.01, 10000, 10000);
if (i % 5 === 0) {
console.log(`Day ${i + 1}: Price = $${price}`);
}
}
// Phase 3: Another downtrend (days 51-60) - prices fall from 99 to 90
for (let i = 50; i < 60; i++) {
const price = 100 - (i - 50);
const timestamp = new Date('2023-01-01').getTime() + i * 86400000;
await tradingEngine.advanceTime(timestamp);
await tradingEngine.updateQuote('AAPL', price - 0.01, price + 0.01, 10000, 10000);
if (i % 5 === 0) {
console.log(`Day ${i + 1}: Price = $${price}`);
}
}
// Test moving averages manually
console.log('\n=== Expected Crossovers ===');
console.log('Around day 35-40: Golden cross (10 SMA crosses above 20 SMA)');
console.log('Around day 55-60: Death cross (10 SMA crosses below 20 SMA)');
// Get results
const closedTrades = tradingEngine.getClosedTrades ? JSON.parse(tradingEngine.getClosedTrades()) : [];
const tradeCount = tradingEngine.getTradeCount ? tradingEngine.getTradeCount() : 0;
const [realizedPnl, unrealizedPnl] = tradingEngine.getTotalPnl();
console.log('\n=== Results ===');
console.log(`Total trades: ${tradeCount}`);
console.log(`Closed trades: ${closedTrades.length}`);
console.log(`Realized P&L: $${realizedPnl.toFixed(2)}`);
console.log(`Unrealized P&L: $${unrealizedPnl.toFixed(2)}`);
// Now let's test the full backtest with this data pattern
console.log('\n=== Running Full Backtest with SMA Strategy ===');
const { BacktestEngine } = await import('./src/backtest/BacktestEngine');
const { StrategyManager } = await import('./src/strategies/StrategyManager');
const { StorageService } = await import('./src/services/StorageService');
const { ModeManager } = await import('./src/core/ModeManager');
const { MarketDataService } = await import('./src/services/MarketDataService');
const { ExecutionService } = await import('./src/services/ExecutionService');
const { DataManager } = await import('./src/data/DataManager');
const container = {
logger,
custom: {}
};
const storageService = new StorageService(container as any);
const marketDataService = new MarketDataService(container as any);
const executionService = new ExecutionService(container as any);
const modeManager = new ModeManager(container as any, marketDataService, executionService, storageService);
container.custom = {
ModeManager: modeManager,
MarketDataService: marketDataService,
ExecutionService: executionService
};
const strategyManager = new StrategyManager(container as any);
const backtestEngine = new BacktestEngine(container as any, storageService, strategyManager);
// Override the data manager to return our predictable data
const dataManager = new DataManager(container as any, storageService);
(backtestEngine as any).dataManager = dataManager;
// Mock the loadHistoricalData to return our pattern
(dataManager as any).loadHistoricalData = async (symbols: string[], startDate: Date, endDate: Date) => {
const data = new Map();
const bars = [];
// Generate the same pattern as above
for (let i = 0; i < 60; i++) {
let price;
if (i < 25) {
price = 100 - i;
} else if (i < 50) {
price = 76 + (i - 25);
} else {
price = 100 - (i - 50);
}
const timestamp = startDate.getTime() + i * 86400000;
bars.push({
type: 'bar',
data: {
symbol: 'AAPL',
open: price - 0.5,
high: price + 0.5,
low: price - 0.5,
close: price,
volume: 1000000,
timestamp
}
});
}
data.set('AAPL', bars);
return data;
};
const config = {
mode: 'backtest' as const,
name: 'Predictable Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2023-01-01',
endDate: '2023-03-01',
initialCapital: 100000,
dataFrequency: '1d',
commission: 0.001,
slippage: 0.0001,
speed: 'max' as const
};
await modeManager.initializeMode(config);
try {
const result = await backtestEngine.runBacktest(config);
console.log('\nBacktest Results:');
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
console.log(`Trades in history: ${result.trades.length}`);
console.log(`Win Rate: ${result.metrics.winRate.toFixed(2)}%`);
console.log('\nTrade Details:');
result.trades.forEach((trade, i) => {
console.log(`Trade ${i + 1}: ${trade.side} ${trade.quantity} @ $${trade.entryPrice.toFixed(2)} -> $${trade.exitPrice?.toFixed(2) || 'OPEN'}`);
});
} catch (error) {
console.error('Backtest failed:', error);
}
}
testPredictableBacktest().catch(console.error);

View file

@ -1,54 +0,0 @@
#!/usr/bin/env bun
/**
* Quick test of backtest with fixed order execution
*/
import { createContainer } from './src/simple-container';
import { BacktestEngine } from './src/backtest/BacktestEngine';
async function runQuickBacktest() {
const container = await createContainer();
const backtestEngine = container.resolve('backtestEngine') as BacktestEngine;
const config = {
name: 'Quick SMA Test',
strategy: 'sma-crossover',
symbols: ['AAPL'],
startDate: '2020-01-01',
endDate: '2021-01-01', // Just 1 year for quick test
initialCapital: 100000,
dataFrequency: '1d',
commission: 0.001,
slippage: 0.0001
};
console.log('Running quick backtest...\n');
try {
const result = await backtestEngine.runBacktest(config);
console.log('Backtest Results:');
console.log(`Total Return: ${result.metrics.totalReturn.toFixed(2)}%`);
console.log(`Total Trades: ${result.metrics.totalTrades}`);
console.log(`Win Rate: ${result.metrics.winRate.toFixed(2)}%`);
console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio.toFixed(2)}`);
console.log(`Max Drawdown: ${result.metrics.maxDrawdown.toFixed(2)}%`);
console.log('\nTrade History:');
console.log(`Trades in history: ${result.trades.length}`);
result.trades.slice(0, 5).forEach(trade => {
console.log(`- ${trade.side} ${trade.quantity} @ $${trade.entryPrice} -> $${trade.exitPrice} (${trade.pnlPercent.toFixed(2)}%)`);
});
if (result.trades.length > 5) {
console.log(`... and ${result.trades.length - 5} more trades`);
}
} catch (error) {
console.error('Backtest failed:', error);
}
}
runQuickBacktest().catch(console.error);

View file

@ -1,145 +0,0 @@
import { createRustBacktest } from './src/backtest/RustBacktestEngine';
import { SimpleMovingAverageCrossoverRust } from './src/strategies/rust/SimpleMovingAverageCrossoverRust';
import { IServiceContainer } from '@stock-bot/di';
// Mock StorageService
class MockStorageService {
async getHistoricalBars(symbol: string, startDate: Date, endDate: Date, frequency: string) {
// Generate mock data
const bars = [];
const msPerDay = 24 * 60 * 60 * 1000;
let currentDate = new Date(startDate);
let price = 100 + Math.random() * 50; // Start between 100-150
while (currentDate <= endDate) {
// Random walk
const change = (Math.random() - 0.5) * 2; // +/- 1%
price *= (1 + change / 100);
bars.push({
symbol,
timestamp: new Date(currentDate),
open: price * (1 + (Math.random() - 0.5) * 0.01),
high: price * (1 + Math.random() * 0.02),
low: price * (1 - Math.random() * 0.02),
close: price,
volume: 1000000 + Math.random() * 500000,
});
currentDate = new Date(currentDate.getTime() + msPerDay);
}
return bars;
}
}
async function testRustBacktest() {
console.log('🚀 Testing Rust Backtest Engine with TypeScript Strategy\n');
// Create minimal container
const container: IServiceContainer = {
logger: {
info: (msg: string, ...args: any[]) => console.log('[INFO]', msg, ...args),
error: (msg: string, ...args: any[]) => console.error('[ERROR]', msg, ...args),
warn: (msg: string, ...args: any[]) => console.warn('[WARN]', msg, ...args),
debug: (msg: string, ...args: any[]) => console.log('[DEBUG]', msg, ...args),
} as any,
custom: {
StorageService: new MockStorageService(),
}
};
// Backtest configuration
const config = {
mode: 'backtest' as const,
name: 'Rust Engine Test',
strategy: 'sma-crossover',
symbols: ['AAPL'], // Just one symbol for testing
startDate: '2023-01-01T00:00:00Z',
endDate: '2023-01-31T00:00:00Z', // Just one month for testing
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
speed: 'max' as const,
};
// Create strategy
const strategy = new SimpleMovingAverageCrossoverRust({
fastPeriod: 10,
slowPeriod: 30,
minHoldingBars: 5,
});
console.log('Configuration:');
console.log(` Symbols: ${config.symbols.join(', ')}`);
console.log(` Period: ${config.startDate} to ${config.endDate}`);
console.log(` Initial Capital: $${config.initialCapital.toLocaleString()}`);
console.log(` Strategy: ${strategy.constructor.name}`);
console.log('');
try {
console.log('Running backtest in Rust engine...\n');
const startTime = Date.now();
try {
const result = await createRustBacktest(container, config, [strategy]);
console.log('Raw result:', result);
const duration = (Date.now() - startTime) / 1000;
console.log(`\n✅ Backtest completed in ${duration.toFixed(2)} seconds`);
if (!result || !result.metrics) {
console.error('Invalid result structure:', result);
return;
}
console.log('\n=== PERFORMANCE METRICS ===');
console.log(`Total Return: ${result.metrics.totalReturn?.toFixed(2) || 'N/A'}%`);
console.log(`Sharpe Ratio: ${result.metrics.sharpeRatio?.toFixed(2) || 'N/A'}`);
console.log(`Max Drawdown: ${result.metrics.maxDrawdown ? (result.metrics.maxDrawdown * 100).toFixed(2) : 'N/A'}%`);
console.log(`Win Rate: ${result.metrics.winRate?.toFixed(1) || 'N/A'}%`);
console.log(`Total Trades: ${result.metrics.totalTrades || 0}`);
console.log(`Profit Factor: ${result.metrics.profitFactor?.toFixed(2) || 'N/A'}`);
console.log('\n=== TRADE STATISTICS ===');
console.log(`Profitable Trades: ${result.metrics.profitableTrades || 0}`);
console.log(`Average Win: $${result.metrics.avgWin?.toFixed(2) || '0.00'}`);
console.log(`Average Loss: $${result.metrics.avgLoss?.toFixed(2) || '0.00'}`);
console.log(`Total P&L: $${result.metrics.totalPnl?.toFixed(2) || '0.00'}`);
console.log('\n=== EQUITY CURVE ===');
if (result.equityCurve.length > 0) {
const firstValue = result.equityCurve[0].value;
const lastValue = result.equityCurve[result.equityCurve.length - 1].value;
console.log(`Starting Value: $${firstValue.toLocaleString()}`);
console.log(`Ending Value: $${lastValue.toLocaleString()}`);
console.log(`Growth: ${((lastValue / firstValue - 1) * 100).toFixed(2)}%`);
}
console.log('\n=== FINAL POSITIONS ===');
const positions = Object.entries(result.finalPositions);
if (positions.length > 0) {
for (const [symbol, position] of positions) {
console.log(`${symbol}: ${position.quantity} shares @ $${position.averagePrice}`);
}
} else {
console.log('No open positions');
}
// Compare with TypeScript engine performance
console.log('\n=== PERFORMANCE COMPARISON ===');
console.log('TypeScript Engine: ~5-10 seconds for 1 year backtest');
console.log(`Rust Engine: ${duration.toFixed(2)} seconds`);
console.log(`Speed Improvement: ${(10 / duration).toFixed(1)}x faster`);
} catch (innerError) {
console.error('Result processing error:', innerError);
}
} catch (error) {
console.error('❌ Backtest failed:', error);
}
}
// Run the test
testRustBacktest().catch(console.error);

View file

@ -1,151 +0,0 @@
#!/usr/bin/env bun
/**
* Test SMA strategy directly to debug trading
*/
import { SimpleMovingAverageCrossover } from './src/strategies/examples/SimpleMovingAverageCrossover';
import { getLogger } from '@stock-bot/logger';
async function testSMAStrategy() {
console.log('=== Testing SMA Strategy Trading ===\n');
const logger = getLogger('test');
const config = {
id: 'test-sma',
name: 'Test SMA',
enabled: true,
symbols: ['AAPL'],
allocation: 1.0
};
const strategy = new SimpleMovingAverageCrossover(config, null, null);
let signalCount = 0;
let orderCount = 0;
const orders: any[] = [];
strategy.on('signal', (signal) => {
signalCount++;
console.log(`\n📊 Signal #${signalCount}:`, {
type: signal.type,
symbol: signal.symbol,
strength: signal.strength,
reason: signal.reason
});
});
strategy.on('order', (order) => {
orderCount++;
orders.push(order);
console.log(`\n📈 Order #${orderCount}:`, order);
});
await strategy.start();
// Generate clear pattern: downtrend then uptrend
console.log('Generating market data with clear trend changes...\n');
// Phase 1: Stable around 100 for first 10 days
for (let i = 0; i < 10; i++) {
const price = 100 + Math.sin(i * 0.5) * 2;
await strategy.onMarketData({
type: 'bar',
data: {
symbol: 'AAPL',
open: price,
high: price + 1,
low: price - 1,
close: price,
volume: 1000000,
timestamp: Date.now() + i * 86400000
}
});
}
// Phase 2: Clear downtrend from 100 to 80 (days 11-30)
for (let i = 10; i < 30; i++) {
const price = 100 - (i - 10); // Falls by $1 per day
await strategy.onMarketData({
type: 'bar',
data: {
symbol: 'AAPL',
open: price,
high: price + 0.5,
low: price - 0.5,
close: price,
volume: 1000000,
timestamp: Date.now() + i * 86400000
}
});
}
// Phase 3: Clear uptrend from 80 to 110 (days 31-60)
for (let i = 30; i < 60; i++) {
const price = 80 + (i - 30); // Rises by $1 per day
await strategy.onMarketData({
type: 'bar',
data: {
symbol: 'AAPL',
open: price,
high: price + 0.5,
low: price - 0.5,
close: price,
volume: 1000000,
timestamp: Date.now() + i * 86400000
}
});
// Simulate position update after first buy
if (i === 45 && orders.length > 0) {
console.log('\n🔄 Simulating position update after buy order...');
await strategy.onOrderUpdate({
orderId: 'test-order-1',
symbol: 'AAPL',
side: 'buy',
status: 'filled',
fills: [{
quantity: orders[0].quantity,
price: 95
}]
});
}
}
// Phase 4: Another downtrend from 110 to 90 (days 61-80)
for (let i = 60; i < 80; i++) {
const price = 110 - (i - 60); // Falls by $1 per day
if (i % 5 === 0) {
console.log(`\nDay ${i + 1}: Price = $${price}`);
}
await strategy.onMarketData({
type: 'bar',
data: {
symbol: 'AAPL',
open: price,
high: price + 0.5,
low: price - 0.5,
close: price,
volume: 1000000,
timestamp: Date.now() + i * 86400000
}
});
}
await strategy.stop();
console.log('\n=== Test Results ===');
console.log(`Total signals generated: ${signalCount}`);
console.log(`Total orders generated: ${orderCount}`);
console.log(`\nExpected behavior:`);
console.log(`- Golden cross around day 40-45 (when 10 SMA crosses above 20 SMA)`);
console.log(`- Death cross around day 70-75 (when 10 SMA crosses below 20 SMA)`);
const perf = strategy.getPerformance();
console.log('\nStrategy performance:', perf);
}
testSMAStrategy().catch(console.error);

View file

@ -1,89 +0,0 @@
#!/usr/bin/env bun
/**
* Test strategy signal generation
*/
import { SimpleMovingAverageCrossover } from './src/strategies/examples/SimpleMovingAverageCrossover';
import { MarketData } from './src/types';
async function testStrategySignals() {
console.log('Testing strategy signal generation...\n');
// Create strategy with mock config
const config = {
id: 'test-sma',
name: 'Test SMA Strategy',
enabled: true,
symbols: ['AAPL'],
allocation: 1.0
};
const strategy = new SimpleMovingAverageCrossover(config, null, null);
await strategy.start();
// Generate 100 days of mock data with a clear trend
const basePrice = 100;
let price = basePrice;
let signalCount = 0;
console.log('Feeding market data to strategy...\n');
for (let day = 0; day < 100; day++) {
// Create uptrend for days 30-50, downtrend for days 60-80
if (day >= 30 && day < 50) {
price += 0.5; // Uptrend
} else if (day >= 60 && day < 80) {
price -= 0.5; // Downtrend
} else {
price += (Math.random() - 0.5) * 0.2; // Small random movement
}
const marketData: MarketData = {
type: 'bar',
data: {
symbol: 'AAPL',
open: price - 0.1,
high: price + 0.2,
low: price - 0.2,
close: price,
volume: 1000000,
timestamp: Date.now() + day * 86400000
}
};
// Listen for signals
strategy.once('signal', (signal) => {
signalCount++;
console.log(`Day ${day}: Signal generated!`);
console.log(` Type: ${signal.type}`);
console.log(` Strength: ${signal.strength}`);
console.log(` Reason: ${signal.reason}`);
console.log(` Metadata:`, signal.metadata);
});
// Listen for orders
strategy.once('order', (order) => {
console.log(`Day ${day}: Order generated!`);
console.log(` Side: ${order.side}`);
console.log(` Quantity: ${order.quantity}`);
console.log(` Type: ${order.orderType}`);
});
// Process the market data
await strategy.onMarketData(marketData);
if (day % 10 === 0) {
console.log(`Day ${day}: Price = ${price.toFixed(2)}, Total signals = ${signalCount}`);
}
}
console.log(`\n✅ Test completed. Total signals generated: ${signalCount}`);
const perf = strategy.getPerformance();
console.log('\nStrategy Performance:', perf);
await strategy.stop();
}
testStrategySignals().catch(console.error);

View file

@ -1,101 +0,0 @@
import { RustBacktestAdapter } from './src/backtest/RustBacktestAdapter';
import { IServiceContainer } from '@stock-bot/di';
import { BacktestConfig } from './src/types';
// Mock container
const mockContainer: IServiceContainer = {
logger: {
info: console.log,
error: console.error,
warn: console.warn,
debug: console.log,
},
mongodb: {} as any,
postgres: {} as any,
redis: {} as any,
custom: {},
} as IServiceContainer;
// Mock storage service
class MockStorageService {
async getHistoricalBars(symbol: string, startDate: Date, endDate: Date, frequency: string) {
const bars = [];
const startTime = startDate.getTime();
const endTime = endDate.getTime();
const dayMs = 24 * 60 * 60 * 1000;
let time = startTime;
let dayIndex = 0;
// Simple oscillating price for testing
while (time <= endTime) {
const price = 100 + 10 * Math.sin(dayIndex * 0.2);
bars.push({
timestamp: new Date(time),
open: price * 0.99,
high: price * 1.01,
low: price * 0.98,
close: price,
volume: 1000000,
vwap: price,
});
time += dayMs;
dayIndex++;
}
return bars;
}
}
// Test the backtest
async function testTradeFormat() {
console.log('=== Testing Trade Format ===\n');
const adapter = new RustBacktestAdapter(mockContainer);
(adapter as any).storageService = new MockStorageService();
const config: BacktestConfig = {
name: 'Trade Format Test',
strategy: 'Simple Moving Average Crossover',
symbols: ['TEST'],
startDate: '2024-01-01T00:00:00Z',
endDate: '2024-03-01T00:00:00Z',
initialCapital: 100000,
commission: 0.001,
slippage: 0.0001,
dataFrequency: '1d',
config: {
fastPeriod: 5,
slowPeriod: 15,
},
};
try {
const result = await adapter.runBacktest(config);
console.log('\n=== Trade Format ===');
console.log('Number of trades:', result.trades.length);
console.log('\nFirst 3 trades:');
result.trades.slice(0, 3).forEach((trade, idx) => {
console.log(`\nTrade ${idx + 1}:`, JSON.stringify(trade, null, 2));
});
// Check what format the trades are in
if (result.trades.length > 0) {
const firstTrade = result.trades[0];
console.log('\n=== Trade Structure Analysis ===');
console.log('Keys:', Object.keys(firstTrade));
console.log('Has entryDate/exitDate?', 'entryDate' in firstTrade && 'exitDate' in firstTrade);
console.log('Has timestamp?', 'timestamp' in firstTrade);
console.log('Has side field?', 'side' in firstTrade);
console.log('Side value:', firstTrade.side);
}
} catch (error) {
console.error('Test failed:', error);
}
}
testTradeFormat().catch(console.error);

View file

@ -1,107 +0,0 @@
#!/usr/bin/env bun
/**
* Test the new trade history functionality
*/
import { TradingEngine } from '@stock-bot/core';
async function testTradeHistory() {
console.log('Testing trade history functionality...\n');
// Create a trading engine in backtest mode
const config = {
startTime: Date.now() - 86400000, // 24 hours ago
endTime: Date.now(),
speedMultiplier: 1.0
};
const engine = new TradingEngine('backtest', config as any);
console.log('Trading engine created in', engine.getMode(), 'mode');
console.log('Initial trade count:', engine.getTradeCount());
console.log('Initial closed trades:', engine.getClosedTradeCount());
// Simulate some trades
console.log('\n--- Simulating trades ---');
// Buy 100 shares at $50
console.log('Processing BUY: 100 shares @ $50');
engine.processFillWithMetadata(
'AAPL',
50.0,
100,
'buy',
1.0,
'ORDER001',
'STRATEGY001'
);
console.log('Trade count after buy:', engine.getTradeCount());
console.log('Closed trades after buy:', engine.getClosedTradeCount());
// Sell 50 shares at $55
console.log('\nProcessing SELL: 50 shares @ $55');
engine.processFillWithMetadata(
'AAPL',
55.0,
50,
'sell',
1.0,
'ORDER002',
'STRATEGY001'
);
console.log('Trade count after partial sell:', engine.getTradeCount());
console.log('Closed trades after partial sell:', engine.getClosedTradeCount());
// Get closed trades
const closedTradesJson = engine.getClosedTrades();
const closedTrades = JSON.parse(closedTradesJson);
console.log('\n--- Closed Trades ---');
closedTrades.forEach((trade: any) => {
console.log(`Trade ${trade.id}:`);
console.log(` Symbol: ${trade.symbol}`);
console.log(` Entry: ${trade.entry_price} @ ${new Date(trade.entry_time).toISOString()}`);
console.log(` Exit: ${trade.exit_price} @ ${new Date(trade.exit_time).toISOString()}`);
console.log(` Quantity: ${trade.quantity}`);
console.log(` P&L: $${trade.pnl.toFixed(2)} (${trade.pnl_percent.toFixed(2)}%)`);
console.log(` Duration: ${trade.duration_ms}ms`);
});
// Sell remaining 50 shares at $52
console.log('\nProcessing SELL: 50 shares @ $52');
engine.processFillWithMetadata(
'AAPL',
52.0,
50,
'sell',
1.0,
'ORDER003',
'STRATEGY001'
);
console.log('Trade count after full close:', engine.getTradeCount());
console.log('Closed trades after full close:', engine.getClosedTradeCount());
// Get all trade history
const allTradesJson = engine.getTradeHistory();
const allTrades = JSON.parse(allTradesJson);
console.log('\n--- All Trade History ---');
console.log(`Total trades executed: ${allTrades.length}`);
allTrades.forEach((trade: any) => {
console.log(`${trade.id}: ${trade.side} ${trade.quantity} ${trade.symbol} @ ${trade.price}`);
});
// Get final P&L
const [realizedPnl, unrealizedPnl] = engine.getTotalPnl();
console.log('\n--- Final P&L ---');
console.log(`Realized P&L: $${realizedPnl.toFixed(2)}`);
console.log(`Unrealized P&L: $${unrealizedPnl.toFixed(2)}`);
console.log('\n✅ Trade history test completed successfully!');
}
testTradeHistory().catch(console.error);

View file

@ -1,5 +1,5 @@
import { TechnicalIndicators, IncrementalSMA, IncrementalEMA, IncrementalRSI } from '@stock-bot/core';
import { TechnicalAnalysis, IncrementalIndicators, SignalGenerator } from '../src/indicators/TechnicalAnalysis';
import { IncrementalSMA, TechnicalIndicators } from '@stock-bot/engine';
import { IncrementalIndicators, SignalGenerator, TechnicalAnalysis } from '../src/indicators/TechnicalAnalysis';
describe('Technical Analysis Library', () => {
let ta: TechnicalAnalysis;