linxus fs fixes
This commit is contained in:
parent
ac23b70146
commit
0b7846fe67
292 changed files with 41947 additions and 41947 deletions
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue