use crate::csv_export::*;
use crate::backtest::{HyperliquidBacktest, HyperliquidCommission, FundingPayment};
use crate::data::HyperliquidData;
use crate::errors::Result;
use crate::tests::mock_data::{
generate_mock_data, generate_mock_funding_payments,
generate_position_sequence
};
use chrono::{DateTime, FixedOffset, TimeZone};
use std::path::Path;
use std::fs;
use std::io::Read;
#[test]
fn test_enhanced_csv_export_trait() -> Result<()> {
let data = generate_mock_data("BTC", 72, true, false);
let strategy_name = "Test Strategy".to_string();
let initial_capital = 10000.0;
let commission = HyperliquidCommission::default();
let mut backtest = HyperliquidBacktest::new(
data.clone(),
strategy_name.clone(),
initial_capital,
commission.clone(),
);
backtest.initialize_base_backtest()?;
let positions = vec![1.0; data.len()];
backtest.calculate_with_funding_and_positions(&positions)?;
let temp_file = "test_enhanced_export.csv";
backtest.export_to_csv(temp_file)?;
assert!(Path::new(temp_file).exists());
let mut file = fs::File::open(temp_file)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert!(content.contains("timestamp"));
assert!(content.contains("price"));
assert!(content.contains("position"));
assert!(content.contains("equity"));
assert!(content.contains("funding_rate"));
assert!(content.contains("funding_pnl"));
fs::remove_file(temp_file)?;
Ok(())
}
#[test]
fn test_enhanced_csv_export_ext_trait() -> Result<()> {
let data = generate_mock_data("BTC", 72, true, false);
let strategy_name = "Test Strategy".to_string();
let initial_capital = 10000.0;
let commission = HyperliquidCommission::default();
let mut backtest = HyperliquidBacktest::new(
data.clone(),
strategy_name.clone(),
initial_capital,
commission.clone(),
);
backtest.initialize_base_backtest()?;
let positions = vec![1.0; data.len()];
backtest.calculate_with_funding_and_positions(&positions)?;
let temp_file = "test_extended_export.csv";
backtest.export_to_csv_extended(temp_file, true, true, true)?;
assert!(Path::new(temp_file).exists());
let mut file = fs::File::open(temp_file)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert!(content.contains("timestamp"));
assert!(content.contains("price"));
assert!(content.contains("position"));
assert!(content.contains("equity"));
assert!(content.contains("funding_rate"));
assert!(content.contains("funding_pnl"));
assert!(content.contains("trading_pnl"));
assert!(content.contains("total_pnl"));
fs::remove_file(temp_file)?;
Ok(())
}
#[test]
fn test_export_funding_payments() -> Result<()> {
let payments = generate_mock_funding_payments(72, 1.0);
let temp_file = "test_funding_payments.csv";
export_funding_payments_to_csv(&payments, temp_file)?;
assert!(Path::new(temp_file).exists());
let mut file = fs::File::open(temp_file)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert!(content.contains("timestamp"));
assert!(content.contains("funding_rate"));
assert!(content.contains("position_size"));
assert!(content.contains("price"));
assert!(content.contains("payment_amount"));
fs::remove_file(temp_file)?;
Ok(())
}
#[test]
fn test_export_strategy_comparison() -> Result<()> {
let data = generate_mock_data("BTC", 72, true, false);
let strategy1_name = "Strategy 1".to_string();
let strategy2_name = "Strategy 2".to_string();
let initial_capital = 10000.0;
let commission = HyperliquidCommission::default();
let mut backtest1 = HyperliquidBacktest::new(
data.clone(),
strategy1_name.clone(),
initial_capital,
commission.clone(),
);
let mut backtest2 = HyperliquidBacktest::new(
data.clone(),
strategy2_name.clone(),
initial_capital,
commission.clone(),
);
backtest1.initialize_base_backtest()?;
backtest2.initialize_base_backtest()?;
let positions1 = generate_position_sequence(data.len(), "constant_long");
let positions2 = generate_position_sequence(data.len(), "alternating");
backtest1.calculate_with_funding_and_positions(&positions1)?;
backtest2.calculate_with_funding_and_positions(&positions2)?;
let comparison = StrategyComparisonData {
strategies: vec![backtest1, backtest2],
};
let temp_file = "test_strategy_comparison.csv";
comparison.export_to_csv(temp_file)?;
assert!(Path::new(temp_file).exists());
let mut file = fs::File::open(temp_file)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert!(content.contains("timestamp"));
assert!(content.contains("price"));
assert!(content.contains("Strategy 1_position"));
assert!(content.contains("Strategy 1_equity"));
assert!(content.contains("Strategy 2_position"));
assert!(content.contains("Strategy 2_equity"));
fs::remove_file(temp_file)?;
Ok(())
}
#[test]
fn test_export_funding_rate_history() -> Result<()> {
let data = generate_mock_data("BTC", 72, true, false);
let temp_file = "test_funding_history.csv";
export_funding_rate_history(&data, temp_file)?;
assert!(Path::new(temp_file).exists());
let mut file = fs::File::open(temp_file)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert!(content.contains("timestamp"));
assert!(content.contains("funding_rate"));
fs::remove_file(temp_file)?;
Ok(())
}
#[test]
fn test_csv_export_edge_cases() -> Result<()> {
let empty_data = HyperliquidData {
symbol: "BTC".to_string(),
datetime: Vec::new(),
open: Vec::new(),
high: Vec::new(),
low: Vec::new(),
close: Vec::new(),
volume: Vec::new(),
funding_rates: Vec::new(),
};
let strategy_name = "Empty Strategy".to_string();
let initial_capital = 10000.0;
let commission = HyperliquidCommission::default();
let mut empty_backtest = HyperliquidBacktest::new(
empty_data.clone(),
strategy_name.clone(),
initial_capital,
commission.clone(),
);
empty_backtest.initialize_base_backtest()?;
let temp_file = "test_empty_export.csv";
empty_backtest.export_to_csv(temp_file)?;
assert!(Path::new(temp_file).exists());
let mut file = fs::File::open(temp_file)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert!(content.contains("timestamp"));
assert_eq!(content.lines().count(), 1);
fs::remove_file(temp_file)?;
let empty_payments: Vec<FundingPayment> = Vec::new();
let temp_file = "test_empty_payments.csv";
export_funding_payments_to_csv(&empty_payments, temp_file)?;
assert!(Path::new(temp_file).exists());
let mut file = fs::File::open(temp_file)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert!(content.contains("timestamp"));
assert_eq!(content.lines().count(), 1);
fs::remove_file(temp_file)?;
Ok(())
}
#[test]
fn test_csv_export_invalid_path() {
let data = generate_mock_data("BTC", 72, true, false);
let strategy_name = "Test Strategy".to_string();
let initial_capital = 10000.0;
let commission = HyperliquidCommission::default();
let mut backtest = HyperliquidBacktest::new(
data.clone(),
strategy_name.clone(),
initial_capital,
commission.clone(),
);
backtest.initialize_base_backtest().unwrap();
let invalid_path = "/invalid/path/that/does/not/exist/file.csv";
let result = backtest.export_to_csv(invalid_path);
assert!(result.is_err());
if let Err(e) = result {
match e {
crate::errors::HyperliquidBacktestError::Io(_) => {}, _ => panic!("Expected IO error"),
}
}
}
#[test]
fn test_csv_export_special_characters() -> Result<()> {
let data = generate_mock_data("BTC", 10, true, false);
let strategy_name = "Strategy with, special \"characters\"".to_string();
let initial_capital = 10000.0;
let commission = HyperliquidCommission::default();
let mut backtest = HyperliquidBacktest::new(
data.clone(),
strategy_name.clone(),
initial_capital,
commission.clone(),
);
backtest.initialize_base_backtest()?;
let positions = vec![1.0; data.len()];
backtest.calculate_with_funding_and_positions(&positions)?;
let temp_file = "test_special_chars.csv";
backtest.export_to_csv(temp_file)?;
assert!(Path::new(temp_file).exists());
let mut file = fs::File::open(temp_file)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
assert!(content.contains("timestamp"));
assert!(content.lines().count() > 1);
fs::remove_file(temp_file)?;
Ok(())
}