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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ConnectionState {
36 Disconnected,
38 Connecting,
40 Connected,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct ClientConfig {
47 pub host: String,
49 pub port: u16,
51 pub client_id: i32,
53 pub connect_options: Option<String>,
55 pub optional_capabilities: Option<String>,
57 pub prefer_protobuf: bool,
60}
61
62impl ClientConfig {
63 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#[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
93pub struct EventPump<W> {
95 client: TwsApiClient,
96 wrapper: W,
97}
98
99impl<W: Wrapper> EventPump<W> {
100 pub async fn run(mut self) -> TwsApiResult<()> {
102 self.client.run_with(&mut self.wrapper).await
103 }
104}
105
106impl TwsApiClient {
107 pub fn into_event_pump<W: Wrapper>(self, wrapper: W) -> EventPump<W> {
109 EventPump {
110 client: self,
111 wrapper,
112 }
113 }
114 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 pub const fn server_version(&self) -> i32 {
142 self.server_version
143 }
144
145 pub fn connection_time(&self) -> &str {
147 &self.connection_time
148 }
149
150 pub const fn state(&self) -> ConnectionState {
152 self.state
153 }
154
155 pub async fn disconnect(&mut self) -> TwsApiResult<()> {
157 self.state = ConnectionState::Disconnected;
158 self.stream.shutdown().await?;
159 Ok(())
160 }
161
162 pub const fn api_ready(&self) -> bool {
164 self.api_ready
165 }
166
167 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 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 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 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 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 pub async fn raw_request(&mut self, message: Outgoing, fields: String) -> TwsApiResult<()> {
228 self.send_request(RawRequest { message, fields }).await
229 }
230
231 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 pub async fn req_mkt_data(&mut self, request: MarketDataRequest) -> TwsApiResult<()> {
239 self.send_request(request).await
240 }
241
242 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 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 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 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 pub async fn req_mkt_depth(&mut self, request: MarketDepthRequest) -> TwsApiResult<()> {
283 self.send_request(request).await
284 }
285
286 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 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 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 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 pub async fn req_auto_open_orders(&mut self, auto_bind: bool) -> TwsApiResult<()> {
347 self.send_request(AutoOpenOrdersRequest { auto_bind }).await
348 }
349
350 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 pub async fn req_global_cancel(&mut self, order_cancel: OrderCancel) -> TwsApiResult<()> {
361 self.send_request(GlobalCancelRequest { order_cancel })
362 .await
363 }
364
365 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 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 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 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 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 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 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 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 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 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 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 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 pub async fn req_executions(&mut self, request: ExecutionRequest) -> TwsApiResult<()> {
518 self.send_request(request).await
519 }
520
521 pub async fn req_contract_details(
523 &mut self,
524 request: ContractDetailsRequest,
525 ) -> TwsApiResult<()> {
526 self.send_request(request).await
527 }
528
529 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 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 pub async fn req_news_bulletins(&mut self, all_messages: bool) -> TwsApiResult<()> {
549 self.send_request(NewsBulletinsRequest { all_messages })
550 .await
551 }
552
553 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 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 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 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 pub async fn req_historical_data(
594 &mut self,
595 request: HistoricalDataRequest,
596 ) -> TwsApiResult<()> {
597 self.send_request(request).await
598 }
599
600 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 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 pub async fn req_scanner_subscription(
621 &mut self,
622 request: ScannerSubscriptionRequest,
623 ) -> TwsApiResult<()> {
624 self.send_request(request).await
625 }
626
627 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 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 pub async fn req_tick_by_tick_data(&mut self, request: TickByTickRequest) -> TwsApiResult<()> {
654 self.send_request(request).await
655 }
656
657 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 pub async fn calculate_implied_volatility(
669 &mut self,
670 request: CalculateImpliedVolatilityRequest,
671 ) -> TwsApiResult<()> {
672 self.send_request(request).await
673 }
674
675 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 pub async fn calculate_option_price(
687 &mut self,
688 request: CalculateOptionPriceRequest,
689 ) -> TwsApiResult<()> {
690 self.send_request(request).await
691 }
692
693 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 pub async fn exercise_options(&mut self, request: ExerciseOptionsRequest) -> TwsApiResult<()> {
705 self.send_request(request).await
706 }
707
708 pub async fn req_head_timestamp(&mut self, request: HeadTimestampRequest) -> TwsApiResult<()> {
710 self.send_request(request).await
711 }
712
713 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 pub async fn req_histogram_data(&mut self, request: HistogramDataRequest) -> TwsApiResult<()> {
725 self.send_request(request).await
726 }
727
728 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 pub async fn req_historical_ticks(
740 &mut self,
741 request: HistoricalTicksRequest,
742 ) -> TwsApiResult<()> {
743 self.send_request(request).await
744 }
745
746 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 pub async fn req_real_time_bars(&mut self, request: RealTimeBarsRequest) -> TwsApiResult<()> {
758 self.send_request(request).await
759 }
760
761 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 pub async fn req_news_providers(&mut self) -> TwsApiResult<()> {
773 self.send_request(EmptyRequest {
774 message: Outgoing::ReqNewsProviders,
775 })
776 .await
777 }
778
779 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 pub async fn req_historical_news(
798 &mut self,
799 request: HistoricalNewsRequest,
800 ) -> TwsApiResult<()> {
801 self.send_request(request).await
802 }
803
804 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 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 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 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 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 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 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 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 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 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 pub async fn req_family_codes(&mut self) -> TwsApiResult<()> {
923 self.send_request(EmptyRequest {
924 message: Outgoing::ReqFamilyCodes,
925 })
926 .await
927 }
928
929 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 pub async fn req_completed_orders(&mut self, api_only: bool) -> TwsApiResult<()> {
940 self.send_request(CompletedOrdersRequest { api_only }).await
941 }
942
943 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 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 pub async fn req_wsh_event_data(&mut self, request: WshEventDataRequest) -> TwsApiResult<()> {
965 self.send_request(request).await
966 }
967
968 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 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 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 pub async fn req_config_protobuf(&mut self, protobuf_data: &[u8]) -> TwsApiResult<()> {
998 self.send_protobuf(Outgoing::ReqConfig, protobuf_data).await
999 }
1000
1001 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 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 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 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 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 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 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 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}