1use std::{fmt, rc::Rc};
8
9use async_trait::async_trait;
10use futures_util::{Stream, StreamExt, stream::LocalBoxStream};
11use navi_types::{
12 AuxDataItem, Candlestick, DataArgs, DividendsField, EarningsField, SplitsField, SymbolInfo,
13 SymbolType, SyminfoFields, TickItem, TimeUnit, VolumeType,
14};
15use serde::{Deserialize, Serialize};
16use time::OffsetDateTime;
17
18use crate::{CandlestickItem, Currency, Market, TimeFrame, market_ext::MarketExt};
19
20#[derive(Debug, Clone, Default, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase", default)]
27pub struct PartialSymbolInfo {
28 pub market: Option<Market>,
30 pub description: Option<String>,
32 pub type_: Option<SymbolType>,
34 pub country: Option<String>,
36 pub isin: Option<String>,
38 pub root: Option<String>,
40 pub min_move: Option<i32>,
42 pub price_scale: Option<i32>,
44 pub point_value: Option<f64>,
46 pub currency: Option<Currency>,
48 pub expiration_date: Option<OffsetDateTime>,
50 pub current_contract: Option<String>,
52 pub base_currency: Option<Currency>,
54 pub employees: Option<i64>,
56 pub industry: Option<String>,
58 pub sector: Option<String>,
60 pub min_contract: Option<f64>,
62 pub volume_type: Option<VolumeType>,
64 pub shareholders: Option<i64>,
66 pub shares_outstanding_float: Option<f64>,
68 pub shares_outstanding_total: Option<f64>,
70 pub recommendations_buy: Option<i32>,
72 pub recommendations_buy_strong: Option<i32>,
74 pub recommendations_hold: Option<i32>,
76 pub recommendations_sell: Option<i32>,
78 pub recommendations_sell_strong: Option<i32>,
80 pub recommendations_date: Option<OffsetDateTime>,
82 pub recommendations_total: Option<i32>,
84 pub target_price_average: Option<f64>,
86 pub target_price_date: Option<OffsetDateTime>,
88 pub target_price_estimates: Option<f64>,
90 pub target_price_high: Option<f64>,
92 pub target_price_low: Option<f64>,
94 pub target_price_median: Option<f64>,
96}
97
98impl PartialSymbolInfo {
99 pub(crate) fn into_symbol_info(self, symbol: &str) -> Result<SymbolInfo, navi_types::Error> {
105 use navi_types::symbol::Symbol;
106 let symbol: Symbol = symbol
107 .parse()
108 .map_err(|_| navi_types::Error::InvalidSymbol)?;
109 let market = match self.market {
110 Some(m) => m,
111 None => symbol
112 .prefix()
113 .parse()
114 .map_err(|_| navi_types::Error::UnknownMarket)?,
115 };
116 Ok(SymbolInfo {
117 symbol,
118 market,
119 description: self.description,
120 type_: self.type_.or_else(|| Some(market.default_type())),
121 country: self
122 .country
123 .or_else(|| Some(market.default_country().to_string())),
124 isin: self.isin,
125 root: self.root,
126 min_move: self.min_move.unwrap_or_else(|| market.default_min_move()),
127 price_scale: self
128 .price_scale
129 .unwrap_or_else(|| market.default_price_scale()),
130 point_value: self.point_value.unwrap_or(1.0),
131 currency: self.currency.unwrap_or_else(|| market.default_currency()),
132 expiration_date: self.expiration_date,
133 current_contract: self.current_contract,
134 base_currency: self.base_currency,
135 employees: self.employees,
136 industry: self.industry,
137 sector: self.sector,
138 min_contract: self.min_contract,
139 recommendations_buy: self.recommendations_buy,
140 recommendations_buy_strong: self.recommendations_buy_strong,
141 recommendations_hold: self.recommendations_hold,
142 recommendations_sell: self.recommendations_sell,
143 recommendations_sell_strong: self.recommendations_sell_strong,
144 recommendations_date: self.recommendations_date,
145 recommendations_total: self.recommendations_total,
146 shareholders: self.shareholders,
147 shares_outstanding_float: self.shares_outstanding_float,
148 shares_outstanding_total: self.shares_outstanding_total,
149 target_price_average: self.target_price_average,
150 target_price_date: self.target_price_date,
151 target_price_estimates: self.target_price_estimates,
152 target_price_high: self.target_price_high,
153 target_price_low: self.target_price_low,
154 target_price_median: self.target_price_median,
155 volume_type: self
156 .volume_type
157 .or_else(|| Some(market.default_volume_type())),
158 })
159 }
160}
161
162#[non_exhaustive]
168#[derive(Debug, thiserror::Error)]
169pub enum DataProviderError<E>
170where
171 E: fmt::Display + fmt::Debug,
172{
173 #[error("invalid symbol: {0}")]
178 InvalidSymbol(String),
179 #[error("{0}")]
181 Other(E),
182}
183
184#[async_trait(?Send)]
205#[allow(clippy::type_complexity)]
206pub trait DataProvider {
207 type Error: fmt::Display + fmt::Debug + 'static;
209
210 async fn symbol_info(
220 &self,
221 symbol: String,
222 fields: SyminfoFields,
223 ) -> Result<PartialSymbolInfo, DataProviderError<Self::Error>>;
224
225 fn candlesticks(
292 &self,
293 symbol: String,
294 timeframe: TimeFrame,
295 from_time: i64,
296 count: Option<usize>,
297 ) -> Result<
298 impl Stream<Item = Result<CandlestickItem, DataProviderError<Self::Error>>> + 'static,
299 DataProviderError<Self::Error>,
300 >;
301
302 fn ticks(
319 &self,
320 _symbol: String,
321 _from_time: i64,
322 _count: Option<usize>,
323 ) -> Result<
324 impl Stream<Item = Result<TickItem, DataProviderError<Self::Error>>> + 'static,
325 DataProviderError<Self::Error>,
326 > {
327 Ok(futures_util::stream::empty())
328 }
329
330 fn currency_rate(
335 &self,
336 _from: Currency,
337 _to: Currency,
338 _from_time: i64,
339 ) -> Result<
340 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
341 DataProviderError<Self::Error>,
342 > {
343 Ok(futures_util::stream::empty())
344 }
345
346 fn financial(
351 &self,
352 _symbol: String,
353 _financial_id: String,
354 _period: String,
355 _currency: Option<Currency>,
356 _from_time: i64,
357 ) -> Result<
358 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
359 DataProviderError<Self::Error>,
360 > {
361 Ok(futures_util::stream::empty())
362 }
363
364 fn earnings(
368 &self,
369 _symbol: String,
370 _field: EarningsField,
371 _currency: Option<Currency>,
372 _from_time: i64,
373 ) -> Result<
374 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
375 DataProviderError<Self::Error>,
376 > {
377 Ok(futures_util::stream::empty())
378 }
379
380 fn dividends(
384 &self,
385 _symbol: String,
386 _field: DividendsField,
387 _currency: Option<Currency>,
388 _from_time: i64,
389 ) -> Result<
390 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
391 DataProviderError<Self::Error>,
392 > {
393 Ok(futures_util::stream::empty())
394 }
395
396 fn economic(
401 &self,
402 _country_code: String,
403 _field: String,
404 _from_time: i64,
405 ) -> Result<
406 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
407 DataProviderError<Self::Error>,
408 > {
409 Ok(futures_util::stream::empty())
410 }
411
412 fn splits(
416 &self,
417 _symbol: String,
418 _field: SplitsField,
419 _from_time: i64,
420 ) -> Result<
421 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
422 DataProviderError<Self::Error>,
423 > {
424 Ok(futures_util::stream::empty())
425 }
426
427 fn data(
440 &self,
441 _function: String,
442 _args: DataArgs,
443 _from_time: i64,
444 ) -> Result<
445 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
446 DataProviderError<Self::Error>,
447 > {
448 Ok(futures_util::stream::empty())
449 }
450}
451
452#[async_trait(?Send)]
460pub trait HistoryProvider {
461 type Error: fmt::Display + fmt::Debug + 'static;
464
465 async fn history_bars_before(
472 &self,
473 symbol: String,
474 timeframe: TimeFrame,
475 before_time: i64,
476 count: usize,
477 ) -> Result<Vec<Candlestick>, DataProviderError<Self::Error>>;
478}
479
480#[async_trait(?Send)]
483impl HistoryProvider for Vec<Candlestick> {
484 type Error = std::convert::Infallible;
485
486 async fn history_bars_before(
487 &self,
488 _symbol: String,
489 _timeframe: TimeFrame,
490 before_time: i64,
491 count: usize,
492 ) -> Result<Vec<Candlestick>, DataProviderError<Self::Error>> {
493 let end = self.partition_point(|c| c.time < before_time);
494 let start = end.saturating_sub(count);
495 Ok(self[start..end].to_vec())
496 }
497}
498
499#[async_trait(?Send)]
500impl HistoryProvider for Vec<CandlestickItem> {
501 type Error = std::convert::Infallible;
502
503 async fn history_bars_before(
504 &self,
505 _symbol: String,
506 _timeframe: TimeFrame,
507 before_time: i64,
508 count: usize,
509 ) -> Result<Vec<Candlestick>, DataProviderError<Self::Error>> {
510 let bars: Vec<Candlestick> = self
511 .iter()
512 .filter_map(|item| {
513 if let CandlestickItem::Bar(c) = item {
514 if c.time < before_time { Some(*c) } else { None }
515 } else {
516 None
517 }
518 })
519 .collect();
520 let start = bars.len().saturating_sub(count);
521 Ok(bars[start..].to_vec())
522 }
523}
524
525#[async_trait(?Send)]
526impl<P> HistoryProvider for Rc<P>
527where
528 P: HistoryProvider + 'static,
529{
530 type Error = P::Error;
531
532 async fn history_bars_before(
533 &self,
534 symbol: String,
535 timeframe: TimeFrame,
536 before_time: i64,
537 count: usize,
538 ) -> Result<Vec<Candlestick>, DataProviderError<Self::Error>> {
539 (**self)
540 .history_bars_before(symbol, timeframe, before_time, count)
541 .await
542 }
543}
544
545#[derive(Debug, thiserror::Error)]
550pub(crate) enum InternalProviderError {
551 #[error("invalid symbol: {0}")]
553 InvalidSymbol(String),
554 #[error("error fetching symbol info for {symbol}: {message}")]
556 SymbolInfoError { symbol: String, message: String },
557 #[error("error fetching {symbol}/{timeframe}: {message}")]
559 CandlesticksError {
560 symbol: String,
561 timeframe: TimeFrame,
562 message: String,
563 },
564 #[error("auxiliary data error: {message}")]
566 AuxDataError { message: String },
567}
568
569#[async_trait(?Send)]
576pub(crate) trait InternalProvider {
577 async fn symbol_info(
578 &self,
579 _symbol: String,
580 _fields: SyminfoFields,
581 ) -> Result<PartialSymbolInfo, InternalProviderError> {
582 Ok(PartialSymbolInfo::default())
583 }
584
585 fn candlesticks(
586 &self,
587 _symbol: &str,
588 _timeframe: TimeFrame,
589 _from_time: i64,
590 _count: Option<usize>,
591 ) -> Result<
592 LocalBoxStream<'static, Result<CandlestickItem, InternalProviderError>>,
593 InternalProviderError,
594 > {
595 Ok(Box::pin(futures_util::stream::empty()))
596 }
597
598 fn currency_rate(
599 &self,
600 _from: Currency,
601 _to: Currency,
602 _from_time: i64,
603 ) -> Result<
604 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
605 InternalProviderError,
606 > {
607 Ok(Box::pin(futures_util::stream::empty()))
608 }
609
610 fn financial(
611 &self,
612 _symbol: String,
613 _financial_id: String,
614 _period: String,
615 _currency: Option<Currency>,
616 _from_time: i64,
617 ) -> Result<
618 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
619 InternalProviderError,
620 > {
621 Ok(Box::pin(futures_util::stream::empty()))
622 }
623
624 fn earnings(
625 &self,
626 _symbol: String,
627 _field: EarningsField,
628 _currency: Option<Currency>,
629 _from_time: i64,
630 ) -> Result<
631 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
632 InternalProviderError,
633 > {
634 Ok(Box::pin(futures_util::stream::empty()))
635 }
636
637 fn dividends(
638 &self,
639 _symbol: String,
640 _field: DividendsField,
641 _currency: Option<Currency>,
642 _from_time: i64,
643 ) -> Result<
644 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
645 InternalProviderError,
646 > {
647 Ok(Box::pin(futures_util::stream::empty()))
648 }
649
650 fn economic(
651 &self,
652 _country_code: String,
653 _field: String,
654 _from_time: i64,
655 ) -> Result<
656 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
657 InternalProviderError,
658 > {
659 Ok(Box::pin(futures_util::stream::empty()))
660 }
661
662 fn splits(
663 &self,
664 _symbol: String,
665 _field: SplitsField,
666 _from_time: i64,
667 ) -> Result<
668 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
669 InternalProviderError,
670 > {
671 Ok(Box::pin(futures_util::stream::empty()))
672 }
673
674 fn data(
675 &self,
676 _function: String,
677 _args: DataArgs,
678 _from_time: i64,
679 ) -> Result<
680 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
681 InternalProviderError,
682 > {
683 Ok(Box::pin(futures_util::stream::empty()))
684 }
685}
686
687fn map_aux_stream_error<E>(
690 result: Result<AuxDataItem, DataProviderError<E>>,
691) -> Result<AuxDataItem, InternalProviderError>
692where
693 E: fmt::Display + fmt::Debug,
694{
695 result.map_err(|e| match e {
696 DataProviderError::InvalidSymbol(msg) => InternalProviderError::InvalidSymbol(msg),
697 DataProviderError::Other(e) => InternalProviderError::AuxDataError {
698 message: e.to_string(),
699 },
700 })
701}
702
703fn map_aux_creation_error<E>(e: DataProviderError<E>) -> InternalProviderError
706where
707 E: fmt::Display + fmt::Debug,
708{
709 match e {
710 DataProviderError::InvalidSymbol(msg) => InternalProviderError::InvalidSymbol(msg),
711 DataProviderError::Other(e) => InternalProviderError::AuxDataError {
712 message: e.to_string(),
713 },
714 }
715}
716
717#[async_trait(?Send)]
718impl<T> InternalProvider for T
719where
720 T: DataProvider + 'static,
721{
722 async fn symbol_info(
723 &self,
724 symbol: String,
725 fields: SyminfoFields,
726 ) -> Result<PartialSymbolInfo, InternalProviderError> {
727 DataProvider::symbol_info(self, symbol.clone(), fields)
728 .await
729 .map_err(|e| match e {
730 DataProviderError::InvalidSymbol(msg) => InternalProviderError::InvalidSymbol(msg),
731 DataProviderError::Other(e) => InternalProviderError::SymbolInfoError {
732 symbol,
733 message: e.to_string(),
734 },
735 })
736 }
737
738 fn candlesticks(
739 &self,
740 symbol: &str,
741 timeframe: TimeFrame,
742 from_time: i64,
743 count: Option<usize>,
744 ) -> Result<
745 LocalBoxStream<'static, Result<CandlestickItem, InternalProviderError>>,
746 InternalProviderError,
747 > {
748 let symbol_owned = symbol.to_string();
749
750 if timeframe.unit == TimeUnit::Tick {
752 let n = timeframe.quantity.get() as usize;
753 let raw =
754 DataProvider::ticks(self, symbol_owned.clone(), from_time, count).map_err(|e| {
755 match e {
756 DataProviderError::InvalidSymbol(msg) => {
757 InternalProviderError::InvalidSymbol(msg)
758 }
759 DataProviderError::Other(e) => InternalProviderError::AuxDataError {
760 message: e.to_string(),
761 },
762 }
763 })?;
764 let mapped = raw.map(move |result| {
765 result.map_err(|e| match e {
766 DataProviderError::InvalidSymbol(msg) => {
767 InternalProviderError::InvalidSymbol(msg)
768 }
769 DataProviderError::Other(e) => InternalProviderError::AuxDataError {
770 message: e.to_string(),
771 },
772 })
773 });
774 return Ok(Box::pin(synthesize_ticks(mapped, n)));
775 }
776
777 let stream =
778 DataProvider::candlesticks(self, symbol_owned.clone(), timeframe, from_time, count)
779 .map_err(|e| match e {
780 DataProviderError::InvalidSymbol(msg) => {
781 InternalProviderError::InvalidSymbol(msg)
782 }
783 DataProviderError::Other(e) => InternalProviderError::CandlesticksError {
784 symbol: symbol_owned.clone(),
785 timeframe,
786 message: e.to_string(),
787 },
788 })?;
789
790 Ok(Box::pin(stream.map(move |result| {
791 result.map_err(|e| match e {
792 DataProviderError::InvalidSymbol(msg) => InternalProviderError::InvalidSymbol(msg),
793 DataProviderError::Other(e) => InternalProviderError::CandlesticksError {
794 symbol: symbol_owned.clone(),
795 timeframe,
796 message: e.to_string(),
797 },
798 })
799 })))
800 }
801
802 fn currency_rate(
803 &self,
804 from: Currency,
805 to: Currency,
806 from_time: i64,
807 ) -> Result<
808 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
809 InternalProviderError,
810 > {
811 let stream = DataProvider::currency_rate(self, from, to, from_time)
812 .map_err(map_aux_creation_error)?;
813 Ok(Box::pin(stream.map(map_aux_stream_error)))
814 }
815
816 fn financial(
817 &self,
818 symbol: String,
819 financial_id: String,
820 period: String,
821 currency: Option<Currency>,
822 from_time: i64,
823 ) -> Result<
824 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
825 InternalProviderError,
826 > {
827 let stream =
828 DataProvider::financial(self, symbol, financial_id, period, currency, from_time)
829 .map_err(map_aux_creation_error)?;
830 Ok(Box::pin(stream.map(map_aux_stream_error)))
831 }
832
833 fn earnings(
834 &self,
835 symbol: String,
836 field: EarningsField,
837 currency: Option<Currency>,
838 from_time: i64,
839 ) -> Result<
840 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
841 InternalProviderError,
842 > {
843 let stream = DataProvider::earnings(self, symbol, field, currency, from_time)
844 .map_err(map_aux_creation_error)?;
845 Ok(Box::pin(stream.map(map_aux_stream_error)))
846 }
847
848 fn dividends(
849 &self,
850 symbol: String,
851 field: DividendsField,
852 currency: Option<Currency>,
853 from_time: i64,
854 ) -> Result<
855 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
856 InternalProviderError,
857 > {
858 let stream = DataProvider::dividends(self, symbol, field, currency, from_time)
859 .map_err(map_aux_creation_error)?;
860 Ok(Box::pin(stream.map(map_aux_stream_error)))
861 }
862
863 fn economic(
864 &self,
865 country_code: String,
866 field: String,
867 from_time: i64,
868 ) -> Result<
869 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
870 InternalProviderError,
871 > {
872 let stream = DataProvider::economic(self, country_code, field, from_time)
873 .map_err(map_aux_creation_error)?;
874 Ok(Box::pin(stream.map(map_aux_stream_error)))
875 }
876
877 fn splits(
878 &self,
879 symbol: String,
880 field: SplitsField,
881 from_time: i64,
882 ) -> Result<
883 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
884 InternalProviderError,
885 > {
886 let stream =
887 DataProvider::splits(self, symbol, field, from_time).map_err(map_aux_creation_error)?;
888 Ok(Box::pin(stream.map(map_aux_stream_error)))
889 }
890
891 fn data(
892 &self,
893 function: String,
894 args: DataArgs,
895 from_time: i64,
896 ) -> Result<
897 LocalBoxStream<'static, Result<AuxDataItem, InternalProviderError>>,
898 InternalProviderError,
899 > {
900 let stream =
901 DataProvider::data(self, function, args, from_time).map_err(map_aux_creation_error)?;
902 Ok(Box::pin(stream.map(map_aux_stream_error)))
903 }
904}
905
906#[async_trait(?Send)]
913impl DataProvider for Vec<CandlestickItem> {
914 type Error = std::convert::Infallible;
915
916 async fn symbol_info(
917 &self,
918 _symbol: String,
919 _fields: SyminfoFields,
920 ) -> Result<PartialSymbolInfo, DataProviderError<Self::Error>> {
921 Ok(PartialSymbolInfo::default())
922 }
923
924 fn candlesticks(
925 &self,
926 _symbol: String,
927 _timeframe: TimeFrame,
928 _from_time: i64,
929 count: Option<usize>,
930 ) -> Result<
931 impl Stream<Item = Result<CandlestickItem, DataProviderError<Self::Error>>> + 'static,
932 DataProviderError<Self::Error>,
933 > {
934 let mut items = self.clone();
935 if let Some(count) = count {
936 let history_end_idx = items
937 .iter()
938 .position(|item| matches!(item, CandlestickItem::HistoryEnd))
939 .unwrap_or(items.len());
940 let bar_indices: Vec<usize> = items[..history_end_idx]
941 .iter()
942 .enumerate()
943 .filter_map(|(idx, item)| matches!(item, CandlestickItem::Bar(_)).then_some(idx))
944 .collect();
945 if bar_indices.len() > count {
946 let first_keep = bar_indices[bar_indices.len() - count];
947 items.drain(..first_keep);
948 }
949 }
950 Ok(futures_util::stream::iter(items.into_iter().map(Ok)))
951 }
952}
953
954#[async_trait(?Send)]
960impl<P> DataProvider for Rc<P>
961where
962 P: DataProvider + 'static,
963{
964 type Error = P::Error;
965
966 async fn symbol_info(
967 &self,
968 symbol: String,
969 fields: SyminfoFields,
970 ) -> Result<PartialSymbolInfo, DataProviderError<Self::Error>> {
971 (**self).symbol_info(symbol, fields).await
972 }
973
974 fn candlesticks(
975 &self,
976 symbol: String,
977 timeframe: TimeFrame,
978 from_time: i64,
979 count: Option<usize>,
980 ) -> Result<
981 impl Stream<Item = Result<CandlestickItem, DataProviderError<Self::Error>>> + 'static,
982 DataProviderError<Self::Error>,
983 > {
984 (**self).candlesticks(symbol, timeframe, from_time, count)
985 }
986
987 fn ticks(
988 &self,
989 symbol: String,
990 from_time: i64,
991 count: Option<usize>,
992 ) -> Result<
993 impl Stream<Item = Result<TickItem, DataProviderError<Self::Error>>> + 'static,
994 DataProviderError<Self::Error>,
995 > {
996 (**self).ticks(symbol, from_time, count)
997 }
998
999 fn currency_rate(
1000 &self,
1001 from: Currency,
1002 to: Currency,
1003 from_time: i64,
1004 ) -> Result<
1005 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
1006 DataProviderError<Self::Error>,
1007 > {
1008 (**self).currency_rate(from, to, from_time)
1009 }
1010
1011 fn financial(
1012 &self,
1013 symbol: String,
1014 financial_id: String,
1015 period: String,
1016 currency: Option<Currency>,
1017 from_time: i64,
1018 ) -> Result<
1019 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
1020 DataProviderError<Self::Error>,
1021 > {
1022 (**self).financial(symbol, financial_id, period, currency, from_time)
1023 }
1024
1025 fn earnings(
1026 &self,
1027 symbol: String,
1028 field: EarningsField,
1029 currency: Option<Currency>,
1030 from_time: i64,
1031 ) -> Result<
1032 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
1033 DataProviderError<Self::Error>,
1034 > {
1035 (**self).earnings(symbol, field, currency, from_time)
1036 }
1037
1038 fn dividends(
1039 &self,
1040 symbol: String,
1041 field: DividendsField,
1042 currency: Option<Currency>,
1043 from_time: i64,
1044 ) -> Result<
1045 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
1046 DataProviderError<Self::Error>,
1047 > {
1048 (**self).dividends(symbol, field, currency, from_time)
1049 }
1050
1051 fn economic(
1052 &self,
1053 country_code: String,
1054 field: String,
1055 from_time: i64,
1056 ) -> Result<
1057 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
1058 DataProviderError<Self::Error>,
1059 > {
1060 (**self).economic(country_code, field, from_time)
1061 }
1062
1063 fn splits(
1064 &self,
1065 symbol: String,
1066 field: SplitsField,
1067 from_time: i64,
1068 ) -> Result<
1069 impl Stream<Item = Result<AuxDataItem, DataProviderError<Self::Error>>> + 'static,
1070 DataProviderError<Self::Error>,
1071 > {
1072 (**self).splits(symbol, field, from_time)
1073 }
1074}
1075
1076#[async_trait(?Send)]
1085impl DataProvider for Vec<Candlestick> {
1086 type Error = std::convert::Infallible;
1087
1088 async fn symbol_info(
1089 &self,
1090 _symbol: String,
1091 _fields: SyminfoFields,
1092 ) -> Result<PartialSymbolInfo, DataProviderError<Self::Error>> {
1093 Ok(PartialSymbolInfo::default())
1094 }
1095
1096 fn candlesticks(
1097 &self,
1098 _symbol: String,
1099 _timeframe: TimeFrame,
1100 _from_time: i64,
1101 count: Option<usize>,
1102 ) -> Result<
1103 impl Stream<Item = Result<CandlestickItem, DataProviderError<Self::Error>>> + 'static,
1104 DataProviderError<Self::Error>,
1105 > {
1106 let bars = if let Some(count) = count {
1107 let start = self.len().saturating_sub(count);
1108 self[start..].to_vec()
1109 } else {
1110 self.clone()
1111 };
1112 let bar_items = bars.into_iter().map(|c| Ok(CandlestickItem::Bar(c)));
1113 let end = std::iter::once(Ok(CandlestickItem::HistoryEnd));
1114 Ok(futures_util::stream::iter(bar_items.chain(end)))
1115 }
1116}
1117
1118#[pin_project::pin_project]
1127struct SynthesizeTicksStream<S> {
1128 #[pin]
1129 raw: S,
1130 n: usize,
1132 history_ended: bool,
1134 acc: Option<Candlestick>,
1136 tick_count: usize,
1138 pending: std::collections::VecDeque<Result<CandlestickItem, InternalProviderError>>,
1140}
1141
1142impl<S> SynthesizeTicksStream<S> {
1143 fn new(raw: S, n: usize) -> Self {
1144 Self {
1145 raw,
1146 n,
1147 history_ended: false,
1148 acc: None,
1149 tick_count: 0,
1150 pending: std::collections::VecDeque::new(),
1151 }
1152 }
1153}
1154
1155impl<S> futures_util::Stream for SynthesizeTicksStream<S>
1156where
1157 S: futures_util::Stream<Item = Result<TickItem, InternalProviderError>>,
1158{
1159 type Item = Result<CandlestickItem, InternalProviderError>;
1160
1161 fn poll_next(
1162 self: std::pin::Pin<&mut Self>,
1163 cx: &mut std::task::Context<'_>,
1164 ) -> std::task::Poll<Option<Self::Item>> {
1165 use std::task::Poll;
1166
1167 let mut this = self.project();
1168
1169 loop {
1170 if let Some(item) = this.pending.pop_front() {
1171 return Poll::Ready(Some(item));
1173 }
1174
1175 let tick_item = match this.raw.as_mut().poll_next(cx) {
1177 Poll::Pending => return Poll::Pending,
1178 Poll::Ready(None) => {
1179 if *this.n > 1
1181 && let Some(bar) = this.acc.take()
1182 {
1183 return Poll::Ready(Some(Ok(CandlestickItem::Bar(bar))));
1184 }
1185 return Poll::Ready(None);
1186 }
1187 Poll::Ready(Some(item)) => item,
1188 };
1189
1190 match tick_item {
1191 Err(e) => return Poll::Ready(Some(Err(e))),
1192 Ok(TickItem::HistoryEnd) => {
1193 if *this.n > 1
1195 && let Some(bar) = this.acc.take()
1196 {
1197 this.pending.push_back(Ok(CandlestickItem::Bar(bar)));
1198 *this.tick_count = 0;
1199 }
1200 *this.history_ended = true;
1201 this.pending.push_back(Ok(CandlestickItem::HistoryEnd));
1202 }
1203 Ok(TickItem::Tick(tick)) => {
1204 if *this.n == 1 {
1205 this.pending
1207 .push_back(Ok(CandlestickItem::Bar(Candlestick::from_tick(tick))));
1208 } else {
1209 match this.acc {
1212 None => {
1213 let mut bar = Candlestick::from_tick(tick);
1214 bar.ask = f64::NAN;
1215 bar.bid = f64::NAN;
1216 *this.acc = Some(bar);
1217 *this.tick_count = 1;
1218 }
1219 Some(bar) => {
1220 bar.high = bar.high.max(tick.price);
1221 bar.low = bar.low.min(tick.price);
1222 bar.close = tick.price;
1223 bar.volume += tick.volume;
1224 *this.tick_count += 1;
1225 }
1226 }
1227
1228 if *this.history_ended {
1229 if let Some(bar) = *this.acc {
1231 this.pending.push_back(Ok(CandlestickItem::Bar(bar)));
1232 }
1233 if *this.tick_count >= *this.n {
1235 *this.acc = None;
1236 *this.tick_count = 0;
1237 }
1238 } else {
1239 if *this.tick_count >= *this.n {
1241 if let Some(bar) = this.acc.take() {
1242 this.pending.push_back(Ok(CandlestickItem::Bar(bar)));
1243 }
1244 *this.tick_count = 0;
1245 }
1246 }
1247 }
1248 }
1249 }
1250 }
1251 }
1252}
1253
1254fn synthesize_ticks<S>(raw: S, n: usize) -> SynthesizeTicksStream<S>
1256where
1257 S: futures_util::Stream<Item = Result<TickItem, InternalProviderError>>,
1258{
1259 SynthesizeTicksStream::new(raw, n)
1260}