use super::contract::{Contracts, OptionContract};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Options {
pub(crate) option_chain: OptionChainContainer,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct OptionChainContainer {
pub result: Vec<OptionChainResult>,
pub error: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct OptionChainResult {
pub underlying_symbol: Option<String>,
pub expiration_dates: Option<Vec<i64>>,
pub strikes: Option<Vec<f64>>,
pub has_mini_options: Option<bool>,
pub quote: Option<serde_json::Value>,
pub options: Vec<OptionChainData>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct OptionChainData {
pub expiration_date: i64,
pub has_mini_options: Option<bool>,
pub calls: Option<Vec<OptionContract>>,
pub puts: Option<Vec<OptionContract>>,
}
impl Options {
pub(crate) fn first_result(&self) -> Option<&OptionChainResult> {
self.option_chain.result.first()
}
pub fn expiration_dates(&self) -> Vec<i64> {
self.first_result()
.and_then(|r| r.expiration_dates.clone())
.unwrap_or_default()
}
pub fn strikes(&self) -> Vec<f64> {
self.first_result()
.and_then(|r| r.strikes.clone())
.unwrap_or_default()
}
pub fn calls(&self) -> Contracts {
let contracts = self
.first_result()
.map(|r| {
r.options
.iter()
.flat_map(|chain| chain.calls.as_deref().unwrap_or_default().iter())
.cloned()
.collect()
})
.unwrap_or_default();
Contracts(contracts)
}
pub fn puts(&self) -> Contracts {
let contracts = self
.first_result()
.map(|r| {
r.options
.iter()
.flat_map(|chain| chain.puts.as_deref().unwrap_or_default().iter())
.cloned()
.collect()
})
.unwrap_or_default();
Contracts(contracts)
}
}
#[cfg(feature = "dataframe")]
impl Options {
pub fn to_dataframe(&self) -> ::polars::prelude::PolarsResult<::polars::prelude::DataFrame> {
use ::polars::prelude::*;
let calls = self.calls();
let puts = self.puts();
let mut calls_df = calls.to_dataframe()?;
let mut puts_df = puts.to_dataframe()?;
let call_types = Series::new("option_type".into(), vec!["call"; calls.len()]);
let put_types = Series::new("option_type".into(), vec!["put"; puts.len()]);
calls_df.with_column(call_types.into())?;
puts_df.with_column(put_types.into())?;
calls_df.vstack(&puts_df)
}
}