use crate::data::HyperliquidData;
use crate::errors::Result;
use chrono::{DateTime, FixedOffset, TimeZone};
fn create_test_data() -> HyperliquidData {
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();
let mut funding_rates = Vec::new();
let base_timestamp = 1640995200;
for i in 0..24 {
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(base_timestamp + i * 3600, 0).unwrap();
datetime.push(timestamp);
open.push(100.0 + (i as f64));
high.push(105.0 + (i as f64));
low.push(95.0 + (i as f64));
close.push(102.0 + (i as f64));
volume.push(1000.0 + (i as f64 * 100.0));
funding_rates.push(0.0001);
}
HyperliquidData {
symbol: "BTC".to_string(),
datetime,
open,
high,
low,
close,
volume,
funding_rates,
}
}
#[test]
fn test_get_price_at_or_near_exact_match() {
let data = create_test_data();
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(1640995200, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_some());
assert_eq!(price.unwrap(), 102.0); }
#[test]
fn test_get_price_at_or_near_close_match() {
let data = create_test_data();
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(1640995200 + 1800, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_some());
assert_eq!(price.unwrap(), 102.0); }
#[test]
fn test_get_price_at_or_near_between_entries() {
let data = create_test_data();
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(1640995200 + 3600 + 1800, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_some());
assert_eq!(price.unwrap(), 103.0); }
#[test]
fn test_get_price_at_or_near_outside_range_but_within_window() {
let data = create_test_data();
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(1640995200 - 1800, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_some());
assert_eq!(price.unwrap(), 102.0);
let last_timestamp = 1640995200 + 23 * 3600;
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(last_timestamp + 1800, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_some());
assert_eq!(price.unwrap(), 125.0); }
#[test]
fn test_get_price_at_or_near_far_outside_range() {
let data = create_test_data();
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(1640995200 - 2 * 24 * 3600, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_none());
let last_timestamp = 1640995200 + 23 * 3600;
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(last_timestamp + 2 * 24 * 3600, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_none()); }
#[test]
fn test_get_price_at_or_near_empty_data() {
let 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 timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(1640995200, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_none()); }
#[test]
fn test_get_price_at_or_near_edge_cases() {
let mut 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 timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(1640995200, 0).unwrap();
data.datetime.push(timestamp);
data.open.push(100.0);
data.high.push(105.0);
data.low.push(95.0);
data.close.push(102.0);
data.volume.push(1000.0);
data.funding_rates.push(0.0001);
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_some());
assert_eq!(price.unwrap(), 102.0);
let near_timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(1640995200 + 1800, 0).unwrap();
let price = data.get_price_at_or_near(near_timestamp);
assert!(price.is_some());
assert_eq!(price.unwrap(), 102.0);
}
#[test]
fn test_get_price_at_or_near_performance() {
let mut 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 base_timestamp = 1640995200;
for i in 0..365*24 {
let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(base_timestamp + i * 3600, 0).unwrap();
data.datetime.push(timestamp);
data.open.push(100.0 + (i as f64 * 0.01));
data.high.push(105.0 + (i as f64 * 0.01));
data.low.push(95.0 + (i as f64 * 0.01));
data.close.push(102.0 + (i as f64 * 0.01));
data.volume.push(1000.0);
data.funding_rates.push(0.0001);
}
use std::time::Instant;
let start = Instant::now();
for i in 0..100 {
let random_offset = (i * 37) % (365 * 24); let timestamp = FixedOffset::east_opt(0).unwrap()
.timestamp_opt(base_timestamp + random_offset * 3600 + 1800, 0).unwrap();
let price = data.get_price_at_or_near(timestamp);
assert!(price.is_some());
}
let duration = start.elapsed();
println!("100 price lookups in large dataset took: {:?}", duration);
assert!(duration.as_secs() < 1, "Price lookup performance test took too long");
}