templar_proxy_oracle_kernel/proxy/circuit_breaker/rule/
monotonic_run.rs1#[cfg(feature = "schemars")]
2use alloc::borrow::ToOwned;
3#[cfg(any(feature = "borsh", feature = "schemars"))]
4use alloc::string::ToString;
5use templar_primitives::Decimal;
6
7use crate::proxy::circuit_breaker::{
8 math::{classify_step_change, StepChange},
9 CircuitBreakerRule, Observation, RingBuffer,
10};
11
12serialize! {
13 #[derive(Debug, Clone, PartialEq, Eq)]
14 pub struct MonotonicRun {
16 pub max_streak: u32,
18 pub min_relative_step_change: Decimal,
20 }
21}
22
23impl CircuitBreakerRule for MonotonicRun {
24 fn should_trip(&self, history: &RingBuffer<Observation>) -> bool {
25 if self.max_streak == 0 || history.len() < 2 {
26 return false;
27 }
28
29 let mut direction = None;
30 let mut streak = 0_u32;
31
32 for current_index in (1..history.len()).rev() {
33 let (Some(previous), Some(current)) =
34 (history.get(current_index - 1), history.get(current_index))
35 else {
36 break;
37 };
38 let step_change = classify_step_change(
39 &previous.price,
40 ¤t.price,
41 self.min_relative_step_change,
42 );
43
44 if step_change == StepChange::Minor {
45 break;
46 }
47
48 if let Some(direction) = direction {
49 if direction != step_change {
50 break;
51 }
52 } else {
53 direction = Some(step_change);
54 }
55
56 streak = streak.saturating_add(1);
57 if streak >= self.max_streak {
58 return true;
59 }
60 }
61
62 false
63 }
64}