Files
wifi-densepose/npm/packages/agentic-synth/examples/stocks/market-data.js
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

404 lines
14 KiB
JavaScript

"use strict";
/**
* Stock Market Data Generation Examples
*
* Demonstrates realistic OHLCV data generation, technical indicators,
* multi-timeframe data, market depth, and tick-by-tick simulation.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateOHLCVData = generateOHLCVData;
exports.generateTechnicalIndicators = generateTechnicalIndicators;
exports.generateMultiTimeframeData = generateMultiTimeframeData;
exports.generateMarketDepth = generateMarketDepth;
exports.generateTickData = generateTickData;
exports.generateMicrostructureMetrics = generateMicrostructureMetrics;
const src_1 = require("../../../src");
/**
* Generate realistic OHLCV (candlestick) data with proper market microstructure
*/
async function generateOHLCVData() {
const synth = new src_1.AgenticSynth();
const ohlcvData = await synth.generate({
count: 390, // One trading day (6.5 hours * 60 minutes)
template: {
timestamp: '{{date.recent}}',
open: '{{number.float(100, 200, 2)}}',
high: '{{number.float(100, 200, 2)}}',
low: '{{number.float(100, 200, 2)}}',
close: '{{number.float(100, 200, 2)}}',
volume: '{{number.int(100000, 10000000)}}',
symbol: 'AAPL',
},
constraints: [
// High must be >= max(open, close)
'bar.high >= Math.max(bar.open, bar.close)',
// Low must be <= min(open, close)
'bar.low <= Math.min(bar.open, bar.close)',
// Volume must be positive
'bar.volume > 0',
],
relationships: [
{
type: 'temporal',
field: 'timestamp',
interval: '1m', // 1-minute bars
},
{
type: 'continuity',
sourceField: 'close',
targetField: 'open',
description: 'Next bar opens at previous close',
},
],
});
// Post-process to ensure OHLCV validity
const validatedData = ohlcvData.map((bar, idx) => {
if (idx > 0) {
bar.open = ohlcvData[idx - 1].close; // Open = previous close
}
bar.high = Math.max(bar.open, bar.close, bar.high);
bar.low = Math.min(bar.open, bar.close, bar.low);
return bar;
});
console.log('Generated OHLCV Data (first 5 bars):');
console.log(validatedData.slice(0, 5));
return validatedData;
}
/**
* Generate price data with technical indicators pre-calculated
*/
async function generateTechnicalIndicators() {
const synth = new src_1.AgenticSynth();
// First generate base price series
const priceData = await synth.generate({
count: 100,
template: {
price: '{{number.float(150, 160, 2)}}',
volume: '{{number.int(1000000, 5000000)}}',
},
});
// Calculate indicators (simplified for demonstration)
const calculateSMA = (data, period) => {
const sma = [];
for (let i = 0; i < data.length; i++) {
if (i < period - 1) {
sma.push(data[i]);
}
else {
const sum = data.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0);
sma.push(sum / period);
}
}
return sma;
};
const calculateRSI = (data, period = 14) => {
const rsi = [];
for (let i = 0; i < data.length; i++) {
if (i < period) {
rsi.push(50); // Neutral RSI for initial period
}
else {
const gains = [];
const losses = [];
for (let j = i - period + 1; j <= i; j++) {
const change = data[j] - data[j - 1];
if (change > 0)
gains.push(change);
else
losses.push(Math.abs(change));
}
const avgGain = gains.reduce((a, b) => a + b, 0) / period;
const avgLoss = losses.reduce((a, b) => a + b, 0) / period;
const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;
rsi.push(100 - 100 / (1 + rs));
}
}
return rsi;
};
const prices = priceData.map((d) => d.price);
const sma20 = calculateSMA(prices, 20);
const sma50 = calculateSMA(prices, 50);
const rsi = calculateRSI(prices);
const technicalData = priceData.map((bar, idx) => ({
timestamp: new Date(Date.now() - (priceData.length - idx) * 60000),
price: bar.price,
sma_20: Number(sma20[idx].toFixed(2)),
sma_50: Number(sma50[idx].toFixed(2)),
rsi_14: Number(rsi[idx].toFixed(2)),
macd: Number((sma20[idx] - sma50[idx]).toFixed(2)),
macd_signal: Number((sma20[idx] - sma50[idx]) * 0.9).toFixed(2), // Simplified
bb_upper: Number((sma20[idx] * 1.02).toFixed(2)),
bb_middle: Number(sma20[idx].toFixed(2)),
bb_lower: Number((sma20[idx] * 0.98).toFixed(2)),
volume: bar.volume,
symbol: 'AAPL',
}));
console.log('Technical Indicators (last 5 bars):');
console.log(technicalData.slice(-5));
return technicalData;
}
/**
* Generate data across multiple timeframes with proper aggregation
*/
async function generateMultiTimeframeData() {
const synth = new src_1.AgenticSynth();
// Generate 1-minute bars (base timeframe)
const bars1m = await synth.generate({
count: 1560, // 4 trading days worth of 1-minute data
template: {
timestamp: '{{date.recent}}',
open: '{{number.float(100, 200, 2)}}',
high: '{{number.float(100, 200, 2)}}',
low: '{{number.float(100, 200, 2)}}',
close: '{{number.float(100, 200, 2)}}',
volume: '{{number.int(10000, 100000)}}',
symbol: 'AAPL',
},
});
// Aggregate to 5-minute bars
const bars5m = [];
for (let i = 0; i < bars1m.length; i += 5) {
const chunk = bars1m.slice(i, i + 5);
if (chunk.length === 5) {
bars5m.push({
timestamp: chunk[0].timestamp,
open: chunk[0].open,
high: Math.max(...chunk.map((b) => b.high)),
low: Math.min(...chunk.map((b) => b.low)),
close: chunk[4].close,
volume: chunk.reduce((sum, b) => sum + b.volume, 0),
symbol: 'AAPL',
});
}
}
// Aggregate to 1-hour bars
const bars1h = [];
for (let i = 0; i < bars1m.length; i += 60) {
const chunk = bars1m.slice(i, i + 60);
if (chunk.length === 60) {
bars1h.push({
timestamp: chunk[0].timestamp,
open: chunk[0].open,
high: Math.max(...chunk.map((b) => b.high)),
low: Math.min(...chunk.map((b) => b.low)),
close: chunk[59].close,
volume: chunk.reduce((sum, b) => sum + b.volume, 0),
symbol: 'AAPL',
});
}
}
// Aggregate to 1-day bars
const bars1d = [];
for (let i = 0; i < bars1m.length; i += 390) {
const chunk = bars1m.slice(i, i + 390);
if (chunk.length === 390) {
bars1d.push({
timestamp: chunk[0].timestamp,
open: chunk[0].open,
high: Math.max(...chunk.map((b) => b.high)),
low: Math.min(...chunk.map((b) => b.low)),
close: chunk[389].close,
volume: chunk.reduce((sum, b) => sum + b.volume, 0),
symbol: 'AAPL',
});
}
}
console.log('Multi-timeframe data generated:');
console.log(`1m bars: ${bars1m.length}`);
console.log(`5m bars: ${bars5m.length}`);
console.log(`1h bars: ${bars1h.length}`);
console.log(`1d bars: ${bars1d.length}`);
return {
'1m': bars1m,
'5m': bars5m,
'1h': bars1h,
'1d': bars1d,
};
}
/**
* Generate realistic Level 2 market depth data (order book)
*/
async function generateMarketDepth() {
const synth = new src_1.AgenticSynth();
const midPrice = 150.0;
const tickSize = 0.01;
const depth = 20; // 20 levels on each side
const marketDepth = await synth.generate({
count: 100,
template: {
timestamp: '{{date.recent}}',
symbol: 'AAPL',
bids: [],
asks: [],
spread: 0,
midPrice: midPrice,
},
});
// Generate order book levels
const enrichedDepth = marketDepth.map((snapshot) => {
const bids = [];
const asks = [];
// Generate bid side (below mid price)
for (let i = 0; i < depth; i++) {
bids.push({
price: Number((midPrice - i * tickSize).toFixed(2)),
size: Math.floor(Math.random() * 10000) + 100,
orders: Math.floor(Math.random() * 50) + 1,
});
}
// Generate ask side (above mid price)
for (let i = 0; i < depth; i++) {
asks.push({
price: Number((midPrice + (i + 1) * tickSize).toFixed(2)),
size: Math.floor(Math.random() * 10000) + 100,
orders: Math.floor(Math.random() * 50) + 1,
});
}
const bestBid = bids[0].price;
const bestAsk = asks[0].price;
return {
...snapshot,
bids,
asks,
spread: Number((bestAsk - bestBid).toFixed(2)),
midPrice: Number(((bestBid + bestAsk) / 2).toFixed(2)),
};
});
console.log('Market Depth (first snapshot):');
console.log({
timestamp: enrichedDepth[0].timestamp,
bestBid: enrichedDepth[0].bids[0],
bestAsk: enrichedDepth[0].asks[0],
spread: enrichedDepth[0].spread,
totalBidVolume: enrichedDepth[0].bids.reduce((sum, b) => sum + b.size, 0),
totalAskVolume: enrichedDepth[0].asks.reduce((sum, a) => sum + a.size, 0),
});
return enrichedDepth;
}
/**
* Generate high-frequency tick-by-tick trade data
*/
async function generateTickData() {
const synth = new src_1.AgenticSynth();
const tickData = await synth.generate({
count: 10000, // 10k ticks (typical for a few minutes of active trading)
template: {
timestamp: '{{date.recent}}',
symbol: 'AAPL',
price: '{{number.float(149.5, 150.5, 2)}}',
size: '{{number.int(1, 1000)}}',
side: '{{random.arrayElement(["buy", "sell"])}}',
exchange: '{{random.arrayElement(["NASDAQ", "NYSE", "BATS", "IEX"])}}',
conditions: [],
},
constraints: [
'tick.size > 0',
'tick.price > 0',
],
relationships: [
{
type: 'temporal',
field: 'timestamp',
interval: '10ms', // High-frequency ticks
},
],
});
// Add trade conditions (regulatory tags)
const enrichedTicks = tickData.map((tick) => {
const conditions = [];
if (tick.size >= 100)
conditions.push('BLOCK');
if (tick.size >= 10000)
conditions.push('INSTITUTIONAL');
if (Math.random() < 0.05)
conditions.push('ODD_LOT');
if (Math.random() < 0.1)
conditions.push('EXTENDED_HOURS');
return {
...tick,
conditions,
};
});
// Calculate tick statistics
const buyTicks = enrichedTicks.filter((t) => t.side === 'buy');
const sellTicks = enrichedTicks.filter((t) => t.side === 'sell');
const avgBuyPrice = buyTicks.reduce((sum, t) => sum + t.price, 0) / buyTicks.length;
const avgSellPrice = sellTicks.reduce((sum, t) => sum + t.price, 0) / sellTicks.length;
console.log('Tick Data Statistics:');
console.log({
totalTicks: enrichedTicks.length,
buyTicks: buyTicks.length,
sellTicks: sellTicks.length,
avgBuyPrice: avgBuyPrice.toFixed(2),
avgSellPrice: avgSellPrice.toFixed(2),
priceImbalance: (avgBuyPrice - avgSellPrice).toFixed(4),
avgTradeSize: enrichedTicks.reduce((sum, t) => sum + t.size, 0) / enrichedTicks.length,
});
return enrichedTicks;
}
/**
* Generate market microstructure metrics for analysis
*/
async function generateMicrostructureMetrics() {
const synth = new src_1.AgenticSynth();
const metrics = await synth.generate({
count: 390, // One trading day
template: {
timestamp: '{{date.recent}}',
symbol: 'AAPL',
effectiveSpread: '{{number.float(0.01, 0.05, 4)}}',
realizedSpread: '{{number.float(0.005, 0.03, 4)}}',
priceImpact: '{{number.float(0.001, 0.02, 4)}}',
toxicity: '{{number.float(0, 1, 4)}}',
orderImbalance: '{{number.float(-1, 1, 4)}}',
volatility: '{{number.float(0.01, 0.05, 4)}}',
},
constraints: [
'metrics.effectiveSpread >= metrics.realizedSpread',
'metrics.toxicity >= 0 && metrics.toxicity <= 1',
'metrics.orderImbalance >= -1 && metrics.orderImbalance <= 1',
],
});
console.log('Microstructure Metrics (sample):');
console.log(metrics.slice(0, 5));
return metrics;
}
// ============================================================================
// Main Execution
// ============================================================================
async function main() {
console.log('='.repeat(80));
console.log('Stock Market Data Generation Examples');
console.log('='.repeat(80));
console.log();
try {
console.log('1. Generating OHLCV Data...');
await generateOHLCVData();
console.log();
console.log('2. Generating Technical Indicators...');
await generateTechnicalIndicators();
console.log();
console.log('3. Generating Multi-Timeframe Data...');
await generateMultiTimeframeData();
console.log();
console.log('4. Generating Market Depth...');
await generateMarketDepth();
console.log();
console.log('5. Generating Tick Data...');
await generateTickData();
console.log();
console.log('6. Generating Microstructure Metrics...');
await generateMicrostructureMetrics();
console.log();
console.log('All examples completed successfully!');
}
catch (error) {
console.error('Error generating market data:', error);
process.exit(1);
}
}
// Run if executed directly
if (require.main === module) {
main();
}
//# sourceMappingURL=market-data.js.map