nautilus_model/python/data/
bet.rs1use std::{
17 collections::hash_map::DefaultHasher,
18 hash::{Hash, Hasher},
19};
20
21use pyo3::{basic::CompareOp, prelude::*};
22use rust_decimal::Decimal;
23
24use crate::{
25 data::bet::{calc_bets_pnl, inverse_probability_to_bet, probability_to_bet, Bet, BetPosition},
26 enums::{BetSide, OrderSide},
27};
28
29#[pymethods]
30impl Bet {
31 #[new]
32 fn py_new(price: Decimal, stake: Decimal, side: BetSide) -> PyResult<Self> {
33 Ok(Bet::new(price, stake, side))
34 }
35
36 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
37 match op {
38 CompareOp::Eq => self.eq(other).into_py(py),
39 CompareOp::Ne => self.ne(other).into_py(py),
40 _ => py.NotImplemented(),
41 }
42 }
43
44 fn __hash__(&self) -> isize {
45 let mut h = DefaultHasher::new();
46 self.hash(&mut h);
47 h.finish() as isize
48 }
49
50 fn __repr__(&self) -> String {
51 format!("{self:?}")
52 }
53
54 fn __str__(&self) -> String {
55 self.to_string()
56 }
57
58 #[staticmethod]
60 #[pyo3(name = "from_stake_or_liability")]
61 fn py_from_stake_or_liability(
62 price: Decimal,
63 volume: Decimal,
64 side: BetSide,
65 ) -> PyResult<Self> {
66 Ok(Bet::from_stake_or_liability(price, volume, side))
67 }
68
69 #[staticmethod]
71 #[pyo3(name = "from_stake")]
72 fn py_from_stake(price: Decimal, stake: Decimal, side: BetSide) -> PyResult<Self> {
73 Ok(Bet::from_stake(price, stake, side))
74 }
75
76 #[staticmethod]
80 #[pyo3(name = "from_liability")]
81 fn py_from_liability(price: Decimal, liability: Decimal, side: BetSide) -> PyResult<Self> {
82 Ok(Bet::from_liability(price, liability, side))
83 }
84
85 #[getter]
87 #[pyo3(name = "price")]
88 fn py_price(&self) -> Decimal {
89 self.price()
90 }
91
92 #[getter]
94 #[pyo3(name = "stake")]
95 fn py_stake(&self) -> Decimal {
96 self.stake()
97 }
98
99 #[getter]
101 #[pyo3(name = "side")]
102 fn py_side(&self) -> BetSide {
103 self.side()
104 }
105
106 #[pyo3(name = "exposure")]
108 fn py_exposure(&self) -> Decimal {
109 self.exposure()
110 }
111
112 #[pyo3(name = "liability")]
114 fn py_liability(&self) -> Decimal {
115 self.liability()
116 }
117
118 #[pyo3(name = "profit")]
120 fn py_profit(&self) -> Decimal {
121 self.profit()
122 }
123
124 #[pyo3(name = "outcome_win_payoff")]
126 fn py_outcome_win_payoff(&self) -> Decimal {
127 self.outcome_win_payoff()
128 }
129
130 #[pyo3(name = "outcome_lose_payoff")]
132 fn py_outcome_lose_payoff(&self) -> Decimal {
133 self.outcome_lose_payoff()
134 }
135
136 #[pyo3(name = "hedging_stake")]
138 fn py_hedging_stake(&self, price: Decimal) -> Decimal {
139 self.hedging_stake(price)
140 }
141
142 #[pyo3(name = "hedging_bet")]
144 fn py_hedging_bet(&self, price: Decimal) -> Self {
145 self.hedging_bet(price)
146 }
147}
148
149#[pymethods]
150impl BetPosition {
151 #[new]
152 fn py_new() -> Self {
153 Self::default()
154 }
155
156 fn __repr__(&self) -> String {
157 format!("{self:?}")
158 }
159
160 fn __str__(&self) -> String {
161 self.to_string()
162 }
163
164 #[getter]
166 #[pyo3(name = "price")]
167 fn py_price(&self) -> Decimal {
168 self.price()
169 }
170
171 #[getter]
173 #[pyo3(name = "side")]
174 fn py_side(&self) -> Option<BetSide> {
175 self.side()
176 }
177
178 #[getter]
180 #[pyo3(name = "exposure")]
181 fn py_exposure(&self) -> Decimal {
182 self.exposure()
183 }
184
185 #[getter]
187 #[pyo3(name = "realized_pnl")]
188 fn py_realized_pnl(&self) -> Decimal {
189 self.realized_pnl()
190 }
191
192 #[pyo3(name = "add_bet")]
194 fn py_add_bet(&mut self, bet: &Bet) {
195 self.add_bet(bet.clone());
196 }
197
198 #[pyo3(name = "as_bet")]
200 fn py_as_bet(&self) -> Option<Bet> {
201 self.as_bet()
202 }
203
204 #[pyo3(name = "unrealized_pnl")]
206 fn py_unrealized_pnl(&self, price: Decimal) -> Decimal {
207 self.unrealized_pnl(price)
208 }
209
210 #[pyo3(name = "total_pnl")]
212 fn py_total_pnl(&self, price: Decimal) -> Decimal {
213 self.total_pnl(price)
214 }
215
216 #[pyo3(name = "flattening_bet")]
218 fn py_flattening_bet(&self, price: Decimal) -> Option<Bet> {
219 self.flattening_bet(price)
220 }
221
222 #[pyo3(name = "reset")]
224 fn py_reset(&mut self) {
225 self.reset();
226 }
227}
228
229#[pyfunction]
230#[pyo3(name = "calc_bets_pnl")]
231pub fn py_calc_bets_pnl(bets: Vec<Bet>) -> PyResult<Decimal> {
232 Ok(calc_bets_pnl(&bets))
233}
234
235#[pyfunction]
236#[pyo3(name = "probability_to_bet")]
237pub fn py_probability_to_bet(
238 probability: Decimal,
239 volume: Decimal,
240 side: OrderSide,
241) -> PyResult<Bet> {
242 Ok(probability_to_bet(probability, volume, side.as_specified()))
243}
244
245#[pyfunction]
246#[pyo3(name = "inverse_probability_to_bet")]
247pub fn py_inverse_probability_to_bet(
248 probability: Decimal,
249 volume: Decimal,
250 side: OrderSide,
251) -> PyResult<Bet> {
252 Ok(inverse_probability_to_bet(
253 probability,
254 volume,
255 side.as_specified(),
256 ))
257}