Skip to main content

nautilus_execution/reconciliation/
types.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//! Shared reconciliation value types.
17
18use indexmap::IndexMap;
19use nautilus_model::{
20    enums::OrderSide,
21    identifiers::VenueOrderId,
22    reports::{FillReport, OrderStatusReport},
23};
24use rust_decimal::Decimal;
25
26/// Immutable snapshot of fill data for position simulation.
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct FillSnapshot {
29    /// The event timestamp (nanoseconds).
30    pub ts_event: u64,
31    /// The order side (BUY or SELL).
32    pub side: OrderSide,
33    /// The fill quantity.
34    pub qty: Decimal,
35    /// The fill price.
36    pub px: Decimal,
37    /// The venue order ID.
38    pub venue_order_id: VenueOrderId,
39}
40
41/// Represents a position snapshot from the venue.
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct VenuePositionSnapshot {
44    /// The position side (LONG, SHORT, or FLAT).
45    pub side: OrderSide, // Using OrderSide to represent position side for simplicity
46    /// The position quantity (always positive, even for SHORT).
47    pub qty: Decimal,
48    /// The average entry price (can be zero for FLAT positions).
49    pub avg_px: Decimal,
50}
51
52/// Result of the fill adjustment process.
53#[derive(Debug, Clone, PartialEq)]
54pub enum FillAdjustmentResult {
55    /// No adjustment needed - return fills unchanged.
56    NoAdjustment,
57    /// Add synthetic opening fill to oldest lifecycle.
58    AddSyntheticOpening {
59        /// The synthetic fill to add at the beginning.
60        synthetic_fill: FillSnapshot,
61        /// All existing fills to keep.
62        existing_fills: Vec<FillSnapshot>,
63    },
64    /// Replace entire current lifecycle with single synthetic fill.
65    ReplaceCurrentLifecycle {
66        /// The single synthetic fill representing the entire position.
67        synthetic_fill: FillSnapshot,
68        /// The first venue order ID to use.
69        first_venue_order_id: VenueOrderId,
70    },
71    /// Filter fills to current lifecycle only (after last zero-crossing).
72    FilterToCurrentLifecycle {
73        /// Timestamp of the last zero-crossing.
74        last_zero_crossing_ts: u64,
75        /// Fills from current lifecycle.
76        current_lifecycle_fills: Vec<FillSnapshot>,
77    },
78}
79
80impl FillSnapshot {
81    /// Create a new fill snapshot.
82    #[must_use]
83    pub fn new(
84        ts_event: u64,
85        side: OrderSide,
86        qty: Decimal,
87        px: Decimal,
88        venue_order_id: VenueOrderId,
89    ) -> Self {
90        Self {
91            ts_event,
92            side,
93            qty,
94            px,
95            venue_order_id,
96        }
97    }
98
99    /// Return signed direction multiplier: +1 for BUY, -1 for SELL.
100    #[must_use]
101    pub fn direction(&self) -> i8 {
102        match self.side {
103            OrderSide::Buy => 1,
104            OrderSide::Sell => -1,
105            _ => 0,
106        }
107    }
108}
109
110/// Result of processing fill reports for reconciliation.
111#[derive(Debug, Clone)]
112pub struct ReconciliationResult {
113    /// Order status reports keyed by venue order ID.
114    pub orders: IndexMap<VenueOrderId, OrderStatusReport>,
115    /// Fill reports keyed by venue order ID.
116    pub fills: IndexMap<VenueOrderId, Vec<FillReport>>,
117}