Skip to content

Commit 1cd11d7

Browse files
committed
Generic Agg will take a candle factory rather than rely on Default
This adds more flexibility in the types we can aggregate in case we need runtime parameters as part of that logic.
1 parent 69ef410 commit 1cd11d7

File tree

11 files changed

+49
-16
lines changed

11 files changed

+49
-16
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ To use this crate in your project, add the following to your Cargo.toml:
5757

5858
```toml
5959
[dependencies]
60-
trade_aggregation = "12"
60+
trade_aggregation = "13"
6161
```
6262

6363
Lets aggregate all trades into time based 1 minute candles, consisting of open, high, low and close information.
@@ -87,7 +87,7 @@ fn main() {
8787
let time_rule = TimeRule::new(M1, TimestampResolution::Millisecond);
8888
// Notice how the aggregator is generic over the output candle type,
8989
// the aggregation rule as well as the input trade data
90-
let mut aggregator = GenericAggregator::<MyCandle, TimeRule, Trade>::new(time_rule, false);
90+
let mut aggregator = GenericAggregator::<MyCandle, TimeRule, Trade>::new(time_rule, false, MyCandle::default);
9191

9292
for t in &trades {
9393
if let Some(candle) = aggregator.update(t) {

benches/candle_aggregation.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,28 @@ struct CandleAll {
3737

3838
fn time_aggregation_open(trades: &[Trade]) {
3939
let time_rule = TimeRule::new(M1, TimestampResolution::Millisecond);
40-
let mut aggregator = GenericAggregator::<CandleOpen, TimeRule, Trade>::new(time_rule, false);
40+
let mut aggregator = GenericAggregator::<CandleOpen, TimeRule, Trade>::new(
41+
time_rule,
42+
false,
43+
CandleOpen::default,
44+
);
4145
let _candles = aggregate_all_trades(trades, &mut aggregator);
4246
}
4347

4448
fn time_aggregation_ohlc(trades: &[Trade]) {
4549
let time_rule = TimeRule::new(M1, TimestampResolution::Millisecond);
46-
let mut aggregator = GenericAggregator::<CandleOHLC, TimeRule, Trade>::new(time_rule, false);
50+
let mut aggregator = GenericAggregator::<CandleOHLC, TimeRule, Trade>::new(
51+
time_rule,
52+
false,
53+
CandleOHLC::default,
54+
);
4755
let _candles = aggregate_all_trades(trades, &mut aggregator);
4856
}
4957

5058
fn time_aggregation_all(trades: &[Trade]) {
5159
let time_rule = TimeRule::new(M1, TimestampResolution::Millisecond);
52-
let mut aggregator = GenericAggregator::<CandleAll, TimeRule, Trade>::new(time_rule, false);
60+
let mut aggregator =
61+
GenericAggregator::<CandleAll, TimeRule, Trade>::new(time_rule, false, CandleAll::default);
5362
let _candles = aggregate_all_trades(trades, &mut aggregator);
5463
}
5564

examples/aggregate_all_ohlc.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ fn main() {
2525

2626
// specify the aggregation rule to be time based
2727
let time_rule = TimeRule::new(M1, TimestampResolution::Millisecond);
28-
let mut aggregator = GenericAggregator::<MyCandle, TimeRule, Trade>::new(time_rule, false);
28+
let mut aggregator =
29+
GenericAggregator::<MyCandle, TimeRule, Trade>::new(time_rule, false, MyCandle::default);
2930

3031
let candles = aggregate_all_trades(&trades, &mut aggregator);
3132
println!("got {} candles", candles.len());

examples/streaming_aggregate_ohlc.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ fn main() {
2020

2121
// specify the aggregation rule to be time based
2222
let time_rule = TimeRule::new(M1, TimestampResolution::Millisecond);
23-
let mut aggregator = GenericAggregator::<MyCandle, TimeRule, Trade>::new(time_rule, false);
23+
let mut aggregator =
24+
GenericAggregator::<MyCandle, TimeRule, Trade>::new(time_rule, false, MyCandle::default);
2425

2526
for t in &trades {
2627
if let Some(candle) = aggregator.update(t) {

examples/user_trade_type.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ fn main() {
8888

8989
// specify the aggregation rule to be time based
9090
let time_rule = TimeRule::new(M1, TimestampResolution::Millisecond);
91-
let mut aggregator = GenericAggregator::<MyCandle, TimeRule, Tick>::new(time_rule, false);
91+
let mut aggregator =
92+
GenericAggregator::<MyCandle, TimeRule, Tick>::new(time_rule, false, MyCandle::default);
9293

9394
let candles = aggregate_all_trades(&ticks, &mut aggregator);
9495
println!("got {} candles", candles.len());

src/aggregation_rules/aligned_time_rule.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ mod tests {
105105
let mut aggregator = GenericAggregator::<MyCandle, AlignedTimeRule, Trade>::new(
106106
AlignedTimeRule::new(M15, TimestampResolution::Millisecond),
107107
false,
108+
MyCandle::default,
108109
);
109110
let candles = aggregate_all_trades(&trades, &mut aggregator);
110111
assert_eq!(candles.len(), 396);
@@ -126,6 +127,7 @@ mod tests {
126127
let mut aggregator = GenericAggregator::<MyCandle, AlignedTimeRule, Trade>::new(
127128
AlignedTimeRule::new(M1, TimestampResolution::Microsecond),
128129
false,
130+
MyCandle::default,
129131
);
130132
let candles = aggregate_all_trades(&trades, &mut aggregator);
131133

@@ -167,6 +169,7 @@ mod tests {
167169
let mut aggregator = GenericAggregator::<OhlcCandle, AlignedTimeRule, Trade>::new(
168170
AlignedTimeRule::new(M1, TimestampResolution::Millisecond),
169171
false,
172+
OhlcCandle::default,
170173
);
171174
let candles = aggregate_all_trades(&trades, &mut aggregator);
172175
assert_eq!(candles.len(), 2);
@@ -204,6 +207,7 @@ mod tests {
204207
let mut aggregator = GenericAggregator::<OhlcCandle, AlignedTimeRule, Trade>::new(
205208
AlignedTimeRule::new(M1, TimestampResolution::Millisecond),
206209
false,
210+
OhlcCandle::default,
207211
);
208212
let candles = aggregate_all_trades(&trades, &mut aggregator);
209213
assert_eq!(candles.len(), 2);

src/aggregation_rules/relative_price_rule.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ mod tests {
125125
// 0.5% candles
126126
const THRESHOLD: f64 = 0.005;
127127
let rule = RelativePriceRule::new(0.01).unwrap();
128-
let mut aggregator = GenericAggregator::<OhlcCandle, _, Trade>::new(rule, false);
128+
let mut aggregator =
129+
GenericAggregator::<OhlcCandle, _, Trade>::new(rule, false, OhlcCandle::default);
129130
let candles = aggregate_all_trades(&trades, &mut aggregator);
130131
assert!(!candles.is_empty());
131132

@@ -141,7 +142,8 @@ mod tests {
141142

142143
const THRESHOLD: f64 = 0.005;
143144
let rule = RelativePriceRule::new(THRESHOLD).unwrap();
144-
let mut aggregator = GenericAggregator::<OhlcCandle, _, Trade>::new(rule, false);
145+
let mut aggregator =
146+
GenericAggregator::<OhlcCandle, _, Trade>::new(rule, false, OhlcCandle::default);
145147
let candles = aggregate_all_trades(&trades, &mut aggregator);
146148
println!("got {} candles", candles.len());
147149

src/aggregation_rules/tick_rule.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@ mod tests {
5555
fn tick_rule() {
5656
let trades = load_trades_from_csv("data/Bitmex_XBTUSD_1M.csv").unwrap();
5757

58-
let mut aggregator =
59-
GenericAggregator::<OhlcCandle, TickRule, Trade>::new(TickRule::new(1000), false);
58+
let mut aggregator = GenericAggregator::<OhlcCandle, TickRule, Trade>::new(
59+
TickRule::new(1000),
60+
false,
61+
OhlcCandle::default,
62+
);
6063
let candles = aggregate_all_trades(&trades, &mut aggregator);
6164
// As there are 1 million trades in the test data, this will create 1000 candles
6265
assert_eq!(candles.len(), 1000);

src/aggregation_rules/time_rule.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ mod tests {
7878
let mut aggregator = GenericAggregator::<OhlcCandle, TimeRule, Trade>::new(
7979
TimeRule::new(M15, TimestampResolution::Millisecond),
8080
false,
81+
OhlcCandle::default,
8182
);
8283
let candles = aggregate_all_trades(&trades, &mut aggregator);
8384
println!("got {} candles", candles.len());
@@ -92,20 +93,23 @@ mod tests {
9293
let mut aggregator = GenericAggregator::<OhlcCandle, TimeRule, Trade>::new(
9394
TimeRule::new(M15, TimestampResolution::Millisecond),
9495
false,
96+
OhlcCandle::default,
9597
);
9698
let candles = aggregate_all_trades(&trades, &mut aggregator);
9799
assert_eq!(candles.len(), 396);
98100

99101
let mut aggregator = GenericAggregator::<OhlcCandle, TimeRule, Trade>::new(
100102
TimeRule::new(M5, TimestampResolution::Millisecond),
101103
false,
104+
OhlcCandle::default,
102105
);
103106
let candles = aggregate_all_trades(&trades, &mut aggregator);
104107
assert_eq!(candles.len(), 1190);
105108

106109
let mut aggregator = GenericAggregator::<OhlcCandle, TimeRule, Trade>::new(
107110
TimeRule::new(H1, TimestampResolution::Millisecond),
108111
false,
112+
OhlcCandle::default,
109113
);
110114
let candles = aggregate_all_trades(&trades, &mut aggregator);
111115
assert_eq!(candles.len(), 99);
@@ -138,20 +142,23 @@ mod tests {
138142
let mut aggregator = GenericAggregator::<OhlcCandle, TimeRule, Trade>::new(
139143
TimeRule::new(M15, TimestampResolution::Millisecond),
140144
false,
145+
OhlcCandle::default,
141146
);
142147
let candles = aggregate_all_trades(&trades_ms, &mut aggregator);
143148
assert_eq!(candles.len(), 396);
144149

145150
let mut aggregator = GenericAggregator::<OhlcCandle, TimeRule, Trade>::new(
146151
TimeRule::new(M15, TimestampResolution::Microsecond),
147152
false,
153+
OhlcCandle::default,
148154
);
149155
let candles = aggregate_all_trades(&trades_micros, &mut aggregator);
150156
assert_eq!(candles.len(), 396);
151157

152158
let mut aggregator = GenericAggregator::<OhlcCandle, TimeRule, Trade>::new(
153159
TimeRule::new(M15, TimestampResolution::Nanosecond),
154160
false,
161+
OhlcCandle::default,
155162
);
156163
let candles = aggregate_all_trades(&trades_ns, &mut aggregator);
157164
assert_eq!(candles.len(), 396);

src/aggregator.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,13 @@ where
5353
/// Examples uses include ensuring the close and open price of the current and next candle are equal.
5454
/// If that's desired, set the field to true during construction of `Self`.
5555
/// E.g on Tradingview the time aggregation would have this set to `false`, which may create gaps between close and open of subsequent candles.
56-
pub fn new(aggregation_rule: R, include_trade_that_triggered_rule: bool) -> Self {
56+
pub fn new<F: Fn() -> C>(
57+
aggregation_rule: R,
58+
include_trade_that_triggered_rule: bool,
59+
init_candle: F,
60+
) -> Self {
5761
Self {
58-
candle: Default::default(),
62+
candle: init_candle(),
5963
aggregation_rule,
6064
include_trade_that_triggered_rule,
6165
_trade_type: PhantomData,
@@ -120,7 +124,8 @@ mod tests {
120124
.expect("Could not load trades from file!");
121125

122126
let rule = TimeRule::new(M1, TimestampResolution::Millisecond);
123-
let mut a = GenericAggregator::<MyCandle, TimeRule, Trade>::new(rule, false);
127+
let mut a =
128+
GenericAggregator::<MyCandle, TimeRule, Trade>::new(rule, false, MyCandle::default);
124129

125130
let mut candle_counter: usize = 0;
126131
for t in trades.iter() {

0 commit comments

Comments
 (0)