Construct run bars by counting consecutive price-direction runs. A bar closes when `threshold` consecutive moves occur in the same direction. Trailing partial bars that have not met the threshold are dropped.
(trades: &[Trade], threshold: usize)
| 123 | /// `threshold` consecutive moves occur in the same direction. Trailing partial bars |
| 124 | /// that have not met the threshold are dropped. |
| 125 | pub fn run_bars(trades: &[Trade], threshold: usize) -> Vec<StandardBar> { |
| 126 | assert!(threshold > 0, "threshold must be positive"); |
| 127 | if trades.len() < 2 { |
| 128 | return Vec::new(); |
| 129 | } |
| 130 | |
| 131 | let mut bars = Vec::new(); |
| 132 | let mut start_idx = 0usize; |
| 133 | let mut prev_price = trades[0].price; |
| 134 | let mut prev_sign = 0i8; |
| 135 | let mut run_len = 0usize; |
| 136 | |
| 137 | for (i, trade) in trades.iter().enumerate().skip(1) { |
| 138 | let sign = trade_sign(trade.price, prev_price, prev_sign); |
| 139 | if sign != 0 { |
| 140 | if sign == prev_sign { |
| 141 | run_len += 1; |
| 142 | } else { |
| 143 | run_len = 1; |
| 144 | prev_sign = sign; |
| 145 | } |
| 146 | } |
| 147 | prev_price = trade.price; |
| 148 | |
| 149 | if run_len >= threshold { |
| 150 | bars.push(build_bar(&trades[start_idx..=i])); |
| 151 | start_idx = i + 1; |
| 152 | run_len = 0; |
| 153 | prev_sign = 0; |
| 154 | if start_idx < trades.len() { |
| 155 | prev_price = trades[start_idx].price; |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | bars |
| 161 | } |
| 162 | |
| 163 | /// Construct imbalance bars by accumulating signed imbalance (tick, volume, or dollar) |
| 164 | /// until the absolute imbalance crosses `threshold`. Trailing partial bars that have |