// import { DataFrame } from '@stock-bot/data-frame'; // import { getLogger } from '@stock-bot/logger'; // import { atr, bollingerBands, ema, macd, rsi, sma } from '@stock-bot/utils'; // // Vector operations interface // export interface VectorOperation { // name: string; // inputs: string[]; // output: string; // operation: (inputs: number[][]) => number[]; // } // // Vectorized strategy context // export interface VectorizedContext { // data: DataFrame; // lookback: number; // indicators: Record; // signals: Record; // } // // Performance metrics for vectorized backtesting // export interface VectorizedMetrics { // totalReturns: number; // sharpeRatio: number; // maxDrawdown: number; // winRate: number; // profitFactor: number; // totalTrades: number; // avgTrade: number; // returns: number[]; // drawdown: number[]; // equity: number[]; // } // // Vectorized backtest result // export interface VectorizedBacktestResult { // metrics: VectorizedMetrics; // trades: VectorizedTrade[]; // equity: number[]; // timestamps: number[]; // signals: Record; // } // export interface VectorizedTrade { // entryIndex: number; // exitIndex: number; // entryPrice: number; // exitPrice: number; // quantity: number; // side: 'LONG' | 'SHORT'; // pnl: number; // return: number; // duration: number; // } // // Vectorized strategy engine // export class VectorEngine { // private logger = getLogger('vector-engine'); // private operations: Map = new Map(); // constructor() { // this.registerDefaultOperations(); // } // private registerDefaultOperations(): void { // // Register common mathematical operations // this.registerOperation({ // name: 'add', // inputs: ['a', 'b'], // output: 'result', // operation: ([a, b]) => a.map((val, i) => val + b[i]), // }); // this.registerOperation({ // name: 'subtract', // inputs: ['a', 'b'], // output: 'result', // operation: ([a, b]) => a.map((val, i) => val - b[i]), // }); // this.registerOperation({ // name: 'multiply', // inputs: ['a', 'b'], // output: 'result', // operation: ([a, b]) => a.map((val, i) => val * b[i]), // }); // this.registerOperation({ // name: 'divide', // inputs: ['a', 'b'], // output: 'result', // operation: ([a, b]) => a.map((val, i) => (b[i] !== 0 ? val / b[i] : NaN)), // }); // // Register comparison operations // this.registerOperation({ // name: 'greater_than', // inputs: ['a', 'b'], // output: 'result', // operation: ([a, b]) => a.map((val, i) => (val > b[i] ? 1 : 0)), // }); // this.registerOperation({ // name: 'less_than', // inputs: ['a', 'b'], // output: 'result', // operation: ([a, b]) => a.map((val, i) => (val < b[i] ? 1 : 0)), // }); // this.registerOperation({ // name: 'crossover', // inputs: ['a', 'b'], // output: 'result', // operation: ([a, b]) => { // const result = new Array(a.length).fill(0); // for (let i = 1; i < a.length; i++) { // if (a[i] > b[i] && a[i - 1] <= b[i - 1]) { // result[i] = 1; // } // } // return result; // }, // }); // this.registerOperation({ // name: 'crossunder', // inputs: ['a', 'b'], // output: 'result', // operation: ([a, b]) => { // const result = new Array(a.length).fill(0); // for (let i = 1; i < a.length; i++) { // if (a[i] < b[i] && a[i - 1] >= b[i - 1]) { // result[i] = 1; // } // } // return result; // }, // }); // } // registerOperation(operation: VectorOperation): void { // this.operations.set(operation.name, operation); // this.logger.debug(`Registered operation: ${operation.name}`); // } // // Execute vectorized strategy // async executeVectorizedStrategy( // data: DataFrame, // strategyCode: string // ): Promise { // try { // const context = this.prepareContext(data); // const signals = this.executeStrategy(context, strategyCode); // const trades = this.generateTrades(data, signals); // const metrics = this.calculateMetrics(data, trades); // return { // metrics, // trades, // equity: metrics.equity, // timestamps: data.getColumn('timestamp'), // signals, // }; // } catch (error) { // this.logger.error('Vectorized strategy execution failed', error); // throw error; // } // } // private prepareContext(data: DataFrame): VectorizedContext { // const close = data.getColumn('close'); // const high = data.getColumn('high'); // const low = data.getColumn('low'); // const volume = data.getColumn('volume'); // // Calculate common indicators // const indicators: Record = { // sma_20: sma(close, 20), // sma_50: sma(close, 50), // ema_12: ema(close, 12), // ema_26: ema(close, 26), // rsi: rsi(close), // }; // const m = macd(close); // indicators.macd = m.macd; // indicators.macd_signal = m.signal; // indicators.macd_histogram = m.histogram; // const bb = bollingerBands(close); // indicators.bb_upper = bb.upper; // indicators.bb_middle = bb.middle; // indicators.bb_lower = bb.lower; // return { // data, // lookback: 100, // indicators, // signals: {}, // }; // } // private executeStrategy( // context: VectorizedContext, // strategyCode: string // ): Record { // // This is a simplified strategy execution // // In production, you'd want a more sophisticated strategy compiler/interpreter // const signals: Record = { // buy: new Array(context.data.length).fill(0), // sell: new Array(context.data.length).fill(0), // }; // // Example: Simple moving average crossover strategy // if (strategyCode.includes('sma_crossover')) { // const sma20 = context.indicators.sma_20; // const sma50 = context.indicators.sma_50; // for (let i = 1; i < sma20.length; i++) { // // Buy signal: SMA20 crosses above SMA50 // if (!isNaN(sma20[i]) && !isNaN(sma50[i]) && !isNaN(sma20[i - 1]) && !isNaN(sma50[i - 1])) { // if (sma20[i] > sma50[i] && sma20[i - 1] <= sma50[i - 1]) { // signals.buy[i] = 1; // } // // Sell signal: SMA20 crosses below SMA50 // else if (sma20[i] < sma50[i] && sma20[i - 1] >= sma50[i - 1]) { // signals.sell[i] = 1; // } // } // } // } // return signals; // } // private generateTrades(data: DataFrame, signals: Record): VectorizedTrade[] { // const trades: VectorizedTrade[] = []; // const close = data.getColumn('close'); // const timestamps = data.getColumn('timestamp'); // let position: { index: number; price: number; side: 'LONG' | 'SHORT' } | null = null; // for (let i = 0; i < close.length; i++) { // if (signals.buy[i] === 1 && !position) { // // Open long position // position = { // index: i, // price: close[i], // side: 'LONG', // }; // } else if (signals.sell[i] === 1) { // if (position && position.side === 'LONG') { // // Close long position // const trade: VectorizedTrade = { // entryIndex: position.index, // exitIndex: i, // entryPrice: position.price, // exitPrice: close[i], // quantity: 1, // Simplified: always trade 1 unit // side: 'LONG', // pnl: close[i] - position.price, // return: (close[i] - position.price) / position.price, // duration: timestamps[i] - timestamps[position.index], // }; // trades.push(trade); // position = null; // } else if (!position) { // // Open short position // position = { // index: i, // price: close[i], // side: 'SHORT', // }; // } // } else if (signals.buy[i] === 1 && position && position.side === 'SHORT') { // // Close short position // const trade: VectorizedTrade = { // entryIndex: position.index, // exitIndex: i, // entryPrice: position.price, // exitPrice: close[i], // quantity: 1, // side: 'SHORT', // pnl: position.price - close[i], // return: (position.price - close[i]) / position.price, // duration: timestamps[i] - timestamps[position.index], // }; // trades.push(trade); // position = null; // } // } // return trades; // } // private calculateMetrics(data: DataFrame, trades: VectorizedTrade[]): VectorizedMetrics { // if (trades.length === 0) { // return { // totalReturns: 0, // sharpeRatio: 0, // maxDrawdown: 0, // winRate: 0, // profitFactor: 0, // totalTrades: 0, // avgTrade: 0, // returns: [], // drawdown: [], // equity: [], // }; // } // const returns = trades.map(t => t.return); // const pnls = trades.map(t => t.pnl); // // Calculate equity curve // const equity: number[] = [10000]; // Starting capital // let currentEquity = 10000; // for (const trade of trades) { // currentEquity += trade.pnl; // equity.push(currentEquity); // } // // Calculate drawdown // const drawdown: number[] = []; // let peak = equity[0]; // for (const eq of equity) { // if (eq > peak) { // peak = eq; // } // drawdown.push((peak - eq) / peak); // } // const totalReturns = (equity[equity.length - 1] - equity[0]) / equity[0]; // const avgReturn = returns.reduce((sum, r) => sum + r, 0) / returns.length; // const returnStd = Math.sqrt( // returns.reduce((sum, r) => sum + Math.pow(r - avgReturn, 2), 0) / returns.length // ); // const winningTrades = trades.filter(t => t.pnl > 0); // const losingTrades = trades.filter(t => t.pnl < 0); // const grossProfit = winningTrades.reduce((sum, t) => sum + t.pnl, 0); // const grossLoss = Math.abs(losingTrades.reduce((sum, t) => sum + t.pnl, 0)); // return { // totalReturns, // sharpeRatio: returnStd !== 0 ? (avgReturn / returnStd) * Math.sqrt(252) : 0, // maxDrawdown: Math.max(...drawdown), // winRate: winningTrades.length / trades.length, // profitFactor: grossLoss !== 0 ? grossProfit / grossLoss : Infinity, // totalTrades: trades.length, // avgTrade: pnls.reduce((sum, pnl) => sum + pnl, 0) / trades.length, // returns, // drawdown, // equity, // }; // } // // Utility methods for vectorized operations // applyOperation(operationName: string, inputs: Record): number[] { // const operation = this.operations.get(operationName); // if (!operation) { // throw new Error(`Operation '${operationName}' not found`); // } // const inputArrays = operation.inputs.map(inputName => { // if (!inputs[inputName]) { // throw new Error(`Input '${inputName}' not provided for operation '${operationName}'`); // } // return inputs[inputName]; // }); // return operation.operation(inputArrays); // } // // Batch processing for multiple strategies // async batchBacktest( // data: DataFrame, // strategies: Array<{ id: string; code: string }> // ): Promise> { // const results: Record = {}; // for (const strategy of strategies) { // try { // this.logger.info(`Running vectorized backtest for strategy: ${strategy.id}`); // results[strategy.id] = await this.executeVectorizedStrategy(data, strategy.code); // } catch (error) { // this.logger.error(`Backtest failed for strategy: ${strategy.id}`, error); // // Continue with other strategies // } // } // return results; // } // }