Skip to main content

qs_backtest/strategy/
feedback.rs

1//! Borrowed execution facts supplied to a historical strategy boundary.
2
3use qs_core::types::FutureEffect;
4
5use crate::ledger::ActionDisposition;
6
7/// One committed execution fact in replay commit order.
8#[derive(Debug, Clone)]
9pub enum StrategyFeedbackEvent {
10    Effect {
11        action_id: Option<String>,
12        effect: FutureEffect,
13    },
14    Disposition(ActionDisposition),
15}
16
17impl StrategyFeedbackEvent {
18    pub fn action_id(&self) -> Option<&str> {
19        match self {
20            Self::Effect { action_id, .. } => action_id.as_deref(),
21            Self::Disposition(disposition) => Some(&disposition.action_id),
22        }
23    }
24
25    pub const fn effect(&self) -> Option<&FutureEffect> {
26        match self {
27            Self::Effect { effect, .. } => Some(effect),
28            Self::Disposition(_) => None,
29        }
30    }
31
32    pub const fn disposition(&self) -> Option<&ActionDisposition> {
33        match self {
34            Self::Effect { .. } => None,
35            Self::Disposition(disposition) => Some(disposition),
36        }
37    }
38}
39
40/// Existing post-commit effects and newly terminal action dispositions.
41///
42/// The dynamic replay owner supplies only successfully committed effects and each newly terminal disposition in stable order.
43#[derive(Debug, Clone, Copy, Default)]
44pub struct StrategyFeedback<'a> {
45    effects: &'a [FutureEffect],
46    dispositions: &'a [ActionDisposition],
47    events: &'a [StrategyFeedbackEvent],
48}
49
50impl<'a> StrategyFeedback<'a> {
51    pub const fn new(effects: &'a [FutureEffect], dispositions: &'a [ActionDisposition]) -> Self {
52        Self {
53            effects,
54            dispositions,
55            events: &[],
56        }
57    }
58
59    pub(crate) const fn with_events(
60        effects: &'a [FutureEffect],
61        dispositions: &'a [ActionDisposition],
62        events: &'a [StrategyFeedbackEvent],
63    ) -> Self {
64        Self {
65            effects,
66            dispositions,
67            events,
68        }
69    }
70
71    pub const fn effects(self) -> &'a [FutureEffect] {
72        self.effects
73    }
74
75    pub const fn dispositions(self) -> &'a [ActionDisposition] {
76        self.dispositions
77    }
78
79    pub const fn events(self) -> &'a [StrategyFeedbackEvent] {
80        self.events
81    }
82
83    pub const fn is_empty(self) -> bool {
84        self.effects.is_empty() && self.dispositions.is_empty()
85    }
86}