120 lines
No EOL
4.8 KiB
TypeScript
120 lines
No EOL
4.8 KiB
TypeScript
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);
|
|
}); |