Skip to main content

navi_vm/
run_handle.rs

1use std::{collections::VecDeque, sync::Arc};
2
3use futures_util::{StreamExt as _, stream::LocalBoxStream};
4
5use crate::{
6    Candlestick, CandlestickItem, Error, Event, TimeFrame,
7    data_provider::InternalProviderError,
8    instance::{ExecuteMode, Instance},
9};
10
11enum Phase {
12    SendScriptInfo,
13    Running,
14    FinalConfirm,
15    Done,
16}
17
18/// A handle to an active execution run returned by [`Instance::run`].
19///
20/// Call [`next_event`](Self::next_event) to iterate events one at a time.
21/// The handle implements [`Deref`](std::ops::Deref) and
22/// [`DerefMut`](std::ops::DerefMut) targeting [`Instance`], so all instance
23/// methods — including
24/// [`save_state`](crate::Instance::save_state)
25/// — are available directly through the handle while the run is in progress.
26///
27/// # Example
28///
29/// ```rust,ignore
30/// let mut handle = instance.run("NASDAQ:AAPL", TimeFrame::days(1));
31/// while let Some(result) = handle.next_event().await {
32///     let event = result?;
33///     if matches!(event, Event::BarEnd) && handle.current_bar_confirmed() {
34///         let snapshot = handle.save_state()?;
35///         persist_snapshot(snapshot);
36///     }
37/// }
38/// let instance = handle.into_instance();
39/// ```
40pub struct RunHandle {
41    instance: Instance,
42    stream: Option<LocalBoxStream<'static, Result<CandlestickItem, InternalProviderError>>>,
43    pending: VecDeque<Event>,
44    pending_realtime: Option<Candlestick>,
45    last_confirmed: bool,
46    /// `true` after a [`CandlestickItem::HistoryEnd`] has been received.
47    /// Determines whether subsequent [`CandlestickItem::Bar`] items are routed
48    /// as historical (confirmed) or realtime bars.
49    realtime_mode: bool,
50    phase: Phase,
51    /// An error encountered while creating the main stream in
52    /// [`RunHandle::new`].
53    ///
54    /// Returned as the first event from [`next_event`] so the caller gets a
55    /// clean `Err` rather than silently receiving no data.
56    initial_error: Option<Error>,
57}
58
59impl RunHandle {
60    pub(crate) fn new(
61        instance: Instance,
62        symbol: String,
63        from_time: i64,
64        timeframe: TimeFrame,
65    ) -> Self {
66        let (stream, initial_error) = match instance
67            .data_provider
68            .as_ref()
69            .map(|p| p.candlesticks(&symbol, timeframe, from_time, None))
70        {
71            None => (None, None),
72            Some(Ok(s)) => (Some(s), None),
73            Some(Err(e)) => (
74                None,
75                Some(Error::DataProvider {
76                    message: e.to_string(),
77                }),
78            ),
79        };
80        let phase = if stream.is_some() {
81            Phase::SendScriptInfo
82        } else {
83            Phase::Done
84        };
85        Self {
86            instance,
87            stream,
88            pending: VecDeque::new(),
89            pending_realtime: None,
90            last_confirmed: true,
91            realtime_mode: false,
92            phase,
93            initial_error,
94        }
95    }
96
97    /// Consumes the handle and returns the instance.
98    #[inline]
99    pub fn into_instance(self) -> Instance {
100        self.instance
101    }
102
103    fn drain_instance_events(&mut self) {
104        self.pending.extend(self.instance.events.drain(..));
105    }
106
107    fn should_split_realtime(&self, candlestick: &Candlestick) -> bool {
108        matches!(
109            self.instance.candlesticks.last(),
110            Some(last_candlestick)
111                if last_candlestick.time != candlestick.time && !self.instance.last_bar_confirmed
112        )
113    }
114
115    /// Returns the next event from the run, or `None` when execution is
116    /// complete.
117    pub async fn next_event(&mut self) -> Option<Result<Event, Error>> {
118        if let Some(e) = self.initial_error.take() {
119            return Some(Err(e));
120        }
121        loop {
122            if let Some(event) = self.pending.pop_front() {
123                return Some(Ok(event));
124            }
125            if let Some(candlestick) = self.pending_realtime.take() {
126                if !self.instance.mtf_wait.is_zero()
127                    && let Err(e) = self.instance.pre_drain_sub_streams().await
128                {
129                    return Some(Err(Error::DataProvider {
130                        message: e.to_string(),
131                    }));
132                }
133                self.last_confirmed = false;
134                if let Err(e) = self
135                    .instance
136                    .execute(ExecuteMode::Realtime(candlestick))
137                    .await
138                {
139                    return Some(Err(e));
140                }
141                self.drain_instance_events();
142                continue;
143            }
144            match self.phase {
145                Phase::Done => return None,
146
147                Phase::SendScriptInfo => {
148                    let event = Event::SessionInfo {
149                        script_info: Arc::clone(&self.instance.script_info),
150                        symbol_info: Box::new(self.instance.symbol_info.clone()),
151                    };
152                    let warnings = self.instance.warnings();
153                    self.phase = Phase::Running;
154                    if !warnings.is_empty() {
155                        self.pending.push_back(Event::Warning(warnings));
156                    }
157                    return Some(Ok(event));
158                }
159
160                Phase::Running => {
161                    // Poll the candlestick stream. The borrow of `self.stream` ends
162                    // once `raw` is assigned (an owned value), before we touch
163                    // `self.instance` below.
164                    let raw = match self.stream.as_mut() {
165                        Some(s) => s.next().await,
166                        None => None,
167                    };
168                    let Some(result) = raw else {
169                        if !self.last_confirmed {
170                            self.phase = Phase::FinalConfirm;
171                            continue;
172                        }
173                        self.phase = Phase::Done;
174                        return None;
175                    };
176                    let item = match result {
177                        Ok(item) => item,
178                        Err(e) => {
179                            return Some(Err(Error::DataProvider {
180                                message: e.to_string(),
181                            }));
182                        }
183                    };
184                    match item {
185                        CandlestickItem::HistoryEnd => {
186                            self.realtime_mode = true;
187                            self.pending.push_back(Event::HistoryEnd);
188                        }
189                        CandlestickItem::Bar(c) if !self.realtime_mode => {
190                            self.last_confirmed = true;
191                            if let Err(e) = self.instance.execute(ExecuteMode::Confirmed(c)).await {
192                                return Some(Err(e));
193                            }
194                        }
195                        CandlestickItem::Bar(c) => {
196                            if self.should_split_realtime(&c) {
197                                if let Err(e) = self.instance.execute(ExecuteMode::Confirm).await {
198                                    return Some(Err(e));
199                                }
200                                self.last_confirmed = true;
201                                self.pending_realtime = Some(c);
202                            } else {
203                                if !self.instance.mtf_wait.is_zero()
204                                    && let Err(e) = self.instance.pre_drain_sub_streams().await
205                                {
206                                    return Some(Err(Error::DataProvider {
207                                        message: e.to_string(),
208                                    }));
209                                }
210                                self.last_confirmed = false;
211                                if let Err(e) =
212                                    self.instance.execute(ExecuteMode::Realtime(c)).await
213                                {
214                                    return Some(Err(e));
215                                }
216                            }
217                        }
218                    }
219                    self.drain_instance_events();
220                }
221
222                Phase::FinalConfirm => {
223                    if let Err(e) = self.instance.execute(ExecuteMode::Confirm).await {
224                        return Some(Err(e));
225                    }
226                    self.drain_instance_events();
227                    self.phase = Phase::Done;
228                }
229            }
230        }
231    }
232}
233
234impl std::ops::Deref for RunHandle {
235    type Target = Instance;
236
237    fn deref(&self) -> &Instance {
238        &self.instance
239    }
240}
241
242impl std::ops::DerefMut for RunHandle {
243    fn deref_mut(&mut self) -> &mut Instance {
244        &mut self.instance
245    }
246}