From 7ea26232a0bc9ea481d1f4e4b2ff0286242b972d Mon Sep 17 00:00:00 2001 From: Wil Boayue Date: Mon, 28 Oct 2024 23:30:49 -0700 Subject: [PATCH] get news providers --- examples/news_providers.rs | 10 ++++ src/client.rs | 28 ++++++++-- src/domain.rs | 57 -------------------- src/errors.rs | 2 + src/lib.rs | 1 - src/messages/shared_channel_configuration.rs | 4 ++ src/news.rs | 27 +++++----- src/news/decoders.rs | 18 +++++++ src/news/encoders.rs | 12 +++++ src/orders.rs | 1 + 10 files changed, 85 insertions(+), 75 deletions(-) create mode 100644 examples/news_providers.rs delete mode 100644 src/domain.rs create mode 100644 src/news/decoders.rs create mode 100644 src/news/encoders.rs diff --git a/examples/news_providers.rs b/examples/news_providers.rs new file mode 100644 index 00000000..b723339c --- /dev/null +++ b/examples/news_providers.rs @@ -0,0 +1,10 @@ +use ibapi::Client; + +fn main() { + let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed"); + + let news_providers = client.news_providers().expect("request news providers failed"); + for news_provider in &news_providers { + println!("news provider {:?}", news_provider); + } +} diff --git a/src/client.rs b/src/client.rs index accc812c..2657b84e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -18,7 +18,10 @@ use crate::messages::{IncomingMessages, OutgoingMessages}; use crate::messages::{RequestMessage, ResponseMessage}; use crate::orders::{CancelOrder, Executions, ExerciseOptions, Order, Orders, PlaceOrder}; use crate::transport::{Connection, ConnectionMetadata, InternalSubscription, MessageBus, TcpMessageBus}; -use crate::{accounts, contracts, market_data, orders}; +use crate::{accounts, contracts, market_data, news, orders}; + +#[cfg(test)] +mod tests; // Client @@ -1195,6 +1198,26 @@ impl Client { realtime::market_data(self, contract, generic_ticks, snapshot, regulatory_snapshot) } + // === News === + + /// Requests news providers which the user has subscribed to. + /// + /// # Examples + /// + /// ```no_run + /// use ibapi::Client; + /// + /// let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed"); + /// + /// let news_providers = client.news_providers().expect("request news providers failed"); + /// for news_provider in &news_providers { + /// println!("news provider {:?}", news_provider); + /// } + /// ``` + pub fn news_providers(&self) -> Result, Error> { + news::news_providers(self) + } + // == Internal Use == #[cfg(test)] @@ -1525,6 +1548,3 @@ impl<'a, T: Subscribable> Iterator for SubscriptionTimeoutIter<'a, T> { /// Marker trait for shared channels pub trait SharesChannel {} - -#[cfg(test)] -mod tests; diff --git a/src/domain.rs b/src/domain.rs deleted file mode 100644 index 07969f49..00000000 --- a/src/domain.rs +++ /dev/null @@ -1,57 +0,0 @@ -pub struct DepthMktDataDescription { - pub exchange: String, - pub sec_type: String, - pub listing_exch: String, - pub service_data_type: String, - pub agg_group: i32, -} - -pub struct SmartComponent { - pub bit_number: i32, - pub exchange: String, - pub exchange_letter: String, -} - -pub struct FamilyCode { - pub account_id: String, - pub family_code_str: String, -} - -pub enum ComboParam { - NonGuaranteed, - PriceCondConid, - CondPriceMax, - CondPriceMin, - ChangeToMktTime1, - ChangeToMktTime2, - DiscretionaryPct, - DontLeginNext, - LeginPrio, - MaxSegSize, -} - -pub enum HedgeType { - None, - Delta, - Beta, - Fx, - Pair, -} - -pub enum Right { - None, - Put, - Call, -} - -pub enum VolatilityType { - None, - Daily, - Annual, -} - -pub enum ReferencePriceType { - None, - Midpoint, - BidOrAsk, -} diff --git a/src/errors.rs b/src/errors.rs index b3beac51..a9e92098 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -23,6 +23,7 @@ pub enum Error { Shutdown, StreamEnd, UnexpectedResponse(ResponseMessage), + UnexpectedEndOfStream, } impl std::error::Error for Error {} @@ -45,6 +46,7 @@ impl std::fmt::Display for Error { Error::Shutdown => write!(f, "Shutdown"), Error::StreamEnd => write!(f, "StreamEnd"), Error::UnexpectedResponse(message) => write!(f, "UnexpectedResponse: {:?}", message), + Error::UnexpectedEndOfStream => write!(f, "UnexpectedEndOfStream"), Error::Simple(ref err) => write!(f, "error occurred: {err}"), } diff --git a/src/lib.rs b/src/lib.rs index 01062674..fba94d4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,6 @@ pub(crate) mod transport; /// Every time a new request that requires a contract (i.e. market data, order placing, etc.) is sent to the API, the system will try to match the provided contract object with a single candidate. If there is more than one contract matching the same description, the API will return an error notifying you there is an ambiguity. In these cases the API needs further information to narrow down the list of contracts matching the provided description to a single element. pub mod contracts; // Describes primary data structures used by the model. -//pub(crate) mod domain; pub mod errors; /// APIs for retrieving market data pub mod market_data; diff --git a/src/messages/shared_channel_configuration.rs b/src/messages/shared_channel_configuration.rs index cfb05b2f..a10390ec 100644 --- a/src/messages/shared_channel_configuration.rs +++ b/src/messages/shared_channel_configuration.rs @@ -68,4 +68,8 @@ pub(crate) const CHANNEL_MAPPINGS: &[ChannelMapping] = &[ request: OutgoingMessages::RequestCurrentTime, responses: &[IncomingMessages::CurrentTime], }, + ChannelMapping { + request: OutgoingMessages::RequestNewsProviders, + responses: &[IncomingMessages::NewsProviders], + }, ]; diff --git a/src/news.rs b/src/news.rs index 96e17eca..9f18d365 100644 --- a/src/news.rs +++ b/src/news.rs @@ -1,4 +1,7 @@ -use crate::{Client, Error}; +use crate::{messages::OutgoingMessages, server_versions, Client, Error}; + +mod decoders; +mod encoders; #[derive(Clone, Debug)] pub struct NewsProvider { @@ -14,17 +17,15 @@ pub struct NewsProvider { /// Requests news providers which the user has subscribed to. pub fn news_providers(client: &Client) -> Result, Error> { - // request = RequestNewsProvidersRequest::new() - // packet = request.encode() - // client.send_packet(packet) - // packet = client.receive_packet(request_id) - // ReceiveNewsProvidersResponse::decode(packet) - print!("client: {client:?}"); - Err(Error::NotImplemented) -} + client.check_server_version(server_versions::REQ_NEWS_PROVIDERS, "It does not support news providers requests.")?; -// :reqNewsArticle below. + let request = encoders::encode_request_news_providers()?; + let subscription = client.send_shared_request(OutgoingMessages::RequestNewsProviders, request)?; -// reqHistoricalNews - -//reqNewsArticle s + match subscription.next() { + Some(Ok(message)) => decoders::decode_news_providers(message), + Some(Err(Error::ConnectionReset)) => news_providers(client), + Some(Err(e)) => Err(e), + None => Err(Error::UnexpectedEndOfStream), + } +} diff --git a/src/news/decoders.rs b/src/news/decoders.rs new file mode 100644 index 00000000..29337fc2 --- /dev/null +++ b/src/news/decoders.rs @@ -0,0 +1,18 @@ +use super::{Error, NewsProvider}; +use crate::messages::ResponseMessage; + +pub(super) fn decode_news_providers(mut message: ResponseMessage) -> Result, Error> { + message.skip(); // message type + + let num_providers = message.next_int()?; + let mut news_providers = Vec::with_capacity(num_providers as usize); + + for _ in 0..num_providers { + news_providers.push(NewsProvider { + code: message.next_string()?, + name: message.next_string()?, + }); + } + + Ok(news_providers) +} diff --git a/src/news/encoders.rs b/src/news/encoders.rs new file mode 100644 index 00000000..bf60c53d --- /dev/null +++ b/src/news/encoders.rs @@ -0,0 +1,12 @@ +use crate::{ + messages::{OutgoingMessages, RequestMessage}, + Error, +}; + +pub(super) fn encode_request_news_providers() -> Result { + let mut message = RequestMessage::new(); + + message.push_field(&OutgoingMessages::RequestNewsProviders); + + Ok(message) +} diff --git a/src/orders.rs b/src/orders.rs index 1d7ba370..37da461a 100644 --- a/src/orders.rs +++ b/src/orders.rs @@ -939,6 +939,7 @@ pub struct ExecutionData { } #[derive(Clone, Debug)] +#[allow(clippy::large_enum_variant)] pub enum PlaceOrder { OrderStatus(OrderStatus), OpenOrder(OrderData),