# Test Fixtures Quick Start Guide ## TL;DR **Before** (Slow, 5-10ms per test): ```rust let mut file_mapping = HashMap::new(); file_mapping.insert("ES.FUT".to_string(), "path/to/ES.FUT.dbn".to_string()); let data_source = DbnDataSource::new(file_mapping).await?; let bars = data_source.load_ohlcv_bars("ES.FUT").await?; ``` **After** (Fast, 0.1μs per test): ```rust use fixtures::get_es_fut_bars; let bars = get_es_fut_bars().await?; // That's it! ``` --- ## Quick Examples ### 1. Load Real Data (Fastest Way) ```rust use fixtures::{get_es_fut_bars, get_nq_fut_bars, get_cl_fut_bars}; #[tokio::test] async fn test_my_strategy() -> anyhow::Result<()> { let bars = get_es_fut_bars().await?; // Cached, fast // Test your code... Ok(()) } ``` ### 2. Validate Data Quality ```rust use helpers::{assert_valid_ohlcv, assert_chronological}; #[test] fn test_data_quality() { let bars = load_data(); assert_valid_ohlcv(&bars); // Validates price relationships assert_chronological(&bars); // Validates timestamp order } ``` ### 3. Test Specific Market Conditions ```rust use fixtures::{get_regime_sample, RegimeType}; #[tokio::test] async fn test_trending_strategy() -> anyhow::Result<()> { let bars = get_regime_sample(RegimeType::Trending).await?; // bars now contain trending market data Ok(()) } ``` ### 4. Multi-Symbol Testing ```rust use fixtures::get_multi_symbol_bars; #[tokio::test] async fn test_portfolio() -> anyhow::Result<()> { let symbols = vec!["ES.FUT", "NQ.FUT"]; let data = get_multi_symbol_bars(&symbols).await?; // data["ES.FUT"] → ES.FUT bars // data["NQ.FUT"] → NQ.FUT bars Ok(()) } ``` --- ## API Reference (One Page) ### Load Data | Function | Returns | Use Case | |----------|---------|----------| | `get_es_fut_bars()` | Vec | E-mini S&P 500 (~390 bars) | | `get_nq_fut_bars()` | Vec | E-mini NASDAQ-100 (~390 bars) | | `get_cl_fut_bars()` | Vec | WTI Crude Oil (~1440 bars) | | `get_multi_symbol_bars(&[symbols])` | HashMap | Multiple symbols at once | | `get_bars_for_date(symbol, date)` | Vec | Specific date only | | `get_regime_sample(regime_type)` | Vec | Trending/Ranging/Volatile/Stable | ### Validate Data | Function | Validates | |----------|-----------| | `assert_valid_ohlcv(&bars)` | High≥Low, Open/Close within range, positive prices | | `assert_chronological(&bars)` | Timestamps sorted ascending | | `assert_price_range(&bars, symbol)` | Realistic price ranges (ES: 3000-6000) | | `assert_no_large_gaps(&bars, max_min)` | No gaps > N minutes | ### Validate Trades | Function | Validates | |----------|-----------| | `assert_valid_trade(&trade)` | Exit > Entry time, positive prices, PnL correct | | `assert_valid_trade_sequence(&trades)` | No overlaps, chronological order | ### Validate Metrics | Function | Validates | |----------|-----------| | `assert_sharpe_bounds(sharpe, min, max)` | Sharpe ratio realistic (-3 to 5) | | `assert_drawdown_bounds(dd, max)` | Drawdown ≤ max% | | `assert_win_rate_valid(rate)` | Win rate 0-100% | ### Utilities | Function | Returns | Use Case | |----------|---------|----------| | `calculate_volatility(&bars)` | f64 | Annualized volatility % | | `generate_quality_report(&bars)` | String | Comprehensive data analysis | --- ## Regime Types ```rust pub enum RegimeType { Trending, // Strong directional movement (>1.5% change) Ranging, // Bounded oscillation (<0.8% range) Volatile, // High fluctuations (>0.5% std dev) Stable, // Low volatility (<0.3% std dev) } ``` **Usage**: ```rust let trending = get_regime_sample(RegimeType::Trending).await?; let ranging = get_regime_sample(RegimeType::Ranging).await?; let volatile = get_regime_sample(RegimeType::Volatile).await?; let stable = get_regime_sample(RegimeType::Stable).await?; ``` --- ## Performance | Operation | Time | Notes | |-----------|------|-------| | First call | 5-10ms | Load from DBN file | | Subsequent calls | ~0.1μs | Read from cache | | 100 tests | ~10ms | 50-100x faster | --- ## Common Patterns ### Pattern 1: Basic Strategy Test ```rust use fixtures::get_es_fut_bars; use helpers::assert_valid_ohlcv; #[tokio::test] async fn test_my_strategy() -> anyhow::Result<()> { let bars = get_es_fut_bars().await?; assert_valid_ohlcv(&bars); let signals = my_strategy.generate_signals(&bars); assert!(!signals.is_empty()); Ok(()) } ``` ### Pattern 2: Metrics Validation ```rust use helpers::{assert_sharpe_bounds, assert_drawdown_bounds}; #[test] fn test_backtest_metrics() { let metrics = run_backtest(); assert_sharpe_bounds(metrics.sharpe, -3.0, 5.0); assert_drawdown_bounds(metrics.max_dd, 50.0); } ``` ### Pattern 3: Data Quality Report ```rust use fixtures::get_es_fut_bars; use helpers::generate_quality_report; #[tokio::test] async fn test_print_report() -> anyhow::Result<()> { let bars = get_es_fut_bars().await?; println!("{}", generate_quality_report(&bars)); Ok(()) } ``` ### Pattern 4: Multi-Regime Testing ```rust use fixtures::{get_regime_sample, RegimeType}; #[tokio::test] async fn test_all_regimes() -> anyhow::Result<()> { for regime in &[ RegimeType::Trending, RegimeType::Ranging, RegimeType::Volatile, RegimeType::Stable, ] { let bars = get_regime_sample(*regime).await?; test_strategy_on_regime(&bars, regime); } Ok(()) } ``` --- ## Troubleshooting ### "File not found" error ```bash # Check files exist ls test_data/real/databento/*.dbn # Should see: # ES.FUT_ohlcv-1m_2024-01-02.dbn # NQ.FUT_ohlcv-1m_2024-01-02.dbn # CL.FUT_ohlcv-1m_2024-01-02.dbn ``` ### Tests still slow ```rust // ❌ Don't bypass cache let data_source = DbnDataSource::new(file_mapping).await?; // ✅ Use cached fixtures let bars = get_es_fut_bars().await?; ``` ### Need different date ```rust // Not yet implemented (only 2024-01-02 available) // Add more DBN files to test_data/real/databento/ ``` --- ## Import Cheatsheet ```rust // At top of test file mod fixtures; mod helpers; // In test functions use fixtures::{ get_es_fut_bars, get_nq_fut_bars, get_cl_fut_bars, get_regime_sample, RegimeType, get_multi_symbol_bars, get_bars_for_date, }; use helpers::{ assert_valid_ohlcv, assert_chronological, assert_price_range, assert_valid_trade, assert_valid_trade_sequence, assert_sharpe_bounds, assert_drawdown_bounds, calculate_volatility, generate_quality_report, }; ``` --- ## Full Example Test File ```rust //! My strategy tests mod fixtures; mod helpers; use anyhow::Result; use fixtures::{get_es_fut_bars, get_regime_sample, RegimeType}; use helpers::{assert_valid_ohlcv, assert_chronological}; #[tokio::test] async fn test_strategy_trending() -> Result<()> { // Load trending market data (cached) let bars = get_regime_sample(RegimeType::Trending).await?; // Validate data quality assert_valid_ohlcv(&bars); assert_chronological(&bars); // Test strategy let signals = my_trend_strategy.generate(&bars); assert!(!signals.is_empty(), "Should generate signals in trend"); Ok(()) } #[tokio::test] async fn test_strategy_ranging() -> Result<()> { // Load ranging market data let bars = get_regime_sample(RegimeType::Ranging).await?; // Validate assert_valid_ohlcv(&bars); // Test let signals = my_mean_reversion_strategy.generate(&bars); assert!(!signals.is_empty(), "Should generate signals in range"); Ok(()) } #[tokio::test] async fn test_full_day() -> Result<()> { // Load full day of real data let bars = get_es_fut_bars().await?; // Comprehensive validation assert_valid_ohlcv(&bars); assert_chronological(&bars); // Run full backtest let results = backtest(&bars); // Validate metrics use helpers::{assert_sharpe_bounds, assert_drawdown_bounds}; assert_sharpe_bounds(results.sharpe, -3.0, 5.0); assert_drawdown_bounds(results.max_dd, 50.0); Ok(()) } ``` --- ## Next Steps 1. **Copy pattern above** for your tests 2. **Replace manual DBN loading** with `get_es_fut_bars()` 3. **Add validation helpers** to catch bugs early 4. **Run tests** and enjoy 50-100x speedup! --- ## More Info - Full documentation: `fixtures/README.md` - Performance analysis: `fixtures/PERFORMANCE.md` - Examples: `fixtures_tests.rs` --- **Questions?** See comprehensive docs in `fixtures/README.md` **Quick start**: Just call `get_es_fut_bars().await?` and you're done!