use crate::messages::ResponseMessage;
use crate::Error;
use crate::contracts::{ContractDescription, ContractDetails, MarketRule, OptionChain, SmartComponent};
pub(crate) use crate::market_data::realtime::common::decoders::decode_tick_option_computation;
pub(in crate::contracts) fn decode_contract_details(message: &ResponseMessage) -> Result<ContractDetails, Error> {
decode_contract_data_proto(message.proto()?)
}
pub(in crate::contracts) fn decode_bond_contract_details(message: &ResponseMessage) -> Result<ContractDetails, Error> {
let mut details = decode_contract_data_proto(message.proto()?)?;
split_bond_last_trade_date(&mut details);
Ok(details)
}
fn split_bond_last_trade_date(details: &mut ContractDetails) {
let raw = &details.contract.last_trade_date_or_contract_month;
let parts: Vec<String> = if raw.contains('-') {
raw.split('-').map(str::to_string).collect()
} else {
raw.split_whitespace().map(str::to_string).collect()
};
if let Some(maturity) = parts.first() {
details.maturity = maturity.clone();
}
if let Some(time) = parts.get(1) {
details.last_trade_time = time.clone();
}
if let Some(zone) = parts.get(2) {
details.time_zone_id = zone.clone();
}
}
pub(in crate::contracts) fn decode_option_chain(message: &ResponseMessage) -> Result<OptionChain, Error> {
decode_option_chain_proto(message.proto()?)
}
use crate::contracts::PriceIncrement;
pub(crate) fn decode_contract_data_proto(p: crate::proto::ContractData) -> Result<ContractDetails, Error> {
let proto_contract = crate::proto::decoders::required(p.contract.as_ref(), "contract", "ContractData")?;
let proto_details = crate::proto::decoders::required(p.contract_details.as_ref(), "contract_details", "ContractData")?;
crate::proto::decoders::decode_contract_details(proto_contract, proto_details)
}
pub(crate) fn decode_symbol_samples_proto(p: crate::proto::SymbolSamples) -> Result<Vec<ContractDescription>, Error> {
p.contract_descriptions
.into_iter()
.map(|d| {
let contract = d
.contract
.as_ref()
.map(crate::proto::decoders::decode_contract)
.transpose()?
.unwrap_or_default();
Ok(ContractDescription {
contract,
derivative_security_types: d.derivative_sec_types,
})
})
.collect()
}
pub(crate) fn market_rule_for(market_rule_id: i32) -> impl Fn(&ResponseMessage) -> Result<Option<MarketRule>, Error> {
let decode = crate::common::request_helpers::expect_proto(decode_market_rule_proto);
move |message| {
let rule = decode(message)?;
Ok((rule.market_rule_id == market_rule_id).then_some(rule))
}
}
pub(crate) fn decode_market_rule_proto(p: crate::proto::MarketRule) -> Result<MarketRule, Error> {
Ok(MarketRule {
market_rule_id: p.market_rule_id.unwrap_or_default(),
price_increments: p
.price_increments
.into_iter()
.map(|pi| PriceIncrement {
low_edge: pi.low_edge.unwrap_or_default(),
increment: pi.increment.unwrap_or_default(),
})
.collect(),
})
}
pub(crate) fn decode_option_chain_proto(p: crate::proto::SecDefOptParameter) -> Result<OptionChain, Error> {
Ok(OptionChain {
exchange: p.exchange.unwrap_or_default(),
underlying_contract_id: p.underlying_con_id.unwrap_or_default(),
trading_class: p.trading_class.unwrap_or_default(),
multiplier: p.multiplier.unwrap_or_default(),
expirations: p.expirations,
strikes: p.strikes,
})
}
pub(crate) fn decode_smart_components_proto(p: crate::proto::SmartComponents) -> Result<Vec<SmartComponent>, Error> {
Ok(p.smart_components
.into_iter()
.map(|c| SmartComponent {
bit_number: c.bit_number.unwrap_or_default(),
exchange: c.exchange.unwrap_or_default(),
exchange_letter: c.exchange_letter.unwrap_or_default(),
})
.collect())
}
#[cfg(test)]
#[path = "decoders_tests.rs"]
mod tests;