use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use super::{
ExchangeStrategyType, OptionExpirationType, OptionType, RegCodeType, SecurityStatusType,
SecurityType, Side, Symbol, option_timestamp_ms,
};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecurityDefinition {
#[serde(rename = "exchSym")]
pub exch_sym: Symbol,
#[serde(rename = "exchangeSource", default)]
pub exchange_source: Option<String>,
#[serde(rename = "activationTime", default, with = "option_timestamp_ms")]
pub activation_time: Option<OffsetDateTime>,
#[serde(rename = "expirationTime", default, with = "option_timestamp_ms")]
pub expiration_time: Option<OffsetDateTime>,
#[serde(rename = "marketComplex", default)]
pub market_complex: Option<String>,
#[serde(rename = "marketGroup", default)]
pub market_group: Option<String>,
#[serde(rename = "marketSymbol", default)]
pub market_symbol: Option<String>,
#[serde(rename = "cfiCode", default)]
pub cfi_code: Option<String>,
#[serde(rename = "allowOpenOrders", default)]
pub allow_open_orders: Option<bool>,
#[serde(rename = "maturityMonth", default)]
pub maturity_month: Option<i32>,
#[serde(rename = "maturityYear", default)]
pub maturity_year: Option<i32>,
#[serde(rename = "productDescription", default)]
pub product_description: Option<String>,
#[serde(rename = "userDefinded", default)]
pub user_defined: Option<bool>,
#[serde(rename = "intradayDefinded", default)]
pub intraday_defined: Option<bool>,
#[serde(rename = "optionType", default)]
pub option_type: Option<OptionType>,
#[serde(rename = "optionExpirationType", default)]
pub option_expiration_type: Option<OptionExpirationType>,
#[serde(rename = "strikePrice", default)]
pub strike_price: Option<f64>,
#[serde(rename = "underlyingSymbol", default)]
pub underlying_symbol: Option<Symbol>,
#[serde(rename = "variableTickTableCode", default)]
pub variable_tick_table_code: Option<i32>,
#[serde(rename = "exchangeStrategyType", default)]
pub exchange_strategy_type: Option<ExchangeStrategyType>,
#[serde(rename = "securityType", default)]
pub security_type: Option<SecurityType>,
#[serde(rename = "securityId", default)]
pub security_id: Option<String>,
#[serde(default)]
pub legs: Option<Vec<SecurityDefinitionLeg>>,
#[serde(rename = "depthLevels", default)]
pub depth_levels: Option<i32>,
#[serde(rename = "mainFraction", default)]
pub main_fraction: Option<f64>,
#[serde(rename = "subFraction", default)]
pub sub_fraction: Option<f64>,
#[serde(default)]
pub scale: Option<i32>,
#[serde(rename = "minPriceIncrement", default)]
pub min_price_increment: Option<f64>,
#[serde(rename = "minPriceIncrementValue", default)]
pub min_price_increment_value: Option<f64>,
#[serde(rename = "regCode", default)]
pub reg_code: Option<RegCodeType>,
#[serde(rename = "currencyCode", default)]
pub currency_code: Option<String>,
#[serde(rename = "displayFactor", default)]
pub display_factor: Option<f64>,
#[serde(rename = "allowTrading", default)]
pub allow_trading: Option<bool>,
#[serde(rename = "scalingFactorScreen", default)]
pub scaling_factor_screen: Option<f64>,
#[serde(rename = "exchangeSymbol", default)]
pub exchange_symbol: Option<Symbol>,
#[serde(rename = "creationDate", default, with = "option_timestamp_ms")]
pub creation_date: Option<OffsetDateTime>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecurityDefinitionLeg {
pub symbol: Symbol,
#[serde(default)]
pub ratio: Option<i32>,
#[serde(default)]
pub side: Option<Side>,
#[serde(rename = "securityId", default)]
pub security_id: Option<String>,
#[serde(default)]
pub exchange: Option<String>,
#[serde(rename = "legExchangeSymbol", default)]
pub leg_exchange_symbol: Option<Symbol>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecurityMarginAndValue {
#[serde(rename = "exchSym")]
pub exch_sym: Symbol,
#[serde(rename = "currentPrice", default)]
pub current_price: Option<f64>,
#[serde(rename = "currentTime", default, with = "option_timestamp_ms")]
pub current_time: Option<OffsetDateTime>,
#[serde(rename = "currentValue", default)]
pub current_value: Option<f64>,
#[serde(rename = "initialMarginLong", default)]
pub initial_margin_long: Option<f64>,
#[serde(rename = "initialMaginShort", default)]
pub initial_margin_short: Option<f64>,
#[serde(rename = "maintMarginLong", default)]
pub maint_margin_long: Option<f64>,
#[serde(rename = "maintMarginShort", default)]
pub maint_margin_short: Option<f64>,
#[serde(rename = "spanSettlePrice", default)]
pub span_settle_price: Option<f64>,
#[serde(rename = "spanSettleValue", default)]
pub span_settle_value: Option<f64>,
#[serde(rename = "marginScheduleDetails", default)]
pub margin_schedule_details: Option<Vec<MarginScheduleDetail>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MarginScheduleDetail {
#[serde(rename = "startTime", default, with = "option_timestamp_ms")]
pub start_time: Option<OffsetDateTime>,
#[serde(rename = "endTime", default, with = "option_timestamp_ms")]
pub end_time: Option<OffsetDateTime>,
#[serde(default)]
pub margin: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecurityStatus {
#[serde(rename = "exchSym")]
pub exch_sym: Symbol,
#[serde(default)]
pub status: Option<SecurityStatusType>,
#[serde(rename = "statusValue", default)]
pub status_value: Option<i32>,
#[serde(rename = "dateTime", default, with = "option_timestamp_ms")]
pub date_time: Option<OffsetDateTime>,
#[serde(rename = "tradeDate", default, with = "option_timestamp_ms")]
pub trade_date: Option<OffsetDateTime>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn security_definition_with_typos() {
let json = r#"{
"exchSym": "XCME:ES.U16",
"userDefinded": true,
"intradayDefinded": false,
"securityType": "FUT"
}"#;
let sd: SecurityDefinition = serde_json::from_str(json).unwrap();
assert_eq!(sd.exch_sym, "XCME:ES.U16");
assert_eq!(sd.user_defined, Some(true));
assert_eq!(sd.intraday_defined, Some(false));
assert_eq!(sd.security_type, Some(SecurityType::Fut));
}
#[test]
fn security_margin_typo_preserved() {
let json = r#"{
"exchSym": "XCME:ES.U16",
"initialMarginLong": 5000.0,
"initialMaginShort": 5000.0
}"#;
let sm: SecurityMarginAndValue = serde_json::from_str(json).unwrap();
assert_eq!(sm.initial_margin_long, Some(5000.0));
assert_eq!(sm.initial_margin_short, Some(5000.0));
}
#[test]
fn security_status_deserialize() {
let json = r#"{
"exchSym": "XCME:ES.U16",
"status": 17,
"statusValue": 17
}"#;
let ss: SecurityStatus = serde_json::from_str(json).unwrap();
assert_eq!(ss.status, Some(SecurityStatusType::Open));
}
}