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}
58
59impl ClientConfig {
60 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#[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
89pub struct EventPump<W> {
91 client: TwsApiClient,
92 wrapper: W,
93}
94
95impl<W: Wrapper> EventPump<W> {
96 pub async fn run(mut self) -> TwsApiResult<()> {
98 self.client.run_with(&mut self.wrapper).await
99 }
100}
101
102impl TwsApiClient {
103 pub fn into_event_pump<W: Wrapper>(self, wrapper: W) -> EventPump<W> {
105 EventPump {
106 client: self,
107 wrapper,
108 }
109 }
110 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 pub const fn server_version(&self) -> i32 {
138 self.server_version
139 }
140
141 pub fn connection_time(&self) -> &str {
143 &self.connection_time
144 }
145
146 pub const fn state(&self) -> ConnectionState {
148 self.state
149 }
150
151 pub async fn disconnect(&mut self) -> TwsApiResult<()> {
153 self.state = ConnectionState::Disconnected;
154 self.stream.shutdown().await?;
155 Ok(())
156 }
157
158 pub const fn api_ready(&self) -> bool {
160 self.api_ready
161 }
162
163 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 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 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 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 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 pub async fn raw_request(&mut self, message: Outgoing, fields: String) -> TwsApiResult<()> {
221 self.send_request(RawRequest { message, fields }).await
222 }
223
224 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 pub async fn req_mkt_data(&mut self, request: MarketDataRequest) -> TwsApiResult<()> {
232 self.send_request(request).await
233 }
234
235 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 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 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 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 pub async fn req_mkt_depth(&mut self, request: MarketDepthRequest) -> TwsApiResult<()> {
276 self.send_request(request).await
277 }
278
279 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 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 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 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 pub async fn req_auto_open_orders(&mut self, auto_bind: bool) -> TwsApiResult<()> {
340 self.send_request(AutoOpenOrdersRequest { auto_bind }).await
341 }
342
343 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 pub async fn req_global_cancel(&mut self, order_cancel: OrderCancel) -> TwsApiResult<()> {
354 self.send_request(GlobalCancelRequest { order_cancel })
355 .await
356 }
357
358 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 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 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 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 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 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 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 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 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 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 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 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 pub async fn req_executions(&mut self, request: ExecutionRequest) -> TwsApiResult<()> {
511 self.send_request(request).await
512 }
513
514 pub async fn req_contract_details(
516 &mut self,
517 request: ContractDetailsRequest,
518 ) -> TwsApiResult<()> {
519 self.send_request(request).await
520 }
521
522 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 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 pub async fn req_news_bulletins(&mut self, all_messages: bool) -> TwsApiResult<()> {
542 self.send_request(NewsBulletinsRequest { all_messages })
543 .await
544 }
545
546 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 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 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 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 pub async fn req_historical_data(
587 &mut self,
588 request: HistoricalDataRequest,
589 ) -> TwsApiResult<()> {
590 self.send_request(request).await
591 }
592
593 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 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 pub async fn req_scanner_subscription(
614 &mut self,
615 request: ScannerSubscriptionRequest,
616 ) -> TwsApiResult<()> {
617 self.send_request(request).await
618 }
619
620 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 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 pub async fn req_tick_by_tick_data(&mut self, request: TickByTickRequest) -> TwsApiResult<()> {
647 self.send_request(request).await
648 }
649
650 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 pub async fn calculate_implied_volatility(
662 &mut self,
663 request: CalculateImpliedVolatilityRequest,
664 ) -> TwsApiResult<()> {
665 self.send_request(request).await
666 }
667
668 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 pub async fn calculate_option_price(
680 &mut self,
681 request: CalculateOptionPriceRequest,
682 ) -> TwsApiResult<()> {
683 self.send_request(request).await
684 }
685
686 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 pub async fn exercise_options(&mut self, request: ExerciseOptionsRequest) -> TwsApiResult<()> {
698 self.send_request(request).await
699 }
700
701 pub async fn req_head_timestamp(&mut self, request: HeadTimestampRequest) -> TwsApiResult<()> {
703 self.send_request(request).await
704 }
705
706 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 pub async fn req_histogram_data(&mut self, request: HistogramDataRequest) -> TwsApiResult<()> {
718 self.send_request(request).await
719 }
720
721 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 pub async fn req_historical_ticks(
733 &mut self,
734 request: HistoricalTicksRequest,
735 ) -> TwsApiResult<()> {
736 self.send_request(request).await
737 }
738
739 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 pub async fn req_real_time_bars(&mut self, request: RealTimeBarsRequest) -> TwsApiResult<()> {
751 self.send_request(request).await
752 }
753
754 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 pub async fn req_news_providers(&mut self) -> TwsApiResult<()> {
766 self.send_request(EmptyRequest {
767 message: Outgoing::ReqNewsProviders,
768 })
769 .await
770 }
771
772 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 pub async fn req_historical_news(
791 &mut self,
792 request: HistoricalNewsRequest,
793 ) -> TwsApiResult<()> {
794 self.send_request(request).await
795 }
796
797 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 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 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 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 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 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 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 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 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 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 pub async fn req_family_codes(&mut self) -> TwsApiResult<()> {
916 self.send_request(EmptyRequest {
917 message: Outgoing::ReqFamilyCodes,
918 })
919 .await
920 }
921
922 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 pub async fn req_completed_orders(&mut self, api_only: bool) -> TwsApiResult<()> {
933 self.send_request(CompletedOrdersRequest { api_only }).await
934 }
935
936 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 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 pub async fn req_wsh_event_data(&mut self, request: WshEventDataRequest) -> TwsApiResult<()> {
958 self.send_request(request).await
959 }
960
961 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 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 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 pub async fn req_config_protobuf(&mut self, protobuf_data: &[u8]) -> TwsApiResult<()> {
991 self.send_protobuf(Outgoing::ReqConfig, protobuf_data).await
992 }
993
994 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 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 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 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 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 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 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 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}