greed 0.5.2

A rust tool to automate trades 📈
Documentation
use crate::tactic::r#for::ForResult;
use crate::tactic::state::TacticState;
use crate::tactic::when::{WhenResult, WhenRule};

pub struct WhenAllOfRule {
    rules: Vec<Box<dyn WhenRule>>,
}

impl WhenAllOfRule {
    pub fn boxed(rules: Vec<Box<dyn WhenRule>>) -> Box<dyn WhenRule> {
        Box::new(Self { rules })
    }
}

impl WhenRule for WhenAllOfRule {
    fn evaluate(&self, state: &TacticState, for_result: ForResult) -> WhenResult {
        let filtered_assets = for_result
            .target_assets
            .into_iter()
            .filter(|t| {
                self.rules.iter().all(|rule| {
                    let asset_result = ForResult {
                        target_assets: vec![t.clone()],
                    };
                    rule.evaluate(state, asset_result).conditions_satisfied
                })
            })
            .collect::<Vec<_>>();
        WhenResult {
            conditions_satisfied: !filtered_assets.is_empty(),
            target_assets: filtered_assets,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::asset::AssetSymbol;
    use crate::tactic::null::NullRule;
    use crate::tactic::r#for::ForResult;
    use crate::tactic::state::TacticState;
    use crate::tactic::target::TargetAsset;
    use crate::tactic::when::when_all_of::WhenAllOfRule;
    use crate::tactic::when::when_always::WhenAlwaysRule;
    use crate::tactic::when::WhenResult;

    #[test]
    fn evaluate_not_satisfied() {
        let state = TacticState::fixture();
        let rule = WhenAllOfRule::boxed(vec![WhenAlwaysRule::boxed(), NullRule::when_boxed()]);
        let target_assets = target_assets();
        let for_result = ForResult {
            target_assets: target_assets.clone(),
        };
        let result = rule.evaluate(&state, for_result);
        let expected = WhenResult {
            conditions_satisfied: false,
            target_assets: vec![],
        };
        assert_eq!(expected, result)
    }

    #[test]
    fn evaluate_satisfied() {
        let state = TacticState::fixture();
        let rule = WhenAllOfRule::boxed(vec![WhenAlwaysRule::boxed()]);
        let target_assets = target_assets();
        let for_result = ForResult {
            target_assets: target_assets.clone(),
        };
        let result = rule.evaluate(&state, for_result);
        let expected = WhenResult {
            conditions_satisfied: true,
            target_assets: target_assets.clone(),
        };
        assert_eq!(expected, result)
    }

    fn target_assets() -> Vec<TargetAsset> {
        vec![
            TargetAsset::full_percent(AssetSymbol::new("SPY")),
            TargetAsset::full_percent(AssetSymbol::new("VTI")),
        ]
    }
}