Skip to main content

ibapi/scanner/
sync.rs

1//! Synchronous implementation of scanner functionality
2
3use super::common::{decoders, encoders};
4use super::*;
5use crate::client::blocking::{ClientRequestBuilders, Subscription};
6use crate::client::sync::Client;
7use crate::common::request_helpers::{self, expect_proto};
8use crate::contracts::TagValue;
9use crate::messages::OutgoingMessages;
10use crate::Error;
11
12impl Client {
13    /// Requests an XML list of scanner parameters valid in TWS.
14    ///
15    /// # Errors
16    /// [`Error::Timeout`] if TWS sends no answer within 30 seconds, or within [`one_shot_timeout`](crate::client::blocking::ClientBuilder::one_shot_timeout) when set.
17    ///
18    /// # Examples
19    ///
20    /// ```no_run
21    /// use ibapi::client::blocking::Client;
22    ///
23    /// let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");
24    /// let xml = client.scanner_parameters().expect("scanner_parameters failed");
25    /// println!("scanner parameters: {} chars", xml.len());
26    /// ```
27    pub fn scanner_parameters(&self) -> Result<String, Error> {
28        request_helpers::blocking::one_shot_shared(
29            self,
30            OutgoingMessages::RequestScannerParameters,
31            encoders::encode_scanner_parameters,
32            expect_proto(decoders::decode_scanner_parameters_proto),
33        )
34    }
35
36    /// Starts a subscription to market scan results based on the provided parameters.
37    ///
38    /// # Examples
39    ///
40    /// ```no_run
41    /// use ibapi::client::blocking::Client;
42    /// use ibapi::scanner::ScannerSubscription;
43    /// use ibapi::contracts::TagValue;
44    ///
45    /// let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");
46    ///
47    /// let mut sub = ScannerSubscription::default();
48    /// sub.instrument = Some("STK".to_string());
49    /// sub.location_code = Some("STK.US.MAJOR".to_string());
50    /// sub.scan_code = Some("TOP_PERC_GAIN".to_string());
51    /// // Further customize the subscription object as needed, for example:
52    /// // sub.above_price = Some(1.0);
53    /// // sub.below_price = Some(100.0);
54    /// // sub.number_of_rows = 20;
55    ///
56    /// // Filter options are advanced and not always needed. Pass an empty Vec if not used.
57    /// let mut filter_options: Vec<TagValue> = Vec::new();
58    /// // Example of adding a filter:
59    /// // filter_options.push(TagValue { tag: "marketCapAbove".to_string(), value: "1000000000".to_string() });
60    ///
61    /// match client.scanner_subscription(&sub, &filter_options) {
62    ///     Ok(subscription) => {
63    ///         // Iterate over received scanner data.
64    ///         // Note: Scanner subscriptions can be continuous or return a snapshot.
65    ///         // This example just takes the first batch if available.
66    ///         match subscription.iter_data().next() {
67    ///             Some(Ok(scanner_results_vec)) => {
68    ///                 println!("Scanner Results (first batch):");
69    ///                 for data in scanner_results_vec {
70    ///                     println!("  Rank: {}, Symbol: {}",
71    ///                              data.rank,
72    ///                              data.contract_details.contract.symbol);
73    ///                 }
74    ///             }
75    ///             Some(Err(e)) => eprintln!("Scanner error: {e:?}"),
76    ///             None => println!("No scanner results received in the first check."),
77    ///         }
78    ///         // In a real application, you might continuously iterate or handle updates.
79    ///         // Remember to cancel the subscription when no longer needed if it's continuous.
80    ///         // subscription.cancel();
81    ///     }
82    ///     Err(e) => {
83    ///         eprintln!("Failed to start scanner subscription: {e:?}");
84    ///     }
85    /// };
86    /// ```
87    pub fn scanner_subscription(&self, subscription: &ScannerSubscription, filter: &[TagValue]) -> Result<Subscription<Vec<ScannerData>>, Error> {
88        let builder = self.request();
89        let request = encoders::encode_scanner_subscription(builder.request_id(), subscription, filter)?;
90        builder.send(request)
91    }
92}
93
94#[cfg(test)]
95#[path = "sync_tests.rs"]
96mod tests;