Files
foxhunt/services/backtesting_service/DBN_REPOSITORY_USAGE.md
jgrusewski e8a68ee39f Download 360 DBN files (36.3 MB) using Rust databento client
- Created data/examples/download_ml_training_data.rs using reqwest + Databento HTTP API
- Downloaded 90 days × 4 symbols (ES.FUT, NQ.FUT, ZN.FUT, 6E.FUT)
- Files saved to test_data/real/databento/ml_training/
- Total: 360 files, 15 MB compressed DBN format
- Used existing Rust pattern from download_nq_fut.rs
- API key loaded from .env file
- 100% success rate (360/360 files)
- Ready for ML training benchmarks

Next: Create simplified training benchmark for RTX 3050 Ti GPU measurements
2025-10-13 13:30:02 +02:00

369 lines
9.9 KiB
Markdown

# DbnMarketDataRepository - Advanced Query Usage Examples
## Overview
The `DbnMarketDataRepository` provides advanced querying capabilities for DBN (Databento Binary) market data, optimized for complex test scenarios and backtesting operations.
## Performance Targets
- **<10ms** for typical queries (~400 bars)
- Zero-copy parsing with SIMD optimizations
- Efficient filtering and aggregation
## Basic Setup
```rust
use backtesting_service::dbn_repository::DbnMarketDataRepository;
use std::collections::HashMap;
// Create repository with file mapping
let mut file_mapping = HashMap::new();
file_mapping.insert(
"ES.FUT".to_string(),
"test_data/real/databento/ES.FUT_ohlcv-1m_2024-01-02.dbn".to_string(),
);
let repo = DbnMarketDataRepository::new(file_mapping).await?;
```
## Advanced Query Methods
### 1. Time Range Queries
Load data with precise DateTime filtering:
```rust
use chrono::{TimeZone, Utc};
let start = Utc.with_ymd_and_hms(2024, 1, 2, 9, 30, 0).unwrap(); // Market open
let end = Utc.with_ymd_and_hms(2024, 1, 2, 16, 0, 0).unwrap(); // Market close
let symbols = vec!["ES.FUT".to_string()];
let bars = repo.load_by_time_range(&symbols, start, end).await?;
println!("Loaded {} bars for market hours", bars.len());
```
### 2. Volume Filtering
Filter for high-liquidity bars:
```rust
use rust_decimal::Decimal;
// Load only bars with volume >= 100
let min_volume = Decimal::new(100, 0);
let start_time = 1704153600_000_000_000i64;
let end_time = 1704240000_000_000_000i64;
let symbols = vec!["ES.FUT".to_string()];
let high_liquidity_bars = repo.load_with_volume_filter(
&symbols,
min_volume,
start_time,
end_time
).await?;
println!("High liquidity bars: {}", high_liquidity_bars.len());
```
### 3. Regime-Specific Sampling
Load data matching specific market regimes:
```rust
// Load trending regime samples (>0.5% intrabar range)
let trending_samples = repo.load_regime_samples(
"trending",
20, // limit to 20 samples
&vec!["ES.FUT".to_string()]
).await?;
// Load ranging/sideways regime samples (<0.2% range)
let ranging_samples = repo.load_regime_samples(
"ranging",
20,
&vec!["ES.FUT".to_string()]
).await?;
// Load volatile regime samples (>0.8% range + high volume)
let volatile_samples = repo.load_regime_samples(
"volatile",
10,
&vec!["ES.FUT".to_string()]
).await?;
// Load stable regime samples (<0.15% range)
let stable_samples = repo.load_regime_samples(
"stable",
15,
&vec!["ES.FUT".to_string()]
).await?;
```
**Supported Regime Types:**
- `"trending"` - High price movement (>0.5% range)
- `"ranging"` / `"sideways"` - Low volatility (<0.2% range)
- `"volatile"` - High volatility + high volume (>0.8% range)
- `"stable"` - Very low volatility (<0.15% range)
### 4. Date Range Discovery
Get available date ranges for symbols:
```rust
let (first, last) = repo.get_date_range("ES.FUT").await?;
println!("Data available from {} to {}", first, last);
println!("Days of data: {}", (last - first).num_days());
```
### 5. Timeframe Resampling
Aggregate minute bars into larger timeframes:
```rust
// Load 1-minute bars
let bars = repo.load_historical_data(&symbols, start_time, end_time).await?;
// Resample to 5-minute bars
let bars_5m = repo.resample_bars(&bars, 5)?;
// Resample to 15-minute bars
let bars_15m = repo.resample_bars(&bars, 15)?;
// Resample to 1-hour bars
let bars_1h = repo.resample_bars(&bars, 60)?;
println!("1m: {} bars", bars.len());
println!("5m: {} bars", bars_5m.len());
println!("15m: {} bars", bars_15m.len());
println!("1h: {} bars", bars_1h.len());
```
### 6. Rolling Statistics
Calculate moving window statistics:
```rust
let bars = repo.load_historical_data(&symbols, start_time, end_time).await?;
// 20-bar rolling window
let window_size = 20;
let stats = repo.calculate_rolling_stats(&bars, window_size);
for (i, (mean, std_dev, min, max)) in stats.iter().enumerate() {
println!(
"Window {}: mean={:.2}, std={:.2}, range=[{:.2}, {:.2}]",
i, mean, std_dev, min, max
);
}
```
**Returns:** `Vec<(mean, std_dev, min, max)>` for each window
### 7. Summary Statistics
Generate comprehensive statistics:
```rust
let bars = repo.load_historical_data(&symbols, start_time, end_time).await?;
let stats = repo.generate_summary_stats(&bars);
println!("Summary Statistics:");
println!(" Count: {}", stats.get("count").unwrap());
println!(" Mean Close: {:.2}", stats.get("mean_close").unwrap());
println!(" Std Close: {:.2}", stats.get("std_close").unwrap());
println!(" Min Close: {:.2}", stats.get("min_close").unwrap());
println!(" Max Close: {:.2}", stats.get("max_close").unwrap());
println!(" Mean Volume: {:.0}", stats.get("mean_volume").unwrap());
println!(" Total Volume: {:.0}", stats.get("total_volume").unwrap());
```
**Available Statistics:**
- `count` - Number of bars
- `mean_close` - Average close price
- `std_close` - Standard deviation of close prices
- `min_close` - Minimum close price
- `max_close` - Maximum close price
- `mean_volume` - Average volume per bar
- `total_volume` - Cumulative volume
## Complex Test Scenarios
### Example 1: Multi-Timeframe Analysis
```rust
// Load base data
let symbols = vec!["ES.FUT".to_string()];
let bars_1m = repo.load_historical_data(&symbols, start_time, end_time).await?;
// Create multiple timeframes
let bars_5m = repo.resample_bars(&bars_1m, 5)?;
let bars_15m = repo.resample_bars(&bars_1m, 15)?;
let bars_1h = repo.resample_bars(&bars_1m, 60)?;
// Analyze each timeframe
for (tf_name, bars) in [
("1m", &bars_1m),
("5m", &bars_5m),
("15m", &bars_15m),
("1h", &bars_1h),
] {
let stats = repo.generate_summary_stats(bars);
println!("{}: {} bars, volatility={:.2}%",
tf_name,
bars.len(),
stats.get("std_close").unwrap() / stats.get("mean_close").unwrap() * 100.0
);
}
```
### Example 2: Regime Detection Testing
```rust
// Test adaptive strategy across different regimes
for regime in ["trending", "ranging", "volatile", "stable"] {
let samples = repo.load_regime_samples(regime, 50, &symbols).await?;
println!("\nTesting {} regime with {} samples", regime, samples.len());
// Run strategy on regime-specific data
let trades = strategy.backtest(&samples).await?;
println!(" Trades: {}", trades.len());
println!(" Win rate: {:.1}%", calculate_win_rate(&trades));
}
```
### Example 3: Liquidity Analysis
```rust
// Compare high vs low liquidity performance
let all_bars = repo.load_historical_data(&symbols, start_time, end_time).await?;
let high_liq = repo.load_with_volume_filter(
&symbols,
Decimal::new(200, 0),
start_time,
end_time
).await?;
let low_liq = all_bars
.into_iter()
.filter(|b| b.volume < Decimal::new(50, 0))
.collect::<Vec<_>>();
println!("High liquidity bars: {} ({:.1}%)",
high_liq.len(),
100.0 * high_liq.len() as f64 / (high_liq.len() + low_liq.len()) as f64
);
// Test strategy on both conditions
let high_liq_pnl = strategy.backtest(&high_liq).await?.total_pnl();
let low_liq_pnl = strategy.backtest(&low_liq).await?.total_pnl();
println!("High liquidity PnL: ${:.2}", high_liq_pnl);
println!("Low liquidity PnL: ${:.2}", low_liq_pnl);
```
## Performance Benchmarks
```rust
use std::time::Instant;
let start = Instant::now();
let bars = repo.load_historical_data(&symbols, start_time, end_time).await?;
let duration = start.elapsed();
println!("Performance:");
println!(" Bars loaded: {}", bars.len());
println!(" Time: {:.2}ms", duration.as_secs_f64() * 1000.0);
println!(" Rate: {:.0} bars/ms", bars.len() as f64 / duration.as_millis() as f64);
// Target: <10ms for ~400 bars
assert!(duration.as_millis() < 10, "Performance target missed");
```
## Error Handling
```rust
// Invalid regime type
match repo.load_regime_samples("invalid", 10, &symbols).await {
Ok(_) => panic!("Should have failed"),
Err(e) => assert!(e.to_string().contains("Unknown regime type")),
}
// Symbol not found
let result = repo.get_date_range("INVALID").await;
assert!(result.is_err());
// Empty data
let empty_bars = Vec::new();
assert!(repo.resample_bars(&empty_bars, 5)?.is_empty());
assert!(repo.generate_summary_stats(&empty_bars).is_empty());
```
## Best Practices
1. **Use Time Range Queries** for precise filtering:
```rust
// Better: DateTime-based
let bars = repo.load_by_time_range(&symbols, start, end).await?;
// Avoid: Manual nanosecond conversion
let start_nanos = start.timestamp_nanos_opt().unwrap();
```
2. **Cache Resampled Data** to avoid redundant computation:
```rust
let bars_1m = repo.load_historical_data(&symbols, start, end).await?;
let bars_5m = repo.resample_bars(&bars_1m, 5)?; // Cache this result
```
3. **Use Volume Filtering** for realistic trading scenarios:
```rust
// Focus on tradeable liquidity
let min_volume = Decimal::new(100, 0);
let bars = repo.load_with_volume_filter(&symbols, min_volume, start, end).await?;
```
4. **Validate Regime Samples** before testing:
```rust
let samples = repo.load_regime_samples("trending", 100, &symbols).await?;
if samples.len() < 50 {
println!("Warning: Insufficient {} regime samples", "trending");
}
```
## Integration with Backtesting Service
```rust
use backtesting_service::{
dbn_repository::DbnMarketDataRepository,
strategy_engine::StrategyEngine,
};
// Create repository
let repo = DbnMarketDataRepository::new(file_mapping).await?;
// Load regime-specific data
let volatile_data = repo.load_regime_samples("volatile", 100, &symbols).await?;
// Run backtesting
let engine = StrategyEngine::new(strategy_config);
let results = engine.backtest(&volatile_data).await?;
// Analyze results
println!("Volatile regime performance:");
println!(" Sharpe Ratio: {:.2}", results.sharpe_ratio);
println!(" Max Drawdown: {:.2}%", results.max_drawdown_pct);
```
## See Also
- `DbnDataSource` - Underlying DBN file loader
- `MarketDataRepository` trait - Repository interface
- `StrategyEngine` - Backtesting execution engine
- `TESTING_PLAN.md` - Overall ML testing strategy