ibapi 5.4.0

An unofficial Rust client for the Interactive Brokers TWS API: market data, orders, and account data, with async (Tokio) and blocking clients for TWS and IB Gateway.
Documentation
//! Asynchronous implementation of scanner functionality

use super::common::{decoders, encoders};
use super::*;
use crate::client::ClientRequestBuilders;
use crate::common::request_helpers::{self, expect_proto};
use crate::contracts::TagValue;
use crate::messages::OutgoingMessages;
use crate::subscriptions::Subscription;
use crate::{Client, Error};

impl Client {
    /// Requests an XML list of scanner parameters valid in TWS.
    ///
    /// # Errors
    /// [`Error::Timeout`] if TWS sends no answer within 30 seconds, or within [`one_shot_timeout`](crate::ClientBuilder::one_shot_timeout) when set.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ibapi::prelude::*;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let client = Client::connect("127.0.0.1:4002", 100).await.expect("connection failed");
    ///     let xml = client.scanner_parameters().await.expect("scanner_parameters failed");
    ///     println!("scanner parameters: {} chars", xml.len());
    /// }
    /// ```
    pub async fn scanner_parameters(&self) -> Result<String, Error> {
        request_helpers::one_shot_shared(
            self,
            OutgoingMessages::RequestScannerParameters,
            encoders::encode_scanner_parameters,
            expect_proto(decoders::decode_scanner_parameters_proto),
        )
        .await
    }

    /// Starts a subscription to market scan results based on the provided parameters.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ibapi::prelude::*;
    /// use ibapi::scanner::ScannerSubscription;
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let client = Client::connect("127.0.0.1:4002", 100).await.expect("connection failed");
    ///
    ///     let mut sub = ScannerSubscription::default();
    ///     sub.instrument = Some("STK".to_string());
    ///     sub.location_code = Some("STK.US.MAJOR".to_string());
    ///     sub.scan_code = Some("TOP_PERC_GAIN".to_string());
    ///
    ///     let filter: Vec<ibapi::contracts::TagValue> = Vec::new();
    ///
    ///     let subscription = client
    ///         .scanner_subscription(&sub, &filter)
    ///         .await
    ///         .expect("scanner_subscription failed");
    ///
    ///     // Take the first batch of results, if any.
    ///     let mut data = subscription.filter_data();
    ///     if let Some(batch) = data.next().await {
    ///         match batch {
    ///             Ok(rows) => {
    ///                 for row in rows {
    ///                     println!(
    ///                         "rank: {}, symbol: {}",
    ///                         row.rank, row.contract_details.contract.symbol
    ///                     );
    ///                 }
    ///             }
    ///             Err(e) => eprintln!("scanner error: {e:?}"),
    ///         }
    ///     }
    /// }
    /// ```
    pub async fn scanner_subscription(
        &self,
        subscription: &ScannerSubscription,
        filter: &[TagValue],
    ) -> Result<Subscription<Vec<ScannerData>>, Error> {
        let builder = self.request();
        let request = encoders::encode_scanner_subscription(builder.request_id(), subscription, filter)?;
        builder.send(request).await
    }
}

#[cfg(test)]
#[path = "async_tests.rs"]
mod tests;