finance_query/backtesting/condition/
composite.rs1use crate::backtesting::strategy::StrategyContext;
6use crate::indicators::Indicator;
7
8use super::Condition;
9
10#[derive(Clone)]
12pub struct And<C1: Condition, C2: Condition> {
13 left: C1,
14 right: C2,
15}
16
17impl<C1: Condition, C2: Condition> And<C1, C2> {
18 pub fn new(left: C1, right: C2) -> Self {
20 Self { left, right }
21 }
22}
23
24impl<C1: Condition, C2: Condition> Condition for And<C1, C2> {
25 fn evaluate(&self, ctx: &StrategyContext) -> bool {
26 self.left.evaluate(ctx) && self.right.evaluate(ctx)
27 }
28
29 fn required_indicators(&self) -> Vec<(String, Indicator)> {
30 let mut indicators = self.left.required_indicators();
31 indicators.extend(self.right.required_indicators());
32 indicators.sort_by(|a, b| a.0.cmp(&b.0));
34 indicators.dedup_by(|a, b| a.0 == b.0);
35 indicators
36 }
37
38 fn description(&self) -> String {
39 format!(
40 "({} AND {})",
41 self.left.description(),
42 self.right.description()
43 )
44 }
45}
46
47#[derive(Clone)]
49pub struct Or<C1: Condition, C2: Condition> {
50 left: C1,
51 right: C2,
52}
53
54impl<C1: Condition, C2: Condition> Or<C1, C2> {
55 pub fn new(left: C1, right: C2) -> Self {
57 Self { left, right }
58 }
59}
60
61impl<C1: Condition, C2: Condition> Condition for Or<C1, C2> {
62 fn evaluate(&self, ctx: &StrategyContext) -> bool {
63 self.left.evaluate(ctx) || self.right.evaluate(ctx)
64 }
65
66 fn required_indicators(&self) -> Vec<(String, Indicator)> {
67 let mut indicators = self.left.required_indicators();
68 indicators.extend(self.right.required_indicators());
69 indicators.sort_by(|a, b| a.0.cmp(&b.0));
71 indicators.dedup_by(|a, b| a.0 == b.0);
72 indicators
73 }
74
75 fn description(&self) -> String {
76 format!(
77 "({} OR {})",
78 self.left.description(),
79 self.right.description()
80 )
81 }
82}
83
84#[derive(Clone)]
86pub struct Not<C: Condition> {
87 inner: C,
88}
89
90impl<C: Condition> Not<C> {
91 pub fn new(inner: C) -> Self {
93 Self { inner }
94 }
95}
96
97impl<C: Condition> Condition for Not<C> {
98 fn evaluate(&self, ctx: &StrategyContext) -> bool {
99 !self.inner.evaluate(ctx)
100 }
101
102 fn required_indicators(&self) -> Vec<(String, Indicator)> {
103 self.inner.required_indicators()
104 }
105
106 fn description(&self) -> String {
107 format!("NOT ({})", self.inner.description())
108 }
109}
110
111#[derive(Clone)]
132pub struct ConditionBuilder<C: Condition> {
133 conditions: Vec<C>,
134}
135
136impl<C: Condition> Default for ConditionBuilder<C> {
137 fn default() -> Self {
138 Self::new()
139 }
140}
141
142impl<C: Condition> ConditionBuilder<C> {
143 pub fn new() -> Self {
145 Self {
146 conditions: Vec::new(),
147 }
148 }
149
150 pub fn with_condition(mut self, condition: C) -> Self {
152 self.conditions.push(condition);
153 self
154 }
155}
156
157#[derive(Clone)]
159pub struct All<C: Condition> {
160 conditions: Vec<C>,
161}
162
163impl<C: Condition> Condition for All<C> {
164 fn evaluate(&self, ctx: &StrategyContext) -> bool {
165 self.conditions.iter().all(|c| c.evaluate(ctx))
166 }
167
168 fn required_indicators(&self) -> Vec<(String, Indicator)> {
169 let mut indicators = Vec::new();
170 for c in &self.conditions {
171 indicators.extend(c.required_indicators());
172 }
173 indicators.sort_by(|a, b| a.0.cmp(&b.0));
175 indicators.dedup_by(|a, b| a.0 == b.0);
176 indicators
177 }
178
179 fn description(&self) -> String {
180 let descs: Vec<_> = self.conditions.iter().map(|c| c.description()).collect();
181 format!("ALL({})", descs.join(" AND "))
182 }
183}
184
185#[derive(Clone)]
187pub struct Any<C: Condition> {
188 conditions: Vec<C>,
189}
190
191impl<C: Condition> Condition for Any<C> {
192 fn evaluate(&self, ctx: &StrategyContext) -> bool {
193 self.conditions.iter().any(|c| c.evaluate(ctx))
194 }
195
196 fn required_indicators(&self) -> Vec<(String, Indicator)> {
197 let mut indicators = Vec::new();
198 for c in &self.conditions {
199 indicators.extend(c.required_indicators());
200 }
201 indicators.sort_by(|a, b| a.0.cmp(&b.0));
203 indicators.dedup_by(|a, b| a.0 == b.0);
204 indicators
205 }
206
207 fn description(&self) -> String {
208 let descs: Vec<_> = self.conditions.iter().map(|c| c.description()).collect();
209 format!("ANY({})", descs.join(" OR "))
210 }
211}
212
213impl<C: Condition> ConditionBuilder<C> {
214 pub fn all(self) -> All<C> {
216 All {
217 conditions: self.conditions,
218 }
219 }
220
221 pub fn any(self) -> Any<C> {
223 Any {
224 conditions: self.conditions,
225 }
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232 use crate::backtesting::condition::{always_false, always_true};
233
234 #[test]
235 fn test_and_description() {
236 let cond = And::new(always_true(), always_false());
237 assert_eq!(cond.description(), "(always true AND always false)");
238 }
239
240 #[test]
241 fn test_or_description() {
242 let cond = Or::new(always_true(), always_false());
243 assert_eq!(cond.description(), "(always true OR always false)");
244 }
245
246 #[test]
247 fn test_not_description() {
248 let cond = Not::new(always_true());
249 assert_eq!(cond.description(), "NOT (always true)");
250 }
251
252 #[test]
253 fn test_all_description() {
254 let all = ConditionBuilder::new()
255 .with_condition(always_true())
256 .with_condition(always_false())
257 .all();
258 assert_eq!(all.description(), "ALL(always true AND always false)");
259 }
260
261 #[test]
262 fn test_any_description() {
263 let any = ConditionBuilder::new()
264 .with_condition(always_true())
265 .with_condition(always_false())
266 .any();
267 assert_eq!(any.description(), "ANY(always true OR always false)");
268 }
269}