#!/usr/bin/env node /** * Production Module Benchmark Suite * * Comprehensive benchmarks for: * - Fractional Kelly Engine * - Hybrid LSTM-Transformer * - DRL Portfolio Manager * - Sentiment Alpha Pipeline * * Measures: latency, throughput, accuracy, memory usage */ import { performance } from 'perf_hooks'; // Benchmark configuration const benchConfig = { iterations: 100, warmupIterations: 10, dataPoints: { small: 100, medium: 500, large: 1000 } }; // Memory tracking function getMemoryMB() { const usage = process.memoryUsage(); return { heap: Math.round(usage.heapUsed / 1024 / 1024 * 100) / 100, total: Math.round(usage.heapTotal / 1024 / 1024 * 100) / 100 }; } // Benchmark runner async function benchmark(name, fn, iterations = benchConfig.iterations) { // Warmup for (let i = 0; i < benchConfig.warmupIterations; i++) { await fn(); } if (global.gc) global.gc(); const memBefore = getMemoryMB(); const times = []; for (let i = 0; i < iterations; i++) { const start = performance.now(); await fn(); times.push(performance.now() - start); } const memAfter = getMemoryMB(); times.sort((a, b) => a - b); return { name, iterations, min: times[0].toFixed(3), max: times[times.length - 1].toFixed(3), mean: (times.reduce((a, b) => a + b, 0) / times.length).toFixed(3), median: times[Math.floor(times.length / 2)].toFixed(3), p95: times[Math.floor(times.length * 0.95)].toFixed(3), p99: times[Math.floor(times.length * 0.99)].toFixed(3), throughput: (iterations / (times.reduce((a, b) => a + b, 0) / 1000)).toFixed(1), memDelta: (memAfter.heap - memBefore.heap).toFixed(2) }; } // ============= Kelly Criterion Benchmarks ============= function benchmarkKelly() { // Inline implementation for isolated benchmarking class KellyCriterion { calculateFullKelly(winProbability, decimalOdds) { const b = decimalOdds - 1; const p = winProbability; const q = 1 - p; return Math.max(0, (b * p - q) / b); } calculateFractionalKelly(winProbability, decimalOdds, fraction = 0.2) { const fullKelly = this.calculateFullKelly(winProbability, decimalOdds); if (fullKelly <= 0) return { stake: 0, edge: 0 }; const adjustedKelly = Math.min(fullKelly * fraction, 0.05); const edge = (winProbability * decimalOdds) - 1; return { stake: adjustedKelly * 10000, stakePercent: adjustedKelly * 100, edge: edge * 100 }; } calculateMultiBetKelly(bets, fraction = 0.2) { const results = bets.map(bet => ({ ...bet, kelly: this.calculateFractionalKelly(bet.winProbability, bet.decimalOdds, fraction) })); const totalKelly = results.reduce((sum, b) => sum + (b.kelly.stakePercent || 0), 0); const scaleFactor = totalKelly > 5 ? 5 / totalKelly : 1; return results.map(r => ({ ...r, kelly: { ...r.kelly, stake: (r.kelly.stake || 0) * scaleFactor } })); } } const kelly = new KellyCriterion(); return { single: () => kelly.calculateFractionalKelly(0.55, 2.0), multi10: () => kelly.calculateMultiBetKelly( Array(10).fill(null).map(() => ({ winProbability: 0.5 + Math.random() * 0.1, decimalOdds: 1.8 + Math.random() * 0.4 })) ), multi100: () => kelly.calculateMultiBetKelly( Array(100).fill(null).map(() => ({ winProbability: 0.5 + Math.random() * 0.1, decimalOdds: 1.8 + Math.random() * 0.4 })) ) }; } // ============= LSTM-Transformer Benchmarks ============= function benchmarkLSTMTransformer() { class LSTMCell { constructor(inputSize, hiddenSize) { this.inputSize = inputSize; this.hiddenSize = hiddenSize; const scale = Math.sqrt(2.0 / (inputSize + hiddenSize)); this.Wf = Array(hiddenSize).fill(null).map(() => Array(inputSize + hiddenSize).fill(null).map(() => (Math.random() - 0.5) * 2 * scale) ); } sigmoid(x) { return 1 / (1 + Math.exp(-Math.max(-500, Math.min(500, x)))); } forward(x, hPrev) { const combined = [...x, ...hPrev]; const h = this.Wf.map(row => this.sigmoid(row.reduce((sum, w, j) => sum + w * combined[j], 0)) ); return { h, c: h }; } } class LSTMLayer { constructor(inputSize, hiddenSize) { this.cell = new LSTMCell(inputSize, hiddenSize); this.hiddenSize = hiddenSize; } forward(sequence) { let h = new Array(this.hiddenSize).fill(0); for (const x of sequence) { const result = this.cell.forward(x, h); h = result.h; } return h; } } function softmax(arr) { let max = arr[0]; for (let i = 1; i < arr.length; i++) if (arr[i] > max) max = arr[i]; const exp = arr.map(x => Math.exp(x - max)); const sum = exp.reduce((a, b) => a + b, 0); return exp.map(x => x / sum); } function attention(Q, K, V, dim) { const scale = Math.sqrt(dim); const scores = Q.map((q, i) => K.map((k, j) => q.reduce((sum, qv, idx) => sum + qv * k[idx], 0) / scale) ); const weights = scores.map(row => softmax(row)); return weights.map((row, i) => V[0].map((_, j) => row.reduce((sum, w, k) => sum + w * V[k][j], 0)) ); } const lstm = new LSTMLayer(10, 64); return { lstmSmall: () => lstm.forward(Array(10).fill(null).map(() => Array(10).fill(null).map(() => Math.random()) )), lstmMedium: () => lstm.forward(Array(50).fill(null).map(() => Array(10).fill(null).map(() => Math.random()) )), lstmLarge: () => lstm.forward(Array(100).fill(null).map(() => Array(10).fill(null).map(() => Math.random()) )), attention: () => { const seq = Array(20).fill(null).map(() => Array(64).fill(null).map(() => Math.random()) ); return attention(seq, seq, seq, 64); } }; } // ============= DRL Benchmarks ============= function benchmarkDRL() { class NeuralNetwork { constructor(inputDim, hiddenDim, outputDim) { const scale = Math.sqrt(2.0 / (inputDim + hiddenDim)); this.W1 = Array(inputDim).fill(null).map(() => Array(hiddenDim).fill(null).map(() => (Math.random() - 0.5) * 2 * scale) ); this.W2 = Array(hiddenDim).fill(null).map(() => Array(outputDim).fill(null).map(() => (Math.random() - 0.5) * 2 * scale) ); this.inputDim = inputDim; this.hiddenDim = hiddenDim; this.outputDim = outputDim; } forward(input) { // Layer 1 with ReLU const h = new Array(this.hiddenDim).fill(0); for (let i = 0; i < this.hiddenDim; i++) { for (let j = 0; j < this.inputDim; j++) { h[i] += input[j] * this.W1[j][i]; } h[i] = Math.max(0, h[i]); } // Output layer const output = new Array(this.outputDim).fill(0); for (let i = 0; i < this.outputDim; i++) { for (let j = 0; j < this.hiddenDim; j++) { output[i] += h[j] * this.W2[j][i]; } } return output; } } class ReplayBuffer { constructor(capacity) { this.capacity = capacity; this.buffer = []; this.position = 0; } push(data) { if (this.buffer.length < this.capacity) this.buffer.push(null); this.buffer[this.position] = data; this.position = (this.position + 1) % this.capacity; } sample(batchSize) { const batch = []; for (let i = 0; i < Math.min(batchSize, this.buffer.length); i++) { batch.push(this.buffer[Math.floor(Math.random() * this.buffer.length)]); } return batch; } } const network = new NeuralNetwork(100, 128, 10); const buffer = new ReplayBuffer(10000); // Pre-fill buffer for (let i = 0; i < 1000; i++) { buffer.push({ state: Array(100).fill(Math.random()), reward: Math.random() }); } return { networkForward: () => network.forward(Array(100).fill(null).map(() => Math.random())), bufferSample: () => buffer.sample(64), bufferPush: () => buffer.push({ state: Array(100).fill(Math.random()), reward: Math.random() }), fullStep: () => { const state = Array(100).fill(null).map(() => Math.random()); const action = network.forward(state); buffer.push({ state, action, reward: Math.random() }); return action; } }; } // ============= Sentiment Benchmarks ============= function benchmarkSentiment() { const positiveWords = new Set([ 'growth', 'profit', 'gains', 'bullish', 'upgrade', 'beat', 'exceeded', 'outperform', 'strong', 'surge', 'rally', 'breakthrough', 'innovation' ]); const negativeWords = new Set([ 'loss', 'decline', 'bearish', 'downgrade', 'miss', 'below', 'weak', 'underperform', 'crash', 'plunge', 'risk', 'concern', 'warning' ]); function lexiconAnalyze(text) { const words = text.toLowerCase().replace(/[^\w\s]/g, '').split(/\s+/); let score = 0; let count = 0; for (const word of words) { if (positiveWords.has(word)) { score++; count++; } else if (negativeWords.has(word)) { score--; count++; } } return { score: count > 0 ? score / count : 0, confidence: Math.min(1, count / 5) }; } function hashEmbed(text, dim = 64) { const words = text.toLowerCase().split(/\s+/); const embedding = new Array(dim).fill(0); for (const word of words) { let hash = 0; for (let i = 0; i < word.length; i++) { hash = ((hash << 5) - hash) + word.charCodeAt(i); hash = hash & hash; } for (let i = 0; i < dim; i++) { embedding[i] += Math.sin(hash * (i + 1)) / words.length; } } return embedding; } const sampleTexts = [ 'Strong quarterly earnings beat analyst expectations with record revenue growth', 'Company warns of significant losses amid declining market demand', 'Neutral outlook as market conditions remain stable', 'Major breakthrough innovation drives optimistic investor sentiment' ]; return { lexiconSingle: () => lexiconAnalyze(sampleTexts[0]), lexiconBatch: () => sampleTexts.map(t => lexiconAnalyze(t)), embedSingle: () => hashEmbed(sampleTexts[0]), embedBatch: () => sampleTexts.map(t => hashEmbed(t)), fullPipeline: () => { const results = sampleTexts.map(text => ({ lexicon: lexiconAnalyze(text), embedding: hashEmbed(text) })); // Aggregate const scores = results.map(r => 0.4 * r.lexicon.score + 0.6 * Math.tanh( r.embedding.reduce((a, b) => a + b, 0) * 0.1 )); return scores.reduce((a, b) => a + b, 0) / scores.length; } }; } // ============= Main Benchmark Runner ============= async function runBenchmarks() { console.log('═'.repeat(70)); console.log('PRODUCTION MODULE BENCHMARK SUITE'); console.log('═'.repeat(70)); console.log(); console.log(`Iterations: ${benchConfig.iterations} | Warmup: ${benchConfig.warmupIterations}`); console.log(); const results = []; // 1. Kelly Criterion Benchmarks console.log('1. FRACTIONAL KELLY ENGINE'); console.log('─'.repeat(70)); const kellyBench = benchmarkKelly(); const kellySingle = await benchmark('Kelly Single Bet', kellyBench.single, 1000); const kellyMulti10 = await benchmark('Kelly Multi (10 bets)', kellyBench.multi10); const kellyMulti100 = await benchmark('Kelly Multi (100 bets)', kellyBench.multi100); console.log(` Single bet: ${kellySingle.mean}ms (${kellySingle.throughput}/s)`); console.log(` 10 bets: ${kellyMulti10.mean}ms (${kellyMulti10.throughput}/s)`); console.log(` 100 bets: ${kellyMulti100.mean}ms (${kellyMulti100.throughput}/s)`); results.push(kellySingle, kellyMulti10, kellyMulti100); console.log(); // 2. LSTM-Transformer Benchmarks console.log('2. HYBRID LSTM-TRANSFORMER'); console.log('─'.repeat(70)); const lstmBench = benchmarkLSTMTransformer(); const lstmSmall = await benchmark('LSTM (seq=10)', lstmBench.lstmSmall); const lstmMedium = await benchmark('LSTM (seq=50)', lstmBench.lstmMedium); const lstmLarge = await benchmark('LSTM (seq=100)', lstmBench.lstmLarge); const attention = await benchmark('Attention (seq=20)', lstmBench.attention); console.log(` LSTM seq=10: ${lstmSmall.mean}ms (${lstmSmall.throughput}/s)`); console.log(` LSTM seq=50: ${lstmMedium.mean}ms (${lstmMedium.throughput}/s)`); console.log(` LSTM seq=100: ${lstmLarge.mean}ms (${lstmLarge.throughput}/s)`); console.log(` Attention: ${attention.mean}ms (${attention.throughput}/s)`); results.push(lstmSmall, lstmMedium, lstmLarge, attention); console.log(); // 3. DRL Benchmarks console.log('3. DRL PORTFOLIO MANAGER'); console.log('─'.repeat(70)); const drlBench = benchmarkDRL(); const networkFwd = await benchmark('Network Forward', drlBench.networkForward, 1000); const bufferSample = await benchmark('Buffer Sample (64)', drlBench.bufferSample, 1000); const bufferPush = await benchmark('Buffer Push', drlBench.bufferPush, 1000); const fullStep = await benchmark('Full RL Step', drlBench.fullStep); console.log(` Network fwd: ${networkFwd.mean}ms (${networkFwd.throughput}/s)`); console.log(` Buffer sample: ${bufferSample.mean}ms (${bufferSample.throughput}/s)`); console.log(` Buffer push: ${bufferPush.mean}ms (${bufferPush.throughput}/s)`); console.log(` Full RL step: ${fullStep.mean}ms (${fullStep.throughput}/s)`); results.push(networkFwd, bufferSample, bufferPush, fullStep); console.log(); // 4. Sentiment Benchmarks console.log('4. SENTIMENT ALPHA PIPELINE'); console.log('─'.repeat(70)); const sentBench = benchmarkSentiment(); const lexSingle = await benchmark('Lexicon Single', sentBench.lexiconSingle, 1000); const lexBatch = await benchmark('Lexicon Batch (4)', sentBench.lexiconBatch); const embedSingle = await benchmark('Embedding Single', sentBench.embedSingle, 1000); const embedBatch = await benchmark('Embedding Batch (4)', sentBench.embedBatch); const fullPipe = await benchmark('Full Pipeline', sentBench.fullPipeline); console.log(` Lexicon: ${lexSingle.mean}ms (${lexSingle.throughput}/s)`); console.log(` Lexicon batch: ${lexBatch.mean}ms (${lexBatch.throughput}/s)`); console.log(` Embedding: ${embedSingle.mean}ms (${embedSingle.throughput}/s)`); console.log(` Embed batch: ${embedBatch.mean}ms (${embedBatch.throughput}/s)`); console.log(` Full pipeline: ${fullPipe.mean}ms (${fullPipe.throughput}/s)`); results.push(lexSingle, lexBatch, embedSingle, embedBatch, fullPipe); console.log(); // Summary console.log('═'.repeat(70)); console.log('BENCHMARK SUMMARY'); console.log('═'.repeat(70)); console.log(); // Find fastest and slowest const sorted = [...results].sort((a, b) => parseFloat(a.mean) - parseFloat(b.mean)); console.log('Fastest Operations:'); for (const r of sorted.slice(0, 5)) { console.log(` ${r.name.padEnd(25)} ${r.mean}ms (${r.throughput}/s)`); } console.log(); console.log('Production Readiness:'); console.log('─'.repeat(70)); console.log(' Module │ Latency │ Throughput │ Status'); console.log('─'.repeat(70)); const modules = [ { name: 'Kelly Engine', latency: kellyMulti10.mean, throughput: kellyMulti10.throughput }, { name: 'LSTM-Transformer', latency: lstmMedium.mean, throughput: lstmMedium.throughput }, { name: 'DRL Portfolio', latency: fullStep.mean, throughput: fullStep.throughput }, { name: 'Sentiment Alpha', latency: fullPipe.mean, throughput: fullPipe.throughput } ]; for (const m of modules) { const status = parseFloat(m.latency) < 10 ? '✓ Ready' : parseFloat(m.latency) < 50 ? '⚠ Acceptable' : '✗ Optimize'; console.log(` ${m.name.padEnd(24)} │ ${m.latency.padStart(6)}ms │ ${m.throughput.padStart(8)}/s │ ${status}`); } console.log(); console.log('═'.repeat(70)); console.log('Benchmark suite completed'); console.log('═'.repeat(70)); return results; } // Run benchmarks runBenchmarks().catch(console.error);