openpit/param/fee.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 super::{define_signed_value_type, CashFlow, ParamKind, Pnl, PositionSize};
19
20define_signed_value_type!(
21 /// Fee amount.
22 ///
23 /// Can be negative when representing rebates or fee adjustments in reconciliation.
24 Fee,
25 ParamKind::Fee
26);
27
28impl Fee {
29 /// Converts fee into a negative P&L contribution.
30 pub fn to_pnl(self) -> Pnl {
31 Pnl::new(-self.to_decimal())
32 }
33
34 /// Converts fee into a position size for instruments where fees are paid in the base asset.
35 ///
36 /// The resulting position size is negative (representing an outflow) for positive fees,
37 /// and positive for fee rebates.
38 pub fn to_position_size(self) -> PositionSize {
39 PositionSize::new(-self.to_decimal())
40 }
41
42 /// Converts fee into a cash flow contribution (negates the fee amount).
43 pub fn to_cash_flow(self) -> CashFlow {
44 CashFlow::from_fee(self)
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::Fee;
51 use crate::param::{CashFlow, Pnl, PositionSize};
52 use rust_decimal::Decimal;
53
54 fn d(value: &str) -> Decimal {
55 value
56 .parse()
57 .expect("decimal literal in tests must be valid")
58 }
59
60 #[test]
61 fn converts_to_negative_pnl() {
62 let fee = Fee::new(d("3.18"));
63
64 assert_eq!(fee.to_pnl(), Pnl::new(d("-3.18")));
65 }
66
67 #[test]
68 fn converts_to_position_size() {
69 let fee = Fee::new(d("2.5"));
70 let rebate = Fee::new(d("-2.5"));
71
72 assert_eq!(fee.to_position_size(), PositionSize::new(d("-2.5")));
73 assert_eq!(rebate.to_position_size(), PositionSize::new(d("2.5")));
74 }
75
76 #[test]
77 fn converts_to_cash_flow() {
78 let fee = Fee::new(d("3.18"));
79
80 assert_eq!(fee.to_cash_flow(), CashFlow::new(d("-3.18")));
81 }
82}