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
use crate::aggregation_rules::TimestampResolution;
use crate::{AggregationRule, ModularCandle, TakerTrade};
pub struct AlignedTimeRule {
init: bool,
reference_timestamp: i64,
period_s: i64,
}
impl AlignedTimeRule {
pub fn new(period_s: i64, ts_res: TimestampResolution) -> Self {
let ts_multiplier = match ts_res {
TimestampResolution::Second => 1,
TimestampResolution::Millisecond => 1_000,
TimestampResolution::Microsecond => 1_000_000,
TimestampResolution::Nanosecond => 1_000_000_000,
};
Self {
init: true,
reference_timestamp: 0,
period_s: period_s * ts_multiplier,
}
}
#[must_use]
pub fn aligned_timestamp(&self, timestamp: i64) -> i64 {
timestamp - (timestamp % self.period_s)
}
}
impl<C, T> AggregationRule<C, T> for AlignedTimeRule
where
C: ModularCandle<T>,
T: TakerTrade,
{
fn should_trigger(&mut self, trade: &T, _candle: &C) -> bool {
if self.init {
self.reference_timestamp = self.aligned_timestamp(trade.timestamp());
self.init = false;
}
let should_trigger = trade.timestamp() - self.reference_timestamp > self.period_s;
if should_trigger {
self.init = true;
}
should_trigger
}
}
#[cfg(test)]
mod tests {
use crate::{
aggregate_all_trades,
candle_components::{CandleComponent, CandleComponentUpdate, Close, High, Low, Open},
load_trades_from_csv, GenericAggregator, ModularCandle, Trade, M15,
};
use trade_aggregation_derive::Candle;
use super::*;
#[test]
fn aligned_time_rule() {
#[derive(Debug, Default, Clone, Candle)]
struct AlignedCandle {
pub open: Open,
high: High,
low: Low,
pub close: Close,
}
let trades = load_trades_from_csv("data/Bitmex_XBTUSD_1M.csv").unwrap();
let mut aggregator = GenericAggregator::<AlignedCandle, AlignedTimeRule, Trade>::new(
AlignedTimeRule::new(M15, TimestampResolution::Millisecond),
);
let candles = aggregate_all_trades(&trades, &mut aggregator);
assert_eq!(candles.len(), 396);
let c = &candles[0];
assert_eq!(c.open.value(), 13873.0);
assert_eq!(c.close.value(), 13769.0);
let c = &candles[1];
assert_eq!(c.open.value(), 13768.5);
assert_eq!(c.close.value(), 13721.5);
}
}