Files
rustytorch/demos/rtx-quantumport-demo/src/sample_data.rs
T
2026-03-04 00:08:42 +00:00

371 lines
12 KiB
Rust

//! Sample data utilities for the QuantumPort demo.
use quantumport_shared::{
Asset, AssetClass, AssetReturns, OptimizationMethod, OptimizationObjectives,
OptimizationRequest, PortfolioConstraints,
};
/// Get a comprehensive sample portfolio request.
#[must_use]
pub fn get_comprehensive_request() -> OptimizationRequest {
OptimizationRequest {
assets: get_diversified_portfolio(),
returns: get_simulated_returns(),
objectives: OptimizationObjectives {
target_return: None,
minimize_variance: true,
maximize_skewness: true,
minimize_kurtosis: true,
risk_aversion: 2.0,
skewness_preference: 1.0,
kurtosis_aversion: 0.5,
},
constraints: PortfolioConstraints {
budget: 1.0,
allow_short: false,
max_weight: 0.30,
min_weight: 0.05,
max_assets: Some(8),
sector_constraints: vec![],
max_turnover: None,
},
method: OptimizationMethod::HigherOrder,
}
}
/// Get a diversified portfolio of assets.
#[must_use]
pub fn get_diversified_portfolio() -> Vec<Asset> {
vec![
// US Large Cap
Asset {
symbol: "SPY".to_string(),
name: "S&P 500 ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("US Large Cap".to_string()),
currency: "USD".to_string(),
},
// US Tech
Asset {
symbol: "QQQ".to_string(),
name: "NASDAQ 100 ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("US Technology".to_string()),
currency: "USD".to_string(),
},
// US Small Cap
Asset {
symbol: "IWM".to_string(),
name: "Russell 2000 ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("US Small Cap".to_string()),
currency: "USD".to_string(),
},
// International Developed
Asset {
symbol: "EFA".to_string(),
name: "EAFE ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("International Developed".to_string()),
currency: "USD".to_string(),
},
// Emerging Markets
Asset {
symbol: "EEM".to_string(),
name: "Emerging Markets ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("Emerging Markets".to_string()),
currency: "USD".to_string(),
},
// US Bonds
Asset {
symbol: "AGG".to_string(),
name: "US Aggregate Bond ETF".to_string(),
asset_class: AssetClass::FixedIncome,
sector: None,
currency: "USD".to_string(),
},
// Long-term Treasury
Asset {
symbol: "TLT".to_string(),
name: "20+ Year Treasury Bond ETF".to_string(),
asset_class: AssetClass::FixedIncome,
sector: None,
currency: "USD".to_string(),
},
// High Yield
Asset {
symbol: "HYG".to_string(),
name: "High Yield Corporate Bond ETF".to_string(),
asset_class: AssetClass::FixedIncome,
sector: None,
currency: "USD".to_string(),
},
// Gold
Asset {
symbol: "GLD".to_string(),
name: "Gold ETF".to_string(),
asset_class: AssetClass::Commodity,
sector: None,
currency: "USD".to_string(),
},
// Real Estate
Asset {
symbol: "VNQ".to_string(),
name: "Real Estate ETF".to_string(),
asset_class: AssetClass::RealEstate,
sector: None,
currency: "USD".to_string(),
},
]
}
/// Get simulated historical returns.
#[must_use]
pub fn get_simulated_returns() -> Vec<AssetReturns> {
let num_days = 252; // One year of trading days
vec![
// SPY - moderate return, moderate vol
simulate_asset_returns("SPY", num_days, 0.0004, 0.011, -0.15, 3.2),
// QQQ - higher return, higher vol
simulate_asset_returns("QQQ", num_days, 0.0005, 0.014, -0.25, 3.8),
// IWM - moderate return, high vol
simulate_asset_returns("IWM", num_days, 0.0003, 0.015, -0.30, 4.0),
// EFA - lower return, moderate vol
simulate_asset_returns("EFA", num_days, 0.0002, 0.012, -0.10, 3.1),
// EEM - volatile emerging markets
simulate_asset_returns("EEM", num_days, 0.0003, 0.018, -0.35, 4.5),
// AGG - low return, low vol, positive skew
simulate_asset_returns("AGG", num_days, 0.0001, 0.004, 0.10, 2.8),
// TLT - negative correlation to equities
simulate_asset_returns("TLT", num_days, 0.0001, 0.012, 0.20, 3.0),
// HYG - bond-like but higher vol
simulate_asset_returns("HYG", num_days, 0.0002, 0.007, -0.20, 3.5),
// GLD - safe haven, positive skew
simulate_asset_returns("GLD", num_days, 0.0002, 0.009, 0.25, 3.2),
// VNQ - real estate, equity-like
simulate_asset_returns("VNQ", num_days, 0.0003, 0.015, -0.25, 4.0),
]
}
/// Simulate returns for a single asset.
fn simulate_asset_returns(
symbol: &str,
num_days: usize,
mean: f64,
std: f64,
_skew: f64,
_kurt: f64,
) -> AssetReturns {
let mut returns = Vec::with_capacity(num_days);
let mut seed = symbol
.bytes()
.fold(0u64, |acc, b| acc.wrapping_add(b as u64))
* 12345;
for _ in 0..num_days {
// LCG pseudo-random - use modulo to ensure [0, 1) range
seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
let u1 = ((seed >> 16) % 32768) as f64 / 32768.0 + 0.0001; // Avoid 0
seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
let u2 = ((seed >> 16) % 32768) as f64 / 32768.0;
// Box-Muller transform for normal distribution
let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos();
// Clamp to reasonable daily return range (-15% to +15%)
let ret = (mean + std * z).clamp(-0.15, 0.15);
returns.push(ret);
}
AssetReturns {
symbol: symbol.to_string(),
returns,
start_date: "2023-01-01".to_string(),
end_date: "2023-12-31".to_string(),
}
}
/// Create a request for aggressive growth portfolio.
#[must_use]
pub fn get_aggressive_growth_request() -> OptimizationRequest {
let assets = vec![
Asset {
symbol: "QQQ".to_string(),
name: "NASDAQ 100 ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("US Technology".to_string()),
currency: "USD".to_string(),
},
Asset {
symbol: "ARKK".to_string(),
name: "ARK Innovation ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("Innovation".to_string()),
currency: "USD".to_string(),
},
Asset {
symbol: "SOXX".to_string(),
name: "Semiconductor ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("Semiconductors".to_string()),
currency: "USD".to_string(),
},
Asset {
symbol: "XBI".to_string(),
name: "Biotech ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("Biotech".to_string()),
currency: "USD".to_string(),
},
];
let returns = vec![
simulate_asset_returns("QQQ", 252, 0.0006, 0.016, -0.20, 3.5),
simulate_asset_returns("ARKK", 252, 0.0008, 0.028, -0.40, 5.0),
simulate_asset_returns("SOXX", 252, 0.0007, 0.022, -0.30, 4.2),
simulate_asset_returns("XBI", 252, 0.0005, 0.025, -0.35, 4.8),
];
OptimizationRequest {
assets,
returns,
objectives: OptimizationObjectives {
target_return: Some(0.20),
minimize_variance: true,
maximize_skewness: true,
minimize_kurtosis: true,
risk_aversion: 0.5,
skewness_preference: 0.3,
kurtosis_aversion: 0.2,
},
constraints: PortfolioConstraints::default(),
method: OptimizationMethod::HigherOrder,
}
}
/// Create a request for conservative income portfolio.
#[must_use]
pub fn get_conservative_income_request() -> OptimizationRequest {
let assets = vec![
Asset {
symbol: "AGG".to_string(),
name: "US Aggregate Bond ETF".to_string(),
asset_class: AssetClass::FixedIncome,
sector: None,
currency: "USD".to_string(),
},
Asset {
symbol: "BND".to_string(),
name: "Total Bond Market ETF".to_string(),
asset_class: AssetClass::FixedIncome,
sector: None,
currency: "USD".to_string(),
},
Asset {
symbol: "VCIT".to_string(),
name: "Intermediate Corporate Bond ETF".to_string(),
asset_class: AssetClass::FixedIncome,
sector: None,
currency: "USD".to_string(),
},
Asset {
symbol: "SCHD".to_string(),
name: "Dividend ETF".to_string(),
asset_class: AssetClass::Equity,
sector: Some("Dividend".to_string()),
currency: "USD".to_string(),
},
];
let returns = vec![
simulate_asset_returns("AGG", 252, 0.0001, 0.004, 0.05, 2.8),
simulate_asset_returns("BND", 252, 0.0001, 0.004, 0.05, 2.7),
simulate_asset_returns("VCIT", 252, 0.00012, 0.005, 0.02, 2.9),
simulate_asset_returns("SCHD", 252, 0.0003, 0.008, -0.10, 3.0),
];
OptimizationRequest {
assets,
returns,
objectives: OptimizationObjectives {
target_return: Some(0.05),
minimize_variance: true,
maximize_skewness: true,
minimize_kurtosis: true,
risk_aversion: 3.0,
skewness_preference: 0.8,
kurtosis_aversion: 0.8,
},
constraints: PortfolioConstraints::default(),
method: OptimizationMethod::MinimumVariance,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_comprehensive_request() {
let request = get_comprehensive_request();
assert_eq!(request.assets.len(), 10);
assert_eq!(request.returns.len(), 10);
}
#[test]
fn test_diversified_portfolio() {
let assets = get_diversified_portfolio();
assert_eq!(assets.len(), 10);
// Check for diversity of asset classes
let equity_count = assets
.iter()
.filter(|a| a.asset_class == AssetClass::Equity)
.count();
let fixed_income_count = assets
.iter()
.filter(|a| a.asset_class == AssetClass::FixedIncome)
.count();
assert!(equity_count >= 3);
assert!(fixed_income_count >= 2);
}
#[test]
fn test_simulated_returns() {
let returns = get_simulated_returns();
assert_eq!(returns.len(), 10);
for ret in &returns {
assert_eq!(ret.returns.len(), 252);
}
}
#[test]
fn test_aggressive_growth() {
let request = get_aggressive_growth_request();
assert_eq!(request.assets.len(), 4);
assert!(request.objectives.risk_aversion < 1.0); // Low risk aversion = aggressive
}
#[test]
fn test_conservative_income() {
let request = get_conservative_income_request();
assert_eq!(request.assets.len(), 4);
assert!(request.objectives.risk_aversion > 2.0); // High risk aversion = conservative
}
#[test]
fn test_returns_reasonable_range() {
let returns = get_simulated_returns();
for asset_returns in &returns {
for &r in &asset_returns.returns {
// Daily returns should typically be within -10% to +10%
assert!(r > -0.2 && r < 0.2);
}
}
}
}