Skip to main content

truefix_twsapi_client/
client.rs

1use std::collections::VecDeque;
2use tokio::io::{AsyncReadExt, AsyncWriteExt};
3use tokio::net::TcpStream;
4
5use crate::comm;
6use crate::constants::MAX_MSG_LEN;
7use crate::decoder;
8use crate::error::{TwsApiError, TwsApiResult};
9use crate::events::{Event, Wrapper};
10use crate::message::Outgoing;
11use crate::requests::{
12    AccountDataRequest, AccountSummaryRequest, AccountUpdatesMultiRequest, AutoOpenOrdersRequest,
13    CalculateImpliedVolatilityRequest, CalculateOptionPriceRequest, CancelMarketDepthRequest,
14    CancelOrderRequest, CompletedOrdersRequest, ContractDetailsRequest, EmptyRequest,
15    EncodableRequest, ExecutionRequest, ExerciseOptionsRequest, FieldSink, FinancialAdvisorRequest,
16    GlobalCancelRequest, HeadTimestampRequest, HistogramDataRequest, HistoricalDataRequest,
17    HistoricalNewsRequest, HistoricalTicksRequest, IdRequest, MarketDataRequest,
18    MarketDataTypeRequest, MarketDepthRequest, MatchingSymbolsRequest, NewsArticleRequest,
19    NewsBulletinsRequest, PlaceOrderRequest, PnlRequest, PnlSingleRequest, PositionsMultiRequest,
20    RawRequest, RealTimeBarsRequest, ReplaceFinancialAdvisorRequest, ScannerSubscriptionRequest,
21    SecDefOptParamsRequest, SetServerLogLevelRequest, SmartComponentsRequest, StartApiRequest,
22    SubscribeToGroupEventsRequest, TickByTickRequest, UpdateDisplayGroupRequest,
23    VerifyAndAuthMessageRequest, VerifyAndAuthRequest, VerifyMessageRequest, VerifyRequest,
24    VersionedRequest, WshEventDataRequest, encode_request_frame_with_protobuf,
25    protobuf_min_server_version, validate_attached_orders_parameters, validate_order_parameters,
26};
27use crate::server_versions::{
28    MAX_CLIENT_VER, MIN_CLIENT_VER, MIN_SERVER_VER_OPTIONAL_CAPABILITIES, MIN_SERVER_VER_POSITIONS,
29    MIN_SERVER_VER_PROTOBUF,
30};
31use crate::types::{OrderCancel, TagValue};
32
33/// Client connection state.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ConnectionState {
36    /// No active socket.
37    Disconnected,
38    /// Socket opened and handshake in progress.
39    Connecting,
40    /// Handshake completed.
41    Connected,
42}
43
44/// TWS/Gateway client configuration.
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct ClientConfig {
47    /// Host name or IP address. Empty values are normalized to `127.0.0.1`.
48    pub host: String,
49    /// TWS/Gateway socket port.
50    pub port: u16,
51    /// TWS API client id.
52    pub client_id: i32,
53    /// Optional connect options appended to the enhanced handshake version string.
54    pub connect_options: Option<String>,
55    /// Optional capabilities sent by `start_api` when supported by the server.
56    pub optional_capabilities: Option<String>,
57    /// Whether to use the IB protobuf extension after `startApi`. Some local
58    /// Gateway deployments negotiate a modern version but reject `jextend`.
59    pub prefer_protobuf: bool,
60}
61
62impl ClientConfig {
63    /// Creates a new configuration.
64    pub fn new(host: impl Into<String>, port: u16, client_id: i32) -> Self {
65        let host = host.into();
66        Self {
67            host: if host.is_empty() {
68                "127.0.0.1".to_owned()
69            } else {
70                host
71            },
72            port,
73            client_id,
74            connect_options: None,
75            optional_capabilities: None,
76            prefer_protobuf: true,
77        }
78    }
79}
80
81/// Thin TWS/Gateway protocol client.
82#[derive(Debug)]
83pub struct TwsApiClient {
84    config: ClientConfig,
85    stream: TcpStream,
86    state: ConnectionState,
87    server_version: i32,
88    connection_time: String,
89    api_ready: bool,
90    pending_events: VecDeque<Event>,
91}
92
93/// An owned asynchronous event loop. Spawn `run` on a Tokio task when a background reader is desired.
94pub struct EventPump<W> {
95    client: TwsApiClient,
96    wrapper: W,
97}
98
99impl<W: Wrapper> EventPump<W> {
100    /// Runs until the connection closes or an event cannot be decoded.
101    pub async fn run(mut self) -> TwsApiResult<()> {
102        self.client.run_with(&mut self.wrapper).await
103    }
104}
105
106impl TwsApiClient {
107    /// Moves this client into an owned asynchronous event pump.
108    pub fn into_event_pump<W: Wrapper>(self, wrapper: W) -> EventPump<W> {
109        EventPump {
110            client: self,
111            wrapper,
112        }
113    }
114    /// Opens a TCP connection and performs the enhanced TWS API handshake.
115    pub async fn connect(config: ClientConfig) -> TwsApiResult<Self> {
116        let addr = format!("{}:{}", config.host, config.port);
117        let mut stream = TcpStream::connect(addr).await?;
118        let handshake = comm::make_client_handshake(
119            MIN_CLIENT_VER,
120            MAX_CLIENT_VER,
121            config.connect_options.as_deref(),
122        );
123        stream.write_all(&handshake).await?;
124
125        let mut client = Self {
126            config,
127            stream,
128            state: ConnectionState::Connecting,
129            server_version: 0,
130            connection_time: String::new(),
131            api_ready: false,
132            pending_events: VecDeque::new(),
133        };
134        client.read_handshake().await?;
135        client.state = ConnectionState::Connected;
136        client.start_api().await?;
137        Ok(client)
138    }
139
140    /// Returns the negotiated server version.
141    pub const fn server_version(&self) -> i32 {
142        self.server_version
143    }
144
145    /// Returns the connection time reported by TWS/Gateway.
146    pub fn connection_time(&self) -> &str {
147        &self.connection_time
148    }
149
150    /// Returns the current connection state.
151    pub const fn state(&self) -> ConnectionState {
152        self.state
153    }
154
155    /// Closes the socket connection.
156    pub async fn disconnect(&mut self) -> TwsApiResult<()> {
157        self.state = ConnectionState::Disconnected;
158        self.stream.shutdown().await?;
159        Ok(())
160    }
161
162    /// Returns whether initial API callbacks have been received after `startApi`.
163    pub const fn api_ready(&self) -> bool {
164        self.api_ready
165    }
166
167    /// Sends `startApi`.
168    pub async fn start_api(&mut self) -> TwsApiResult<()> {
169        self.send_request(StartApiRequest {
170            client_id: self.config.client_id,
171            optional_capabilities: self.config.optional_capabilities.clone(),
172            include_optional_capabilities: self.server_version
173                >= MIN_SERVER_VER_OPTIONAL_CAPABILITIES,
174        })
175        .await
176    }
177
178    /// Sends `reqCurrentTime`.
179    pub async fn req_current_time(&mut self) -> TwsApiResult<()> {
180        self.send_request(VersionedRequest {
181            message: Outgoing::ReqCurrentTime,
182            version: 1,
183        })
184        .await
185    }
186
187    /// Sends `reqIds`.
188    pub async fn req_ids(&mut self, num_ids: i32) -> TwsApiResult<()> {
189        self.send_request(IdRequest {
190            message: Outgoing::ReqIds,
191            version: Some(1),
192            req_id: num_ids,
193        })
194        .await
195    }
196
197    /// Sends `reqPositions`.
198    pub async fn req_positions(&mut self) -> TwsApiResult<()> {
199        if self.server_version < MIN_SERVER_VER_POSITIONS {
200            return Err(TwsApiError::UnsupportedServerVersion {
201                server_version: self.server_version,
202                min_version: MIN_SERVER_VER_POSITIONS,
203            });
204        }
205        self.send_request(VersionedRequest {
206            message: Outgoing::ReqPositions,
207            version: 1,
208        })
209        .await
210    }
211
212    /// Sends any field-encoded request.
213    pub async fn send_request<R>(&mut self, request: R) -> TwsApiResult<()>
214    where
215        R: EncodableRequest,
216    {
217        let frame = encode_request_frame_with_protobuf(
218            &request,
219            self.server_version,
220            self.api_ready && self.config.prefer_protobuf,
221        )?;
222        self.stream.write_all(&frame).await?;
223        Ok(())
224    }
225
226    /// Sends a raw field-encoded request. `fields` must contain only fields after the message id.
227    pub async fn raw_request(&mut self, message: Outgoing, fields: String) -> TwsApiResult<()> {
228        self.send_request(RawRequest { message, fields }).await
229    }
230
231    /// Sends `setServerLogLevel`.
232    pub async fn set_server_log_level(&mut self, log_level: i32) -> TwsApiResult<()> {
233        self.send_request(SetServerLogLevelRequest { log_level })
234            .await
235    }
236
237    /// Sends `reqMktData`.
238    pub async fn req_mkt_data(&mut self, request: MarketDataRequest) -> TwsApiResult<()> {
239        self.send_request(request).await
240    }
241
242    /// Sends `cancelMktData`.
243    pub async fn cancel_mkt_data(&mut self, req_id: i32) -> TwsApiResult<()> {
244        self.send_request(IdRequest {
245            message: Outgoing::CancelMktData,
246            version: Some(2),
247            req_id,
248        })
249        .await
250    }
251
252    /// Sends `reqMarketDataType`.
253    pub async fn req_market_data_type(&mut self, market_data_type: i32) -> TwsApiResult<()> {
254        self.send_request(MarketDataTypeRequest { market_data_type })
255            .await
256    }
257
258    /// Sends `reqSmartComponents`.
259    pub async fn req_smart_components(
260        &mut self,
261        req_id: i32,
262        bbo_exchange: &str,
263    ) -> TwsApiResult<()> {
264        self.send_request(SmartComponentsRequest {
265            req_id,
266            bbo_exchange: bbo_exchange.to_owned(),
267        })
268        .await
269    }
270
271    /// Sends `reqMarketRule`.
272    pub async fn req_market_rule(&mut self, market_rule_id: i32) -> TwsApiResult<()> {
273        self.send_request(IdRequest {
274            message: Outgoing::ReqMarketRule,
275            version: None,
276            req_id: market_rule_id,
277        })
278        .await
279    }
280
281    /// Sends `reqMktDepth`.
282    pub async fn req_mkt_depth(&mut self, request: MarketDepthRequest) -> TwsApiResult<()> {
283        self.send_request(request).await
284    }
285
286    /// Sends `cancelMktDepth`.
287    pub async fn cancel_mkt_depth(
288        &mut self,
289        req_id: i32,
290        is_smart_depth: bool,
291    ) -> TwsApiResult<()> {
292        self.send_request(CancelMarketDepthRequest {
293            req_id,
294            is_smart_depth,
295        })
296        .await
297    }
298
299    /// Sends `placeOrder`.
300    pub async fn place_order(&mut self, request: PlaceOrderRequest) -> TwsApiResult<()> {
301        if self.use_protobuf(Outgoing::PlaceOrder) {
302            if let Some(validation) = validate_order_parameters(&request.order, self.server_version)
303            {
304                return Err(TwsApiError::UnsupportedRequestParameter {
305                    server_version: self.server_version,
306                    min_version: validation.min_version,
307                    parameter: validation.parameter,
308                });
309            }
310            if let Some(validation) =
311                validate_attached_orders_parameters(&request.order, self.server_version)
312            {
313                return Err(TwsApiError::UnsupportedRequestParameter {
314                    server_version: self.server_version,
315                    min_version: validation.min_version,
316                    parameter: validation.parameter,
317                });
318            }
319        }
320        self.send_request(request).await
321    }
322
323    /// Sends `cancelOrder`.
324    pub async fn cancel_order(
325        &mut self,
326        order_id: i32,
327        order_cancel: OrderCancel,
328    ) -> TwsApiResult<()> {
329        self.send_request(CancelOrderRequest {
330            order_id,
331            order_cancel,
332        })
333        .await
334    }
335
336    /// Sends `reqOpenOrders`.
337    pub async fn req_open_orders(&mut self) -> TwsApiResult<()> {
338        self.send_request(VersionedRequest {
339            message: Outgoing::ReqOpenOrders,
340            version: 1,
341        })
342        .await
343    }
344
345    /// Sends `reqAutoOpenOrders`.
346    pub async fn req_auto_open_orders(&mut self, auto_bind: bool) -> TwsApiResult<()> {
347        self.send_request(AutoOpenOrdersRequest { auto_bind }).await
348    }
349
350    /// Sends `reqAllOpenOrders`.
351    pub async fn req_all_open_orders(&mut self) -> TwsApiResult<()> {
352        self.send_request(VersionedRequest {
353            message: Outgoing::ReqAllOpenOrders,
354            version: 1,
355        })
356        .await
357    }
358
359    /// Sends `reqGlobalCancel`.
360    pub async fn req_global_cancel(&mut self, order_cancel: OrderCancel) -> TwsApiResult<()> {
361        self.send_request(GlobalCancelRequest { order_cancel })
362            .await
363    }
364
365    /// Sends `reqAccountUpdates`.
366    pub async fn req_account_updates(
367        &mut self,
368        subscribe: bool,
369        account_code: &str,
370    ) -> TwsApiResult<()> {
371        self.send_request(AccountDataRequest {
372            subscribe,
373            account_code: account_code.to_owned(),
374        })
375        .await
376    }
377
378    /// Sends `reqAccountSummary`.
379    pub async fn req_account_summary(
380        &mut self,
381        req_id: i32,
382        group_name: &str,
383        tags: &str,
384    ) -> TwsApiResult<()> {
385        self.send_request(AccountSummaryRequest {
386            req_id,
387            group_name: group_name.to_owned(),
388            tags: tags.to_owned(),
389        })
390        .await
391    }
392
393    /// Sends `cancelAccountSummary`.
394    pub async fn cancel_account_summary(&mut self, req_id: i32) -> TwsApiResult<()> {
395        self.send_request(IdRequest {
396            message: Outgoing::CancelAccountSummary,
397            version: None,
398            req_id,
399        })
400        .await
401    }
402
403    /// Sends `cancelPositions`.
404    pub async fn cancel_positions(&mut self) -> TwsApiResult<()> {
405        self.send_request(VersionedRequest {
406            message: Outgoing::CancelPositions,
407            version: 1,
408        })
409        .await
410    }
411
412    /// Sends `reqPositionsMulti`.
413    pub async fn req_positions_multi(
414        &mut self,
415        req_id: i32,
416        account: &str,
417        model_code: &str,
418    ) -> TwsApiResult<()> {
419        self.send_request(PositionsMultiRequest {
420            req_id,
421            account: account.to_owned(),
422            model_code: model_code.to_owned(),
423        })
424        .await
425    }
426
427    /// Sends `cancelPositionsMulti`.
428    pub async fn cancel_positions_multi(&mut self, req_id: i32) -> TwsApiResult<()> {
429        self.send_request(IdRequest {
430            message: Outgoing::CancelPositionsMulti,
431            version: Some(1),
432            req_id,
433        })
434        .await
435    }
436
437    /// Sends `reqAccountUpdatesMulti`.
438    pub async fn req_account_updates_multi(
439        &mut self,
440        req_id: i32,
441        account: &str,
442        model_code: &str,
443        ledger_and_nlv: bool,
444    ) -> TwsApiResult<()> {
445        self.send_request(AccountUpdatesMultiRequest {
446            req_id,
447            account: account.to_owned(),
448            model_code: model_code.to_owned(),
449            ledger_and_nlv,
450        })
451        .await
452    }
453
454    /// Sends `cancelAccountUpdatesMulti`.
455    pub async fn cancel_account_updates_multi(&mut self, req_id: i32) -> TwsApiResult<()> {
456        self.send_request(IdRequest {
457            message: Outgoing::CancelAccountUpdatesMulti,
458            version: Some(1),
459            req_id,
460        })
461        .await
462    }
463
464    /// Sends `reqPnL`.
465    pub async fn req_pnl(
466        &mut self,
467        req_id: i32,
468        account: &str,
469        model_code: &str,
470    ) -> TwsApiResult<()> {
471        self.send_request(PnlRequest {
472            req_id,
473            account: account.to_owned(),
474            model_code: model_code.to_owned(),
475        })
476        .await
477    }
478
479    /// Sends `cancelPnL`.
480    pub async fn cancel_pnl(&mut self, req_id: i32) -> TwsApiResult<()> {
481        self.send_request(IdRequest {
482            message: Outgoing::CancelPnl,
483            version: None,
484            req_id,
485        })
486        .await
487    }
488
489    /// Sends `reqPnLSingle`.
490    pub async fn req_pnl_single(
491        &mut self,
492        req_id: i32,
493        account: &str,
494        model_code: &str,
495        con_id: i32,
496    ) -> TwsApiResult<()> {
497        self.send_request(PnlSingleRequest {
498            req_id,
499            account: account.to_owned(),
500            model_code: model_code.to_owned(),
501            con_id,
502        })
503        .await
504    }
505
506    /// Sends `cancelPnLSingle`.
507    pub async fn cancel_pnl_single(&mut self, req_id: i32) -> TwsApiResult<()> {
508        self.send_request(IdRequest {
509            message: Outgoing::CancelPnlSingle,
510            version: None,
511            req_id,
512        })
513        .await
514    }
515
516    /// Sends `reqExecutions`.
517    pub async fn req_executions(&mut self, request: ExecutionRequest) -> TwsApiResult<()> {
518        self.send_request(request).await
519    }
520
521    /// Sends `reqContractDetails`.
522    pub async fn req_contract_details(
523        &mut self,
524        request: ContractDetailsRequest,
525    ) -> TwsApiResult<()> {
526        self.send_request(request).await
527    }
528
529    /// Sends `cancelContractData`.
530    pub async fn cancel_contract_data(&mut self, req_id: i32) -> TwsApiResult<()> {
531        self.send_request(IdRequest {
532            message: Outgoing::CancelContractData,
533            version: None,
534            req_id,
535        })
536        .await
537    }
538
539    /// Sends `reqMktDepthExchanges`.
540    pub async fn req_mkt_depth_exchanges(&mut self) -> TwsApiResult<()> {
541        self.send_request(EmptyRequest {
542            message: Outgoing::ReqMktDepthExchanges,
543        })
544        .await
545    }
546
547    /// Sends `reqNewsBulletins`.
548    pub async fn req_news_bulletins(&mut self, all_messages: bool) -> TwsApiResult<()> {
549        self.send_request(NewsBulletinsRequest { all_messages })
550            .await
551    }
552
553    /// Sends `cancelNewsBulletins`.
554    pub async fn cancel_news_bulletins(&mut self) -> TwsApiResult<()> {
555        self.send_request(VersionedRequest {
556            message: Outgoing::CancelNewsBulletins,
557            version: 1,
558        })
559        .await
560    }
561
562    /// Sends `reqManagedAccts`.
563    pub async fn req_managed_accounts(&mut self) -> TwsApiResult<()> {
564        self.send_request(VersionedRequest {
565            message: Outgoing::ReqManagedAccounts,
566            version: 1,
567        })
568        .await
569    }
570
571    /// Sends `requestFA`.
572    pub async fn request_fa(&mut self, fa_data_type: i32) -> TwsApiResult<()> {
573        self.send_request(FinancialAdvisorRequest { fa_data_type })
574            .await
575    }
576
577    /// Sends `replaceFA`.
578    pub async fn replace_fa(
579        &mut self,
580        req_id: i32,
581        fa_data_type: i32,
582        xml: &str,
583    ) -> TwsApiResult<()> {
584        self.send_request(ReplaceFinancialAdvisorRequest {
585            req_id,
586            fa_data_type,
587            xml: xml.to_owned(),
588        })
589        .await
590    }
591
592    /// Sends `reqHistoricalData`.
593    pub async fn req_historical_data(
594        &mut self,
595        request: HistoricalDataRequest,
596    ) -> TwsApiResult<()> {
597        self.send_request(request).await
598    }
599
600    /// Sends `cancelHistoricalData`.
601    pub async fn cancel_historical_data(&mut self, req_id: i32) -> TwsApiResult<()> {
602        self.send_request(IdRequest {
603            message: Outgoing::CancelHistoricalData,
604            version: Some(1),
605            req_id,
606        })
607        .await
608    }
609
610    /// Sends `reqScannerParameters`.
611    pub async fn req_scanner_parameters(&mut self) -> TwsApiResult<()> {
612        self.send_request(VersionedRequest {
613            message: Outgoing::ReqScannerParameters,
614            version: 1,
615        })
616        .await
617    }
618
619    /// Sends `reqScannerSubscription`.
620    pub async fn req_scanner_subscription(
621        &mut self,
622        request: ScannerSubscriptionRequest,
623    ) -> TwsApiResult<()> {
624        self.send_request(request).await
625    }
626
627    /// Sends `cancelScannerSubscription`.
628    pub async fn cancel_scanner_subscription(&mut self, req_id: i32) -> TwsApiResult<()> {
629        self.send_request(IdRequest {
630            message: Outgoing::CancelScannerSubscription,
631            version: Some(1),
632            req_id,
633        })
634        .await
635    }
636
637    /// Sends a request id plus optional tag values.
638    pub async fn id_request_with_options(
639        &mut self,
640        message: Outgoing,
641        req_id: i32,
642        options: &[TagValue],
643    ) -> TwsApiResult<()> {
644        let mut fields = FieldSink::default();
645        fields.push(req_id)?.push(options.len())?;
646        for option in options {
647            fields.push(&option.tag)?.push(&option.value)?;
648        }
649        self.raw_request(message, fields.into_string()).await
650    }
651
652    /// Sends `reqTickByTickData`.
653    pub async fn req_tick_by_tick_data(&mut self, request: TickByTickRequest) -> TwsApiResult<()> {
654        self.send_request(request).await
655    }
656
657    /// Sends `cancelTickByTickData`.
658    pub async fn cancel_tick_by_tick_data(&mut self, req_id: i32) -> TwsApiResult<()> {
659        self.send_request(IdRequest {
660            message: Outgoing::CancelTickByTickData,
661            version: None,
662            req_id,
663        })
664        .await
665    }
666
667    /// Sends `calculateImpliedVolatility`.
668    pub async fn calculate_implied_volatility(
669        &mut self,
670        request: CalculateImpliedVolatilityRequest,
671    ) -> TwsApiResult<()> {
672        self.send_request(request).await
673    }
674
675    /// Sends `cancelCalculateImpliedVolatility`.
676    pub async fn cancel_calculate_implied_volatility(&mut self, req_id: i32) -> TwsApiResult<()> {
677        self.send_request(IdRequest {
678            message: Outgoing::CancelCalcImpliedVolat,
679            version: Some(1),
680            req_id,
681        })
682        .await
683    }
684
685    /// Sends `calculateOptionPrice`.
686    pub async fn calculate_option_price(
687        &mut self,
688        request: CalculateOptionPriceRequest,
689    ) -> TwsApiResult<()> {
690        self.send_request(request).await
691    }
692
693    /// Sends `cancelCalculateOptionPrice`.
694    pub async fn cancel_calculate_option_price(&mut self, req_id: i32) -> TwsApiResult<()> {
695        self.send_request(IdRequest {
696            message: Outgoing::CancelCalcOptionPrice,
697            version: Some(1),
698            req_id,
699        })
700        .await
701    }
702
703    /// Sends `exerciseOptions`.
704    pub async fn exercise_options(&mut self, request: ExerciseOptionsRequest) -> TwsApiResult<()> {
705        self.send_request(request).await
706    }
707
708    /// Sends `reqHeadTimeStamp`.
709    pub async fn req_head_timestamp(&mut self, request: HeadTimestampRequest) -> TwsApiResult<()> {
710        self.send_request(request).await
711    }
712
713    /// Sends `cancelHeadTimeStamp`.
714    pub async fn cancel_head_timestamp(&mut self, req_id: i32) -> TwsApiResult<()> {
715        self.send_request(IdRequest {
716            message: Outgoing::CancelHeadTimestamp,
717            version: None,
718            req_id,
719        })
720        .await
721    }
722
723    /// Sends `reqHistogramData`.
724    pub async fn req_histogram_data(&mut self, request: HistogramDataRequest) -> TwsApiResult<()> {
725        self.send_request(request).await
726    }
727
728    /// Sends `cancelHistogramData`.
729    pub async fn cancel_histogram_data(&mut self, req_id: i32) -> TwsApiResult<()> {
730        self.send_request(IdRequest {
731            message: Outgoing::CancelHistogramData,
732            version: None,
733            req_id,
734        })
735        .await
736    }
737
738    /// Sends `reqHistoricalTicks`.
739    pub async fn req_historical_ticks(
740        &mut self,
741        request: HistoricalTicksRequest,
742    ) -> TwsApiResult<()> {
743        self.send_request(request).await
744    }
745
746    /// Sends `cancelHistoricalTicks`.
747    pub async fn cancel_historical_ticks(&mut self, req_id: i32) -> TwsApiResult<()> {
748        self.send_request(IdRequest {
749            message: Outgoing::CancelHistoricalTicks,
750            version: None,
751            req_id,
752        })
753        .await
754    }
755
756    /// Sends `reqRealTimeBars`.
757    pub async fn req_real_time_bars(&mut self, request: RealTimeBarsRequest) -> TwsApiResult<()> {
758        self.send_request(request).await
759    }
760
761    /// Sends `cancelRealTimeBars`.
762    pub async fn cancel_real_time_bars(&mut self, req_id: i32) -> TwsApiResult<()> {
763        self.send_request(IdRequest {
764            message: Outgoing::CancelRealTimeBars,
765            version: Some(1),
766            req_id,
767        })
768        .await
769    }
770
771    /// Sends `reqNewsProviders`.
772    pub async fn req_news_providers(&mut self) -> TwsApiResult<()> {
773        self.send_request(EmptyRequest {
774            message: Outgoing::ReqNewsProviders,
775        })
776        .await
777    }
778
779    /// Sends `reqNewsArticle`.
780    pub async fn req_news_article(
781        &mut self,
782        req_id: i32,
783        provider_code: &str,
784        article_id: &str,
785        options: &[TagValue],
786    ) -> TwsApiResult<()> {
787        self.send_request(NewsArticleRequest {
788            req_id,
789            provider_code: provider_code.to_owned(),
790            article_id: article_id.to_owned(),
791            options: options.to_vec(),
792        })
793        .await
794    }
795
796    /// Sends `reqHistoricalNews`.
797    pub async fn req_historical_news(
798        &mut self,
799        request: HistoricalNewsRequest,
800    ) -> TwsApiResult<()> {
801        self.send_request(request).await
802    }
803
804    /// Sends `queryDisplayGroups`.
805    pub async fn query_display_groups(&mut self, req_id: i32) -> TwsApiResult<()> {
806        self.send_request(IdRequest {
807            message: Outgoing::QueryDisplayGroups,
808            version: Some(1),
809            req_id,
810        })
811        .await
812    }
813
814    /// Sends `subscribeToGroupEvents`.
815    pub async fn subscribe_to_group_events(
816        &mut self,
817        req_id: i32,
818        group_id: i32,
819    ) -> TwsApiResult<()> {
820        self.send_request(SubscribeToGroupEventsRequest { req_id, group_id })
821            .await
822    }
823
824    /// Sends `updateDisplayGroup`.
825    pub async fn update_display_group(
826        &mut self,
827        req_id: i32,
828        contract_info: &str,
829    ) -> TwsApiResult<()> {
830        self.send_request(UpdateDisplayGroupRequest {
831            req_id,
832            contract_info: contract_info.to_owned(),
833        })
834        .await
835    }
836
837    /// Sends `unsubscribeFromGroupEvents`.
838    pub async fn unsubscribe_from_group_events(&mut self, req_id: i32) -> TwsApiResult<()> {
839        self.send_request(IdRequest {
840            message: Outgoing::UnsubscribeFromGroupEvents,
841            version: Some(1),
842            req_id,
843        })
844        .await
845    }
846
847    /// Sends `verifyRequest`.
848    pub async fn verify_request(&mut self, api_name: &str, api_version: &str) -> TwsApiResult<()> {
849        self.send_request(VerifyRequest {
850            api_name: api_name.to_owned(),
851            api_version: api_version.to_owned(),
852        })
853        .await
854    }
855
856    /// Sends `verifyMessage`.
857    pub async fn verify_message(&mut self, api_data: &str) -> TwsApiResult<()> {
858        self.send_request(VerifyMessageRequest {
859            api_data: api_data.to_owned(),
860        })
861        .await
862    }
863
864    /// Sends `verifyAndAuthRequest`.
865    pub async fn verify_and_auth_request(
866        &mut self,
867        api_name: &str,
868        api_version: &str,
869        opaque_isv_key: &str,
870    ) -> TwsApiResult<()> {
871        self.send_request(VerifyAndAuthRequest {
872            api_name: api_name.to_owned(),
873            api_version: api_version.to_owned(),
874            opaque_isv_key: opaque_isv_key.to_owned(),
875        })
876        .await
877    }
878
879    /// Sends `verifyAndAuthMessage`.
880    pub async fn verify_and_auth_message(
881        &mut self,
882        api_data: &str,
883        xyz_response: &str,
884    ) -> TwsApiResult<()> {
885        self.send_request(VerifyAndAuthMessageRequest {
886            api_data: api_data.to_owned(),
887            xyz_response: xyz_response.to_owned(),
888        })
889        .await
890    }
891
892    /// Sends `reqSecDefOptParams`.
893    pub async fn req_sec_def_opt_params(
894        &mut self,
895        req_id: i32,
896        underlying_symbol: &str,
897        fut_fop_exchange: &str,
898        underlying_sec_type: &str,
899        underlying_con_id: i32,
900    ) -> TwsApiResult<()> {
901        self.send_request(SecDefOptParamsRequest {
902            req_id,
903            underlying_symbol: underlying_symbol.to_owned(),
904            fut_fop_exchange: fut_fop_exchange.to_owned(),
905            underlying_sec_type: underlying_sec_type.to_owned(),
906            underlying_con_id,
907        })
908        .await
909    }
910
911    /// Sends `reqSoftDollarTiers`.
912    pub async fn req_soft_dollar_tiers(&mut self, req_id: i32) -> TwsApiResult<()> {
913        self.send_request(IdRequest {
914            message: Outgoing::ReqSoftDollarTiers,
915            version: None,
916            req_id,
917        })
918        .await
919    }
920
921    /// Sends `reqFamilyCodes`.
922    pub async fn req_family_codes(&mut self) -> TwsApiResult<()> {
923        self.send_request(EmptyRequest {
924            message: Outgoing::ReqFamilyCodes,
925        })
926        .await
927    }
928
929    /// Sends `reqMatchingSymbols`.
930    pub async fn req_matching_symbols(&mut self, req_id: i32, pattern: &str) -> TwsApiResult<()> {
931        self.send_request(MatchingSymbolsRequest {
932            req_id,
933            pattern: pattern.to_owned(),
934        })
935        .await
936    }
937
938    /// Sends `reqCompletedOrders`.
939    pub async fn req_completed_orders(&mut self, api_only: bool) -> TwsApiResult<()> {
940        self.send_request(CompletedOrdersRequest { api_only }).await
941    }
942
943    /// Sends `reqWshMetaData`.
944    pub async fn req_wsh_meta_data(&mut self, req_id: i32) -> TwsApiResult<()> {
945        self.send_request(IdRequest {
946            message: Outgoing::ReqWshMetaData,
947            version: None,
948            req_id,
949        })
950        .await
951    }
952
953    /// Sends `cancelWshMetaData`.
954    pub async fn cancel_wsh_meta_data(&mut self, req_id: i32) -> TwsApiResult<()> {
955        self.send_request(IdRequest {
956            message: Outgoing::CancelWshMetaData,
957            version: None,
958            req_id,
959        })
960        .await
961    }
962
963    /// Sends `reqWshEventData`.
964    pub async fn req_wsh_event_data(&mut self, request: WshEventDataRequest) -> TwsApiResult<()> {
965        self.send_request(request).await
966    }
967
968    /// Sends `cancelWshEventData`.
969    pub async fn cancel_wsh_event_data(&mut self, req_id: i32) -> TwsApiResult<()> {
970        self.send_request(IdRequest {
971            message: Outgoing::CancelWshEventData,
972            version: None,
973            req_id,
974        })
975        .await
976    }
977
978    /// Sends `reqUserInfo`.
979    pub async fn req_user_info(&mut self, req_id: i32) -> TwsApiResult<()> {
980        self.send_request(IdRequest {
981            message: Outgoing::ReqUserInfo,
982            version: None,
983            req_id,
984        })
985        .await
986    }
987
988    /// Sends `reqCurrentTimeInMillis`.
989    pub async fn req_current_time_in_millis(&mut self) -> TwsApiResult<()> {
990        self.send_request(EmptyRequest {
991            message: Outgoing::ReqCurrentTimeInMillis,
992        })
993        .await
994    }
995
996    /// Sends `reqConfig` protobuf payload.
997    pub async fn req_config_protobuf(&mut self, protobuf_data: &[u8]) -> TwsApiResult<()> {
998        self.send_protobuf(Outgoing::ReqConfig, protobuf_data).await
999    }
1000
1001    /// Sends `updateConfig` protobuf payload.
1002    pub async fn update_config_protobuf(&mut self, protobuf_data: &[u8]) -> TwsApiResult<()> {
1003        self.send_protobuf(Outgoing::UpdateConfig, protobuf_data)
1004            .await
1005    }
1006
1007    /// Sends an already-serialized protobuf payload with the protobuf-adjusted outgoing id.
1008    pub async fn send_protobuf(&mut self, msg: Outgoing, protobuf_data: &[u8]) -> TwsApiResult<()> {
1009        let frame = comm::make_msg_proto(msg.protobuf_id(), protobuf_data);
1010        self.stream.write_all(&frame).await?;
1011        Ok(())
1012    }
1013
1014    /// Returns whether this server version supports protobuf for `message`.
1015    pub fn use_protobuf(&self, message: Outgoing) -> bool {
1016        protobuf_min_server_version(message)
1017            .is_some_and(|min_version| self.server_version >= min_version)
1018    }
1019
1020    /// Sends protobuf for `message` only when the negotiated server version supports it.
1021    pub async fn send_protobuf_request(
1022        &mut self,
1023        message: Outgoing,
1024        protobuf_data: &[u8],
1025    ) -> TwsApiResult<()> {
1026        if !self.use_protobuf(message) {
1027            return Err(TwsApiError::UnsupportedServerVersion {
1028                server_version: self.server_version,
1029                min_version: protobuf_min_server_version(message).unwrap_or(i32::MAX),
1030            });
1031        }
1032        self.send_protobuf(message, protobuf_data).await
1033    }
1034
1035    /// Reads one raw payload frame from the socket.
1036    pub async fn read_payload(&mut self) -> TwsApiResult<Vec<u8>> {
1037        let size = self.stream.read_u32().await?;
1038        let size = usize::try_from(size).map_err(|_| TwsApiError::FrameTooLarge(size))?;
1039        if size > MAX_MSG_LEN {
1040            return Err(TwsApiError::FrameTooLarge(size as u32));
1041        }
1042        let mut payload = vec![0; size];
1043        self.stream.read_exact(&mut payload).await?;
1044        Ok(payload)
1045    }
1046
1047    /// Reads and decodes one incoming event.
1048    pub async fn read_event(&mut self) -> TwsApiResult<Event> {
1049        if let Some(event) = self.pending_events.pop_front() {
1050            return Ok(event);
1051        }
1052        let payload = self.read_payload().await?;
1053        let event =
1054            decoder::decode_payload(self.server_version >= MIN_SERVER_VER_PROTOBUF, &payload)?;
1055        if matches!(
1056            event,
1057            Event::NextValidId { .. } | Event::ManagedAccounts { .. }
1058        ) {
1059            self.api_ready = true;
1060        }
1061        if let Some(next_event) = follow_up_event(&event) {
1062            self.pending_events.push_back(next_event);
1063        }
1064        Ok(event)
1065    }
1066
1067    /// Reads one event and dispatches it to typed [`Wrapper`] callbacks.
1068    pub async fn read_event_with<W: Wrapper>(&mut self, wrapper: &mut W) -> TwsApiResult<Event> {
1069        let event = self.read_event().await?;
1070        wrapper.dispatch(event.clone());
1071        Ok(event)
1072    }
1073
1074    /// Runs the event loop until the socket closes or a decoding error occurs.
1075    pub async fn run_with<W: Wrapper>(&mut self, wrapper: &mut W) -> TwsApiResult<()> {
1076        loop {
1077            self.read_event_with(wrapper).await?;
1078        }
1079    }
1080
1081    async fn read_handshake(&mut self) -> TwsApiResult<()> {
1082        loop {
1083            let payload = self.read_payload().await?;
1084            let fields = comm::read_fields(&payload);
1085            if fields.len() == 2 {
1086                let mut fields = fields.into_iter();
1087                let server_version =
1088                    parse_i32(fields.next().ok_or(TwsApiError::MalformedHandshake)?)?;
1089                self.server_version = server_version;
1090                self.connection_time =
1091                    String::from_utf8_lossy(fields.next().ok_or(TwsApiError::MalformedHandshake)?)
1092                        .into_owned();
1093                return Ok(());
1094            }
1095
1096            let event = decoder::decode_payload(false, &payload)?;
1097            self.pending_events.push_back(event.clone());
1098            if let Some(next_event) = follow_up_event(&event) {
1099                self.pending_events.push_back(next_event);
1100            }
1101        }
1102    }
1103}
1104
1105fn follow_up_event(event: &Event) -> Option<Event> {
1106    match event {
1107        Event::ScannerData { req_id, .. } => Some(Event::ScannerDataEnd { req_id: *req_id }),
1108        _ => None,
1109    }
1110}
1111
1112#[cfg(test)]
1113#[allow(clippy::items_after_test_module)]
1114mod tests {
1115    use super::follow_up_event;
1116    use crate::events::{Event, ScannerDataRow};
1117    use crate::types::Contract;
1118
1119    #[test]
1120    fn scanner_data_enqueues_end_event() {
1121        let event = Event::ScannerData {
1122            req_id: 7,
1123            rows: vec![ScannerDataRow {
1124                rank: 1,
1125                contract: Box::new(Contract::default()),
1126                market_name: "NASDAQ".to_owned(),
1127                distance: "0".to_owned(),
1128                benchmark: "bm".to_owned(),
1129                projection: "proj".to_owned(),
1130                combo_key: "ck".to_owned(),
1131            }],
1132        };
1133
1134        assert_eq!(
1135            follow_up_event(&event),
1136            Some(Event::ScannerDataEnd { req_id: 7 })
1137        );
1138    }
1139}
1140
1141fn parse_i32(field: &[u8]) -> TwsApiResult<i32> {
1142    let text = String::from_utf8_lossy(field).into_owned();
1143    text.parse::<i32>()
1144        .map_err(|source| TwsApiError::InvalidInteger {
1145            field: text,
1146            source,
1147        })
1148}