use crate::model::Bar;
use crate::studies::{Indicator, IndicatorValue};
use crate::tokens::DESIGN_TOKENS;
use egui::Color32;
pub type CalculateFn = Box<dyn Fn(&[Bar]) -> Vec<IndicatorValue> + Send>;
pub struct CustomIndicator {
name: String,
desc: String,
calculate_fn: CalculateFn,
values: Vec<IndicatorValue>,
colors: Vec<Color32>,
is_overlay: bool,
line_cnt: usize,
line_names: Vec<String>,
visible: bool,
}
impl CustomIndicator {
pub fn new(name: impl Into<String>, calculate_fn: CalculateFn) -> Self {
let name = name.into();
Self {
line_names: vec![name.clone()],
name,
desc: String::new(),
calculate_fn,
values: Vec::new(),
colors: vec![DESIGN_TOKENS.semantic.extended.caution], is_overlay: true,
line_cnt: 1,
visible: true,
}
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.desc = desc.into();
self
}
pub fn with_color(mut self, color: Color32) -> Self {
self.colors = vec![color];
self
}
pub fn with_colors(mut self, colors: Vec<Color32>) -> Self {
self.colors = colors;
self
}
pub fn with_overlay(mut self, is_overlay: bool) -> Self {
self.is_overlay = is_overlay;
self
}
pub fn with_line_cnt(mut self, count: usize) -> Self {
self.line_cnt = count;
self
}
pub fn with_line_names(mut self, names: Vec<String>) -> Self {
self.line_names = names;
self
}
}
impl Indicator for CustomIndicator {
fn name(&self) -> &str {
&self.name
}
fn desc(&self) -> &str {
&self.desc
}
fn calculate(&mut self, data: &[Bar]) {
self.values = (self.calculate_fn)(data);
}
fn values(&self) -> &[IndicatorValue] {
&self.values
}
fn colors(&self) -> Vec<Color32> {
self.colors.clone()
}
fn set_colors(&mut self, colors: Vec<Color32>) {
if !colors.is_empty() {
self.colors = colors;
}
}
fn is_overlay(&self) -> bool {
self.is_overlay
}
fn line_cnt(&self) -> usize {
self.line_cnt
}
fn line_names(&self) -> Vec<String> {
self.line_names.clone()
}
fn is_visible(&self) -> bool {
self.visible
}
fn set_visible(&mut self, visible: bool) {
self.visible = visible;
}
fn clone_box(&self) -> Box<dyn Indicator> {
Box::new(Self {
name: self.name.clone(),
desc: self.desc.clone(),
calculate_fn: Box::new(|_| Vec::new()), values: self.values.clone(),
colors: self.colors.clone(),
is_overlay: self.is_overlay,
line_cnt: self.line_cnt,
line_names: self.line_names.clone(),
visible: self.visible,
})
}
}