Skip to main content

openpit/core/
execution_report.rs

1// Copyright The Pit Project Owners. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16// Please see https://github.com/openpitkit and the OWNERS file for details.
17
18use crate::core::request_trait::HasLock;
19use crate::impl_request_has_field;
20use crate::impl_request_has_field_passthrough;
21use crate::param::{AccountId, Fee, Pnl, PositionEffect, PositionSide, Quantity, Side, Trade};
22use crate::pretrade::PreTradeLock;
23
24use super::{
25    HasAccountId, HasAutoBorrow, HasClosePosition, HasExecutionReportIsTerminal,
26    HasExecutionReportLastTrade, HasExecutionReportPositionEffect, HasExecutionReportPositionSide,
27    HasFee, HasInstrument, HasLeavesQuantity, HasOrderCollateralAsset, HasOrderLeverage,
28    HasOrderPositionSide, HasOrderPrice, HasPnl, HasReduceOnly, HasSide, HasTradeAmount,
29    Instrument,
30};
31
32//--------------------------------------------------------------------------------------------------
33
34/// Data: main operation parameters reported by the execution.
35/// No `#[non_exhaustive]`: these are client-facing convenience structs meant to be constructed via
36/// struct literals from external crates.
37#[derive(Clone, Debug, PartialEq, Eq)]
38pub struct ExecutionReportOperation {
39    pub instrument: Instrument,
40    pub account_id: AccountId,
41    /// Economic direction of the reported execution event.
42    pub side: Side,
43}
44
45/// Adds main operation parameters reported by the execution.
46/// No `#[non_exhaustive]`: these are client-facing convenience structs meant to be constructed via
47/// struct literals from external crates.
48#[derive(Clone, Debug, PartialEq, Eq)]
49pub struct WithExecutionReportOperation<T> {
50    pub inner: T,
51    pub operation: ExecutionReportOperation,
52}
53
54impl_request_has_field!(
55    ExecutionReportOperation,
56    WithExecutionReportOperation,
57    operation,
58    HasInstrument, instrument, &Instrument, instrument;
59);
60impl_request_has_field_passthrough!(
61    WithExecutionReportOperation,
62    inner,
63    HasReduceOnly, reduce_only, bool;
64    HasClosePosition, close_position, bool;
65    HasAutoBorrow, auto_borrow, bool;
66    HasPnl, pnl, Pnl;
67    HasFee, fee, Fee;
68    HasLeavesQuantity, leaves_quantity, Quantity;
69    HasLock, lock, PreTradeLock;
70    HasOrderPrice, price, Option<crate::param::Price>;
71    HasOrderPositionSide, position_side, Option<PositionSide>;
72    HasOrderLeverage, leverage, Option<crate::param::Leverage>;
73    HasOrderCollateralAsset, collateral_asset, Option<&crate::param::Asset>;
74    HasExecutionReportLastTrade, last_trade, Option<Trade>;
75    HasExecutionReportIsTerminal, is_terminal, bool;
76    HasExecutionReportPositionEffect, position_effect, Option<PositionEffect>;
77    HasExecutionReportPositionSide, position_side, Option<PositionSide>;
78);
79impl_request_has_field!(
80    ExecutionReportOperation,
81    WithExecutionReportOperation,
82    operation,
83    HasAccountId, account_id, AccountId, account_id;
84    HasSide, side, Side, side;
85);
86impl_request_has_field_passthrough!(
87    WithFinancialImpact,
88    inner,
89    HasInstrument, instrument, &Instrument;
90);
91impl_request_has_field_passthrough!(
92    WithFinancialImpact,
93    inner,
94    HasAccountId, account_id, AccountId;
95    HasSide, side, Side;
96    HasTradeAmount, trade_amount, crate::param::TradeAmount;
97    HasReduceOnly, reduce_only, bool;
98    HasClosePosition, close_position, bool;
99    HasAutoBorrow, auto_borrow, bool;
100    HasLeavesQuantity, leaves_quantity, Quantity;
101    HasLock, lock, PreTradeLock;
102    HasOrderPrice, price, Option<crate::param::Price>;
103    HasOrderPositionSide, position_side, Option<PositionSide>;
104    HasOrderLeverage, leverage, Option<crate::param::Leverage>;
105    HasOrderCollateralAsset, collateral_asset, Option<&crate::param::Asset>;
106    HasExecutionReportLastTrade, last_trade, Option<Trade>;
107    HasExecutionReportIsTerminal, is_terminal, bool;
108    HasExecutionReportPositionEffect, position_effect, Option<PositionEffect>;
109    HasExecutionReportPositionSide, position_side, Option<PositionSide>;
110);
111
112//--------------------------------------------------------------------------------------------------
113
114/// Data: financial impact parameters reported by the execution.
115/// No `#[non_exhaustive]`: these are client-facing convenience structs meant to be constructed via
116/// struct literals from external crates.
117#[derive(Clone, Debug, PartialEq, Eq)]
118pub struct FinancialImpact {
119    /// Realized trading result contributed by this report.
120    ///
121    /// Positive values for gains, negative values for losses. Fees can be included in this value,
122    /// but if included, the included value must be excluded from `fee` value.
123    pub pnl: Pnl,
124    /// Fee or rebate associated with this report event.
125    ///
126    /// Negative values for fees, positive values for rebates.
127    pub fee: Fee,
128}
129
130/// Adds financial impact parameters reported by the execution.
131/// No `#[non_exhaustive]`: these are client-facing convenience structs meant to be constructed via
132/// struct literals from external crates.
133#[derive(Clone, Debug, PartialEq, Eq)]
134pub struct WithFinancialImpact<T> {
135    pub inner: T,
136    pub financial_impact: FinancialImpact,
137}
138
139impl_request_has_field!(
140    FinancialImpact,
141    WithFinancialImpact,
142    financial_impact,
143    HasPnl, pnl, Pnl, pnl;
144    HasFee, fee, Fee, fee;
145);
146impl_request_has_field_passthrough!(
147    WithExecutionReportFillDetails,
148    inner,
149    HasInstrument, instrument, &Instrument;
150);
151impl_request_has_field_passthrough!(
152    WithExecutionReportFillDetails,
153    inner,
154    HasAccountId, account_id, AccountId;
155    HasSide, side, Side;
156    HasTradeAmount, trade_amount, crate::param::TradeAmount;
157    HasReduceOnly, reduce_only, bool;
158    HasClosePosition, close_position, bool;
159    HasAutoBorrow, auto_borrow, bool;
160    HasPnl, pnl, Pnl;
161    HasFee, fee, Fee;
162    HasOrderPrice, price, Option<crate::param::Price>;
163    HasOrderPositionSide, position_side, Option<PositionSide>;
164    HasOrderLeverage, leverage, Option<crate::param::Leverage>;
165    HasOrderCollateralAsset, collateral_asset, Option<&crate::param::Asset>;
166    HasExecutionReportPositionEffect, position_effect, Option<PositionEffect>;
167    HasExecutionReportPositionSide, position_side, Option<PositionSide>;
168);
169
170//--------------------------------------------------------------------------------------------------
171
172/// Data: trade reported by the execution.
173/// No `#[non_exhaustive]`: these are client-facing convenience structs meant to be constructed via
174/// struct literals from external crates.
175#[derive(Clone, Debug, PartialEq, Eq)]
176pub struct ExecutionReportFillDetails {
177    pub last_trade: Option<Trade>,
178    /// Remaining order quantity after this fill.
179    pub leaves_quantity: Quantity,
180    /// Order lock payload.
181    pub lock: PreTradeLock,
182    /// Whether this report closes the report stream for the order.
183    pub is_terminal: bool,
184}
185
186/// Adds financial impact parameters reported by the execution.
187/// No `#[non_exhaustive]`: these are client-facing convenience structs meant to be constructed via
188/// struct literals from external crates.
189#[derive(Clone, Debug, PartialEq, Eq)]
190pub struct WithExecutionReportFillDetails<T> {
191    pub inner: T,
192    pub fill: ExecutionReportFillDetails,
193}
194
195impl_request_has_field!(
196    ExecutionReportFillDetails,
197    WithExecutionReportFillDetails,
198    fill,
199    HasExecutionReportLastTrade, last_trade, Option<Trade>, last_trade;
200    HasLeavesQuantity, leaves_quantity, Quantity, leaves_quantity;
201    HasLock, lock, PreTradeLock, lock;
202    HasExecutionReportIsTerminal, is_terminal, bool, is_terminal;
203);
204impl_request_has_field_passthrough!(
205    WithExecutionReportPositionImpact,
206    inner,
207    HasInstrument, instrument, &Instrument;
208);
209impl_request_has_field_passthrough!(
210    WithExecutionReportPositionImpact,
211    inner,
212    HasAccountId, account_id, AccountId;
213    HasSide, side, Side;
214    HasTradeAmount, trade_amount, crate::param::TradeAmount;
215    HasReduceOnly, reduce_only, bool;
216    HasClosePosition, close_position, bool;
217    HasAutoBorrow, auto_borrow, bool;
218    HasPnl, pnl, Pnl;
219    HasFee, fee, Fee;
220    HasLeavesQuantity, leaves_quantity, Quantity;
221    HasLock, lock, PreTradeLock;
222    HasOrderPrice, price, Option<crate::param::Price>;
223    HasOrderPositionSide, position_side, Option<PositionSide>;
224    HasOrderLeverage, leverage, Option<crate::param::Leverage>;
225    HasOrderCollateralAsset, collateral_asset, Option<&crate::param::Asset>;
226    HasExecutionReportLastTrade, last_trade, Option<Trade>;
227    HasExecutionReportIsTerminal, is_terminal, bool;
228);
229
230//--------------------------------------------------------------------------------------------------
231
232/// Data: position impact parameters reported by the execution.
233#[derive(Clone, Debug, Default, PartialEq, Eq)]
234/// No `#[non_exhaustive]`: these are client-facing convenience structs meant to be constructed via
235/// struct literals from external crates.
236pub struct ExecutionReportPositionImpact {
237    /// Whether this execution opened or closed exposure.
238    pub position_effect: Option<PositionEffect>,
239    /// Hedge-mode leg affected by this execution, when provided.
240    pub position_side: Option<PositionSide>,
241}
242
243/// Adds position impact parameters reported by the execution.
244/// No `#[non_exhaustive]`: these are client-facing convenience structs meant to be constructed via
245/// struct literals from external crates.
246#[derive(Clone, Debug, PartialEq, Eq)]
247pub struct WithExecutionReportPositionImpact<T> {
248    pub inner: T,
249    pub position_impact: ExecutionReportPositionImpact,
250}
251
252impl_request_has_field!(
253    ExecutionReportPositionImpact,
254    WithExecutionReportPositionImpact,
255    position_impact,
256    HasExecutionReportPositionEffect, position_effect, Option<PositionEffect>, position_effect;
257    HasExecutionReportPositionSide, position_side, Option<PositionSide>, position_side;
258);
259
260//--------------------------------------------------------------------------------------------------
261
262#[cfg(test)]
263mod tests {
264    use crate::param::{AccountId, Quantity};
265    use crate::pretrade::PreTradeLock;
266
267    use super::{
268        ExecutionReportFillDetails, ExecutionReportOperation, WithExecutionReportOperation,
269    };
270
271    fn fill() -> ExecutionReportFillDetails {
272        ExecutionReportFillDetails {
273            last_trade: None,
274            leaves_quantity: Quantity::from_str("0").expect("must be valid"),
275            lock: PreTradeLock::default(),
276            is_terminal: false,
277        }
278    }
279
280    #[test]
281    fn execution_report_operation_account_id_via_has_account_id() {
282        use crate::param::Asset;
283        use crate::param::Side;
284        use crate::{HasAccountId, Instrument};
285
286        let id = AccountId::from_u64(99);
287        let op = ExecutionReportOperation {
288            instrument: Instrument::new(
289                Asset::new("SPX").expect("must be valid"),
290                Asset::new("USD").expect("must be valid"),
291            ),
292            account_id: id,
293            side: Side::Sell,
294        };
295        assert_eq!(op.account_id(), Ok(id));
296
297        let wrapped = WithExecutionReportOperation {
298            inner: (),
299            operation: op,
300        };
301        assert_eq!(wrapped.account_id(), Ok(id));
302    }
303
304    #[test]
305    fn fill_defaults_are_stable() {
306        let f = fill();
307        assert_eq!(f.last_trade, None);
308        assert_eq!(
309            f.leaves_quantity,
310            Quantity::from_str("0").expect("must be valid")
311        );
312        assert_eq!(f.lock, PreTradeLock::default());
313        assert!(!f.is_terminal);
314    }
315}