1use super::{traits::State, BoxIndicator, Error, Indicator, Params};
4
5#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Hash, Serialize, Deserialize)]
7pub struct Operation {
8 pub indicator: Indicator,
9 pub parameters: Option<Params>,
10}
11
12impl Operation {
13 pub fn constant(op: Indicator) -> Result<Self, Error> {
15 Self::new(op, None)
16 }
17
18 pub fn new(op: Indicator, params: Option<Params>) -> Result<Self, Error> {
21 match op {
22 Indicator::MovingAverageConvergenceDivergence
23 | Indicator::MoneyFlowIndex
24 | Indicator::EfficiencyRatio
25 | Indicator::RateOfChange
26 | Indicator::AverageTrueRange
27 | Indicator::ExponentialMovingAverage
28 | Indicator::SimpleMovingAverage
29 | Indicator::RelativeStrengthIndex
30 | Indicator::FastStochastic
31 | Indicator::SlowStochastic
32 | Indicator::Spread
33 | Indicator::AskRate
34 | Indicator::BidRate
35 | Indicator::EntryRate
36 | Indicator::ExitRate
37 | Indicator::Maximum
38 | Indicator::Minimum => {
39 let params = params.ok_or_else(|| Error::ExpectedParams(op.clone()))?;
40 if params.len() != op.parameters() {
41 Err(Error::InvalidParams(op, params))
42 } else {
43 Ok(Operation {
44 indicator: op,
45 parameters: Some(params),
46 })
47 }
48 }
49 Indicator::TrueRange | Indicator::OnBalanceVolume | Indicator::ClosePrice => {
50 Ok(Operation {
51 indicator: op,
52 parameters: None,
53 })
54 }
55 }
56 }
57
58 pub fn construct<S: State>(&self) -> Result<BoxIndicator<S>, Error> {
60 self.indicator.construct(self.parameters.as_ref())
61 }
62}
63
64impl std::fmt::Debug for Operation {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 match &self.parameters {
67 Some(params) => {
68 if params.len() > 0 {
69 write!(
70 f,
71 "{:?}({})",
72 self.indicator,
73 params
74 .iter()
75 .map(|p| p.to_string())
76 .collect::<Vec<String>>()
77 .join(", ")
78 )
79 } else {
80 write!(f, "{:?}", self.indicator)
81 }
82 }
83 None => write!(f, "{:?}", self.indicator),
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn var_test() {
94 let params = vec![
95 (Indicator::TrueRange.into_op(), true),
96 (Indicator::AverageTrueRange.into_op(), false),
97 (Indicator::Maximum.with_params(vec![10]), true),
98 (Indicator::Maximum.with_params(vec![10, 40, 10]), false),
99 (
100 Indicator::MovingAverageConvergenceDivergence.with_params(vec![10, 40]),
101 false,
102 ),
103 (
104 Indicator::MovingAverageConvergenceDivergence.with_params(vec![10, 40, 10]),
105 true,
106 ),
107 ];
108
109 for (res, ok) in params {
110 assert_eq!(res.is_ok(), ok, "{:?}", res);
111 }
112 }
113}