running prettier for cleanup

This commit is contained in:
Boki 2025-06-11 10:13:25 -04:00
parent 24b7ed15e4
commit 8955544593
151 changed files with 29158 additions and 27966 deletions

View file

@ -1,239 +1,236 @@
import { getLogger } from '@stock-bot/logger';
import { EventBus } from '@stock-bot/event-bus';
import { VectorEngine, VectorizedBacktestResult } from '@stock-bot/vector-engine';
import { DataFrame } from '@stock-bot/data-frame';
import { ExecutionMode, BacktestContext, BacktestResult } from '../framework/execution-mode';
export interface VectorizedModeConfig {
batchSize?: number;
enableOptimization?: boolean;
parallelProcessing?: boolean;
}
export class VectorizedMode extends ExecutionMode {
private vectorEngine: VectorEngine;
private config: VectorizedModeConfig;
private logger = getLogger('vectorized-mode');
constructor(
context: BacktestContext,
eventBus: EventBus,
config: VectorizedModeConfig = {}
) {
super(context, eventBus);
this.vectorEngine = new VectorEngine();
this.config = {
batchSize: 10000,
enableOptimization: true,
parallelProcessing: true,
...config
};
}
async initialize(): Promise<void> {
await super.initialize();
this.logger.info('Vectorized mode initialized', {
backtestId: this.context.backtestId,
config: this.config
});
}
async execute(): Promise<BacktestResult> {
const startTime = Date.now();
this.logger.info('Starting vectorized backtest execution');
try {
// Load all data at once for vectorized processing
const data = await this.loadHistoricalData();
// Convert to DataFrame format
const dataFrame = this.createDataFrame(data);
// Execute vectorized strategy
const strategyCode = this.generateStrategyCode();
const vectorResult = await this.vectorEngine.executeVectorizedStrategy(
dataFrame,
strategyCode
);
// Convert to standard backtest result format
const result = this.convertVectorizedResult(vectorResult, startTime);
// Emit completion event
await this.eventBus.publishBacktestUpdate(
this.context.backtestId,
100,
{ status: 'completed', result }
);
this.logger.info('Vectorized backtest completed', {
backtestId: this.context.backtestId,
duration: Date.now() - startTime,
totalTrades: result.trades.length
});
return result;
} catch (error) {
this.logger.error('Vectorized backtest failed', {
error,
backtestId: this.context.backtestId
});
await this.eventBus.publishBacktestUpdate(
this.context.backtestId,
0,
{ status: 'failed', error: error.message }
);
throw error;
}
}
private async loadHistoricalData(): Promise<any[]> {
// Load all historical data at once
// This is much more efficient than loading tick by tick
const data = [];
// Simulate loading data (in production, this would be a bulk database query)
const startTime = new Date(this.context.startDate).getTime();
const endTime = new Date(this.context.endDate).getTime();
const interval = 60000; // 1 minute intervals
for (let timestamp = startTime; timestamp <= endTime; timestamp += interval) {
// Simulate OHLCV data
const basePrice = 100 + Math.sin(timestamp / 1000000) * 10;
const volatility = 0.02;
const open = basePrice + (Math.random() - 0.5) * volatility * basePrice;
const close = open + (Math.random() - 0.5) * volatility * basePrice;
const high = Math.max(open, close) + Math.random() * volatility * basePrice;
const low = Math.min(open, close) - Math.random() * volatility * basePrice;
const volume = Math.floor(Math.random() * 10000) + 1000;
data.push({
timestamp,
symbol: this.context.symbol,
open,
high,
low,
close,
volume
});
}
return data;
}
private createDataFrame(data: any[]): DataFrame {
return new DataFrame(data, {
columns: ['timestamp', 'symbol', 'open', 'high', 'low', 'close', 'volume'],
dtypes: {
timestamp: 'number',
symbol: 'string',
open: 'number',
high: 'number',
low: 'number',
close: 'number',
volume: 'number'
}
});
}
private generateStrategyCode(): string {
// Convert strategy configuration to vectorized strategy code
// This is a simplified example - in production you'd have a more sophisticated compiler
const strategy = this.context.strategy;
if (strategy.type === 'sma_crossover') {
return 'sma_crossover';
}
// Add more strategy types as needed
return strategy.code || 'sma_crossover';
}
private convertVectorizedResult(
vectorResult: VectorizedBacktestResult,
startTime: number
): BacktestResult {
return {
backtestId: this.context.backtestId,
strategy: this.context.strategy,
symbol: this.context.symbol,
startDate: this.context.startDate,
endDate: this.context.endDate,
mode: 'vectorized',
duration: Date.now() - startTime,
trades: vectorResult.trades.map(trade => ({
id: `trade_${trade.entryIndex}_${trade.exitIndex}`,
symbol: this.context.symbol,
side: trade.side,
entryTime: vectorResult.timestamps[trade.entryIndex],
exitTime: vectorResult.timestamps[trade.exitIndex],
entryPrice: trade.entryPrice,
exitPrice: trade.exitPrice,
quantity: trade.quantity,
pnl: trade.pnl,
commission: 0, // Simplified
slippage: 0
})),
performance: {
totalReturn: vectorResult.metrics.totalReturns,
sharpeRatio: vectorResult.metrics.sharpeRatio,
maxDrawdown: vectorResult.metrics.maxDrawdown,
winRate: vectorResult.metrics.winRate,
profitFactor: vectorResult.metrics.profitFactor,
totalTrades: vectorResult.metrics.totalTrades,
winningTrades: vectorResult.trades.filter(t => t.pnl > 0).length,
losingTrades: vectorResult.trades.filter(t => t.pnl <= 0).length,
avgTrade: vectorResult.metrics.avgTrade,
avgWin: vectorResult.trades.filter(t => t.pnl > 0)
.reduce((sum, t) => sum + t.pnl, 0) / vectorResult.trades.filter(t => t.pnl > 0).length || 0,
avgLoss: vectorResult.trades.filter(t => t.pnl <= 0)
.reduce((sum, t) => sum + t.pnl, 0) / vectorResult.trades.filter(t => t.pnl <= 0).length || 0,
largestWin: Math.max(...vectorResult.trades.map(t => t.pnl), 0),
largestLoss: Math.min(...vectorResult.trades.map(t => t.pnl), 0)
},
equity: vectorResult.equity,
drawdown: vectorResult.metrics.drawdown,
metadata: {
mode: 'vectorized',
dataPoints: vectorResult.timestamps.length,
signals: Object.keys(vectorResult.signals),
optimizations: this.config.enableOptimization ? ['vectorized_computation'] : []
}
};
}
async cleanup(): Promise<void> {
await super.cleanup();
this.logger.info('Vectorized mode cleanup completed');
}
// Batch processing capabilities
async batchBacktest(strategies: Array<{ id: string; config: any }>): Promise<Record<string, BacktestResult>> {
this.logger.info('Starting batch vectorized backtest', {
strategiesCount: strategies.length
});
const data = await this.loadHistoricalData();
const dataFrame = this.createDataFrame(data);
const strategyConfigs = strategies.map(s => ({
id: s.id,
code: this.generateStrategyCode()
}));
const batchResults = await this.vectorEngine.batchBacktest(dataFrame, strategyConfigs);
const results: Record<string, BacktestResult> = {};
for (const [strategyId, vectorResult] of Object.entries(batchResults)) {
results[strategyId] = this.convertVectorizedResult(vectorResult, Date.now());
}
return results;
}
}
export default VectorizedMode;
import { DataFrame } from '@stock-bot/data-frame';
import { EventBus } from '@stock-bot/event-bus';
import { getLogger } from '@stock-bot/logger';
import { VectorEngine, VectorizedBacktestResult } from '@stock-bot/vector-engine';
import { BacktestContext, BacktestResult, ExecutionMode } from '../framework/execution-mode';
export interface VectorizedModeConfig {
batchSize?: number;
enableOptimization?: boolean;
parallelProcessing?: boolean;
}
export class VectorizedMode extends ExecutionMode {
private vectorEngine: VectorEngine;
private config: VectorizedModeConfig;
private logger = getLogger('vectorized-mode');
constructor(context: BacktestContext, eventBus: EventBus, config: VectorizedModeConfig = {}) {
super(context, eventBus);
this.vectorEngine = new VectorEngine();
this.config = {
batchSize: 10000,
enableOptimization: true,
parallelProcessing: true,
...config,
};
}
async initialize(): Promise<void> {
await super.initialize();
this.logger.info('Vectorized mode initialized', {
backtestId: this.context.backtestId,
config: this.config,
});
}
async execute(): Promise<BacktestResult> {
const startTime = Date.now();
this.logger.info('Starting vectorized backtest execution');
try {
// Load all data at once for vectorized processing
const data = await this.loadHistoricalData();
// Convert to DataFrame format
const dataFrame = this.createDataFrame(data);
// Execute vectorized strategy
const strategyCode = this.generateStrategyCode();
const vectorResult = await this.vectorEngine.executeVectorizedStrategy(
dataFrame,
strategyCode
);
// Convert to standard backtest result format
const result = this.convertVectorizedResult(vectorResult, startTime);
// Emit completion event
await this.eventBus.publishBacktestUpdate(this.context.backtestId, 100, {
status: 'completed',
result,
});
this.logger.info('Vectorized backtest completed', {
backtestId: this.context.backtestId,
duration: Date.now() - startTime,
totalTrades: result.trades.length,
});
return result;
} catch (error) {
this.logger.error('Vectorized backtest failed', {
error,
backtestId: this.context.backtestId,
});
await this.eventBus.publishBacktestUpdate(this.context.backtestId, 0, {
status: 'failed',
error: error.message,
});
throw error;
}
}
private async loadHistoricalData(): Promise<any[]> {
// Load all historical data at once
// This is much more efficient than loading tick by tick
const data = [];
// Simulate loading data (in production, this would be a bulk database query)
const startTime = new Date(this.context.startDate).getTime();
const endTime = new Date(this.context.endDate).getTime();
const interval = 60000; // 1 minute intervals
for (let timestamp = startTime; timestamp <= endTime; timestamp += interval) {
// Simulate OHLCV data
const basePrice = 100 + Math.sin(timestamp / 1000000) * 10;
const volatility = 0.02;
const open = basePrice + (Math.random() - 0.5) * volatility * basePrice;
const close = open + (Math.random() - 0.5) * volatility * basePrice;
const high = Math.max(open, close) + Math.random() * volatility * basePrice;
const low = Math.min(open, close) - Math.random() * volatility * basePrice;
const volume = Math.floor(Math.random() * 10000) + 1000;
data.push({
timestamp,
symbol: this.context.symbol,
open,
high,
low,
close,
volume,
});
}
return data;
}
private createDataFrame(data: any[]): DataFrame {
return new DataFrame(data, {
columns: ['timestamp', 'symbol', 'open', 'high', 'low', 'close', 'volume'],
dtypes: {
timestamp: 'number',
symbol: 'string',
open: 'number',
high: 'number',
low: 'number',
close: 'number',
volume: 'number',
},
});
}
private generateStrategyCode(): string {
// Convert strategy configuration to vectorized strategy code
// This is a simplified example - in production you'd have a more sophisticated compiler
const strategy = this.context.strategy;
if (strategy.type === 'sma_crossover') {
return 'sma_crossover';
}
// Add more strategy types as needed
return strategy.code || 'sma_crossover';
}
private convertVectorizedResult(
vectorResult: VectorizedBacktestResult,
startTime: number
): BacktestResult {
return {
backtestId: this.context.backtestId,
strategy: this.context.strategy,
symbol: this.context.symbol,
startDate: this.context.startDate,
endDate: this.context.endDate,
mode: 'vectorized',
duration: Date.now() - startTime,
trades: vectorResult.trades.map(trade => ({
id: `trade_${trade.entryIndex}_${trade.exitIndex}`,
symbol: this.context.symbol,
side: trade.side,
entryTime: vectorResult.timestamps[trade.entryIndex],
exitTime: vectorResult.timestamps[trade.exitIndex],
entryPrice: trade.entryPrice,
exitPrice: trade.exitPrice,
quantity: trade.quantity,
pnl: trade.pnl,
commission: 0, // Simplified
slippage: 0,
})),
performance: {
totalReturn: vectorResult.metrics.totalReturns,
sharpeRatio: vectorResult.metrics.sharpeRatio,
maxDrawdown: vectorResult.metrics.maxDrawdown,
winRate: vectorResult.metrics.winRate,
profitFactor: vectorResult.metrics.profitFactor,
totalTrades: vectorResult.metrics.totalTrades,
winningTrades: vectorResult.trades.filter(t => t.pnl > 0).length,
losingTrades: vectorResult.trades.filter(t => t.pnl <= 0).length,
avgTrade: vectorResult.metrics.avgTrade,
avgWin:
vectorResult.trades.filter(t => t.pnl > 0).reduce((sum, t) => sum + t.pnl, 0) /
vectorResult.trades.filter(t => t.pnl > 0).length || 0,
avgLoss:
vectorResult.trades.filter(t => t.pnl <= 0).reduce((sum, t) => sum + t.pnl, 0) /
vectorResult.trades.filter(t => t.pnl <= 0).length || 0,
largestWin: Math.max(...vectorResult.trades.map(t => t.pnl), 0),
largestLoss: Math.min(...vectorResult.trades.map(t => t.pnl), 0),
},
equity: vectorResult.equity,
drawdown: vectorResult.metrics.drawdown,
metadata: {
mode: 'vectorized',
dataPoints: vectorResult.timestamps.length,
signals: Object.keys(vectorResult.signals),
optimizations: this.config.enableOptimization ? ['vectorized_computation'] : [],
},
};
}
async cleanup(): Promise<void> {
await super.cleanup();
this.logger.info('Vectorized mode cleanup completed');
}
// Batch processing capabilities
async batchBacktest(
strategies: Array<{ id: string; config: any }>
): Promise<Record<string, BacktestResult>> {
this.logger.info('Starting batch vectorized backtest', {
strategiesCount: strategies.length,
});
const data = await this.loadHistoricalData();
const dataFrame = this.createDataFrame(data);
const strategyConfigs = strategies.map(s => ({
id: s.id,
code: this.generateStrategyCode(),
}));
const batchResults = await this.vectorEngine.batchBacktest(dataFrame, strategyConfigs);
const results: Record<string, BacktestResult> = {};
for (const [strategyId, vectorResult] of Object.entries(batchResults)) {
results[strategyId] = this.convertVectorizedResult(vectorResult, Date.now());
}
return results;
}
}
export default VectorizedMode;