use pine_builtin_macro::BuiltinFunction;
use pine_core::{
Color, PineOutput, Plot as PlotStruct, PlotOutput, Plotarrow as PlotarrowStruct,
Plotbar as PlotbarStruct, Plotcandle as PlotcandleStruct, Plotchar as PlotcharStruct,
Plotshape as PlotshapeStruct,
};
use pine_interpreter::{Builtin, BuiltinFn, Interpreter, RuntimeError, Value};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(BuiltinFunction)]
#[builtin(name = "plot")]
struct Plot<O: PineOutput + PlotOutput> {
series: Value<O>,
#[arg(default = "")]
title: String,
#[arg(default = None)]
color: Option<Color>,
#[arg(default = 1.0)]
linewidth: f64,
#[arg(default = "line")]
style: String,
#[arg(default = false)]
trackprice: bool,
#[arg(default = 0.0)]
histbase: f64,
#[arg(default = 0.0)]
offset: f64,
#[arg(default = false)]
join: bool,
#[arg(default = true)]
editable: bool,
#[arg(default = None)]
show_last: Option<f64>,
#[arg(default = "all")]
display: String,
#[arg(default = None)]
format: Option<String>,
#[arg(default = None)]
precision: Option<f64>,
#[arg(default = false)]
force_overlay: bool,
#[arg(default = "solid")]
linestyle: String,
}
impl<O: PineOutput + PlotOutput> Plot<O> {
fn execute(&self, ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
let plot = PlotStruct {
series: self.series.as_number()?,
title: self.title.clone(),
color: self.color.clone(),
linewidth: self.linewidth,
style: self.style.clone(),
trackprice: self.trackprice,
histbase: self.histbase,
offset: self.offset,
join: self.join,
editable: self.editable,
show_last: self.show_last,
display: self.display.clone(),
format: self.format.clone(),
precision: self.precision,
force_overlay: self.force_overlay,
linestyle: self.linestyle.clone(),
};
ctx.output.add_plot(plot);
Ok(Value::Na)
}
}
#[derive(BuiltinFunction)]
#[builtin(name = "plotarrow")]
struct Plotarrow<O: PineOutput + PlotOutput> {
series: Value<O>,
#[arg(default = "")]
title: String,
#[arg(default = None)]
colorup: Option<Color>,
#[arg(default = None)]
colordown: Option<Color>,
#[arg(default = 0.0)]
offset: f64,
#[arg(default = 5.0)]
minheight: f64,
#[arg(default = 100.0)]
maxheight: f64,
#[arg(default = true)]
editable: bool,
#[arg(default = None)]
show_last: Option<f64>,
#[arg(default = "all")]
display: String,
#[arg(default = None)]
format: Option<String>,
#[arg(default = None)]
precision: Option<f64>,
#[arg(default = false)]
force_overlay: bool,
}
impl<O: PineOutput + PlotOutput> Plotarrow<O> {
fn execute(&self, ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
let plotarrow = PlotarrowStruct {
series: self.series.as_number()?,
title: self.title.clone(),
colorup: self.colorup.clone(),
colordown: self.colordown.clone(),
offset: self.offset,
minheight: self.minheight,
maxheight: self.maxheight,
editable: self.editable,
show_last: self.show_last,
display: self.display.clone(),
format: self.format.clone(),
precision: self.precision,
force_overlay: self.force_overlay,
};
ctx.output.add_plotarrow(plotarrow);
Ok(Value::Na)
}
}
#[derive(BuiltinFunction)]
#[builtin(name = "plotbar")]
struct Plotbar<O: PineOutput + PlotOutput> {
open: Value<O>,
high: Value<O>,
low: Value<O>,
close: Value<O>,
#[arg(default = "")]
title: String,
#[arg(default = None)]
color: Option<Color>,
#[arg(default = true)]
editable: bool,
#[arg(default = None)]
show_last: Option<f64>,
#[arg(default = "all")]
display: String,
#[arg(default = None)]
format: Option<String>,
#[arg(default = None)]
precision: Option<f64>,
#[arg(default = false)]
force_overlay: bool,
}
impl<O: PineOutput + PlotOutput> Plotbar<O> {
fn execute(&self, ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
let plotbar = PlotbarStruct {
open: self.open.as_number()?,
high: self.high.as_number()?,
low: self.low.as_number()?,
close: self.close.as_number()?,
title: self.title.clone(),
color: self.color.clone(),
editable: self.editable,
show_last: self.show_last,
display: self.display.clone(),
format: self.format.clone(),
precision: self.precision,
force_overlay: self.force_overlay,
};
ctx.output.add_plotbar(plotbar);
Ok(Value::Na)
}
}
#[derive(BuiltinFunction)]
#[builtin(name = "plotcandle")]
struct Plotcandle<O: PineOutput + PlotOutput> {
open: Value<O>,
high: Value<O>,
low: Value<O>,
close: Value<O>,
#[arg(default = "")]
title: String,
#[arg(default = None)]
color: Option<Color>,
#[arg(default = None)]
wickcolor: Option<Color>,
#[arg(default = true)]
editable: bool,
#[arg(default = None)]
show_last: Option<f64>,
#[arg(default = None)]
bordercolor: Option<Color>,
#[arg(default = "all")]
display: String,
#[arg(default = None)]
format: Option<String>,
#[arg(default = None)]
precision: Option<f64>,
#[arg(default = false)]
force_overlay: bool,
}
impl<O: PineOutput + PlotOutput> Plotcandle<O> {
fn execute(&self, ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
let plotcandle = PlotcandleStruct {
open: self.open.as_number()?,
high: self.high.as_number()?,
low: self.low.as_number()?,
close: self.close.as_number()?,
title: self.title.clone(),
color: self.color.clone(),
wickcolor: self.wickcolor.clone(),
editable: self.editable,
show_last: self.show_last,
bordercolor: self.bordercolor.clone(),
display: self.display.clone(),
format: self.format.clone(),
precision: self.precision,
force_overlay: self.force_overlay,
};
ctx.output.add_plotcandle(plotcandle);
Ok(Value::Na)
}
}
#[derive(BuiltinFunction)]
#[builtin(name = "plotchar")]
struct Plotchar<O: PineOutput + PlotOutput> {
series: Value<O>,
#[arg(default = "")]
title: String,
#[arg(default = "★")]
char: String,
#[arg(default = "bottom")]
location: String,
#[arg(default = None)]
color: Option<Color>,
#[arg(default = 0.0)]
offset: f64,
#[arg(default = "")]
text: String,
#[arg(default = None)]
textcolor: Option<Color>,
#[arg(default = true)]
editable: bool,
#[arg(default = "auto")]
size: String,
#[arg(default = None)]
show_last: Option<f64>,
#[arg(default = "all")]
display: String,
#[arg(default = None)]
format: Option<String>,
#[arg(default = None)]
precision: Option<f64>,
#[arg(default = false)]
force_overlay: bool,
}
impl<O: PineOutput + PlotOutput> Plotchar<O> {
fn execute(&self, ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
let plotchar = PlotcharStruct {
series: self.series.as_number()?,
title: self.title.clone(),
char: self.char.clone(),
location: self.location.clone(),
color: self.color.clone(),
offset: self.offset,
text: self.text.clone(),
textcolor: self.textcolor.clone(),
editable: self.editable,
size: self.size.clone(),
show_last: self.show_last,
display: self.display.clone(),
format: self.format.clone(),
precision: self.precision,
force_overlay: self.force_overlay,
};
ctx.output.add_plotchar(plotchar);
Ok(Value::Na)
}
}
#[derive(BuiltinFunction)]
#[builtin(name = "plotshape")]
struct Plotshape<O: PineOutput + PlotOutput> {
series: Value<O>,
#[arg(default = "")]
title: String,
#[arg(default = "circle")]
style: String,
#[arg(default = "bottom")]
location: String,
#[arg(default = None)]
color: Option<Color>,
#[arg(default = 0.0)]
offset: f64,
#[arg(default = "")]
text: String,
#[arg(default = None)]
textcolor: Option<Color>,
#[arg(default = true)]
editable: bool,
#[arg(default = "auto")]
size: String,
#[arg(default = None)]
show_last: Option<f64>,
#[arg(default = "all")]
display: String,
#[arg(default = None)]
format: Option<String>,
#[arg(default = None)]
precision: Option<f64>,
#[arg(default = false)]
force_overlay: bool,
}
impl<O: PineOutput + PlotOutput> Plotshape<O> {
fn execute(&self, ctx: &mut Interpreter<O>) -> Result<Value<O>, RuntimeError> {
let plotshape = PlotshapeStruct {
series: self.series.as_number()?,
title: self.title.clone(),
style: self.style.clone(),
location: self.location.clone(),
color: self.color.clone(),
offset: self.offset,
text: self.text.clone(),
textcolor: self.textcolor.clone(),
editable: self.editable,
size: self.size.clone(),
show_last: self.show_last,
display: self.display.clone(),
format: self.format.clone(),
precision: self.precision,
force_overlay: self.force_overlay,
};
ctx.output.add_plotshape(plotshape);
Ok(Value::Na)
}
}
pub fn register_plot_functions<O: PineOutput + PlotOutput>() -> HashMap<String, Value<O>> {
let mut functions: HashMap<String, Value<O>> = HashMap::new();
let mut plot_fields: HashMap<String, Value<O>> = HashMap::new();
for style in [
"line",
"linebr",
"stepline",
"stepline_diamond",
"steplinebr",
"histogram",
"cross",
"area",
"areabr",
"columns",
"circles",
] {
plot_fields.insert(format!("style_{style}"), Value::String(style.to_string()));
}
for linestyle in ["solid", "dotted", "dashed"] {
plot_fields.insert(
format!("linestyle_{linestyle}"),
Value::String(linestyle.to_string()),
);
}
functions.insert(
"plot".to_string(),
Value::Object {
type_name: "plot".to_string(),
fields: Rc::new(RefCell::new(plot_fields)),
call: Some(Builtin {
call: Rc::new(Plot::<O>::builtin_fn) as BuiltinFn<O>,
signature: Plot::<O>::signature(),
}),
value: None,
},
);
functions.insert("plotarrow".to_string(), Plotarrow::<O>::builtin_value());
functions.insert("plotbar".to_string(), Plotbar::<O>::builtin_value());
functions.insert("plotcandle".to_string(), Plotcandle::<O>::builtin_value());
functions.insert("plotchar".to_string(), Plotchar::<O>::builtin_value());
functions.insert("plotshape".to_string(), Plotshape::<O>::builtin_value());
functions
}