use chrono::{Duration, Utc};
use hyperliquid_backtest::prelude::*;
use rs_backtester::prelude::*;
use std::fs::File;
use std::io::Write;
use tracing::Instrument;
#[tokio::main]
async fn main() -> Result<(), HyperliquidBacktestError> {
init_logger_with_level("info");
log::info!("Starting Comprehensive Hyperliquid Backtester Example");
println!("🚀 Comprehensive Hyperliquid Backtester Example");
println!("===============================================\n");
let initial_capital = 50000.0; let lookback_days = 60;
let end_time = Utc::now().timestamp() as u64;
let start_time = end_time - (lookback_days * 24 * 3600);
println!("📊 Configuration:");
println!(" Initial Capital: ${:.2}", initial_capital);
println!(" Lookback Period: {} days", lookback_days);
println!(" Time Range: {} to {}\n",
chrono::DateTime::from_timestamp(start_time as i64, 0).unwrap().format("%Y-%m-%d"),
chrono::DateTime::from_timestamp(end_time as i64, 0).unwrap().format("%Y-%m-%d"));
println!("📈 Step 1: Fetching Multi-Asset Data");
println!("-----------------------------------");
let assets = vec![
("BTC", "1h"),
("ETH", "1h"),
("SOL", "1h"),
];
let mut asset_data = Vec::new();
for (symbol, interval) in &assets {
let span = performance_span("data_fetch", &[
("symbol", symbol),
("interval", interval),
("days", &lookback_days.to_string())
]);
let fetch_result = async {
log::info!("Fetching {} data with {} interval", symbol, interval);
println!(" Fetching {} data...", symbol);
let data = HyperliquidData::fetch(symbol, interval, start_time, end_time).await?;
log::info!("Successfully fetched {} data points for {}", data.datetime.len(), symbol);
println!(" ✅ {} data points fetched", data.datetime.len());
Ok::<_, HyperliquidBacktestError>((symbol.to_string(), data))
}
.instrument(span)
.await?;
asset_data.push(fetch_result);
}
println!(" 📊 Data Summary:");
for (symbol, data) in &asset_data {
let funding_points = data.funding_rates.len();
let price_range = data.high.iter().fold(0.0, |a, &b| a.max(b)) -
data.low.iter().fold(f64::INFINITY, |a, &b| a.min(b));
println!(" {}: {} OHLC points, {} funding points, price range: ${:.2}",
symbol, data.datetime.len(), funding_points, price_range);
}
println!();
println!("🧠 Step 2: Strategy Development and Testing");
println!("------------------------------------------");
let mut strategy_results = Vec::new();
let strategy_configs = vec![
("Conservative SMA (20/50)", 20, 50, 0.05), ("Aggressive SMA (5/15)", 5, 15, 0.15), ("Balanced SMA (10/30)", 10, 30, 0.10), ];
for (name, short_period, long_period, funding_weight) in strategy_configs {
println!(" Testing strategy: {}", name);
let span = performance_span("strategy_backtest", &[
("strategy", name),
("short_period", &short_period.to_string()),
("long_period", &long_period.to_string())
]);
let backtest_result = async {
let (_, btc_data) = asset_data.iter()
.find(|(symbol, _)| symbol == "BTC")
.ok_or_else(|| HyperliquidBacktestError::DataConversion("BTC data not found".to_string()))?;
let strategy = enhanced_sma_cross(
short_period,
long_period,
FundingAwareConfig {
funding_weight,
min_funding_threshold: 0.0001, }
)?;
let commission = HyperliquidCommission {
maker_rate: 0.0002, taker_rate: 0.0005, funding_enabled: true,
};
let mut backtest = HyperliquidBacktest::new(
btc_data.clone(),
strategy,
initial_capital,
commission,
)?;
log::info!("Running backtest for strategy: {}", name);
backtest.calculate_with_funding()?;
let stats = backtest.enhanced_report()?;
let funding_report = backtest.funding_report()?;
log::info!("Completed backtest for {}: {:.2}% return", name, stats.total_return * 100.0);
Ok::<_, HyperliquidBacktestError>((name.to_string(), stats, funding_report))
}
.instrument(span)
.await?;
strategy_results.push(backtest_result);
let (_, stats, funding_report) = &strategy_results.last().unwrap();
println!(" 📊 Results: {:.2}% return, {:.2}% max drawdown, ${:.2} funding PnL",
stats.total_return * 100.0,
stats.max_drawdown * 100.0,
funding_report.net_funding_pnl);
}
println!();
println!("📊 Step 3: Detailed Performance Analysis");
println!("---------------------------------------");
let best_strategy = strategy_results.iter()
.max_by(|a, b| a.1.total_return.partial_cmp(&b.1.total_return).unwrap())
.unwrap();
println!("🏆 Best Performing Strategy: {}", best_strategy.0);
println!(" Total Return: {:.2}%", best_strategy.1.total_return * 100.0);
println!(" Sharpe Ratio: {:.3}", best_strategy.1.sharpe_ratio);
println!(" Max Drawdown: {:.2}%", best_strategy.1.max_drawdown * 100.0);
println!(" Win Rate: {:.2}%", best_strategy.1.win_rate * 100.0);
println!();
println!("💰 Funding Rate Analysis:");
println!(" Net Funding PnL: ${:.2}", best_strategy.2.net_funding_pnl);
println!(" Total Funding Received: ${:.2}", best_strategy.2.total_funding_received);
println!(" Total Funding Paid: ${:.2}", best_strategy.2.total_funding_paid);
println!(" Average Funding Rate: {:.4}%", best_strategy.2.avg_funding_rate * 100.0);
println!(" Funding Efficiency: {:.2}", best_strategy.2.funding_efficiency);
println!();
println!("⚠️ Step 4: Risk Analysis");
println!("------------------------");
for (name, stats, funding_report) in &strategy_results {
let risk_adjusted_return = stats.total_return / stats.max_drawdown.max(0.01);
let funding_dependency = funding_report.net_funding_pnl.abs() / stats.total_return.abs().max(0.01);
println!(" {}", name);
println!(" Risk-Adjusted Return: {:.2}", risk_adjusted_return);
println!(" Funding Dependency: {:.2}%", funding_dependency * 100.0);
println!(" Volatility: {:.2}%", stats.volatility * 100.0);
println!();
}
println!("💾 Step 5: Exporting Results");
println!("---------------------------");
let (_, btc_data) = asset_data.iter()
.find(|(symbol, _)| symbol == "BTC")
.unwrap();
let best_config = strategy_configs.iter()
.find(|(name, _, _, _)| name == &best_strategy.0)
.unwrap();
let export_strategy = enhanced_sma_cross(
best_config.1,
best_config.2,
FundingAwareConfig {
funding_weight: best_config.3,
min_funding_threshold: 0.0001,
}
)?;
let mut export_backtest = HyperliquidBacktest::new(
btc_data.clone(),
export_strategy,
initial_capital,
HyperliquidCommission::default(),
)?;
export_backtest.calculate_with_funding()?;
let csv_filename = "comprehensive_backtest_results.csv";
export_backtest.export_enhanced_csv(csv_filename)?;
println!(" ✅ Detailed results exported to {}", csv_filename);
let comparison_filename = "strategy_comparison.csv";
let mut comparison_file = File::create(comparison_filename)?;
writeln!(comparison_file, "Strategy,Total Return (%),Sharpe Ratio,Max Drawdown (%),Win Rate (%),Funding PnL ($),Risk-Adjusted Return")?;
for (name, stats, funding_report) in &strategy_results {
let risk_adjusted_return = stats.total_return / stats.max_drawdown.max(0.01);
writeln!(comparison_file, "{},{:.2},{:.3},{:.2},{:.2},{:.2},{:.2}",
name,
stats.total_return * 100.0,
stats.sharpe_ratio,
stats.max_drawdown * 100.0,
stats.win_rate * 100.0,
funding_report.net_funding_pnl,
risk_adjusted_return
)?;
}
println!(" ✅ Strategy comparison exported to {}", comparison_filename);
println!();
println!("🎯 Step 6: Final Performance Summary");
println!("----------------------------------");
println!("📈 Market Data Processed:");
println!(" Total Assets: {}", asset_data.len());
println!(" Total Data Points: {}", asset_data.iter().map(|(_, data)| data.datetime.len()).sum::<usize>());
println!(" Total Funding Points: {}", asset_data.iter().map(|(_, data)| data.funding_rates.len()).sum::<usize>());
println!("\n🧠 Strategies Tested: {}", strategy_results.len());
println!("\n🏆 Best Strategy Performance:");
println!(" Strategy: {}", best_strategy.0);
println!(" Initial Capital: ${:.2}", initial_capital);
println!(" Final Value: ${:.2}", initial_capital * (1.0 + best_strategy.1.total_return));
println!(" Net Profit: ${:.2}", initial_capital * best_strategy.1.total_return);
println!(" Total Return: {:.2}%", best_strategy.1.total_return * 100.0);
println!("\n💰 Funding Impact:");
println!(" Funding PnL: ${:.2}", best_strategy.2.net_funding_pnl);
println!(" Funding as % of Total Return: {:.2}%",
(best_strategy.2.net_funding_pnl / (initial_capital * best_strategy.1.total_return)).abs() * 100.0);
println!("\n📊 Files Generated:");
println!(" - {}: Detailed backtest results with funding data", csv_filename);
println!(" - {}: Strategy performance comparison", comparison_filename);
log::info!("Comprehensive example completed successfully");
println!("\n✅ Comprehensive example completed successfully!");
println!(" Check the generated CSV files for detailed analysis.");
Ok(())
}