1use plotly_derive::FieldSetter;
4use serde::Serialize;
5
6use crate::{
7 common::{
8 Calendar, Dim, Direction, HoverInfo, Label, LegendGroupTitle, Line, PlotType, Visible,
9 },
10 Trace,
11};
12
13#[serde_with::skip_serializing_none]
40#[derive(Serialize, Debug, Clone, FieldSetter)]
41pub struct Ohlc<X, O>
42where
43 X: Serialize + Clone,
44 O: Serialize + Clone,
45{
46 #[field_setter(default = "PlotType::Ohlc")]
47 r#type: PlotType,
48 x: Option<Vec<X>>,
49 open: Option<Vec<O>>,
50 high: Option<Vec<O>>,
51 low: Option<Vec<O>>,
52 close: Option<Vec<O>>,
53 decreasing: Option<Direction>,
54 #[serde(rename = "hoverinfo")]
55 hover_info: Option<HoverInfo>,
56 #[serde(rename = "hoverlabel")]
57 hover_label: Option<Label>,
58 #[serde(rename = "hovertext")]
59 hover_text: Option<Dim<String>>,
60 increasing: Option<Direction>,
61 #[serde(rename = "legendgroup")]
62 legend_group: Option<String>,
63 #[serde(rename = "legendgrouptitle")]
64 legend_group_title: Option<LegendGroupTitle>,
65 line: Option<Line>,
66 name: Option<String>,
67 opacity: Option<f64>,
68 #[serde(rename = "showlegend")]
69 show_legend: Option<bool>,
70 text: Option<Dim<String>>,
71 #[serde(rename = "tickwidth")]
72 tick_width: Option<f64>,
73 visible: Option<Visible>,
74 #[serde(rename = "xcalendar")]
75 x_calendar: Option<Calendar>,
76}
77
78impl<X, O> Ohlc<X, O>
79where
80 X: Serialize + Clone,
81 O: Serialize + Clone,
82{
83 pub fn new(x: Vec<X>, open: Vec<O>, high: Vec<O>, low: Vec<O>, close: Vec<O>) -> Box<Self> {
84 Box::new(Ohlc {
85 r#type: PlotType::Ohlc,
86 x: Some(x),
87 open: Some(open),
88 high: Some(high),
89 low: Some(low),
90 close: Some(close),
91 ..Default::default()
92 })
93 }
94}
95
96impl<X, O> Trace for Ohlc<X, O>
97where
98 X: Serialize + Clone,
99 O: Serialize + Clone,
100{
101 fn to_json(&self) -> String {
102 serde_json::to_string(self).unwrap()
103 }
104}
105
106#[cfg(test)]
107mod test {
108 use serde_json::{json, to_value};
109
110 use super::*;
111
112 #[test]
113 fn test_serialize_default_ohlc() {
114 let trace = Ohlc::<u32, u32>::default();
115 let expected = json!({"type": "ohlc"});
116
117 assert_eq!(to_value(trace).unwrap(), expected);
118 }
119
120 #[test]
121 fn test_serialize_ohlc() {
122 let trace = Ohlc::new(
123 vec![0, 1],
124 vec![5.0, 6.0],
125 vec![10.0, 15.0],
126 vec![4.0, 2.0],
127 vec![6.0, 13.0],
128 )
129 .decreasing(Direction::Decreasing { line: Line::new() })
130 .hover_info(HoverInfo::X)
131 .hover_label(Label::new())
132 .hover_text_array(vec!["1", "2"])
133 .hover_text("1")
134 .increasing(Direction::Increasing { line: Line::new() })
135 .legend_group("legendgroup")
136 .legend_group_title(LegendGroupTitle::new("Legend Group Title"))
137 .line(Line::new())
138 .name("ohlc_trace")
139 .opacity(0.4)
140 .show_legend(true)
141 .text_array(vec!["3", "4"])
142 .text("3")
143 .tick_width(0.1)
144 .visible(Visible::LegendOnly)
145 .x_calendar(Calendar::Nepali);
146
147 let expected = json!({
148 "type": "ohlc",
149 "x": [0, 1],
150 "open": [5.0, 6.0],
151 "high": [10.0, 15.0],
152 "low": [4.0, 2.0],
153 "close": [6.0, 13.0],
154 "decreasing": {"line": {}},
155 "hoverinfo": "x",
156 "hoverlabel": {},
157 "hovertext": "1",
158 "increasing": {"line": {}},
159 "legendgroup": "legendgroup",
160 "legendgrouptitle": {"text": "Legend Group Title"},
161 "line": {},
162 "name": "ohlc_trace",
163 "opacity": 0.4,
164 "showlegend": true,
165 "text": "3",
166 "tickwidth": 0.1,
167 "visible": "legendonly",
168 "xcalendar": "nepali"
169 });
170
171 assert_eq!(to_value(trace).unwrap(), expected);
172 }
173}