use plotly_derive::FieldSetter;
use serde::Serialize;
use crate::{
color::NamedColor,
common::{
Calendar, Dim, Direction, HoverInfo, Label, LegendGroupTitle, Line, PlotType, Visible,
},
Trace,
};
#[serde_with::skip_serializing_none]
#[derive(Serialize, Debug, Clone, FieldSetter)]
pub struct Candlestick<T, O>
where
T: Serialize + Clone,
O: Serialize + Clone,
{
#[field_setter(default = "PlotType::Candlestick")]
r#type: PlotType,
x: Option<Vec<T>>,
open: Option<Vec<O>>,
high: Option<Vec<O>>,
low: Option<Vec<O>>,
close: Option<Vec<O>>,
name: Option<String>,
visible: Option<Visible>,
#[serde(rename = "showlegend")]
show_legend: Option<bool>,
#[serde(rename = "legendgroup")]
legend_group: Option<String>,
#[serde(rename = "legendgrouptitle")]
legend_group_title: Option<LegendGroupTitle>,
opacity: Option<f64>,
text: Option<Dim<String>>,
#[serde(rename = "hovertext")]
hover_text: Option<Dim<String>>,
#[serde(rename = "hoverinfo")]
hover_info: Option<HoverInfo>,
#[serde(rename = "xaxis")]
x_axis: Option<String>,
#[serde(rename = "yaxis")]
y_axis: Option<String>,
line: Option<Line>,
#[serde(rename = "whiskerwidth")]
whisker_width: Option<f64>,
increasing: Option<Direction>,
decreasing: Option<Direction>,
#[serde(rename = "hoverlabel")]
hover_label: Option<Label>,
#[serde(rename = "xcalendar")]
x_calendar: Option<Calendar>,
}
impl<T, O> Candlestick<T, O>
where
T: Serialize + Clone,
O: Serialize + Clone,
{
pub fn new(x: Vec<T>, open: Vec<O>, high: Vec<O>, low: Vec<O>, close: Vec<O>) -> Box<Self> {
let iline = Line::new().width(1.0).color(NamedColor::Green);
let dline = Line::new().width(1.0).color(NamedColor::Red);
Box::new(Candlestick {
x: Some(x),
open: Some(open),
high: Some(high),
low: Some(low),
close: Some(close),
increasing: Some(Direction::Increasing { line: iline }),
decreasing: Some(Direction::Decreasing { line: dline }),
..Default::default()
})
}
}
impl<X, Y> Trace for Candlestick<X, Y>
where
X: Serialize + Clone,
Y: Serialize + Clone,
{
fn to_json(&self) -> String {
serde_json::to_string(self).unwrap()
}
}
#[cfg(test)]
mod tests {
use serde_json::{json, to_value};
use super::*;
#[test]
fn default_candlestick() {
let trace: Candlestick<i32, i32> = Candlestick::default();
let expected = json!({"type": "candlestick"}).to_string();
assert_eq!(trace.to_json(), expected);
}
#[test]
fn serialize_candlestick() {
let trace = Candlestick::new(
vec!["2020-05-20", "2020-05-21"],
vec![5, 6],
vec![9, 11],
vec![2, 3],
vec![6, 5],
)
.name("candlestick_trace")
.visible(Visible::True)
.show_legend(false)
.legend_group("group_1")
.legend_group_title("Legend Group Title")
.opacity(0.3)
.text_array(vec!["text", "here"])
.text("text here")
.hover_text_array(vec!["hover", "text"])
.hover_text("hover text")
.hover_info(HoverInfo::Skip)
.x_axis("x1")
.y_axis("y1")
.line(Line::new())
.whisker_width(0.4)
.increasing(Direction::Increasing { line: Line::new() })
.decreasing(Direction::Decreasing { line: Line::new() })
.hover_label(Label::new())
.x_calendar(Calendar::DiscWorld);
let expected = json!({
"type": "candlestick",
"x": ["2020-05-20", "2020-05-21"],
"open": [5, 6],
"high": [9, 11],
"low": [2, 3],
"close": [6, 5],
"name": "candlestick_trace",
"visible": true,
"showlegend": false,
"legendgroup": "group_1",
"legendgrouptitle": {"text": "Legend Group Title"},
"opacity": 0.3,
"text": "text here",
"hovertext": "hover text",
"hoverinfo": "skip",
"xaxis": "x1",
"yaxis": "y1",
"line": {},
"whiskerwidth": 0.4,
"increasing": {"line": {}},
"decreasing": {"line": {}},
"hoverlabel": {},
"xcalendar": "discworld"
});
assert_eq!(to_value(trace).unwrap(), expected);
}
}