oxtapus 0.2.3

اُختاپوس برایِ پوششِ بخشی از داده‌هایِ موردِ نیاز در مدل-سازی‌هایِ مالی-اقتصادی توسعه داده شده است.
Documentation
use chrono::NaiveDate;
use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OptionMarketWatchRow {
    #[serde(alias = "insCode_P")]
    pub ins_code_p: String,
    #[serde(alias = "insCode_C")]
    pub ins_code_c: String,
    #[serde(alias = "contractSize")]
    pub contract_size: f64,
    #[serde(alias = "uaInsCode")]
    pub ins_code_ua: String,
    #[serde(alias = "lVal18AFC_P")]
    pub symbol_p: String,
    #[serde(alias = "lVal30_P")]
    pub name_p: String,
    #[serde(alias = "zTotTran_P")]
    pub trade_count_p: f64,
    #[serde(alias = "qTotTran5J_P")]
    pub traded_vol_p: f64,
    #[serde(alias = "qTotCap_P")]
    pub traded_val_p: f64,
    #[serde(alias = "notionalValue_P")]
    pub notional_value_p: f64,
    #[serde(alias = "pClosing_P")]
    pub final_p: f64,
    #[serde(alias = "priceYesterday_P")]
    pub y_final_p: f64,
    #[serde(alias = "oP_P")]
    pub open_interest_p: f64,
    #[serde(alias = "pDrCotVal_P")]
    pub close_p: f64,
    #[serde(alias = "lval30_UA")]
    pub symbol_ua: String,
    #[serde(alias = "pClosing_UA")]
    pub final_ua: f64,
    #[serde(alias = "priceYesterday_UA")]
    pub y_final_ua: f64,
    #[serde(alias = "beginDate")]
    pub begin_date: String,
    #[serde(alias = "endDate")]
    pub end_date: String,
    #[serde(alias = "strikePrice")]
    pub strike_price: f64,
    #[serde(alias = "remainedDay")]
    pub t: f64,
    #[serde(alias = "pDrCotVal_C")]
    pub close_c: f64,
    #[serde(alias = "oP_C")]
    pub open_interest_c: f64,
    #[serde(alias = "pClosing_C")]
    pub final_c: f64,
    #[serde(alias = "priceYesterday_C")]
    pub y_final_c: f64,
    #[serde(alias = "notionalValue_C")]
    pub notional_value_c: f64,
    #[serde(alias = "qTotCap_C")]
    pub traded_val_c: f64,
    #[serde(alias = "qTotTran5J_C")]
    pub traded_vol_c: f64,
    #[serde(alias = "zTotTran_C")]
    pub trade_count: f64,
    #[serde(alias = "lVal30_C")]
    pub name_c: String,
    #[serde(alias = "lVal18AFC_C")]
    pub symbol_c: String,
    #[serde(alias = "pMeDem_P")]
    pub bid_price_p: f64,
    #[serde(alias = "qTitMeDem_P")]
    pub bid_vol_p: f64,
    #[serde(alias = "pMeOf_P")]
    pub ask_price_p: f64,
    #[serde(alias = "qTitMeOf_P")]
    pub ask_vol_p: f64,
    #[serde(alias = "pMeDem_C")]
    pub bid_price_c: f64,
    #[serde(alias = "qTitMeDem_C")]
    pub bid_vol_c: f64,
    #[serde(alias = "pMeOf_C")]
    pub ask_price_c: f64,
    #[serde(alias = "qTitMeOf_C")]
    pub ask_vol_c: f64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OptionMarketWatch {
    #[serde(alias = "instrumentOptMarketWatch")]
    pub records: Vec<OptionMarketWatchRow>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
struct OrderBook {
    #[serde(alias = "n")]
    quote: f64,
    #[serde(alias = "zmd")]
    bid_count: f64,
    #[serde(alias = "qmd")]
    bid_vol: f64,
    #[serde(alias = "pmd")]
    bid_price: f64,
    #[serde(alias = "pmo")]
    ask_price: f64,
    #[serde(alias = "qmo")]
    ask_vol: f64,
    #[serde(alias = "zmo")]
    ask_count: f64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MarketWatchRow {
    #[serde(alias = "blDs")]
    order_book: Vec<OrderBook>,
    eps: f64,
    #[serde(alias = "hEven")]
    hour_event: f64,
    #[serde(alias = "insCode")]
    ins_code: String,
    #[serde(alias = "insID")]
    ins_id: String,
    #[serde(alias = "lva")]
    symbol: String,
    #[serde(alias = "lvc")]
    name: String,
    #[serde(alias = "pMax")]
    max_price: f64,
    #[serde(alias = "pMin")]
    min_price: f64,
    #[serde(alias = "pcl")]
    final_: f64,
    #[serde(alias = "pdv")]
    close: f64,
    pe: Option<String>,
    #[serde(alias = "pf")]
    open: f64,
    #[serde(alias = "pmn")]
    low: f64,
    #[serde(alias = "pmx")]
    high: f64,
    #[serde(alias = "py")]
    y_final: f64,
    #[serde(alias = "qtc")]
    traded_val: f64,
    #[serde(alias = "qtj")]
    traded_vol: f64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MarketWatch {
    #[serde(alias = "marketwatch")]
    records: Vec<MarketWatchRow>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct HistoryRecord {
    #[serde(alias = "dEven", deserialize_with = "deserialize_date")]
    date: NaiveDate,
    #[serde(alias = "insCode")]
    ins_code: String,
    #[serde(alias = "priceFirst")]
    open: f64,
    #[serde(alias = "priceMax")]
    high: f64,
    #[serde(alias = "priceMin")]
    low: f64,
    #[serde(alias = "pDrCotVal")]
    close: f64,
    #[serde(alias = "pClosing")]
    final_: f64,
    #[serde(alias = "priceYesterday")]
    y_final: f64,
    #[serde(alias = "qTotTran5J")]
    volume: f64,
    #[serde(alias = "qTotCap")]
    value: f64,
    #[serde(alias = "zTotTran")]
    trade_count: f64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct History {
    #[serde(alias = "closingPriceDaily")]
    pub records: Vec<HistoryRecord>,
}

fn deserialize_date<'de, D>(deserializer: D) -> Result<NaiveDate, D::Error>
where
    D: Deserializer<'de>,
{
    struct DateVisitor;

    impl<'de> Visitor<'de> for DateVisitor {
        type Value = NaiveDate;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("an integer or string representing a date in the format YYYYMMDD")
        }

        fn visit_u64<E>(self, value: u64) -> Result<NaiveDate, E>
        where
            E: de::Error,
        {
            let date_str = format!("{:08}", value);
            NaiveDate::parse_from_str(&date_str, "%Y%m%d")
                .map_err(|_| E::custom(format!("invalid date format: {}", date_str)))
        }
    }

    deserializer.deserialize_any(DateVisitor)
}