Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,409 @@
# Stock Market Data Generation Examples
Comprehensive examples for generating realistic financial market data using agentic-synth. These examples are designed for testing trading systems, backtesting strategies, and financial analysis.
## Overview
This package provides three main categories of financial data generation:
1. **Market Data** (`market-data.ts`) - Time-series price data with technical indicators
2. **Trading Scenarios** (`trading-scenarios.ts`) - Market regime simulations for system testing
3. **Portfolio Simulation** (`portfolio-simulation.ts`) - Multi-asset portfolio management data
## Features
### Market Data Generation
Generate realistic market microstructure data including:
- **OHLCV Data**: Open, High, Low, Close, Volume candlestick bars
- **Technical Indicators**: SMA, RSI, MACD, Bollinger Bands
- **Multi-Timeframe**: 1m, 5m, 1h, 1d aggregation
- **Market Depth**: Level 2 order book data
- **Tick Data**: High-frequency tick-by-tick trades
- **Microstructure Metrics**: Spreads, liquidity, toxicity
### Trading Scenarios
Realistic market conditions for testing trading systems:
- **Bull Markets**: Sustained uptrends with occasional pullbacks
- **Bear Markets**: Downtrends with volatility spikes
- **Volatility Regimes**: Low, medium, high, extreme volatility
- **Flash Crashes**: Rapid price declines with recovery
- **Earnings Events**: Announcement impact with IV crush
- **Market Correlations**: Multi-asset correlation patterns
### Portfolio Simulation
Complete portfolio management workflow:
- **Multi-Asset Portfolios**: Diversified across asset classes
- **Rebalancing**: Calendar, threshold, and opportunistic strategies
- **Risk Metrics**: Sharpe, Sortino, Calmar, Information ratios
- **Drawdown Analysis**: Peak-to-trough analysis with recovery
- **Performance Attribution**: Alpha, beta, tracking error
## Installation
```bash
cd packages/agentic-synth
npm install
```
## Usage
### Running Individual Examples
```bash
# Market data generation
npx ts-node examples/stocks/market-data.ts
# Trading scenarios
npx ts-node examples/stocks/trading-scenarios.ts
# Portfolio simulation
npx ts-node examples/stocks/portfolio-simulation.ts
```
### Importing in Your Code
```typescript
import {
generateOHLCVData,
generateTechnicalIndicators,
generateMultiTimeframeData,
} from './examples/stocks/market-data';
import {
generateBullMarket,
generateBearMarket,
generateFlashCrash,
} from './examples/stocks/trading-scenarios';
import {
generateMultiAssetPortfolio,
generateRebalancingScenarios,
generateRiskAdjustedReturns,
} from './examples/stocks/portfolio-simulation';
// Use in your application
const ohlcvData = await generateOHLCVData();
const bullMarket = await generateBullMarket();
const portfolio = await generateMultiAssetPortfolio();
```
## Examples
### 1. OHLCV Data Generation
Generate realistic candlestick data with proper OHLCV relationships:
```typescript
const ohlcvData = await generateOHLCVData();
// Returns: Array of 390 1-minute bars for a trading day
// Each bar: { timestamp, open, high, low, close, volume, symbol }
```
**Key Features:**
- High >= max(open, close)
- Low <= min(open, close)
- Next bar opens at previous close
- Realistic volume patterns
### 2. Technical Indicators
Calculate common technical indicators on price data:
```typescript
const technicalData = await generateTechnicalIndicators();
// Returns: Price data with SMA, RSI, MACD, Bollinger Bands
```
**Indicators Included:**
- SMA 20 & 50 (Simple Moving Averages)
- RSI 14 (Relative Strength Index)
- MACD & Signal Line
- Bollinger Bands (upper, middle, lower)
### 3. Multi-Timeframe Data
Generate data across multiple timeframes with proper aggregation:
```typescript
const multiTF = await generateMultiTimeframeData();
// Returns: { '1m': [], '5m': [], '1h': [], '1d': [] }
```
**Timeframes:**
- 1-minute bars (base timeframe)
- 5-minute bars (aggregated from 1m)
- 1-hour bars (aggregated from 1m)
- 1-day bars (aggregated from 1m)
### 4. Market Depth (Order Book)
Generate Level 2 market depth data:
```typescript
const marketDepth = await generateMarketDepth();
// Returns: Order book snapshots with bids/asks
```
**Order Book Features:**
- 20 levels on each side
- Realistic size distribution
- Order count per level
- Spread and mid-price calculation
### 5. Bull Market Scenario
Simulate a sustained uptrend:
```typescript
const bullMarket = await generateBullMarket();
// Generates: 252 days of bull market with ~20% annual return
```
**Characteristics:**
- Upward drift with occasional pullbacks
- Lower volatility
- Volume increases on breakouts
- Momentum indicators trend positive
### 6. Flash Crash Simulation
Model rapid price decline and recovery:
```typescript
const flashCrash = await generateFlashCrash();
// Phases: Normal → Crash (15% drop) → Recovery
```
**Phases:**
- **Normal**: Typical trading patterns
- **Crash**: Exponential price decay, wide spreads, liquidity evaporation
- **Recovery**: Quick rebound with reduced liquidity
### 7. Multi-Asset Portfolio
Create a diversified portfolio across asset classes:
```typescript
const portfolio = await generateMultiAssetPortfolio();
// Returns: { portfolioData, portfolioMetrics, assets }
```
**Asset Allocation:**
- 60% Equities (SPY, QQQ, IWM, EFA)
- 30% Fixed Income (AGG, TLT)
- 10% Alternatives (GLD, VNQ)
**Metrics Tracked:**
- Total value and returns
- Sharpe ratio
- Maximum drawdown
- Volatility
- Alpha and beta
### 8. Rebalancing Scenarios
Simulate portfolio rebalancing strategies:
```typescript
const rebalancing = await generateRebalancingScenarios();
// Returns: Rebalance events with trades and costs
```
**Rebalancing Types:**
- **Calendar**: Quarterly (every 63 trading days)
- **Threshold**: When drift exceeds 5%
- **Opportunistic**: Based on market conditions
### 9. Drawdown Analysis
Comprehensive drawdown tracking and analysis:
```typescript
const drawdowns = await generateDrawdownAnalysis();
// Returns: All drawdown periods with recovery info
```
**Drawdown Metrics:**
- Maximum drawdown (peak to trough)
- Drawdown duration
- Recovery duration
- Currently underwater status
- Top 5 largest drawdowns
## Realistic Patterns
All generated data includes realistic market microstructure patterns:
### Price Dynamics
- **Mean Reversion**: Prices tend to revert to moving averages
- **Momentum**: Trends persist with gradual reversals
- **Volatility Clustering**: Volatile periods cluster together
- **Fat Tails**: Extreme moves occur more than normal distribution
### Volume Patterns
- **Volume-Price Relationship**: Volume increases with volatility
- **Institutional Activity**: Block trades and large orders
- **Time-of-Day**: Higher volume at open and close
- **Event-Driven**: Spikes during announcements
### Market Microstructure
- **Bid-Ask Spread**: Realistic spread dynamics
- **Market Impact**: Large orders move prices
- **Liquidity**: Depth varies with market conditions
- **Order Imbalance**: Buy/sell pressure affects prices
## Regulatory Compliance
All generated data follows regulatory standards:
### Trade Conditions
- `BLOCK`: Large institutional trades (100+ shares)
- `INSTITUTIONAL`: Very large orders (10,000+ shares)
- `ODD_LOT`: Non-standard lot sizes
- `EXTENDED_HOURS`: Pre-market and after-hours trades
### Data Quality
- No negative prices or volumes
- OHLCV relationships enforced
- Realistic tick sizes (pennies)
- Proper timestamp ordering
### Risk Disclosures
⚠️ **IMPORTANT**: This is simulated data for testing purposes only. Do not use for:
- Production trading decisions
- Financial advice
- Regulatory reporting
- Real money trading without proper validation
## Performance
Generation performance for typical use cases:
| Dataset | Size | Generation Time |
|---------|------|----------------|
| 1-day OHLCV (1m) | 390 bars | ~50ms |
| 1-year daily | 252 bars | ~30ms |
| Tick data | 10,000 ticks | ~200ms |
| Order book | 100 snapshots | ~150ms |
| Multi-asset portfolio | 252 days | ~500ms |
## Advanced Usage
### Custom Asset Classes
```typescript
const customAssets: Asset[] = [
{
symbol: 'CUSTOM',
assetClass: 'equity',
weight: 0.50,
expectedReturn: 0.15,
volatility: 0.25,
},
// Add more assets...
];
```
### Custom Rebalancing Logic
```typescript
const rebalanceThreshold = 0.10; // 10% drift
const rebalanceFrequency = 21; // Monthly
// Implement custom rebalancing logic
if (shouldRebalance(portfolio, threshold)) {
await rebalance(portfolio, targetWeights);
}
```
### Custom Risk Metrics
```typescript
// Calculate custom risk metrics
const varCalc = (returns: number[], confidence: number) => {
const sorted = returns.sort((a, b) => a - b);
const index = Math.floor(returns.length * (1 - confidence));
return sorted[index];
};
const var95 = varCalc(returns, 0.95);
const cvar95 = returns.filter(r => r <= var95).reduce((a, b) => a + b) / returns.length;
```
## Testing Trading Systems
These examples are ideal for:
1. **Backtesting**: Test strategies against historical scenarios
2. **Stress Testing**: Evaluate performance under extreme conditions
3. **Risk Management**: Validate risk models and limits
4. **Algorithm Development**: Develop and tune trading algorithms
5. **Portfolio Optimization**: Test allocation strategies
### Example Backtest
```typescript
// Generate test data
const bullMarket = await generateBullMarket();
const bearMarket = await generateBearMarket();
const flashCrash = await generateFlashCrash();
// Test strategy on each scenario
const results = {
bull: await backtest(strategy, bullMarket),
bear: await backtest(strategy, bearMarket),
crash: await backtest(strategy, flashCrash),
};
// Analyze results
console.log('Strategy Performance:');
console.log(`Bull Market: ${results.bull.return}%`);
console.log(`Bear Market: ${results.bear.return}%`);
console.log(`Flash Crash: ${results.crash.maxDrawdown}%`);
```
## Contributing
Contributions are welcome! Areas for improvement:
- [ ] Options pricing data
- [ ] Futures and derivatives
- [ ] Cryptocurrency markets
- [ ] FX (foreign exchange) data
- [ ] High-frequency market making scenarios
- [ ] Credit spreads and fixed income
- [ ] Alternative data integration
## Resources
### Financial Concepts
- [Market Microstructure](https://en.wikipedia.org/wiki/Market_microstructure)
- [Technical Analysis](https://www.investopedia.com/technical-analysis-4689657)
- [Portfolio Theory](https://www.investopedia.com/terms/m/modernportfoliotheory.asp)
- [Risk Metrics](https://www.investopedia.com/terms/r/riskadjustedreturn.asp)
### Trading System Development
- [Quantitative Trading](https://www.quantstart.com/)
- [Algorithmic Trading](https://www.algorithmictrading.net/)
- [Backtesting Best Practices](https://www.quantconnect.com/docs/)
### Regulatory Guidelines
- [SEC Trading Rules](https://www.sec.gov/fast-answers)
- [FINRA Regulations](https://www.finra.org/rules-guidance)
- [Market Data Standards](https://www.iso20022.org/)
## License
MIT License - see LICENSE file for details
## Disclaimer
This software is for educational and testing purposes only. The authors are not responsible for any financial losses incurred from using this software. Always consult with a qualified financial advisor before making investment decisions.
**Past performance does not guarantee future results.**

View File

@@ -0,0 +1,61 @@
/**
* Stock Market Data Generation Examples
*
* Demonstrates realistic OHLCV data generation, technical indicators,
* multi-timeframe data, market depth, and tick-by-tick simulation.
*/
interface OHLCVBar {
timestamp: Date;
open: number;
high: number;
low: number;
close: number;
volume: number;
symbol: string;
}
/**
* Generate realistic OHLCV (candlestick) data with proper market microstructure
*/
declare function generateOHLCVData(): Promise<any>;
interface TechnicalIndicators {
timestamp: Date;
price: number;
sma_20: number;
sma_50: number;
rsi_14: number;
macd: number;
macd_signal: number;
bb_upper: number;
bb_middle: number;
bb_lower: number;
volume: number;
symbol: string;
}
/**
* Generate price data with technical indicators pre-calculated
*/
declare function generateTechnicalIndicators(): Promise<TechnicalIndicators[]>;
interface MultiTimeframeData {
'1m': OHLCVBar[];
'5m': OHLCVBar[];
'1h': OHLCVBar[];
'1d': OHLCVBar[];
}
/**
* Generate data across multiple timeframes with proper aggregation
*/
declare function generateMultiTimeframeData(): Promise<MultiTimeframeData>;
/**
* Generate realistic Level 2 market depth data (order book)
*/
declare function generateMarketDepth(): Promise<any>;
/**
* Generate high-frequency tick-by-tick trade data
*/
declare function generateTickData(): Promise<any>;
/**
* Generate market microstructure metrics for analysis
*/
declare function generateMicrostructureMetrics(): Promise<any>;
export { generateOHLCVData, generateTechnicalIndicators, generateMultiTimeframeData, generateMarketDepth, generateTickData, generateMicrostructureMetrics, };
//# sourceMappingURL=market-data.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"market-data.d.ts","sourceRoot":"","sources":["market-data.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,UAAU,QAAQ;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,iBAAe,iBAAiB,iBAmD/B;AAMD,UAAU,mBAAmB;IAC3B,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,iBAAe,2BAA2B,mCAwEzC;AAMD,UAAU,kBAAkB;IAC1B,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,iBAAe,0BAA0B,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAgFvE;AAqBD;;GAEG;AACH,iBAAe,mBAAmB,iBAiEjC;AAgBD;;GAEG;AACH,iBAAe,gBAAgB,iBA+D9B;AAiBD;;GAEG;AACH,iBAAe,6BAA6B,iBA0B3C;AAiDD,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,0BAA0B,EAC1B,mBAAmB,EACnB,gBAAgB,EAChB,6BAA6B,GAC9B,CAAC"}

View File

@@ -0,0 +1,404 @@
"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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,543 @@
/**
* Stock Market Data Generation Examples
*
* Demonstrates realistic OHLCV data generation, technical indicators,
* multi-timeframe data, market depth, and tick-by-tick simulation.
*/
import { AgenticSynth } from '../../../src';
// ============================================================================
// OHLCV Data Generation
// ============================================================================
interface OHLCVBar {
timestamp: Date;
open: number;
high: number;
low: number;
close: number;
volume: number;
symbol: string;
}
/**
* Generate realistic OHLCV (candlestick) data with proper market microstructure
*/
async function generateOHLCVData() {
const synth = new AgenticSynth();
const ohlcvData = await synth.generate<OHLCVBar>({
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;
}
// ============================================================================
// Technical Indicators
// ============================================================================
interface TechnicalIndicators {
timestamp: Date;
price: number;
sma_20: number;
sma_50: number;
rsi_14: number;
macd: number;
macd_signal: number;
bb_upper: number;
bb_middle: number;
bb_lower: number;
volume: number;
symbol: string;
}
/**
* Generate price data with technical indicators pre-calculated
*/
async function generateTechnicalIndicators() {
const synth = new AgenticSynth();
// First generate base price series
const priceData = await synth.generate<{ price: number; volume: number }>({
count: 100,
template: {
price: '{{number.float(150, 160, 2)}}',
volume: '{{number.int(1000000, 5000000)}}',
},
});
// Calculate indicators (simplified for demonstration)
const calculateSMA = (data: number[], period: number): number[] => {
const sma: number[] = [];
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: number[], period: number = 14): number[] => {
const rsi: number[] = [];
for (let i = 0; i < data.length; i++) {
if (i < period) {
rsi.push(50); // Neutral RSI for initial period
} else {
const gains: number[] = [];
const losses: number[] = [];
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: TechnicalIndicators[] = 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;
}
// ============================================================================
// Multi-Timeframe Data
// ============================================================================
interface MultiTimeframeData {
'1m': OHLCVBar[];
'5m': OHLCVBar[];
'1h': OHLCVBar[];
'1d': OHLCVBar[];
}
/**
* Generate data across multiple timeframes with proper aggregation
*/
async function generateMultiTimeframeData(): Promise<MultiTimeframeData> {
const synth = new AgenticSynth();
// Generate 1-minute bars (base timeframe)
const bars1m = await synth.generate<OHLCVBar>({
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: OHLCVBar[] = [];
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: OHLCVBar[] = [];
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: OHLCVBar[] = [];
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,
};
}
// ============================================================================
// Market Depth Data (Order Book)
// ============================================================================
interface OrderBookLevel {
price: number;
size: number;
orders: number;
}
interface MarketDepth {
timestamp: Date;
symbol: string;
bids: OrderBookLevel[];
asks: OrderBookLevel[];
spread: number;
midPrice: number;
}
/**
* Generate realistic Level 2 market depth data (order book)
*/
async function generateMarketDepth() {
const synth = new AgenticSynth();
const midPrice = 150.0;
const tickSize = 0.01;
const depth = 20; // 20 levels on each side
const marketDepth = await synth.generate<MarketDepth>({
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: OrderBookLevel[] = [];
const asks: OrderBookLevel[] = [];
// 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;
}
// ============================================================================
// Tick-by-Tick Data
// ============================================================================
interface Tick {
timestamp: Date;
symbol: string;
price: number;
size: number;
side: 'buy' | 'sell';
exchange: string;
conditions: string[];
}
/**
* Generate high-frequency tick-by-tick trade data
*/
async function generateTickData() {
const synth = new AgenticSynth();
const tickData = await synth.generate<Tick>({
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: string[] = [];
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;
}
// ============================================================================
// Market Microstructure Patterns
// ============================================================================
interface MicrostructureMetrics {
timestamp: Date;
symbol: string;
effectiveSpread: number;
realizedSpread: number;
priceImpact: number;
toxicity: number; // Adverse selection measure
orderImbalance: number;
volatility: number;
}
/**
* Generate market microstructure metrics for analysis
*/
async function generateMicrostructureMetrics() {
const synth = new AgenticSynth();
const metrics = await synth.generate<MicrostructureMetrics>({
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();
}
export {
generateOHLCVData,
generateTechnicalIndicators,
generateMultiTimeframeData,
generateMarketDepth,
generateTickData,
generateMicrostructureMetrics,
};

View File

@@ -0,0 +1,104 @@
/**
* Portfolio Simulation and Management
*
* Generate realistic portfolio data for:
* - Multi-asset portfolios
* - Rebalancing scenarios
* - Risk-adjusted returns
* - Drawdown analysis
* - Performance attribution
*/
interface Asset {
symbol: string;
assetClass: 'equity' | 'fixedIncome' | 'commodity' | 'crypto' | 'alternative';
weight: number;
expectedReturn: number;
volatility: number;
}
interface PortfolioHolding {
timestamp: Date;
symbol: string;
shares: number;
price: number;
marketValue: number;
weight: number;
dayReturn: number;
totalReturn: number;
}
interface PortfolioMetrics {
timestamp: Date;
totalValue: number;
cashBalance: number;
totalReturn: number;
dailyReturn: number;
volatility: number;
sharpeRatio: number;
maxDrawdown: number;
beta: number;
alpha: number;
}
/**
* Generate a diversified multi-asset portfolio
*/
declare function generateMultiAssetPortfolio(): Promise<{
portfolioData: Map<string, PortfolioHolding[]>;
portfolioMetrics: PortfolioMetrics[];
assets: Asset[];
}>;
interface RebalanceEvent {
timestamp: Date;
type: 'calendar' | 'threshold' | 'opportunistic';
holdings: PortfolioHolding[];
targetWeights: Record<string, number>;
actualWeights: Record<string, number>;
trades: Trade[];
transactionCosts: number;
}
interface Trade {
symbol: string;
action: 'buy' | 'sell';
shares: number;
price: number;
value: number;
commission: number;
}
/**
* Generate portfolio rebalancing scenarios
*/
declare function generateRebalancingScenarios(): Promise<RebalanceEvent[]>;
interface RiskMetrics {
timestamp: Date;
portfolioReturn: number;
benchmarkReturn: number;
excessReturn: number;
trackingError: number;
informationRatio: number;
sharpeRatio: number;
sortinoRatio: number;
calmarRatio: number;
beta: number;
alpha: number;
correlation: number;
}
/**
* Calculate comprehensive risk-adjusted return metrics
*/
declare function generateRiskAdjustedReturns(): Promise<RiskMetrics[]>;
interface DrawdownPeriod {
startDate: Date;
troughDate: Date;
endDate: Date | null;
peakValue: number;
troughValue: number;
recoveryValue: number | null;
drawdown: number;
duration: number;
recoveryDuration: number | null;
underwater: boolean;
}
/**
* Analyze portfolio drawdowns
*/
declare function generateDrawdownAnalysis(): Promise<DrawdownPeriod[]>;
export { generateMultiAssetPortfolio, generateRebalancingScenarios, generateRiskAdjustedReturns, generateDrawdownAnalysis, };
//# sourceMappingURL=portfolio-simulation.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"portfolio-simulation.d.ts","sourceRoot":"","sources":["portfolio-simulation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,QAAQ,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,GAAG,aAAa,CAAC;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAMD;;GAEG;AACH,iBAAe,2BAA2B;;;;GAqIzC;AAMD,UAAU,cAAc;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,eAAe,CAAC;IACjD,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,iBAAe,4BAA4B,8BAkG1C;AAMD,UAAU,WAAW;IACnB,SAAS,EAAE,IAAI,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,iBAAe,2BAA2B,2BAmGzC;AAMD,UAAU,cAAc;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,iBAAe,wBAAwB,8BA0FtC;AAwCD,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,GACzB,CAAC"}

View File

@@ -0,0 +1,395 @@
"use strict";
/**
* Portfolio Simulation and Management
*
* Generate realistic portfolio data for:
* - Multi-asset portfolios
* - Rebalancing scenarios
* - Risk-adjusted returns
* - Drawdown analysis
* - Performance attribution
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateMultiAssetPortfolio = generateMultiAssetPortfolio;
exports.generateRebalancingScenarios = generateRebalancingScenarios;
exports.generateRiskAdjustedReturns = generateRiskAdjustedReturns;
exports.generateDrawdownAnalysis = generateDrawdownAnalysis;
const src_1 = require("../../../src");
// ============================================================================
// Multi-Asset Portfolio Generation
// ============================================================================
/**
* Generate a diversified multi-asset portfolio
*/
async function generateMultiAssetPortfolio() {
const synth = new src_1.AgenticSynth();
// Define portfolio composition
const assets = [
// Equities (60%)
{ symbol: 'SPY', assetClass: 'equity', weight: 0.30, expectedReturn: 0.10, volatility: 0.15 },
{ symbol: 'QQQ', assetClass: 'equity', weight: 0.15, expectedReturn: 0.12, volatility: 0.20 },
{ symbol: 'IWM', assetClass: 'equity', weight: 0.10, expectedReturn: 0.11, volatility: 0.18 },
{ symbol: 'EFA', assetClass: 'equity', weight: 0.05, expectedReturn: 0.08, volatility: 0.16 },
// Fixed Income (30%)
{ symbol: 'AGG', assetClass: 'fixedIncome', weight: 0.20, expectedReturn: 0.04, volatility: 0.05 },
{ symbol: 'TLT', assetClass: 'fixedIncome', weight: 0.10, expectedReturn: 0.03, volatility: 0.12 },
// Alternatives (10%)
{ symbol: 'GLD', assetClass: 'commodity', weight: 0.05, expectedReturn: 0.05, volatility: 0.15 },
{ symbol: 'VNQ', assetClass: 'alternative', weight: 0.05, expectedReturn: 0.08, volatility: 0.17 },
];
const days = 252; // One year
const initialValue = 1000000; // $1M portfolio
// Generate price series for each asset
const portfolioData = new Map();
for (const asset of assets) {
const initialPrice = 100;
let currentPrice = initialPrice;
const shares = (initialValue * asset.weight) / initialPrice;
const holdings = [];
for (let day = 0; day < days; day++) {
// Generate correlated returns
const marketReturn = (Math.random() - 0.5) * 0.02;
const idiosyncraticReturn = (Math.random() - 0.5) * asset.volatility * 0.5;
const dailyReturn = marketReturn * 0.7 + idiosyncraticReturn + asset.expectedReturn / 252;
currentPrice *= 1 + dailyReturn;
const marketValue = shares * currentPrice;
const totalReturn = (currentPrice - initialPrice) / initialPrice;
holdings.push({
timestamp: new Date(Date.now() - (days - day) * 86400000),
symbol: asset.symbol,
shares,
price: Number(currentPrice.toFixed(2)),
marketValue: Number(marketValue.toFixed(2)),
weight: asset.weight, // Will be updated later
dayReturn: Number(dailyReturn.toFixed(6)),
totalReturn: Number(totalReturn.toFixed(6)),
});
}
portfolioData.set(asset.symbol, holdings);
}
// Calculate portfolio-level metrics
const portfolioMetrics = [];
for (let day = 0; day < days; day++) {
let totalValue = 0;
let dailyReturn = 0;
assets.forEach((asset) => {
const holding = portfolioData.get(asset.symbol)[day];
totalValue += holding.marketValue;
dailyReturn += holding.dayReturn * asset.weight;
});
// Update weights based on current market values
assets.forEach((asset) => {
const holding = portfolioData.get(asset.symbol)[day];
holding.weight = holding.marketValue / totalValue;
});
// Calculate metrics
const returns = Array.from({ length: Math.min(day + 1, 60) }, (_, i) => {
let ret = 0;
assets.forEach((asset) => {
ret += portfolioData.get(asset.symbol)[day - i]?.dayReturn || 0;
});
return ret;
});
const volatility = Math.sqrt(returns.reduce((sum, r) => sum + Math.pow(r, 2), 0) / returns.length) * Math.sqrt(252);
const totalReturn = (totalValue - initialValue) / initialValue;
const sharpeRatio = (totalReturn * 252) / (volatility + 0.0001);
// Calculate max drawdown
const portfolioValues = Array.from({ length: day + 1 }, (_, i) => {
let val = 0;
assets.forEach((asset) => {
val += portfolioData.get(asset.symbol)[i].marketValue;
});
return val;
});
const maxDrawdown = portfolioValues.reduce((maxDD, val, i) => {
const peak = Math.max(...portfolioValues.slice(0, i + 1));
const dd = (val - peak) / peak;
return Math.min(maxDD, dd);
}, 0);
portfolioMetrics.push({
timestamp: new Date(Date.now() - (days - day) * 86400000),
totalValue: Number(totalValue.toFixed(2)),
cashBalance: 0,
totalReturn: Number(totalReturn.toFixed(6)),
dailyReturn: Number(dailyReturn.toFixed(6)),
volatility: Number(volatility.toFixed(4)),
sharpeRatio: Number(sharpeRatio.toFixed(2)),
maxDrawdown: Number(maxDrawdown.toFixed(4)),
beta: 0.95, // Simplified
alpha: Number(((totalReturn - 0.08 * (day / 252)) / (day / 252 + 0.0001)).toFixed(4)),
});
}
console.log('Multi-Asset Portfolio:');
console.log({
initialValue,
finalValue: portfolioMetrics[portfolioMetrics.length - 1].totalValue,
totalReturn: (portfolioMetrics[portfolioMetrics.length - 1].totalReturn * 100).toFixed(2) + '%',
sharpeRatio: portfolioMetrics[portfolioMetrics.length - 1].sharpeRatio,
maxDrawdown: (portfolioMetrics[portfolioMetrics.length - 1].maxDrawdown * 100).toFixed(2) + '%',
volatility: (portfolioMetrics[portfolioMetrics.length - 1].volatility * 100).toFixed(2) + '%',
});
return { portfolioData, portfolioMetrics, assets };
}
/**
* Generate portfolio rebalancing scenarios
*/
async function generateRebalancingScenarios() {
const synth = new src_1.AgenticSynth();
// Start with portfolio from previous function
const { portfolioData, assets } = await generateMultiAssetPortfolio();
const rebalanceEvents = [];
const rebalanceThreshold = 0.05; // Rebalance if drift > 5%
const rebalanceFrequency = 63; // Quarterly (every 63 trading days)
const days = 252;
for (let day = 0; day < days; day++) {
const currentHoldings = [];
let totalValue = 0;
// Get current holdings
assets.forEach((asset) => {
const holding = portfolioData.get(asset.symbol)[day];
currentHoldings.push(holding);
totalValue += holding.marketValue;
});
// Calculate current weights
const actualWeights = {};
currentHoldings.forEach((holding) => {
actualWeights[holding.symbol] = holding.marketValue / totalValue;
});
// Check if rebalancing is needed
const targetWeights = {};
assets.forEach((asset) => {
targetWeights[asset.symbol] = asset.weight;
});
let maxDrift = 0;
Object.keys(targetWeights).forEach((symbol) => {
const drift = Math.abs(actualWeights[symbol] - targetWeights[symbol]);
maxDrift = Math.max(maxDrift, drift);
});
const shouldRebalance = maxDrift > rebalanceThreshold || day % rebalanceFrequency === 0;
if (shouldRebalance) {
const trades = [];
let transactionCosts = 0;
// Generate trades to rebalance
Object.keys(targetWeights).forEach((symbol) => {
const currentWeight = actualWeights[symbol];
const targetWeight = targetWeights[symbol];
const targetValue = totalValue * targetWeight;
const currentValue = totalValue * currentWeight;
const deltaValue = targetValue - currentValue;
const holding = currentHoldings.find((h) => h.symbol === symbol);
const deltaShares = deltaValue / holding.price;
if (Math.abs(deltaShares) > 1) {
const commission = Math.abs(deltaValue) * 0.0005; // 5 bps
transactionCosts += commission;
trades.push({
symbol,
action: deltaShares > 0 ? 'buy' : 'sell',
shares: Math.abs(Math.floor(deltaShares)),
price: holding.price,
value: Math.abs(deltaValue),
commission,
});
}
});
rebalanceEvents.push({
timestamp: new Date(Date.now() - (days - day) * 86400000),
type: maxDrift > rebalanceThreshold * 2 ? 'threshold' : 'calendar',
holdings: currentHoldings,
targetWeights,
actualWeights,
trades,
transactionCosts,
});
}
}
console.log('Rebalancing Scenarios:');
console.log({
totalRebalances: rebalanceEvents.length,
avgTransactionCosts: rebalanceEvents.reduce((sum, e) => sum + e.transactionCosts, 0) /
rebalanceEvents.length,
totalTransactionCosts: rebalanceEvents.reduce((sum, e) => sum + e.transactionCosts, 0),
});
return rebalanceEvents;
}
/**
* Calculate comprehensive risk-adjusted return metrics
*/
async function generateRiskAdjustedReturns() {
const { portfolioMetrics } = await generateMultiAssetPortfolio();
const riskFreeRate = 0.04; // 4% annual
const dailyRfRate = riskFreeRate / 252;
const riskMetrics = portfolioMetrics.map((metrics, idx) => {
// Simulate benchmark (S&P 500)
const benchmarkReturn = metrics.dailyReturn * 0.95 + (Math.random() - 0.5) * 0.005;
const excessReturn = metrics.dailyReturn - dailyRfRate;
// Calculate rolling metrics
const window = Math.min(60, idx + 1);
const recentReturns = portfolioMetrics
.slice(Math.max(0, idx - window), idx + 1)
.map((m) => m.dailyReturn);
const recentBenchmarkReturns = Array.from({ length: window }, (_, i) => portfolioMetrics[Math.max(0, idx - window + i)].dailyReturn * 0.95);
// Tracking error
const trackingDiffs = recentReturns.map((r, i) => r - recentBenchmarkReturns[i]);
const trackingError = Math.sqrt(trackingDiffs.reduce((sum, d) => sum + Math.pow(d, 2), 0) / window) * Math.sqrt(252);
// Information ratio
const avgExcessReturn = trackingDiffs.reduce((sum, d) => sum + d, 0) / window;
const informationRatio = (avgExcessReturn * 252) / (trackingError + 0.0001);
// Sortino ratio (downside deviation)
const downsideReturns = recentReturns.filter((r) => r < dailyRfRate);
const downsideDeviation = downsideReturns.length > 0
? Math.sqrt(downsideReturns.reduce((sum, r) => sum + Math.pow(r - dailyRfRate, 2), 0) / downsideReturns.length) * Math.sqrt(252)
: 0.0001;
const avgReturn = recentReturns.reduce((sum, r) => sum + r, 0) / window;
const sortinoRatio = ((avgReturn - dailyRfRate) * 252) / downsideDeviation;
// Calmar ratio
const calmarRatio = (avgReturn * 252) / (Math.abs(metrics.maxDrawdown) + 0.0001);
// Beta and alpha
const benchmarkVar = recentBenchmarkReturns.reduce((sum, r) => sum + Math.pow(r - avgReturn, 2), 0) / window;
const covariance = recentReturns.reduce((sum, r, i) => sum + (r - avgReturn) * (recentBenchmarkReturns[i] - avgReturn), 0) / window;
const beta = covariance / (benchmarkVar + 0.0001);
const alpha = (avgReturn - dailyRfRate - beta * (avgReturn * 0.95 - dailyRfRate)) * 252;
// Correlation
const correlation = covariance / (Math.sqrt(benchmarkVar) * metrics.volatility / Math.sqrt(252) + 0.0001);
return {
timestamp: metrics.timestamp,
portfolioReturn: metrics.dailyReturn,
benchmarkReturn,
excessReturn,
trackingError: Number(trackingError.toFixed(4)),
informationRatio: Number(informationRatio.toFixed(2)),
sharpeRatio: metrics.sharpeRatio,
sortinoRatio: Number(sortinoRatio.toFixed(2)),
calmarRatio: Number(calmarRatio.toFixed(2)),
beta: Number(beta.toFixed(2)),
alpha: Number(alpha.toFixed(4)),
correlation: Number(correlation.toFixed(2)),
};
});
console.log('Risk-Adjusted Returns (final metrics):');
const finalMetrics = riskMetrics[riskMetrics.length - 1];
console.log({
sharpeRatio: finalMetrics.sharpeRatio,
sortinoRatio: finalMetrics.sortinoRatio,
calmarRatio: finalMetrics.calmarRatio,
informationRatio: finalMetrics.informationRatio,
beta: finalMetrics.beta,
alpha: (finalMetrics.alpha * 100).toFixed(2) + '%',
correlation: finalMetrics.correlation,
});
return riskMetrics;
}
/**
* Analyze portfolio drawdowns
*/
async function generateDrawdownAnalysis() {
const { portfolioMetrics } = await generateMultiAssetPortfolio();
const drawdowns = [];
let currentPeak = portfolioMetrics[0].totalValue;
let currentPeakDate = portfolioMetrics[0].timestamp;
let inDrawdown = false;
let troughValue = currentPeak;
let troughDate = currentPeakDate;
let startDate = currentPeakDate;
portfolioMetrics.forEach((metrics, idx) => {
if (metrics.totalValue > currentPeak) {
// New peak
if (inDrawdown) {
// End of drawdown - recovery complete
drawdowns[drawdowns.length - 1].endDate = metrics.timestamp;
drawdowns[drawdowns.length - 1].recoveryValue = metrics.totalValue;
drawdowns[drawdowns.length - 1].recoveryDuration =
(metrics.timestamp.getTime() - troughDate.getTime()) / 86400000;
drawdowns[drawdowns.length - 1].underwater = false;
inDrawdown = false;
}
currentPeak = metrics.totalValue;
currentPeakDate = metrics.timestamp;
}
else if (metrics.totalValue < currentPeak) {
// In drawdown
if (!inDrawdown) {
// Start of new drawdown
startDate = currentPeakDate;
troughValue = metrics.totalValue;
troughDate = metrics.timestamp;
inDrawdown = true;
}
if (metrics.totalValue < troughValue) {
troughValue = metrics.totalValue;
troughDate = metrics.timestamp;
}
// Update or create drawdown record
const dd = (metrics.totalValue - currentPeak) / currentPeak;
const duration = (troughDate.getTime() - startDate.getTime()) / 86400000;
if (drawdowns.length === 0 || !drawdowns[drawdowns.length - 1].underwater) {
drawdowns.push({
startDate,
troughDate,
endDate: null,
peakValue: currentPeak,
troughValue,
recoveryValue: null,
drawdown: dd,
duration,
recoveryDuration: null,
underwater: true,
});
}
else {
drawdowns[drawdowns.length - 1].troughDate = troughDate;
drawdowns[drawdowns.length - 1].troughValue = troughValue;
drawdowns[drawdowns.length - 1].drawdown = dd;
drawdowns[drawdowns.length - 1].duration = duration;
}
}
});
// Sort by drawdown magnitude
const sortedDrawdowns = drawdowns.sort((a, b) => a.drawdown - b.drawdown);
console.log('Drawdown Analysis:');
console.log({
totalDrawdowns: drawdowns.length,
maxDrawdown: (sortedDrawdowns[0].drawdown * 100).toFixed(2) + '%',
avgDrawdown: ((drawdowns.reduce((sum, dd) => sum + dd.drawdown, 0) / drawdowns.length) *
100).toFixed(2) + '%',
longestDrawdown: Math.max(...drawdowns.map((dd) => dd.duration)),
currentlyUnderwater: drawdowns[drawdowns.length - 1]?.underwater || false,
});
console.log('\nTop 5 Drawdowns:');
sortedDrawdowns.slice(0, 5).forEach((dd, idx) => {
console.log(`${idx + 1}. ${(dd.drawdown * 100).toFixed(2)}% over ${dd.duration} days, ` +
`recovered in ${dd.recoveryDuration || 'N/A'} days`);
});
return drawdowns;
}
// ============================================================================
// Main Execution
// ============================================================================
async function main() {
console.log('='.repeat(80));
console.log('Portfolio Simulation and Management');
console.log('='.repeat(80));
console.log();
try {
console.log('1. Generating Multi-Asset Portfolio...');
await generateMultiAssetPortfolio();
console.log();
console.log('2. Generating Rebalancing Scenarios...');
await generateRebalancingScenarios();
console.log();
console.log('3. Calculating Risk-Adjusted Returns...');
await generateRiskAdjustedReturns();
console.log();
console.log('4. Analyzing Drawdowns...');
await generateDrawdownAnalysis();
console.log();
console.log('All portfolio simulations completed successfully!');
}
catch (error) {
console.error('Error generating portfolio simulations:', error);
process.exit(1);
}
}
if (require.main === module) {
main();
}
//# sourceMappingURL=portfolio-simulation.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,596 @@
/**
* Portfolio Simulation and Management
*
* Generate realistic portfolio data for:
* - Multi-asset portfolios
* - Rebalancing scenarios
* - Risk-adjusted returns
* - Drawdown analysis
* - Performance attribution
*/
import { AgenticSynth } from '../../../src';
// ============================================================================
// Portfolio Types and Interfaces
// ============================================================================
interface Asset {
symbol: string;
assetClass: 'equity' | 'fixedIncome' | 'commodity' | 'crypto' | 'alternative';
weight: number;
expectedReturn: number;
volatility: number;
}
interface PortfolioHolding {
timestamp: Date;
symbol: string;
shares: number;
price: number;
marketValue: number;
weight: number;
dayReturn: number;
totalReturn: number;
}
interface PortfolioMetrics {
timestamp: Date;
totalValue: number;
cashBalance: number;
totalReturn: number;
dailyReturn: number;
volatility: number;
sharpeRatio: number;
maxDrawdown: number;
beta: number;
alpha: number;
}
// ============================================================================
// Multi-Asset Portfolio Generation
// ============================================================================
/**
* Generate a diversified multi-asset portfolio
*/
async function generateMultiAssetPortfolio() {
const synth = new AgenticSynth();
// Define portfolio composition
const assets: Asset[] = [
// Equities (60%)
{ symbol: 'SPY', assetClass: 'equity', weight: 0.30, expectedReturn: 0.10, volatility: 0.15 },
{ symbol: 'QQQ', assetClass: 'equity', weight: 0.15, expectedReturn: 0.12, volatility: 0.20 },
{ symbol: 'IWM', assetClass: 'equity', weight: 0.10, expectedReturn: 0.11, volatility: 0.18 },
{ symbol: 'EFA', assetClass: 'equity', weight: 0.05, expectedReturn: 0.08, volatility: 0.16 },
// Fixed Income (30%)
{ symbol: 'AGG', assetClass: 'fixedIncome', weight: 0.20, expectedReturn: 0.04, volatility: 0.05 },
{ symbol: 'TLT', assetClass: 'fixedIncome', weight: 0.10, expectedReturn: 0.03, volatility: 0.12 },
// Alternatives (10%)
{ symbol: 'GLD', assetClass: 'commodity', weight: 0.05, expectedReturn: 0.05, volatility: 0.15 },
{ symbol: 'VNQ', assetClass: 'alternative', weight: 0.05, expectedReturn: 0.08, volatility: 0.17 },
];
const days = 252; // One year
const initialValue = 1000000; // $1M portfolio
// Generate price series for each asset
const portfolioData: Map<string, PortfolioHolding[]> = new Map();
for (const asset of assets) {
const initialPrice = 100;
let currentPrice = initialPrice;
const shares = (initialValue * asset.weight) / initialPrice;
const holdings: PortfolioHolding[] = [];
for (let day = 0; day < days; day++) {
// Generate correlated returns
const marketReturn = (Math.random() - 0.5) * 0.02;
const idiosyncraticReturn = (Math.random() - 0.5) * asset.volatility * 0.5;
const dailyReturn = marketReturn * 0.7 + idiosyncraticReturn + asset.expectedReturn / 252;
currentPrice *= 1 + dailyReturn;
const marketValue = shares * currentPrice;
const totalReturn = (currentPrice - initialPrice) / initialPrice;
holdings.push({
timestamp: new Date(Date.now() - (days - day) * 86400000),
symbol: asset.symbol,
shares,
price: Number(currentPrice.toFixed(2)),
marketValue: Number(marketValue.toFixed(2)),
weight: asset.weight, // Will be updated later
dayReturn: Number(dailyReturn.toFixed(6)),
totalReturn: Number(totalReturn.toFixed(6)),
});
}
portfolioData.set(asset.symbol, holdings);
}
// Calculate portfolio-level metrics
const portfolioMetrics: PortfolioMetrics[] = [];
for (let day = 0; day < days; day++) {
let totalValue = 0;
let dailyReturn = 0;
assets.forEach((asset) => {
const holding = portfolioData.get(asset.symbol)![day];
totalValue += holding.marketValue;
dailyReturn += holding.dayReturn * asset.weight;
});
// Update weights based on current market values
assets.forEach((asset) => {
const holding = portfolioData.get(asset.symbol)![day];
holding.weight = holding.marketValue / totalValue;
});
// Calculate metrics
const returns = Array.from({ length: Math.min(day + 1, 60) }, (_, i) => {
let ret = 0;
assets.forEach((asset) => {
ret += portfolioData.get(asset.symbol)![day - i]?.dayReturn || 0;
});
return ret;
});
const volatility = Math.sqrt(
returns.reduce((sum, r) => sum + Math.pow(r, 2), 0) / returns.length
) * Math.sqrt(252);
const totalReturn = (totalValue - initialValue) / initialValue;
const sharpeRatio = (totalReturn * 252) / (volatility + 0.0001);
// Calculate max drawdown
const portfolioValues = Array.from({ length: day + 1 }, (_, i) => {
let val = 0;
assets.forEach((asset) => {
val += portfolioData.get(asset.symbol)![i].marketValue;
});
return val;
});
const maxDrawdown = portfolioValues.reduce((maxDD, val, i) => {
const peak = Math.max(...portfolioValues.slice(0, i + 1));
const dd = (val - peak) / peak;
return Math.min(maxDD, dd);
}, 0);
portfolioMetrics.push({
timestamp: new Date(Date.now() - (days - day) * 86400000),
totalValue: Number(totalValue.toFixed(2)),
cashBalance: 0,
totalReturn: Number(totalReturn.toFixed(6)),
dailyReturn: Number(dailyReturn.toFixed(6)),
volatility: Number(volatility.toFixed(4)),
sharpeRatio: Number(sharpeRatio.toFixed(2)),
maxDrawdown: Number(maxDrawdown.toFixed(4)),
beta: 0.95, // Simplified
alpha: Number(((totalReturn - 0.08 * (day / 252)) / (day / 252 + 0.0001)).toFixed(4)),
});
}
console.log('Multi-Asset Portfolio:');
console.log({
initialValue,
finalValue: portfolioMetrics[portfolioMetrics.length - 1].totalValue,
totalReturn: (portfolioMetrics[portfolioMetrics.length - 1].totalReturn * 100).toFixed(2) + '%',
sharpeRatio: portfolioMetrics[portfolioMetrics.length - 1].sharpeRatio,
maxDrawdown: (portfolioMetrics[portfolioMetrics.length - 1].maxDrawdown * 100).toFixed(2) + '%',
volatility: (portfolioMetrics[portfolioMetrics.length - 1].volatility * 100).toFixed(2) + '%',
});
return { portfolioData, portfolioMetrics, assets };
}
// ============================================================================
// Rebalancing Scenarios
// ============================================================================
interface RebalanceEvent {
timestamp: Date;
type: 'calendar' | 'threshold' | 'opportunistic';
holdings: PortfolioHolding[];
targetWeights: Record<string, number>;
actualWeights: Record<string, number>;
trades: Trade[];
transactionCosts: number;
}
interface Trade {
symbol: string;
action: 'buy' | 'sell';
shares: number;
price: number;
value: number;
commission: number;
}
/**
* Generate portfolio rebalancing scenarios
*/
async function generateRebalancingScenarios() {
const synth = new AgenticSynth();
// Start with portfolio from previous function
const { portfolioData, assets } = await generateMultiAssetPortfolio();
const rebalanceEvents: RebalanceEvent[] = [];
const rebalanceThreshold = 0.05; // Rebalance if drift > 5%
const rebalanceFrequency = 63; // Quarterly (every 63 trading days)
const days = 252;
for (let day = 0; day < days; day++) {
const currentHoldings: PortfolioHolding[] = [];
let totalValue = 0;
// Get current holdings
assets.forEach((asset) => {
const holding = portfolioData.get(asset.symbol)![day];
currentHoldings.push(holding);
totalValue += holding.marketValue;
});
// Calculate current weights
const actualWeights: Record<string, number> = {};
currentHoldings.forEach((holding) => {
actualWeights[holding.symbol] = holding.marketValue / totalValue;
});
// Check if rebalancing is needed
const targetWeights: Record<string, number> = {};
assets.forEach((asset) => {
targetWeights[asset.symbol] = asset.weight;
});
let maxDrift = 0;
Object.keys(targetWeights).forEach((symbol) => {
const drift = Math.abs(actualWeights[symbol] - targetWeights[symbol]);
maxDrift = Math.max(maxDrift, drift);
});
const shouldRebalance =
maxDrift > rebalanceThreshold || day % rebalanceFrequency === 0;
if (shouldRebalance) {
const trades: Trade[] = [];
let transactionCosts = 0;
// Generate trades to rebalance
Object.keys(targetWeights).forEach((symbol) => {
const currentWeight = actualWeights[symbol];
const targetWeight = targetWeights[symbol];
const targetValue = totalValue * targetWeight;
const currentValue = totalValue * currentWeight;
const deltaValue = targetValue - currentValue;
const holding = currentHoldings.find((h) => h.symbol === symbol)!;
const deltaShares = deltaValue / holding.price;
if (Math.abs(deltaShares) > 1) {
const commission = Math.abs(deltaValue) * 0.0005; // 5 bps
transactionCosts += commission;
trades.push({
symbol,
action: deltaShares > 0 ? 'buy' : 'sell',
shares: Math.abs(Math.floor(deltaShares)),
price: holding.price,
value: Math.abs(deltaValue),
commission,
});
}
});
rebalanceEvents.push({
timestamp: new Date(Date.now() - (days - day) * 86400000),
type: maxDrift > rebalanceThreshold * 2 ? 'threshold' : 'calendar',
holdings: currentHoldings,
targetWeights,
actualWeights,
trades,
transactionCosts,
});
}
}
console.log('Rebalancing Scenarios:');
console.log({
totalRebalances: rebalanceEvents.length,
avgTransactionCosts:
rebalanceEvents.reduce((sum, e) => sum + e.transactionCosts, 0) /
rebalanceEvents.length,
totalTransactionCosts: rebalanceEvents.reduce(
(sum, e) => sum + e.transactionCosts,
0
),
});
return rebalanceEvents;
}
// ============================================================================
// Risk-Adjusted Returns Analysis
// ============================================================================
interface RiskMetrics {
timestamp: Date;
portfolioReturn: number;
benchmarkReturn: number;
excessReturn: number;
trackingError: number;
informationRatio: number;
sharpeRatio: number;
sortinoRatio: number;
calmarRatio: number;
beta: number;
alpha: number;
correlation: number;
}
/**
* Calculate comprehensive risk-adjusted return metrics
*/
async function generateRiskAdjustedReturns() {
const { portfolioMetrics } = await generateMultiAssetPortfolio();
const riskFreeRate = 0.04; // 4% annual
const dailyRfRate = riskFreeRate / 252;
const riskMetrics: RiskMetrics[] = portfolioMetrics.map((metrics, idx) => {
// Simulate benchmark (S&P 500)
const benchmarkReturn = metrics.dailyReturn * 0.95 + (Math.random() - 0.5) * 0.005;
const excessReturn = metrics.dailyReturn - dailyRfRate;
// Calculate rolling metrics
const window = Math.min(60, idx + 1);
const recentReturns = portfolioMetrics
.slice(Math.max(0, idx - window), idx + 1)
.map((m) => m.dailyReturn);
const recentBenchmarkReturns = Array.from(
{ length: window },
(_, i) => portfolioMetrics[Math.max(0, idx - window + i)].dailyReturn * 0.95
);
// Tracking error
const trackingDiffs = recentReturns.map(
(r, i) => r - recentBenchmarkReturns[i]
);
const trackingError =
Math.sqrt(
trackingDiffs.reduce((sum, d) => sum + Math.pow(d, 2), 0) / window
) * Math.sqrt(252);
// Information ratio
const avgExcessReturn =
trackingDiffs.reduce((sum, d) => sum + d, 0) / window;
const informationRatio = (avgExcessReturn * 252) / (trackingError + 0.0001);
// Sortino ratio (downside deviation)
const downsideReturns = recentReturns.filter((r) => r < dailyRfRate);
const downsideDeviation = downsideReturns.length > 0
? Math.sqrt(
downsideReturns.reduce(
(sum, r) => sum + Math.pow(r - dailyRfRate, 2),
0
) / downsideReturns.length
) * Math.sqrt(252)
: 0.0001;
const avgReturn = recentReturns.reduce((sum, r) => sum + r, 0) / window;
const sortinoRatio = ((avgReturn - dailyRfRate) * 252) / downsideDeviation;
// Calmar ratio
const calmarRatio = (avgReturn * 252) / (Math.abs(metrics.maxDrawdown) + 0.0001);
// Beta and alpha
const benchmarkVar =
recentBenchmarkReturns.reduce(
(sum, r) => sum + Math.pow(r - avgReturn, 2),
0
) / window;
const covariance =
recentReturns.reduce(
(sum, r, i) => sum + (r - avgReturn) * (recentBenchmarkReturns[i] - avgReturn),
0
) / window;
const beta = covariance / (benchmarkVar + 0.0001);
const alpha = (avgReturn - dailyRfRate - beta * (avgReturn * 0.95 - dailyRfRate)) * 252;
// Correlation
const correlation = covariance / (Math.sqrt(benchmarkVar) * metrics.volatility / Math.sqrt(252) + 0.0001);
return {
timestamp: metrics.timestamp,
portfolioReturn: metrics.dailyReturn,
benchmarkReturn,
excessReturn,
trackingError: Number(trackingError.toFixed(4)),
informationRatio: Number(informationRatio.toFixed(2)),
sharpeRatio: metrics.sharpeRatio,
sortinoRatio: Number(sortinoRatio.toFixed(2)),
calmarRatio: Number(calmarRatio.toFixed(2)),
beta: Number(beta.toFixed(2)),
alpha: Number(alpha.toFixed(4)),
correlation: Number(correlation.toFixed(2)),
};
});
console.log('Risk-Adjusted Returns (final metrics):');
const finalMetrics = riskMetrics[riskMetrics.length - 1];
console.log({
sharpeRatio: finalMetrics.sharpeRatio,
sortinoRatio: finalMetrics.sortinoRatio,
calmarRatio: finalMetrics.calmarRatio,
informationRatio: finalMetrics.informationRatio,
beta: finalMetrics.beta,
alpha: (finalMetrics.alpha * 100).toFixed(2) + '%',
correlation: finalMetrics.correlation,
});
return riskMetrics;
}
// ============================================================================
// Drawdown Analysis
// ============================================================================
interface DrawdownPeriod {
startDate: Date;
troughDate: Date;
endDate: Date | null;
peakValue: number;
troughValue: number;
recoveryValue: number | null;
drawdown: number;
duration: number;
recoveryDuration: number | null;
underwater: boolean;
}
/**
* Analyze portfolio drawdowns
*/
async function generateDrawdownAnalysis() {
const { portfolioMetrics } = await generateMultiAssetPortfolio();
const drawdowns: DrawdownPeriod[] = [];
let currentPeak = portfolioMetrics[0].totalValue;
let currentPeakDate = portfolioMetrics[0].timestamp;
let inDrawdown = false;
let troughValue = currentPeak;
let troughDate = currentPeakDate;
let startDate = currentPeakDate;
portfolioMetrics.forEach((metrics, idx) => {
if (metrics.totalValue > currentPeak) {
// New peak
if (inDrawdown) {
// End of drawdown - recovery complete
drawdowns[drawdowns.length - 1].endDate = metrics.timestamp;
drawdowns[drawdowns.length - 1].recoveryValue = metrics.totalValue;
drawdowns[drawdowns.length - 1].recoveryDuration =
(metrics.timestamp.getTime() - troughDate.getTime()) / 86400000;
drawdowns[drawdowns.length - 1].underwater = false;
inDrawdown = false;
}
currentPeak = metrics.totalValue;
currentPeakDate = metrics.timestamp;
} else if (metrics.totalValue < currentPeak) {
// In drawdown
if (!inDrawdown) {
// Start of new drawdown
startDate = currentPeakDate;
troughValue = metrics.totalValue;
troughDate = metrics.timestamp;
inDrawdown = true;
}
if (metrics.totalValue < troughValue) {
troughValue = metrics.totalValue;
troughDate = metrics.timestamp;
}
// Update or create drawdown record
const dd = (metrics.totalValue - currentPeak) / currentPeak;
const duration = (troughDate.getTime() - startDate.getTime()) / 86400000;
if (drawdowns.length === 0 || !drawdowns[drawdowns.length - 1].underwater) {
drawdowns.push({
startDate,
troughDate,
endDate: null,
peakValue: currentPeak,
troughValue,
recoveryValue: null,
drawdown: dd,
duration,
recoveryDuration: null,
underwater: true,
});
} else {
drawdowns[drawdowns.length - 1].troughDate = troughDate;
drawdowns[drawdowns.length - 1].troughValue = troughValue;
drawdowns[drawdowns.length - 1].drawdown = dd;
drawdowns[drawdowns.length - 1].duration = duration;
}
}
});
// Sort by drawdown magnitude
const sortedDrawdowns = drawdowns.sort((a, b) => a.drawdown - b.drawdown);
console.log('Drawdown Analysis:');
console.log({
totalDrawdowns: drawdowns.length,
maxDrawdown: (sortedDrawdowns[0].drawdown * 100).toFixed(2) + '%',
avgDrawdown: (
(drawdowns.reduce((sum, dd) => sum + dd.drawdown, 0) / drawdowns.length) *
100
).toFixed(2) + '%',
longestDrawdown: Math.max(...drawdowns.map((dd) => dd.duration)),
currentlyUnderwater: drawdowns[drawdowns.length - 1]?.underwater || false,
});
console.log('\nTop 5 Drawdowns:');
sortedDrawdowns.slice(0, 5).forEach((dd, idx) => {
console.log(
`${idx + 1}. ${(dd.drawdown * 100).toFixed(2)}% over ${dd.duration} days, ` +
`recovered in ${dd.recoveryDuration || 'N/A'} days`
);
});
return drawdowns;
}
// ============================================================================
// Main Execution
// ============================================================================
async function main() {
console.log('='.repeat(80));
console.log('Portfolio Simulation and Management');
console.log('='.repeat(80));
console.log();
try {
console.log('1. Generating Multi-Asset Portfolio...');
await generateMultiAssetPortfolio();
console.log();
console.log('2. Generating Rebalancing Scenarios...');
await generateRebalancingScenarios();
console.log();
console.log('3. Calculating Risk-Adjusted Returns...');
await generateRiskAdjustedReturns();
console.log();
console.log('4. Analyzing Drawdowns...');
await generateDrawdownAnalysis();
console.log();
console.log('All portfolio simulations completed successfully!');
} catch (error) {
console.error('Error generating portfolio simulations:', error);
process.exit(1);
}
}
if (require.main === module) {
main();
}
export {
generateMultiAssetPortfolio,
generateRebalancingScenarios,
generateRiskAdjustedReturns,
generateDrawdownAnalysis,
};

View File

@@ -0,0 +1,74 @@
/**
* Trading Scenarios Generation
*
* Generate realistic market scenarios for testing trading systems:
* - Bull/bear markets
* - Volatility patterns
* - Flash crashes
* - Earnings announcements
* - Market correlations
*/
/**
* Generate sustained uptrend with occasional pullbacks
*/
declare function generateBullMarket(): Promise<any>;
/**
* Generate sustained downtrend with sharp selloffs
*/
declare function generateBearMarket(): Promise<any>;
interface VolatilityRegime {
timestamp: Date;
price: number;
realizedVol: number;
impliedVol: number;
vix: number;
regime: 'low' | 'medium' | 'high' | 'extreme';
symbol: string;
}
/**
* Generate varying volatility regimes
*/
declare function generateVolatilityPatterns(): Promise<VolatilityRegime[]>;
interface FlashCrashEvent {
phase: 'normal' | 'crash' | 'recovery';
timestamp: Date;
price: number;
volume: number;
spread: number;
liquidityScore: number;
symbol: string;
}
/**
* Simulate flash crash with rapid price decline and recovery
*/
declare function generateFlashCrash(): Promise<FlashCrashEvent[]>;
interface EarningsEvent {
phase: 'pre-announcement' | 'announcement' | 'post-announcement';
timestamp: Date;
price: number;
volume: number;
impliedVolatility: number;
optionVolume: number;
surprise: 'beat' | 'miss' | 'inline';
symbol: string;
}
/**
* Simulate earnings announcement with volatility crush
*/
declare function generateEarningsScenario(): Promise<EarningsEvent[]>;
interface CorrelationData {
timestamp: Date;
spy: number;
qqq: number;
iwm: number;
vix: number;
dxy: number;
correlation_spy_qqq: number;
correlation_spy_vix: number;
}
/**
* Generate correlated multi-asset data
*/
declare function generateCorrelatedMarkets(): Promise<CorrelationData[]>;
export { generateBullMarket, generateBearMarket, generateVolatilityPatterns, generateFlashCrash, generateEarningsScenario, generateCorrelatedMarkets, };
//# sourceMappingURL=trading-scenarios.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"trading-scenarios.d.ts","sourceRoot":"","sources":["trading-scenarios.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAyBH;;GAEG;AACH,iBAAe,kBAAkB,iBA2DhC;AAMD;;GAEG;AACH,iBAAe,kBAAkB,iBA4DhC;AAMD,UAAU,gBAAgB;IACxB,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IAC9C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,iBAAe,0BAA0B,gCAyCxC;AAMD,UAAU,eAAe;IACvB,KAAK,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;IACvC,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,iBAAe,kBAAkB,+BAiFhC;AAMD,UAAU,aAAa;IACrB,KAAK,EAAE,kBAAkB,GAAG,cAAc,GAAG,mBAAmB,CAAC;IACjE,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,iBAAe,wBAAwB,6BA+FtC;AAMD,UAAU,eAAe;IACvB,SAAS,EAAE,IAAI,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,iBAAe,yBAAyB,+BAmFvC;AAgDD,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,GAC1B,CAAC"}

View File

@@ -0,0 +1,427 @@
"use strict";
/**
* Trading Scenarios Generation
*
* Generate realistic market scenarios for testing trading systems:
* - Bull/bear markets
* - Volatility patterns
* - Flash crashes
* - Earnings announcements
* - Market correlations
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateBullMarket = generateBullMarket;
exports.generateBearMarket = generateBearMarket;
exports.generateVolatilityPatterns = generateVolatilityPatterns;
exports.generateFlashCrash = generateFlashCrash;
exports.generateEarningsScenario = generateEarningsScenario;
exports.generateCorrelatedMarkets = generateCorrelatedMarkets;
const src_1 = require("../../../src");
// ============================================================================
// Bull Market Scenario
// ============================================================================
/**
* Generate sustained uptrend with occasional pullbacks
*/
async function generateBullMarket() {
const synth = new src_1.AgenticSynth();
const basePrice = 100;
const days = 252; // One trading year
const barsPerDay = 390; // 1-minute bars
const bullMarket = await synth.generate({
count: days * barsPerDay,
template: {
timestamp: '{{date.recent}}',
price: 0,
volume: '{{number.int(1000000, 5000000)}}',
regime: 'bull',
volatility: '{{number.float(0.01, 0.03, 4)}}',
trend: '{{number.float(0.5, 1, 2)}}',
momentum: '{{number.float(0.3, 0.9, 2)}}',
symbol: 'BULL',
},
});
// Generate price series with upward drift
let currentPrice = basePrice;
const enrichedData = bullMarket.map((bar, idx) => {
// Daily drift: ~0.08% per bar (20% annual return)
const drift = 0.0008;
const volatility = bar.volatility;
const random = (Math.random() - 0.5) * 2; // -1 to 1
// Occasional pullbacks (10% chance)
const pullback = Math.random() < 0.1 ? -0.002 : 0;
currentPrice *= 1 + drift + volatility * random + pullback;
// Increase volume on breakouts
const volumeMultiplier = currentPrice > basePrice * 1.1 ? 1.5 : 1;
return {
...bar,
price: Number(currentPrice.toFixed(2)),
volume: Math.floor(bar.volume * volumeMultiplier),
};
});
console.log('Bull Market Scenario:');
console.log({
initialPrice: enrichedData[0].price,
finalPrice: enrichedData[enrichedData.length - 1].price,
totalReturn: (((enrichedData[enrichedData.length - 1].price - enrichedData[0].price) /
enrichedData[0].price) *
100).toFixed(2) + '%',
avgVolatility: enrichedData.reduce((sum, b) => sum + b.volatility, 0) /
enrichedData.length,
});
return enrichedData;
}
// ============================================================================
// Bear Market Scenario
// ============================================================================
/**
* Generate sustained downtrend with sharp selloffs
*/
async function generateBearMarket() {
const synth = new src_1.AgenticSynth();
const basePrice = 100;
const days = 126; // Six months of bear market
const bearMarket = await synth.generate({
count: days * 390,
template: {
timestamp: '{{date.recent}}',
price: 0,
volume: '{{number.int(2000000, 8000000)}}', // Higher volume in bear
regime: 'bear',
volatility: '{{number.float(0.02, 0.06, 4)}}', // Higher volatility
trend: '{{number.float(-1, -0.4, 2)}}',
momentum: '{{number.float(-0.9, -0.3, 2)}}',
symbol: 'BEAR',
},
});
let currentPrice = basePrice;
const enrichedData = bearMarket.map((bar, idx) => {
// Daily drift: -0.1% per bar (-25% over 6 months)
const drift = -0.001;
const volatility = bar.volatility;
const random = (Math.random() - 0.5) * 2;
// Sharp selloffs (5% chance of -2% move)
const selloff = Math.random() < 0.05 ? -0.02 : 0;
// Dead cat bounces (3% chance of +1.5% move)
const bounce = Math.random() < 0.03 ? 0.015 : 0;
currentPrice *= 1 + drift + volatility * random + selloff + bounce;
// Volume spikes on panic selling
const volumeMultiplier = selloff < 0 ? 2.5 : 1;
return {
...bar,
price: Number(currentPrice.toFixed(2)),
volume: Math.floor(bar.volume * volumeMultiplier),
};
});
console.log('Bear Market Scenario:');
console.log({
initialPrice: enrichedData[0].price,
finalPrice: enrichedData[enrichedData.length - 1].price,
totalReturn: (((enrichedData[enrichedData.length - 1].price - enrichedData[0].price) /
enrichedData[0].price) *
100).toFixed(2) + '%',
avgVolatility: enrichedData.reduce((sum, b) => sum + b.volatility, 0) /
enrichedData.length,
});
return enrichedData;
}
/**
* Generate varying volatility regimes
*/
async function generateVolatilityPatterns() {
const synth = new src_1.AgenticSynth();
const scenarios = [
{ regime: 'low', vixRange: [10, 15], volRange: [0.005, 0.015] },
{ regime: 'medium', vixRange: [15, 25], volRange: [0.015, 0.03] },
{ regime: 'high', vixRange: [25, 40], volRange: [0.03, 0.05] },
{ regime: 'extreme', vixRange: [40, 80], volRange: [0.05, 0.15] },
];
const allScenarios = [];
for (const scenario of scenarios) {
const data = await synth.generate({
count: 390, // One trading day
template: {
timestamp: '{{date.recent}}',
price: '{{number.float(100, 200, 2)}}',
realizedVol: `{{number.float(${scenario.volRange[0]}, ${scenario.volRange[1]}, 4)}}`,
impliedVol: `{{number.float(${scenario.volRange[0] * 1.1}, ${scenario.volRange[1] * 1.2}, 4)}}`,
vix: `{{number.float(${scenario.vixRange[0]}, ${scenario.vixRange[1]}, 2)}}`,
regime: scenario.regime,
symbol: 'SPY',
},
constraints: [
'bar.impliedVol >= bar.realizedVol', // IV typically > RV
],
});
allScenarios.push(...data);
}
console.log('Volatility Patterns Generated:');
scenarios.forEach((s) => {
const filtered = allScenarios.filter((d) => d.regime === s.regime);
console.log(`${s.regime}: ${filtered.length} bars, avg VIX: ${(filtered.reduce((sum, b) => sum + b.vix, 0) / filtered.length).toFixed(2)}`);
});
return allScenarios;
}
/**
* Simulate flash crash with rapid price decline and recovery
*/
async function generateFlashCrash() {
const synth = new src_1.AgenticSynth();
const basePrice = 150;
const phases = [
{ phase: 'normal', duration: 100, priceChange: 0 },
{ phase: 'crash', duration: 20, priceChange: -0.15 }, // 15% drop
{ phase: 'recovery', duration: 50, priceChange: 0.12 }, // Recover 12%
];
const allData = [];
let currentPrice = basePrice;
for (const phase of phases) {
const phaseData = await synth.generate({
count: phase.duration,
template: {
phase: phase.phase,
timestamp: '{{date.recent}}',
price: 0,
volume: '{{number.int(1000000, 10000000)}}',
spread: '{{number.float(0.01, 0.5, 4)}}',
liquidityScore: '{{number.float(0, 1, 2)}}',
symbol: 'FLASH',
},
});
const pricePerBar = phase.priceChange / phase.duration;
const enrichedPhase = phaseData.map((bar, idx) => {
if (phase.phase === 'crash') {
// Exponential decay during crash
const crashIntensity = Math.pow(idx / phase.duration, 2);
currentPrice *= 1 + pricePerBar * (1 + crashIntensity);
return {
...bar,
price: Number(currentPrice.toFixed(2)),
volume: bar.volume * 5, // Massive volume spike
spread: bar.spread * 10, // Wide spreads
liquidityScore: 0.1, // Liquidity evaporates
};
}
else if (phase.phase === 'recovery') {
// Quick recovery
currentPrice *= 1 + pricePerBar * 1.5;
return {
...bar,
price: Number(currentPrice.toFixed(2)),
volume: bar.volume * 2,
spread: bar.spread * 3,
liquidityScore: 0.4,
};
}
else {
// Normal trading
currentPrice *= 1 + (Math.random() - 0.5) * 0.0002;
return {
...bar,
price: Number(currentPrice.toFixed(2)),
liquidityScore: 0.9,
};
}
});
allData.push(...enrichedPhase);
}
console.log('Flash Crash Simulation:');
console.log({
precrashPrice: allData[99].price,
crashLowPrice: Math.min(...allData.slice(100, 120).map((d) => d.price)),
postRecoveryPrice: allData[allData.length - 1].price,
maxDrawdown: (((Math.min(...allData.map((d) => d.price)) - allData[0].price) /
allData[0].price) *
100).toFixed(2) + '%',
});
return allData;
}
/**
* Simulate earnings announcement with volatility crush
*/
async function generateEarningsScenario() {
const synth = new src_1.AgenticSynth();
const surpriseType = ['beat', 'miss', 'inline'][Math.floor(Math.random() * 3)];
const phases = [
{ phase: 'pre-announcement', duration: 200, ivLevel: 0.8 },
{ phase: 'announcement', duration: 10, ivLevel: 1.2 },
{ phase: 'post-announcement', duration: 180, ivLevel: 0.3 },
];
const allData = [];
let basePrice = 100;
// Determine price reaction based on surprise
const priceReaction = {
beat: 0.08, // 8% pop
miss: -0.12, // 12% drop
inline: 0.02, // 2% drift
}[surpriseType];
for (const phase of phases) {
const phaseData = await synth.generate({
count: phase.duration,
template: {
phase: phase.phase,
timestamp: '{{date.recent}}',
price: 0,
volume: '{{number.int(1000000, 5000000)}}',
impliedVolatility: 0,
optionVolume: '{{number.int(10000, 100000)}}',
surprise: surpriseType,
symbol: 'EARN',
},
});
const enrichedPhase = phaseData.map((bar, idx) => {
if (phase.phase === 'pre-announcement') {
// Building anticipation
basePrice *= 1 + (Math.random() - 0.5) * 0.001;
return {
...bar,
price: Number(basePrice.toFixed(2)),
impliedVolatility: Number((phase.ivLevel * (0.3 + idx / phase.duration * 0.2)).toFixed(4)),
optionVolume: bar.optionVolume * 2, // Heavy options activity
};
}
else if (phase.phase === 'announcement') {
// Immediate reaction
if (idx === 0) {
basePrice *= 1 + priceReaction;
}
return {
...bar,
price: Number(basePrice.toFixed(2)),
volume: bar.volume * 10, // Massive volume spike
impliedVolatility: Number((phase.ivLevel * 0.5).toFixed(4)),
optionVolume: bar.optionVolume * 5,
};
}
else {
// Volatility crush
basePrice *= 1 + (Math.random() - 0.5) * 0.0005;
return {
...bar,
price: Number(basePrice.toFixed(2)),
impliedVolatility: Number((phase.ivLevel * (1 - idx / phase.duration * 0.7)).toFixed(4)),
volume: Math.floor(bar.volume * (2 - idx / phase.duration)),
};
}
});
allData.push(...enrichedPhase);
}
console.log('Earnings Announcement Scenario:');
console.log({
surprise: surpriseType,
preEarningsPrice: allData[199].price,
postEarningsPrice: allData[210].price,
priceChange: (((allData[210].price - allData[199].price) / allData[199].price) *
100).toFixed(2) + '%',
preIV: allData[199].impliedVolatility,
postIV: allData[allData.length - 1].impliedVolatility,
ivCrush: (((allData[allData.length - 1].impliedVolatility - allData[199].impliedVolatility) /
allData[199].impliedVolatility) *
100).toFixed(2) + '%',
});
return allData;
}
/**
* Generate correlated multi-asset data
*/
async function generateCorrelatedMarkets() {
const synth = new src_1.AgenticSynth();
const count = 390;
const baseData = await synth.generate({
count,
template: {
timestamp: '{{date.recent}}',
},
});
// Generate correlated returns
const returns = Array.from({ length: count }, () => {
const marketFactor = (Math.random() - 0.5) * 0.02; // Common market movement
return {
spy: marketFactor + (Math.random() - 0.5) * 0.005,
qqq: marketFactor * 1.3 + (Math.random() - 0.5) * 0.008, // Higher beta
iwm: marketFactor * 1.5 + (Math.random() - 0.5) * 0.01, // Even higher beta
vix: -marketFactor * 3 + (Math.random() - 0.5) * 0.05, // Negative correlation
dxy: -marketFactor * 0.5 + (Math.random() - 0.5) * 0.003, // Slight negative
};
});
// Convert returns to prices
let prices = { spy: 400, qqq: 350, iwm: 180, vix: 15, dxy: 100 };
const correlationData = baseData.map((bar, idx) => {
prices.spy *= 1 + returns[idx].spy;
prices.qqq *= 1 + returns[idx].qqq;
prices.iwm *= 1 + returns[idx].iwm;
prices.vix *= 1 + returns[idx].vix;
prices.dxy *= 1 + returns[idx].dxy;
// Calculate rolling correlation (simplified)
const window = 20;
const start = Math.max(0, idx - window);
const spyReturns = returns.slice(start, idx + 1).map((r) => r.spy);
const qqqReturns = returns.slice(start, idx + 1).map((r) => r.qqq);
const vixReturns = returns.slice(start, idx + 1).map((r) => r.vix);
const correlation = (arr1, arr2) => {
const n = arr1.length;
const mean1 = arr1.reduce((a, b) => a + b, 0) / n;
const mean2 = arr2.reduce((a, b) => a + b, 0) / n;
const numerator = arr1.reduce((sum, val, i) => sum + (val - mean1) * (arr2[i] - mean2), 0);
const denom1 = Math.sqrt(arr1.reduce((sum, val) => sum + Math.pow(val - mean1, 2), 0));
const denom2 = Math.sqrt(arr2.reduce((sum, val) => sum + Math.pow(val - mean2, 2), 0));
return numerator / (denom1 * denom2);
};
return {
timestamp: bar.timestamp,
spy: Number(prices.spy.toFixed(2)),
qqq: Number(prices.qqq.toFixed(2)),
iwm: Number(prices.iwm.toFixed(2)),
vix: Number(prices.vix.toFixed(2)),
dxy: Number(prices.dxy.toFixed(2)),
correlation_spy_qqq: Number(correlation(spyReturns, qqqReturns).toFixed(4)),
correlation_spy_vix: Number(correlation(spyReturns, vixReturns).toFixed(4)),
};
});
console.log('Market Correlation Data:');
console.log({
avgCorrelation_SPY_QQQ: correlationData.reduce((sum, d) => sum + d.correlation_spy_qqq, 0) /
correlationData.length,
avgCorrelation_SPY_VIX: correlationData.reduce((sum, d) => sum + d.correlation_spy_vix, 0) /
correlationData.length,
});
return correlationData;
}
// ============================================================================
// Main Execution
// ============================================================================
async function main() {
console.log('='.repeat(80));
console.log('Trading Scenarios Generation');
console.log('='.repeat(80));
console.log();
try {
console.log('1. Generating Bull Market Scenario...');
await generateBullMarket();
console.log();
console.log('2. Generating Bear Market Scenario...');
await generateBearMarket();
console.log();
console.log('3. Generating Volatility Patterns...');
await generateVolatilityPatterns();
console.log();
console.log('4. Generating Flash Crash...');
await generateFlashCrash();
console.log();
console.log('5. Generating Earnings Scenario...');
await generateEarningsScenario();
console.log();
console.log('6. Generating Correlated Markets...');
await generateCorrelatedMarkets();
console.log();
console.log('All trading scenarios generated successfully!');
}
catch (error) {
console.error('Error generating trading scenarios:', error);
process.exit(1);
}
}
if (require.main === module) {
main();
}
//# sourceMappingURL=trading-scenarios.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,599 @@
/**
* Trading Scenarios Generation
*
* Generate realistic market scenarios for testing trading systems:
* - Bull/bear markets
* - Volatility patterns
* - Flash crashes
* - Earnings announcements
* - Market correlations
*/
import { AgenticSynth } from '../../../src';
// ============================================================================
// Market Regime Types
// ============================================================================
type MarketRegime = 'bull' | 'bear' | 'sideways' | 'volatile' | 'crisis';
interface MarketScenario {
timestamp: Date;
price: number;
volume: number;
regime: MarketRegime;
volatility: number;
trend: number; // -1 to 1
momentum: number;
symbol: string;
}
// ============================================================================
// Bull Market Scenario
// ============================================================================
/**
* Generate sustained uptrend with occasional pullbacks
*/
async function generateBullMarket() {
const synth = new AgenticSynth();
const basePrice = 100;
const days = 252; // One trading year
const barsPerDay = 390; // 1-minute bars
const bullMarket = await synth.generate<MarketScenario>({
count: days * barsPerDay,
template: {
timestamp: '{{date.recent}}',
price: 0,
volume: '{{number.int(1000000, 5000000)}}',
regime: 'bull',
volatility: '{{number.float(0.01, 0.03, 4)}}',
trend: '{{number.float(0.5, 1, 2)}}',
momentum: '{{number.float(0.3, 0.9, 2)}}',
symbol: 'BULL',
},
});
// Generate price series with upward drift
let currentPrice = basePrice;
const enrichedData = bullMarket.map((bar, idx) => {
// Daily drift: ~0.08% per bar (20% annual return)
const drift = 0.0008;
const volatility = bar.volatility;
const random = (Math.random() - 0.5) * 2; // -1 to 1
// Occasional pullbacks (10% chance)
const pullback = Math.random() < 0.1 ? -0.002 : 0;
currentPrice *= 1 + drift + volatility * random + pullback;
// Increase volume on breakouts
const volumeMultiplier = currentPrice > basePrice * 1.1 ? 1.5 : 1;
return {
...bar,
price: Number(currentPrice.toFixed(2)),
volume: Math.floor(bar.volume * volumeMultiplier),
};
});
console.log('Bull Market Scenario:');
console.log({
initialPrice: enrichedData[0].price,
finalPrice: enrichedData[enrichedData.length - 1].price,
totalReturn: (
((enrichedData[enrichedData.length - 1].price - enrichedData[0].price) /
enrichedData[0].price) *
100
).toFixed(2) + '%',
avgVolatility:
enrichedData.reduce((sum, b) => sum + b.volatility, 0) /
enrichedData.length,
});
return enrichedData;
}
// ============================================================================
// Bear Market Scenario
// ============================================================================
/**
* Generate sustained downtrend with sharp selloffs
*/
async function generateBearMarket() {
const synth = new AgenticSynth();
const basePrice = 100;
const days = 126; // Six months of bear market
const bearMarket = await synth.generate<MarketScenario>({
count: days * 390,
template: {
timestamp: '{{date.recent}}',
price: 0,
volume: '{{number.int(2000000, 8000000)}}', // Higher volume in bear
regime: 'bear',
volatility: '{{number.float(0.02, 0.06, 4)}}', // Higher volatility
trend: '{{number.float(-1, -0.4, 2)}}',
momentum: '{{number.float(-0.9, -0.3, 2)}}',
symbol: 'BEAR',
},
});
let currentPrice = basePrice;
const enrichedData = bearMarket.map((bar, idx) => {
// Daily drift: -0.1% per bar (-25% over 6 months)
const drift = -0.001;
const volatility = bar.volatility;
const random = (Math.random() - 0.5) * 2;
// Sharp selloffs (5% chance of -2% move)
const selloff = Math.random() < 0.05 ? -0.02 : 0;
// Dead cat bounces (3% chance of +1.5% move)
const bounce = Math.random() < 0.03 ? 0.015 : 0;
currentPrice *= 1 + drift + volatility * random + selloff + bounce;
// Volume spikes on panic selling
const volumeMultiplier = selloff < 0 ? 2.5 : 1;
return {
...bar,
price: Number(currentPrice.toFixed(2)),
volume: Math.floor(bar.volume * volumeMultiplier),
};
});
console.log('Bear Market Scenario:');
console.log({
initialPrice: enrichedData[0].price,
finalPrice: enrichedData[enrichedData.length - 1].price,
totalReturn: (
((enrichedData[enrichedData.length - 1].price - enrichedData[0].price) /
enrichedData[0].price) *
100
).toFixed(2) + '%',
avgVolatility:
enrichedData.reduce((sum, b) => sum + b.volatility, 0) /
enrichedData.length,
});
return enrichedData;
}
// ============================================================================
// Volatility Patterns
// ============================================================================
interface VolatilityRegime {
timestamp: Date;
price: number;
realizedVol: number;
impliedVol: number;
vix: number;
regime: 'low' | 'medium' | 'high' | 'extreme';
symbol: string;
}
/**
* Generate varying volatility regimes
*/
async function generateVolatilityPatterns() {
const synth = new AgenticSynth();
const scenarios = [
{ regime: 'low', vixRange: [10, 15], volRange: [0.005, 0.015] },
{ regime: 'medium', vixRange: [15, 25], volRange: [0.015, 0.03] },
{ regime: 'high', vixRange: [25, 40], volRange: [0.03, 0.05] },
{ regime: 'extreme', vixRange: [40, 80], volRange: [0.05, 0.15] },
] as const;
const allScenarios: VolatilityRegime[] = [];
for (const scenario of scenarios) {
const data = await synth.generate<VolatilityRegime>({
count: 390, // One trading day
template: {
timestamp: '{{date.recent}}',
price: '{{number.float(100, 200, 2)}}',
realizedVol: `{{number.float(${scenario.volRange[0]}, ${scenario.volRange[1]}, 4)}}`,
impliedVol: `{{number.float(${scenario.volRange[0] * 1.1}, ${scenario.volRange[1] * 1.2}, 4)}}`,
vix: `{{number.float(${scenario.vixRange[0]}, ${scenario.vixRange[1]}, 2)}}`,
regime: scenario.regime,
symbol: 'SPY',
},
constraints: [
'bar.impliedVol >= bar.realizedVol', // IV typically > RV
],
});
allScenarios.push(...data);
}
console.log('Volatility Patterns Generated:');
scenarios.forEach((s) => {
const filtered = allScenarios.filter((d) => d.regime === s.regime);
console.log(`${s.regime}: ${filtered.length} bars, avg VIX: ${
(filtered.reduce((sum, b) => sum + b.vix, 0) / filtered.length).toFixed(2)
}`);
});
return allScenarios;
}
// ============================================================================
// Flash Crash Simulation
// ============================================================================
interface FlashCrashEvent {
phase: 'normal' | 'crash' | 'recovery';
timestamp: Date;
price: number;
volume: number;
spread: number;
liquidityScore: number;
symbol: string;
}
/**
* Simulate flash crash with rapid price decline and recovery
*/
async function generateFlashCrash() {
const synth = new AgenticSynth();
const basePrice = 150;
const phases = [
{ phase: 'normal', duration: 100, priceChange: 0 },
{ phase: 'crash', duration: 20, priceChange: -0.15 }, // 15% drop
{ phase: 'recovery', duration: 50, priceChange: 0.12 }, // Recover 12%
] as const;
const allData: FlashCrashEvent[] = [];
let currentPrice = basePrice;
for (const phase of phases) {
const phaseData = await synth.generate<FlashCrashEvent>({
count: phase.duration,
template: {
phase: phase.phase,
timestamp: '{{date.recent}}',
price: 0,
volume: '{{number.int(1000000, 10000000)}}',
spread: '{{number.float(0.01, 0.5, 4)}}',
liquidityScore: '{{number.float(0, 1, 2)}}',
symbol: 'FLASH',
},
});
const pricePerBar = phase.priceChange / phase.duration;
const enrichedPhase = phaseData.map((bar, idx) => {
if (phase.phase === 'crash') {
// Exponential decay during crash
const crashIntensity = Math.pow(idx / phase.duration, 2);
currentPrice *= 1 + pricePerBar * (1 + crashIntensity);
return {
...bar,
price: Number(currentPrice.toFixed(2)),
volume: bar.volume * 5, // Massive volume spike
spread: bar.spread * 10, // Wide spreads
liquidityScore: 0.1, // Liquidity evaporates
};
} else if (phase.phase === 'recovery') {
// Quick recovery
currentPrice *= 1 + pricePerBar * 1.5;
return {
...bar,
price: Number(currentPrice.toFixed(2)),
volume: bar.volume * 2,
spread: bar.spread * 3,
liquidityScore: 0.4,
};
} else {
// Normal trading
currentPrice *= 1 + (Math.random() - 0.5) * 0.0002;
return {
...bar,
price: Number(currentPrice.toFixed(2)),
liquidityScore: 0.9,
};
}
});
allData.push(...enrichedPhase);
}
console.log('Flash Crash Simulation:');
console.log({
precrashPrice: allData[99].price,
crashLowPrice: Math.min(...allData.slice(100, 120).map((d) => d.price)),
postRecoveryPrice: allData[allData.length - 1].price,
maxDrawdown: (
((Math.min(...allData.map((d) => d.price)) - allData[0].price) /
allData[0].price) *
100
).toFixed(2) + '%',
});
return allData;
}
// ============================================================================
// Earnings Announcement Impact
// ============================================================================
interface EarningsEvent {
phase: 'pre-announcement' | 'announcement' | 'post-announcement';
timestamp: Date;
price: number;
volume: number;
impliedVolatility: number;
optionVolume: number;
surprise: 'beat' | 'miss' | 'inline';
symbol: string;
}
/**
* Simulate earnings announcement with volatility crush
*/
async function generateEarningsScenario() {
const synth = new AgenticSynth();
const surpriseType = ['beat', 'miss', 'inline'][Math.floor(Math.random() * 3)] as 'beat' | 'miss' | 'inline';
const phases = [
{ phase: 'pre-announcement', duration: 200, ivLevel: 0.8 },
{ phase: 'announcement', duration: 10, ivLevel: 1.2 },
{ phase: 'post-announcement', duration: 180, ivLevel: 0.3 },
] as const;
const allData: EarningsEvent[] = [];
let basePrice = 100;
// Determine price reaction based on surprise
const priceReaction = {
beat: 0.08, // 8% pop
miss: -0.12, // 12% drop
inline: 0.02, // 2% drift
}[surpriseType];
for (const phase of phases) {
const phaseData = await synth.generate<EarningsEvent>({
count: phase.duration,
template: {
phase: phase.phase,
timestamp: '{{date.recent}}',
price: 0,
volume: '{{number.int(1000000, 5000000)}}',
impliedVolatility: 0,
optionVolume: '{{number.int(10000, 100000)}}',
surprise: surpriseType,
symbol: 'EARN',
},
});
const enrichedPhase = phaseData.map((bar, idx) => {
if (phase.phase === 'pre-announcement') {
// Building anticipation
basePrice *= 1 + (Math.random() - 0.5) * 0.001;
return {
...bar,
price: Number(basePrice.toFixed(2)),
impliedVolatility: Number((phase.ivLevel * (0.3 + idx / phase.duration * 0.2)).toFixed(4)),
optionVolume: bar.optionVolume * 2, // Heavy options activity
};
} else if (phase.phase === 'announcement') {
// Immediate reaction
if (idx === 0) {
basePrice *= 1 + priceReaction;
}
return {
...bar,
price: Number(basePrice.toFixed(2)),
volume: bar.volume * 10, // Massive volume spike
impliedVolatility: Number((phase.ivLevel * 0.5).toFixed(4)),
optionVolume: bar.optionVolume * 5,
};
} else {
// Volatility crush
basePrice *= 1 + (Math.random() - 0.5) * 0.0005;
return {
...bar,
price: Number(basePrice.toFixed(2)),
impliedVolatility: Number((phase.ivLevel * (1 - idx / phase.duration * 0.7)).toFixed(4)),
volume: Math.floor(bar.volume * (2 - idx / phase.duration)),
};
}
});
allData.push(...enrichedPhase);
}
console.log('Earnings Announcement Scenario:');
console.log({
surprise: surpriseType,
preEarningsPrice: allData[199].price,
postEarningsPrice: allData[210].price,
priceChange: (
((allData[210].price - allData[199].price) / allData[199].price) *
100
).toFixed(2) + '%',
preIV: allData[199].impliedVolatility,
postIV: allData[allData.length - 1].impliedVolatility,
ivCrush: (
((allData[allData.length - 1].impliedVolatility - allData[199].impliedVolatility) /
allData[199].impliedVolatility) *
100
).toFixed(2) + '%',
});
return allData;
}
// ============================================================================
// Market Correlation Data
// ============================================================================
interface CorrelationData {
timestamp: Date;
spy: number; // S&P 500
qqq: number; // Nasdaq
iwm: number; // Russell 2000
vix: number; // Volatility index
dxy: number; // Dollar index
correlation_spy_qqq: number;
correlation_spy_vix: number;
}
/**
* Generate correlated multi-asset data
*/
async function generateCorrelatedMarkets() {
const synth = new AgenticSynth();
const count = 390;
const baseData = await synth.generate<{ timestamp: Date }>({
count,
template: {
timestamp: '{{date.recent}}',
},
});
// Generate correlated returns
const returns = Array.from({ length: count }, () => {
const marketFactor = (Math.random() - 0.5) * 0.02; // Common market movement
return {
spy: marketFactor + (Math.random() - 0.5) * 0.005,
qqq: marketFactor * 1.3 + (Math.random() - 0.5) * 0.008, // Higher beta
iwm: marketFactor * 1.5 + (Math.random() - 0.5) * 0.01, // Even higher beta
vix: -marketFactor * 3 + (Math.random() - 0.5) * 0.05, // Negative correlation
dxy: -marketFactor * 0.5 + (Math.random() - 0.5) * 0.003, // Slight negative
};
});
// Convert returns to prices
let prices = { spy: 400, qqq: 350, iwm: 180, vix: 15, dxy: 100 };
const correlationData: CorrelationData[] = baseData.map((bar, idx) => {
prices.spy *= 1 + returns[idx].spy;
prices.qqq *= 1 + returns[idx].qqq;
prices.iwm *= 1 + returns[idx].iwm;
prices.vix *= 1 + returns[idx].vix;
prices.dxy *= 1 + returns[idx].dxy;
// Calculate rolling correlation (simplified)
const window = 20;
const start = Math.max(0, idx - window);
const spyReturns = returns.slice(start, idx + 1).map((r) => r.spy);
const qqqReturns = returns.slice(start, idx + 1).map((r) => r.qqq);
const vixReturns = returns.slice(start, idx + 1).map((r) => r.vix);
const correlation = (arr1: number[], arr2: number[]): number => {
const n = arr1.length;
const mean1 = arr1.reduce((a, b) => a + b, 0) / n;
const mean2 = arr2.reduce((a, b) => a + b, 0) / n;
const numerator = arr1.reduce(
(sum, val, i) => sum + (val - mean1) * (arr2[i] - mean2),
0
);
const denom1 = Math.sqrt(
arr1.reduce((sum, val) => sum + Math.pow(val - mean1, 2), 0)
);
const denom2 = Math.sqrt(
arr2.reduce((sum, val) => sum + Math.pow(val - mean2, 2), 0)
);
return numerator / (denom1 * denom2);
};
return {
timestamp: bar.timestamp,
spy: Number(prices.spy.toFixed(2)),
qqq: Number(prices.qqq.toFixed(2)),
iwm: Number(prices.iwm.toFixed(2)),
vix: Number(prices.vix.toFixed(2)),
dxy: Number(prices.dxy.toFixed(2)),
correlation_spy_qqq: Number(correlation(spyReturns, qqqReturns).toFixed(4)),
correlation_spy_vix: Number(correlation(spyReturns, vixReturns).toFixed(4)),
};
});
console.log('Market Correlation Data:');
console.log({
avgCorrelation_SPY_QQQ:
correlationData.reduce((sum, d) => sum + d.correlation_spy_qqq, 0) /
correlationData.length,
avgCorrelation_SPY_VIX:
correlationData.reduce((sum, d) => sum + d.correlation_spy_vix, 0) /
correlationData.length,
});
return correlationData;
}
// ============================================================================
// Main Execution
// ============================================================================
async function main() {
console.log('='.repeat(80));
console.log('Trading Scenarios Generation');
console.log('='.repeat(80));
console.log();
try {
console.log('1. Generating Bull Market Scenario...');
await generateBullMarket();
console.log();
console.log('2. Generating Bear Market Scenario...');
await generateBearMarket();
console.log();
console.log('3. Generating Volatility Patterns...');
await generateVolatilityPatterns();
console.log();
console.log('4. Generating Flash Crash...');
await generateFlashCrash();
console.log();
console.log('5. Generating Earnings Scenario...');
await generateEarningsScenario();
console.log();
console.log('6. Generating Correlated Markets...');
await generateCorrelatedMarkets();
console.log();
console.log('All trading scenarios generated successfully!');
} catch (error) {
console.error('Error generating trading scenarios:', error);
process.exit(1);
}
}
if (require.main === module) {
main();
}
export {
generateBullMarket,
generateBearMarket,
generateVolatilityPatterns,
generateFlashCrash,
generateEarningsScenario,
generateCorrelatedMarkets,
};