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
This commit is contained in:
154
docs/examples/dbn_backtesting_integration.rs
Normal file
154
docs/examples/dbn_backtesting_integration.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
//! DBN Backtesting Integration Example
|
||||
//!
|
||||
//! This example demonstrates using DBN data with the backtesting service's
|
||||
//! MarketDataRepository interface.
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! ```bash
|
||||
//! cargo run --example dbn_backtesting_integration
|
||||
//! ```
|
||||
|
||||
use backtesting_service::{
|
||||
dbn_repository::DbnMarketDataRepository,
|
||||
repositories::MarketDataRepository,
|
||||
};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
println!("=== DBN Backtesting Integration Example ===\n");
|
||||
|
||||
// 1. Setup repository with DBN data
|
||||
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(),
|
||||
);
|
||||
|
||||
println!("Creating MarketDataRepository with DBN backend...");
|
||||
let repo = DbnMarketDataRepository::new(file_mapping).await?;
|
||||
|
||||
println!("Available symbols: {:?}", repo.available_symbols());
|
||||
|
||||
// 2. Define backtest time range
|
||||
let start_time = Utc
|
||||
.with_ymd_and_hms(2024, 1, 2, 14, 30, 0)
|
||||
.unwrap()
|
||||
.timestamp_nanos_opt()
|
||||
.unwrap();
|
||||
let end_time = Utc
|
||||
.with_ymd_and_hms(2024, 1, 2, 16, 0, 0)
|
||||
.unwrap()
|
||||
.timestamp_nanos_opt()
|
||||
.unwrap();
|
||||
|
||||
println!(
|
||||
"\nBacktest window: {} to {}",
|
||||
Utc.timestamp_nanos(start_time).format("%Y-%m-%d %H:%M:%S"),
|
||||
Utc.timestamp_nanos(end_time).format("%Y-%m-%d %H:%M:%S")
|
||||
);
|
||||
|
||||
// 3. Load historical data via repository interface
|
||||
let symbols = vec!["ES.FUT".to_string()];
|
||||
println!("\nLoading historical data for {:?}...", symbols);
|
||||
|
||||
let data = repo.load_historical_data(&symbols, start_time, end_time).await?;
|
||||
|
||||
println!("✅ Loaded {} bars via repository interface\n", data.len());
|
||||
|
||||
// 4. Check data availability
|
||||
println!("=== Data Availability Check ===");
|
||||
|
||||
let availability = repo
|
||||
.check_data_availability(&symbols, start_time, end_time)
|
||||
.await?;
|
||||
|
||||
for (symbol, available) in availability.iter() {
|
||||
println!(
|
||||
"{}: {}",
|
||||
symbol,
|
||||
if *available { "✅ Available" } else { "❌ Not available" }
|
||||
);
|
||||
}
|
||||
|
||||
// 5. Simulate simple backtest logic
|
||||
println!("\n=== Simulating Simple Backtest ===");
|
||||
|
||||
let mut position = 0i32;
|
||||
let mut pnl = 0.0;
|
||||
let mut trades = 0;
|
||||
|
||||
for (i, bar) in data.iter().enumerate() {
|
||||
let close_f64 = bar.close.to_string().parse::<f64>().unwrap();
|
||||
|
||||
// Simple strategy: Buy when price drops, sell when price rises
|
||||
if i > 0 {
|
||||
let prev_close = data[i - 1].close.to_string().parse::<f64>().unwrap();
|
||||
let price_change = close_f64 - prev_close;
|
||||
|
||||
if position == 0 && price_change < -1.0 {
|
||||
// Buy signal
|
||||
position = 1;
|
||||
pnl -= close_f64; // Entry cost
|
||||
trades += 1;
|
||||
println!(" [{}] BUY @ {:.2}", bar.timestamp.format("%H:%M"), close_f64);
|
||||
} else if position == 1 && price_change > 1.0 {
|
||||
// Sell signal
|
||||
position = 0;
|
||||
pnl += close_f64; // Exit proceeds
|
||||
trades += 1;
|
||||
println!(" [{}] SELL @ {:.2}", bar.timestamp.format("%H:%M"), close_f64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close any open position
|
||||
if position != 0 {
|
||||
let last_close = data.last().unwrap().close.to_string().parse::<f64>().unwrap();
|
||||
pnl += last_close * position as f64;
|
||||
trades += 1;
|
||||
println!(
|
||||
" [{}] CLOSE @ {:.2}",
|
||||
data.last().unwrap().timestamp.format("%H:%M"),
|
||||
last_close
|
||||
);
|
||||
}
|
||||
|
||||
println!("\n=== Backtest Results ===");
|
||||
println!("Total trades: {}", trades);
|
||||
println!("Final PnL: ${:.2}", pnl);
|
||||
|
||||
// 6. Advanced repository features
|
||||
println!("\n=== Advanced Repository Features ===");
|
||||
|
||||
// Load with volume filter
|
||||
let min_volume = rust_decimal::Decimal::from(50);
|
||||
let high_volume_bars = repo
|
||||
.load_with_volume_filter(&symbols, min_volume, start_time, end_time)
|
||||
.await?;
|
||||
|
||||
println!(
|
||||
"High-volume bars (volume >= {}): {}",
|
||||
min_volume,
|
||||
high_volume_bars.len()
|
||||
);
|
||||
|
||||
// Get date range
|
||||
let (first_ts, last_ts) = repo.get_date_range("ES.FUT").await?;
|
||||
println!("Data range: {} to {}", first_ts, last_ts);
|
||||
|
||||
// Generate summary statistics
|
||||
let stats = repo.generate_summary_stats(&data);
|
||||
println!("\nSummary 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!("\n✅ Example completed successfully!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user