linxus fs fixes

This commit is contained in:
Boki 2025-06-09 22:55:51 -04:00
parent ac23b70146
commit 0b7846fe67
292 changed files with 41947 additions and 41947 deletions

View file

@ -1,239 +1,239 @@
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 { 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;