1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
use std::fs::File;
use crate::{errors::Result, Aggregator, ModularCandle, TakerTrade, Trade};
/// Determine the candle volume which produces the same number of candles
/// as the given time aggregation equivalent
///
/// # Parameters:
/// `total_volume` - sum of traded volume over entire time period
/// `total_time_days` - total number of days
/// `target_time_minutes` - time aggregated candle period which to target
///
/// # Returns:
/// target candle volume for which volume aggregation produces
/// the same number of candles as the time aggregation did
/// e.g.:
/// 10 days of 1 hour candles -> 240 candles
/// assuming 9840 volume traded over 10 days
/// -> each candle should have 41 volume to produce 240 candles using volume aggregation
pub fn candle_volume_from_time_period(
total_volume: f64,
total_time_days: f64,
target_time_minutes: f64,
) -> f64 {
let num_candles = total_time_days * 24.0 * (60.0 / target_time_minutes);
total_volume / num_candles
}
/// Apply an aggregator for all trades at once
///
/// # Arguments:
/// trades: The input trade data to aggregate
/// aggregator: Something that can aggregate
///
/// # Returns:
/// A vector of aggregated candle data
pub fn aggregate_all_trades<A, C, T>(trades: &[T], aggregator: &mut A) -> Vec<C>
where
A: Aggregator<C, T>,
C: ModularCandle<T>,
T: TakerTrade,
{
let mut out: Vec<C> = vec![];
for t in trades {
if let Some(candle) = aggregator.update(t) {
out.push(candle)
}
}
out
}
/// Load trades from csv file
///
/// # Arguments:
/// filename: The path to the csv file
///
/// # Returns
/// If Ok, A vector of the trades inside the file
pub fn load_trades_from_csv(filename: &str) -> Result<Vec<Trade>> {
let f = File::open(filename)?;
let mut r = csv::Reader::from_reader(f);
let mut out: Vec<Trade> = vec![];
for record in r.records() {
let row = record?;
let ts = row[0].parse::<i64>()?;
let price = row[1].parse::<f64>()?;
let size = row[2].parse::<f64>()?;
// convert to Trade
let trade = Trade {
timestamp: ts,
price,
size,
};
out.push(trade);
}
Ok(out)
}
#[cfg(test)]
mod tests {
use round::round;
use super::*;
// TODO: re-enable this test
/*
#[test]
fn test_aggregate_all_trades() {
let trades = load_trades_from_csv("data/Bitmex_XBTUSD_1M.csv").unwrap();
let mut aggregator = GenericAggregator::new(100.0, By::Quote);
let candles = aggregate_all_trades(&trades, &mut aggregator);
assert!(candles.len() > 0);
}
*/
#[test]
fn test_candle_volume_from_time_period() {
let total_volume = 100.0;
let time_days = 10.0;
let target_time_minutes = 5.0;
let vol_threshold =
candle_volume_from_time_period(total_volume, time_days, target_time_minutes);
assert_eq!(round(vol_threshold, 3), 0.035);
let total_volume = 100.0;
let time_days = 10.0;
let target_time_minutes = 10.0;
let vol_threshold =
candle_volume_from_time_period(total_volume, time_days, target_time_minutes);
assert_eq!(round(vol_threshold, 3), 0.069);
let total_volume = 200.0;
let time_days = 10.0;
let target_time_minutes = 10.0;
let vol_threshold =
candle_volume_from_time_period(total_volume, time_days, target_time_minutes);
assert_eq!(round(vol_threshold, 3), 0.139);
let total_volume = 50.0;
let time_days = 10.0;
let target_time_minutes = 10.0;
let vol_threshold =
candle_volume_from_time_period(total_volume, time_days, target_time_minutes);
assert_eq!(round(vol_threshold, 3), 0.035);
let total_volume = 100.0;
let time_days = 5.0;
let target_time_minutes = 5.0;
let vol_threshold =
candle_volume_from_time_period(total_volume, time_days, target_time_minutes);
assert_eq!(round(vol_threshold, 3), 0.069);
let total_volume = 100.0;
let time_days = 5.0;
let target_time_minutes = 10.0;
let vol_threshold =
candle_volume_from_time_period(total_volume, time_days, target_time_minutes);
assert_eq!(round(vol_threshold, 3), 0.139);
}
}