nautilus_backtest/data_iterator.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Static backtest replay using the shared ordered batch iterator.
17
18use nautilus_data::replay::DataIterator;
19use nautilus_model::data::{Data, DataBatch, DataRef};
20
21/// Multi-stream, time-ordered data iterator used by the backtest engine.
22#[derive(Debug, Default)]
23pub struct BacktestDataIterator {
24 iterator: DataIterator,
25}
26
27impl BacktestDataIterator {
28 /// Creates a new empty [`BacktestDataIterator`].
29 #[must_use]
30 pub fn new() -> Self {
31 Self {
32 iterator: DataIterator::new(),
33 }
34 }
35
36 /// Adds (or replaces) a named data stream.
37 ///
38 /// When `append_data` is true the stream gets lower priority on equal replay keys;
39 /// when false (prepend) it wins ties. Named replacements retain their original priority.
40 pub fn add_data(&mut self, name: &str, data: Vec<Data>, append_data: bool) {
41 self.iterator.add_data(name, data, append_data);
42 }
43
44 /// Adds (or replaces) a named typed data stream.
45 ///
46 /// Items are ordered by replay key before insertion. A batch that arrives out of order while
47 /// sharing its backing allocation with another view is copied once, so the shared allocation
48 /// is never reordered.
49 pub fn add_data_batch(&mut self, name: &str, data: DataBatch, append_data: bool) {
50 self.iterator.add_data_batch(name, data, append_data);
51 }
52
53 /// Removes a named data stream.
54 pub fn remove_data(&mut self, name: &str, complete_remove: bool) {
55 self.iterator.remove_data(name, complete_remove);
56 }
57
58 /// Sets the cursor of a named stream to `index` (0-based).
59 pub fn set_index(&mut self, name: &str, index: usize) {
60 self.iterator.set_index(name, index);
61 }
62
63 /// Resets all stream cursors to the beginning.
64 pub fn reset_all_cursors(&mut self) {
65 self.iterator.reset_all_cursors();
66 }
67
68 pub(crate) fn peek(&self) -> Option<DataRef<'_>> {
69 self.iterator.peek()
70 }
71
72 pub(crate) fn advance(&mut self) {
73 self.iterator.advance();
74 }
75
76 /// Returns the next market [`Data`] element across all streams in chronological order.
77 #[expect(clippy::should_implement_trait)]
78 pub fn next(&mut self) -> Option<Data> {
79 self.iterator.next()
80 }
81
82 /// Returns whether all streams have been fully consumed.
83 #[must_use]
84 pub fn is_done(&self) -> bool {
85 self.iterator.is_done()
86 }
87}