1use crate::{errors::MarketResult, indicators::EnhancedMarketSeries, publishers::Publisher};
4use chrono::NaiveDate;
5use serde::{Deserialize, Serialize};
6use std::fmt;
7use std::str::FromStr;
8
9pub struct MarketClient<T: Publisher> {
11 pub site: T,
12}
13
14impl<T: Publisher> MarketClient<T> {
15 pub fn new(site: T) -> Self {
16 MarketClient { site }
17 }
18
19 pub fn create_endpoint(mut self) -> MarketResult<Self> {
21 self.site.create_endpoint()?;
22 Ok(self)
23 }
24
25 #[cfg(feature = "use-async")]
27 pub async fn get_data(mut self) -> MarketResult<Self> {
28 self.site.get_data().await?;
29 Ok(self)
30 }
31
32 #[cfg(feature = "use-sync")]
34 pub fn get_data(mut self) -> MarketResult<Self> {
35 self.site.get_data()?;
36 Ok(self)
37 }
38
39 pub fn to_writer(&self, writer: impl std::io::Write) -> MarketResult<()> {
41 self.site.to_writer(writer)?;
42 Ok(())
43 }
44
45 pub fn transform_data(&mut self) -> Vec<MarketResult<MarketSeries>> {
47 self.site.transform_data()
48 }
49}
50
51#[derive(Debug, Serialize, Deserialize)]
53pub struct MarketSeries {
54 pub symbol: String,
56 pub interval: Interval,
58 pub data: Vec<Series>,
60}
61
62#[derive(Debug, Serialize, Deserialize)]
64pub struct Series {
65 pub date: NaiveDate,
67 pub open: f32,
69 pub close: f32,
71 pub high: f32,
73 pub low: f32,
75 pub volume: f32,
77}
78
79#[derive(Debug, Serialize, Deserialize, Default, Clone)]
81pub enum Interval {
82 Min1,
84 Min5,
86 Min15,
88 Min30,
90 Hour1,
92 Hour2,
94 Hour4,
96 #[default]
98 Daily,
99 Weekly,
101 Monthly,
103}
104
105impl MarketSeries {
106 pub fn enhance_data(self) -> EnhancedMarketSeries {
107 EnhancedMarketSeries {
108 symbol: self.symbol,
109 interval: self.interval,
110 series: self.data,
111 asks: Vec::new(),
112 indicators: Default::default(),
113 }
114 }
115}
116
117impl fmt::Display for MarketSeries {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(
120 f,
121 "MarketSeries: Symbol = {}, Interval = {}, Series =\n{}",
122 self.symbol,
123 self.interval,
124 self.data
125 .iter()
126 .map(|series| format!(" {}", series))
127 .collect::<Vec<String>>()
128 .join("\n")
129 )
130 }
131}
132
133impl fmt::Display for Series {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 write!(
136 f,
137 "Date: {}, Open: {}, Close: {}, High: {}, Low: {}, Volume: {}",
138 self.date, self.open, self.close, self.high, self.low, self.volume
139 )
140 }
141}
142
143impl fmt::Display for Interval {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 let interval_str = match self {
146 Interval::Min1 => "1 minute",
147 Interval::Min5 => "5 minutes",
148 Interval::Min15 => "15 minutes",
149 Interval::Min30 => "30 minutes",
150 Interval::Hour1 => "1 hour",
151 Interval::Hour2 => "2 hours",
152 Interval::Hour4 => "4 hours",
153 Interval::Daily => "Daily",
154 Interval::Weekly => "Weekly",
155 Interval::Monthly => "Monthly",
156 };
157
158 write!(f, "{}", interval_str)
159 }
160}
161
162impl std::str::FromStr for Interval {
165 type Err = &'static str;
166
167 fn from_str(s: &str) -> Result<Self, Self::Err> {
168 match s.to_lowercase().as_str() {
169 "1min" => Ok(Interval::Min1),
170 "5min" => Ok(Interval::Min5),
171 "15min" => Ok(Interval::Min15),
172 "30min" => Ok(Interval::Min30),
173 "60min" => Ok(Interval::Hour1),
174 "1h" => Ok(Interval::Hour1),
175 "2h" => Ok(Interval::Hour2),
176 "4h" => Ok(Interval::Hour4),
177 "1day" => Ok(Interval::Daily),
178 "1week" => Ok(Interval::Weekly),
179 "1month" => Ok(Interval::Monthly),
180 _ => Err("Invalid interval string"),
181 }
182 }
183}
184
185impl From<String> for Interval {
186 fn from(s: String) -> Self {
187 Interval::from_str(&s).unwrap_or_else(|_| Interval::Daily)
188 }
189}