Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ serde_json = "1.0"

# Error handling
thiserror = "1.0"
anyhow = "1.0"

# CSV handling
csv = "1.3"
Expand Down
94 changes: 77 additions & 17 deletions examples/basic_backtest.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
use chrono::Utc;
use chrono::{Duration, TimeZone, Utc, FixedOffset};
use hyperliquid_rust_sdk::{BaseUrl, InfoClient};
use hyperliquid_backtest::prelude::*;

/// # Basic Backtest Example
/// # Basic Backtest Example (Fixed with Working API)
///
/// This example demonstrates how to run a simple backtest using the Hyperliquid backtester.
/// It shows:
/// - Setting up logging for debugging and monitoring
/// - Fetching historical data from Hyperliquid API
/// - Fetching historical data from Hyperliquid API using the correct SDK
/// - Creating a basic SMA crossover strategy
/// - Configuring backtest parameters with realistic commission rates
/// - Running the backtest with funding rates enabled
/// - Analyzing and reporting comprehensive results
/// - Comparing performance with and without funding rates
/// - Exporting results to CSV for further analysis
///
/// The example uses a 10/30 SMA crossover strategy on BTC/USD data over the last 90 days.
/// The example uses a 10/30 SMA crossover strategy on BTC/USD data over the last 30 days.
///
/// ## Supported Symbols
///
/// Based on Hyperliquid API testing, the following symbols work:
/// - BTC, ETH, SOL, AVAX, ATOM (all return data)
/// - All intervals: 1m, 5m, 15m, 1h, 4h, 1d
///
/// ## Usage
///
Expand All @@ -40,20 +47,69 @@ async fn main() -> Result<()> {

log::info!("Starting Hyperliquid Basic Backtest Example");

println!("🚀 Hyperliquid Basic Backtest Example");
println!("=====================================\n");
println!("🚀 Hyperliquid Basic Backtest Example (Fixed)");
println!("============================================\n");

// Fetch historical data for BTC with funding rates
let end_time = Utc::now().timestamp() as u64;
let start_time = end_time - (90 * 24 * 3600); // 90 days of data

println!("Fetching BTC/USD data for the last 90 days...");
let data = HyperliquidData::fetch("BTC", "1h", start_time, end_time).await?;
// Define time range for data fetching (last 30 days for faster testing)
let end_time = Utc::now();
let start_time = end_time - Duration::days(30);
let start_timestamp = start_time.timestamp_millis() as u64;
let end_timestamp = end_time.timestamp_millis() as u64;

println!("Fetching BTC/USD data for the last 30 days...");
println!("Time range: {} to {}",
start_time.format("%Y-%m-%d %H:%M"),
end_time.format("%Y-%m-%d %H:%M"));

// Initialize Hyperliquid client
let info_client = InfoClient::new(None, Some(BaseUrl::Mainnet)).await?;

println!("Data fetched: {} data points from {} to {}\n",
// Fetch OHLCV data using the working SDK
let candles = info_client
.candles_snapshot("BTC".to_string(), "1h".to_string(), start_timestamp, end_timestamp)
.await?;

println!("✅ Successfully fetched {} candles!", candles.len());

if candles.is_empty() {
return Err(HyperliquidBacktestError::api_error("No data received from API"));
}

// Convert candles to our internal format
let mut datetime = Vec::new();
let mut open = Vec::new();
let mut high = Vec::new();
let mut low = Vec::new();
let mut close = Vec::new();
let mut volume = Vec::new();

for candle in &candles {
let timestamp = Utc.timestamp_millis_opt(candle.time_open as i64).unwrap()
.with_timezone(&FixedOffset::east_opt(0).unwrap());

datetime.push(timestamp);
open.push(candle.open.parse::<f64>().unwrap_or(0.0));
high.push(candle.high.parse::<f64>().unwrap_or(0.0));
low.push(candle.low.parse::<f64>().unwrap_or(0.0));
close.push(candle.close.parse::<f64>().unwrap_or(0.0));
volume.push(candle.vlm.parse::<f64>().unwrap_or(0.0));
}

// Create our internal Data struct
let data = HyperliquidData::with_ohlc_data(
"BTC".to_string(),
datetime,
open,
high,
low,
close,
volume,
)?;

println!("Data converted: {} data points from {} to {}\n",
data.len(),
data.datetime.first().unwrap().format("%Y-%m-%d %H:%M"),
data.datetime.last().unwrap().format("%Y-%m-%d %H:%M"));
data.datetime.first().map(|d| d.format("%Y-%m-%d %H:%M").to_string()).unwrap_or_else(|| "N/A".to_string()),
data.datetime.last().map(|d| d.format("%Y-%m-%d %H:%M").to_string()).unwrap_or_else(|| "N/A".to_string()));

// Create a simple SMA crossover strategy using the enhanced_sma_cross function
println!("Setting up SMA crossover strategy (10/30)...");
Expand All @@ -78,8 +134,11 @@ async fn main() -> Result<()> {
initial_capital,
commission.clone(),
);

// Initialize the base backtest first
backtest.initialize_base_backtest()?;

// Run backtest with funding rates
// Then calculate with funding rates
backtest.calculate_with_funding()?;

// Get enhanced report
Expand Down Expand Up @@ -141,7 +200,8 @@ async fn main() -> Result<()> {
initial_capital,
commission_no_funding,
);


backtest_no_funding.initialize_base_backtest()?;
backtest_no_funding.calculate_with_funding()?;

let report_no_funding = backtest_no_funding.enhanced_report()?;
Expand Down
122 changes: 99 additions & 23 deletions examples/simple_data_fetching.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,88 @@
use chrono::{Duration, Utc};
use chrono::{Duration, TimeZone, Utc, FixedOffset};
use hyperliquid_rust_sdk::{BaseUrl, InfoClient};
use hyperliquid_backtest::prelude::*;
use std::fs::File;
use std::io::Write;

/// # Simple OHLC Data Fetching Example
/// # Simple OHLC Data Fetching Example (Fixed with Working API)
///
/// This example demonstrates how to fetch historical OHLC data from Hyperliquid API
/// for different time intervals and trading pairs. It shows:
/// - Basic data fetching for BTC
/// - Basic data fetching for BTC using the correct SDK
/// - Custom time range specification
/// - Data validation and statistics
/// - Saving data to CSV for further analysis
/// - Testing different symbols and intervals
///
/// The example fetches 7 days of hourly data for BTC/USD and saves it to a CSV file.

#[tokio::main]
async fn main() -> Result<()> {
println!("Hyperliquid Simple Data Fetching Example");
println!("=======================================\n");
println!("🚀 Hyperliquid Simple Data Fetching Example (Fixed)");
println!("==================================================\n");

// Define time range for data fetching (last 7 days)
let end_time = Utc::now().timestamp() as u64;
let start_time = end_time - (7 * 24 * 3600); // 7 days of data
let end_time = Utc::now();
let start_time = end_time - Duration::days(7);
let start_timestamp = start_time.timestamp_millis() as u64;
let end_timestamp = end_time.timestamp_millis() as u64;

println!("Fetching BTC/USD hourly data for the last 7 days...");
println!("Time range: {} to {}",
start_time.format("%Y-%m-%d %H:%M"),
end_time.format("%Y-%m-%d %H:%M"));

// Initialize Hyperliquid client
let info_client = InfoClient::new(None, Some(BaseUrl::Mainnet)).await?;

// Fetch BTC data using the convenience method
let btc_data = HyperliquidData::fetch_btc("1h", start_time, end_time).await?;
// Fetch BTC data using the working SDK
let candles = info_client
.candles_snapshot("BTC".to_string(), "1h".to_string(), start_timestamp, end_timestamp)
.await?;

println!("✅ Successfully fetched {} candles!", candles.len());

if candles.is_empty() {
return Err(HyperliquidBacktestError::api_error("No data received from API"));
}

// Convert candles to our internal format
let mut datetime = Vec::new();
let mut open = Vec::new();
let mut high = Vec::new();
let mut low = Vec::new();
let mut close = Vec::new();
let mut volume = Vec::new();

for candle in &candles {
let timestamp = Utc.timestamp_millis_opt(candle.time_open as i64).unwrap()
.with_timezone(&FixedOffset::east_opt(0).unwrap());

datetime.push(timestamp);
open.push(candle.open.parse::<f64>().unwrap_or(0.0));
high.push(candle.high.parse::<f64>().unwrap_or(0.0));
low.push(candle.low.parse::<f64>().unwrap_or(0.0));
close.push(candle.close.parse::<f64>().unwrap_or(0.0));
volume.push(candle.vlm.parse::<f64>().unwrap_or(0.0));
}

// Create our internal Data struct
let btc_data = HyperliquidData::with_ohlc_data(
"BTC".to_string(),
datetime,
open,
high,
low,
close,
volume,
)?;

// Print data statistics
println!("\nData fetched successfully!");
println!("Symbol: {}", btc_data.ticker);
println!("Symbol: {}", btc_data.symbol);
println!("Time range: {} to {}",
btc_data.datetime.first().unwrap().format("%Y-%m-%d %H:%M"),
btc_data.datetime.last().unwrap().format("%Y-%m-%d %H:%M"));
btc_data.datetime.first().map(|d| d.format("%Y-%m-%d %H:%M").to_string()).unwrap_or_else(|| "N/A".to_string()),
btc_data.datetime.last().map(|d| d.format("%Y-%m-%d %H:%M").to_string()).unwrap_or_else(|| "N/A".to_string()));
println!("Number of data points: {}", btc_data.len());
println!("Number of funding rate points: {}", btc_data.funding_rates.len());

Expand Down Expand Up @@ -98,17 +147,44 @@ async fn main() -> Result<()> {
file.write_all(csv_content.as_bytes())?;
println!("Data saved to {}", csv_file);

// Demonstrate fetching data for another asset (ETH)
println!("\nFetching ETH/USD data for comparison...");
let eth_data = HyperliquidData::fetch("ETH", "1h", start_time, end_time).await?;

println!("ETH data fetched: {} data points", eth_data.len());

// Demonstrate fetching data with different time interval
println!("\nFetching BTC/USD data with 5-minute intervals...");
let btc_5m_data = HyperliquidData::fetch_btc("5m", end_time - (24 * 3600), end_time).await?;

println!("BTC 5-minute data fetched: {} data points for the last 24 hours", btc_5m_data.len());
// Try fetching different time intervals
println!("\nFetching 5-minute data for the last 24 hours...");
let btc_5m_candles = info_client
.candles_snapshot("BTC".to_string(), "5m".to_string(), end_timestamp - (24 * 3600 * 1000), end_timestamp)
.await?;
println!("5m data points: {}", btc_5m_candles.len());

// Try fetching ETH data
println!("\nFetching ETH data for comparison...");
let eth_candles = info_client
.candles_snapshot("ETH".to_string(), "1h".to_string(), start_timestamp, end_timestamp)
.await?;
println!("ETH data points: {}", eth_candles.len());

// Try fetching SOL data
println!("\nFetching SOL data for comparison...");
let sol_candles = info_client
.candles_snapshot("SOL".to_string(), "1h".to_string(), start_timestamp, end_timestamp)
.await?;
println!("SOL data points: {}", sol_candles.len());

// Test different intervals for BTC
println!("\nTesting different intervals for BTC...");
let intervals = vec!["1m", "5m", "15m", "1h", "4h", "1d"];

for interval in intervals {
println!("Testing interval: {}", interval);
match info_client
.candles_snapshot("BTC".to_string(), interval.to_string(), start_timestamp, end_timestamp)
.await {
Ok(test_candles) => {
println!(" ✅ {}: {} candles", interval, test_candles.len());
}
Err(e) => {
println!(" ❌ {}: {}", interval, e);
}
}
}

println!("\nExample completed successfully!");

Expand Down
Loading
Loading