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