Skip to main content

tradingview/chart/
utils.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
5pub enum ExtendValue {
6    Right,
7    Left,
8    Both,
9    None,
10}
11
12#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
13pub enum YLocValue {
14    Price,
15    AboveBar,
16    BelowBar,
17}
18
19#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
20pub enum LabelStyleValue {
21    None,
22    XCross,
23    Cross,
24    TriangleUp,
25    TriangleDown,
26    Flag,
27    Circle,
28    ArrowUp,
29    ArrowDown,
30    LabelUp,
31    LabelDown,
32    LabelLeft,
33    LabelRight,
34    LabelLowerLeft,
35    LabelLowerRight,
36    LabelUpperLeft,
37    LabelUpperRight,
38    LabelCenter,
39    Square,
40    Diamond,
41}
42
43#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
44pub enum LineStyleValue {
45    Solid,
46    Dotted,
47    Dashed,
48    ArrowLeft,
49    ArrowRight,
50    ArrowBoth,
51}
52
53#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
54pub enum BoxStyleValue {
55    Solid,
56    Dotted,
57    Dashed,
58}
59
60#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
61pub struct GraphicLabel {
62    pub id: u64,
63    pub x: Option<f64>,
64    pub y: f64,
65    pub y_loc: YLocValue,
66    pub text: String,
67    pub style: LabelStyleValue,
68    pub color: u32,
69    pub text_color: u32,
70    pub size: String,
71    pub text_align: String,
72    pub tool_tip: String,
73}
74
75#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq)]
76pub struct GraphicLine {
77    pub id: u64,
78    pub x1: Option<f64>,
79    pub y1: f64,
80    pub x2: Option<f64>,
81    pub y2: f64,
82    pub extend: ExtendValue,
83    pub style: LineStyleValue,
84    pub color: u32,
85    pub width: f64,
86}
87
88#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
89pub struct GraphicBox {
90    pub id: u64,
91    pub x1: Option<f64>,
92    pub y1: f64,
93    pub x2: Option<f64>,
94    pub y2: f64,
95    pub color: u32,
96    pub bg_color: u32,
97    pub extend: ExtendValue,
98    pub style: BoxStyleValue,
99    pub width: f64,
100    pub text: String,
101    pub text_size: String,
102    pub text_color: u32,
103    pub text_v_align: String,
104    pub text_h_align: String,
105    pub text_wrap: String,
106}
107
108#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
109pub struct GraphicData {
110    pub labels: Vec<GraphicLabel>,
111    pub lines: Vec<GraphicLine>,
112    pub boxes: Vec<GraphicBox>,
113}
114
115fn translate_extend(value: &str) -> ExtendValue {
116    match value {
117        "r" => ExtendValue::Right,
118        "l" => ExtendValue::Left,
119        "b" => ExtendValue::Both,
120        "n" => ExtendValue::None,
121        _ => ExtendValue::None,
122    }
123}
124
125fn translate_y_loc(value: &str) -> YLocValue {
126    match value {
127        "pr" => YLocValue::Price,
128        "ab" => YLocValue::AboveBar,
129        "bl" => YLocValue::BelowBar,
130        _ => YLocValue::Price,
131    }
132}
133
134fn translate_label_style(value: &str) -> LabelStyleValue {
135    match value {
136        "n" => LabelStyleValue::None,
137        "xcr" => LabelStyleValue::XCross,
138        "cr" => LabelStyleValue::Cross,
139        "tup" => LabelStyleValue::TriangleUp,
140        "tdn" => LabelStyleValue::TriangleDown,
141        "flg" => LabelStyleValue::Flag,
142        "cir" => LabelStyleValue::Circle,
143        "aup" => LabelStyleValue::ArrowUp,
144        "adn" => LabelStyleValue::ArrowDown,
145        "lup" => LabelStyleValue::LabelUp,
146        "ldn" => LabelStyleValue::LabelDown,
147        "llf" => LabelStyleValue::LabelLeft,
148        "lrg" => LabelStyleValue::LabelRight,
149        "llwlf" => LabelStyleValue::LabelLowerLeft,
150        "llwrg" => LabelStyleValue::LabelLowerRight,
151        "luplf" => LabelStyleValue::LabelUpperLeft,
152        "luprg" => LabelStyleValue::LabelUpperRight,
153        "lcn" => LabelStyleValue::LabelCenter,
154        "sq" => LabelStyleValue::Square,
155        "dia" => LabelStyleValue::Diamond,
156        _ => LabelStyleValue::None,
157    }
158}
159
160fn translate_line_style(value: &str) -> LineStyleValue {
161    match value {
162        "sol" => LineStyleValue::Solid,
163        "dot" => LineStyleValue::Dotted,
164        "dsh" => LineStyleValue::Dashed,
165        "al" => LineStyleValue::ArrowLeft,
166        "ar" => LineStyleValue::ArrowRight,
167        "ab" => LineStyleValue::ArrowBoth,
168        _ => LineStyleValue::Solid,
169    }
170}
171
172fn translate_box_style(value: &str) -> BoxStyleValue {
173    match value {
174        "sol" => BoxStyleValue::Solid,
175        "dot" => BoxStyleValue::Dotted,
176        "dsh" => BoxStyleValue::Dashed,
177        _ => BoxStyleValue::Solid,
178    }
179}
180
181pub fn graphics_parser(data: &Value) -> GraphicData {
182    let indexes = data
183        .get("indexes")
184        .and_then(|v| v.as_array().cloned())
185        .unwrap_or_default();
186
187    let raw_graphic = data.get("graphic").unwrap_or(&Value::Null);
188
189    // Parse labels
190    let labels = if let Some(dwglabels) = raw_graphic.get("dwglabels").and_then(|v| v.as_object()) {
191        dwglabels
192            .values()
193            .filter_map(|l| {
194                Some(GraphicLabel {
195                    id: l.get("id")?.as_u64()?,
196                    x: l.get("x")
197                        .and_then(|x| x.as_u64())
198                        .and_then(|idx| indexes.get(idx as usize))
199                        .and_then(|v| v.as_f64()),
200                    y: l.get("y")?.as_f64()?,
201                    y_loc: translate_y_loc(l.get("yl")?.as_str()?),
202                    text: l.get("t")?.as_str()?.to_string(),
203                    style: translate_label_style(l.get("st")?.as_str()?),
204                    color: l.get("ci")?.as_u64()? as u32,
205                    text_color: l.get("tci")?.as_u64()? as u32,
206                    size: l.get("sz")?.as_str()?.to_string(),
207                    text_align: l.get("ta")?.as_str()?.to_string(),
208                    tool_tip: l.get("tt")?.as_str()?.to_string(),
209                })
210            })
211            .collect()
212    } else {
213        vec![]
214    };
215
216    // Parse lines
217    let lines = if let Some(dwglines) = raw_graphic.get("dwglines").and_then(|v| v.as_object()) {
218        dwglines
219            .values()
220            .filter_map(|l| {
221                Some(GraphicLine {
222                    id: l.get("id")?.as_u64()?,
223                    x1: l
224                        .get("x1")
225                        .and_then(|x| x.as_u64())
226                        .and_then(|idx| indexes.get(idx as usize))
227                        .and_then(|v| v.as_f64()),
228                    y1: l.get("y1")?.as_f64()?,
229                    x2: l
230                        .get("x2")
231                        .and_then(|x| x.as_u64())
232                        .and_then(|idx| indexes.get(idx as usize))
233                        .and_then(|v| v.as_f64()),
234                    y2: l.get("y2")?.as_f64()?,
235                    extend: translate_extend(l.get("ex")?.as_str()?),
236                    style: translate_line_style(l.get("st")?.as_str()?),
237                    color: l.get("ci")?.as_u64()? as u32,
238                    width: l.get("w")?.as_f64()?,
239                })
240            })
241            .collect()
242    } else {
243        vec![]
244    };
245
246    // Parse boxes
247    let boxes = if let Some(dwgboxes) = raw_graphic.get("dwgboxes").and_then(|v| v.as_object()) {
248        dwgboxes
249            .values()
250            .filter_map(|b| {
251                Some(GraphicBox {
252                    id: b.get("id")?.as_u64()?,
253                    x1: b
254                        .get("x1")
255                        .and_then(|x| x.as_u64())
256                        .and_then(|idx| indexes.get(idx as usize))
257                        .and_then(|v| v.as_f64()),
258                    y1: b.get("y1")?.as_f64()?,
259                    x2: b
260                        .get("x2")
261                        .and_then(|x| x.as_u64())
262                        .and_then(|idx| indexes.get(idx as usize))
263                        .and_then(|v| v.as_f64()),
264                    y2: b.get("y2")?.as_f64()?,
265                    color: b.get("c")?.as_u64()? as u32,
266                    bg_color: b.get("bc")?.as_u64()? as u32,
267                    extend: translate_extend(b.get("ex")?.as_str()?),
268                    style: translate_box_style(b.get("st")?.as_str()?),
269                    width: b.get("w")?.as_f64()?,
270                    text: b.get("t")?.as_str()?.to_string(),
271                    text_size: b.get("ts")?.as_str()?.to_string(),
272                    text_color: b.get("tc")?.as_u64()? as u32,
273                    text_v_align: b.get("tva")?.as_str()?.to_string(),
274                    text_h_align: b.get("tha")?.as_str()?.to_string(),
275                    text_wrap: b.get("tw")?.as_str()?.to_string(),
276                })
277            })
278            .collect()
279    } else {
280        vec![]
281    };
282
283    GraphicData {
284        labels,
285        lines,
286        boxes,
287    }
288}