1use crate::model::instrument::Instrument;
7use crate::model::ticker::TickerData;
8use crate::model::{BasicGreeks, BasicOptionData, OptionType, Spread};
9use chrono::{DateTime, TimeZone, Utc};
10use pretty_simple_display::{DebugPretty, DisplaySimple};
11use serde::{Deserialize, Serialize};
12use serde_json::Value;
13use serde_with::skip_serializing_none;
14
15#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
17pub struct DeliveryPriceData {
18 pub date: String,
20 pub delivery_price: f64,
22}
23
24#[skip_serializing_none]
26#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
27pub struct Greeks {
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub delta: Option<f64>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub gamma: Option<f64>,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 pub vega: Option<f64>,
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub theta: Option<f64>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub rho: Option<f64>,
43}
44
45#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
47pub struct OptionInstrument {
48 pub instrument: Instrument,
50 pub ticker: TickerData,
52}
53
54#[skip_serializing_none]
61#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
62pub struct OptionInstrumentPair {
63 pub call: Option<OptionInstrument>,
65 pub put: Option<OptionInstrument>,
67}
68
69impl OptionInstrumentPair {
70 pub fn expiration(&self) -> Option<DateTime<Utc>> {
77 let expiration_timestamp = match self.instrument() {
78 Some(i) => i.expiration_timestamp,
79 None => return None,
80 };
81
82 if let Some(expiration_timestamp) = expiration_timestamp {
83 Utc.timestamp_millis_opt(expiration_timestamp).single()
84 } else {
85 None
86 }
87 }
88 pub fn instrument(&self) -> Option<Instrument> {
95 self.call
96 .as_ref()
97 .map(|i| i.instrument.clone())
98 .or_else(|| self.put.as_ref().map(|i| i.instrument.clone()))
99 }
100 pub fn ticker(&self) -> Option<TickerData> {
107 self.call
108 .as_ref()
109 .map(|i| i.ticker.clone())
110 .or_else(|| self.put.as_ref().map(|i| i.ticker.clone()))
111 }
112 pub fn volume(&self) -> f64 {
118 let mut volume: f64 = 0.0;
119 if let Some(call) = &self.call {
120 volume += call.ticker.stats.volume
121 }
122 if let Some(put) = &self.put {
123 volume += put.ticker.stats.volume
124 }
125 volume
126 }
127 pub fn open_interest(&self) -> f64 {
133 let mut open_interest: f64 = 0.0;
134 if let Some(call) = &self.call {
135 open_interest += call.ticker.open_interest.unwrap_or(0.0)
136 }
137 if let Some(put) = &self.put {
138 open_interest += put.ticker.open_interest.unwrap_or(0.0)
139 }
140 open_interest
141 }
142
143 pub fn interest_rate(&self) -> f64 {
149 let mut interest_rate: f64 = 0.0;
150 if let Some(call) = &self.call {
151 interest_rate += call.ticker.interest_rate.unwrap_or(0.0)
152 }
153 if let Some(put) = &self.put {
154 interest_rate += put.ticker.interest_rate.unwrap_or(0.0)
155 }
156 interest_rate
157 }
158
159 pub fn value(&self) -> Option<Value> {
166 serde_json::to_value(self).ok()
167 }
168
169 pub fn call_spread(&self) -> Spread {
176 if let Some(call) = &self.call {
177 let bid = call.ticker.best_bid_price;
178 let ask = call.ticker.best_ask_price;
179 let mid = match (bid, ask) {
180 (Some(b), Some(a)) => Some((b + a) / 2.0),
181 (Some(b), None) => Some(b),
182 (None, Some(a)) => Some(a),
183 (None, None) => None,
184 };
185 Spread { bid, ask, mid }
186 } else {
187 Spread {
188 bid: None,
189 ask: None,
190 mid: None,
191 }
192 }
193 }
194
195 pub fn put_spread(&self) -> Spread {
202 if let Some(put) = &self.put {
203 let bid = put.ticker.best_bid_price;
204 let ask = put.ticker.best_ask_price;
205 let mid = match (bid, ask) {
206 (Some(b), Some(a)) => Some((b + a) / 2.0),
207 (Some(b), None) => Some(b),
208 (None, Some(a)) => Some(a),
209 (None, None) => None,
210 };
211 Spread { bid, ask, mid }
212 } else {
213 Spread {
214 bid: None,
215 ask: None,
216 mid: None,
217 }
218 }
219 }
220
221 pub fn iv(&self) -> (Option<f64>, Option<f64>) {
228 let call_iv = self.call.as_ref().and_then(|c| c.ticker.mark_iv);
229 let put_iv = self.put.as_ref().and_then(|p| p.ticker.mark_iv);
230 (call_iv, put_iv)
231 }
232
233 pub fn greeks(&self) -> BasicGreeks {
240 let delta_call = self
241 .call
242 .as_ref()
243 .and_then(|c| c.ticker.greeks.as_ref().and_then(|g| g.delta));
244 let delta_put = self
245 .put
246 .as_ref()
247 .and_then(|p| p.ticker.greeks.as_ref().and_then(|g| g.delta));
248 let gamma = self
249 .call
250 .as_ref()
251 .and_then(|c| c.ticker.greeks.as_ref().and_then(|g| g.gamma))
252 .or_else(|| {
253 self.put
254 .as_ref()
255 .and_then(|p| p.ticker.greeks.as_ref().and_then(|g| g.gamma))
256 });
257 BasicGreeks {
258 delta_call,
259 delta_put,
260 gamma,
261 }
262 }
263
264 pub fn data(&self) -> BasicOptionData {
272 let strike_price: f64 = match self.instrument() {
273 Some(i) => i.strike.unwrap_or(0.0),
274 None => 0.0,
275 };
276 let call_spread = self.call_spread();
277 let call_bid: Option<f64> = call_spread.bid;
278 let call_ask: Option<f64> = call_spread.ask;
279 let put_spread = self.put_spread();
280 let put_bid: Option<f64> = put_spread.bid;
281 let put_ask: Option<f64> = put_spread.ask;
282 let implied_volatility = self.iv();
283 let greeks = self.greeks();
284 let delta_call: Option<f64> = greeks.delta_call;
285 let delta_put: Option<f64> = greeks.delta_put;
286 let gamma: Option<f64> = greeks.gamma;
287 let volume = self.volume();
288 let open_interest: f64 = self.open_interest();
289 let expiration_date: Option<DateTime<Utc>> = self.expiration();
290 let underlying_price: Option<f64> = self.ticker().and_then(|t| t.underlying_price);
291 let risk_free_rate: f64 = self.interest_rate();
292 let extra_fields: Option<Value> = self.value();
293 BasicOptionData {
294 strike_price,
295 call_bid,
296 call_ask,
297 put_bid,
298 put_ask,
299 implied_volatility,
300 delta_call,
301 delta_put,
302 gamma,
303 volume,
304 open_interest,
305 expiration_date,
306 underlying_price,
307 risk_free_rate,
308 extra_fields,
309 }
310 }
311}
312
313#[skip_serializing_none]
315#[derive(DebugPretty, DisplaySimple, Clone, Serialize)]
316pub struct ParsedOptionWithTicker {
317 pub instrument_name: String,
319 pub strike: f64,
321 pub option_type: OptionType,
323 pub expiry: String,
325 pub ticker: TickerData,
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize, Default)]
331#[serde(rename_all = "lowercase")]
332pub enum SortDirection {
333 #[default]
335 Asc,
336 Desc,
338 Default,
340}
341
342impl std::fmt::Display for SortDirection {
343 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
344 match self {
345 SortDirection::Asc => write!(f, "asc"),
346 SortDirection::Desc => write!(f, "desc"),
347 SortDirection::Default => write!(f, "default"),
348 }
349 }
350}