Skip to main content

flowsurface_data/chart/kline/indicators/core/
output.rs

1use crate::chart::kline::IndicatorInstanceId;
2use indicator_engine::{OutputPrecision, ReadoutBehavior};
3
4/// The value domain supported by a declared indicator output.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub enum OutputValueType {
7    Number,
8    Boolean,
9    Ohlc,
10    Range,
11}
12
13/// A stable, definition-local output channel declaration.
14#[derive(Debug, Clone, PartialEq)]
15pub struct OutputChannelSpec {
16    pub id: String,
17    pub label: String,
18    pub value_type: OutputValueType,
19    pub precision: OutputPrecision,
20    pub line_width: f32,
21    pub readout: ReadoutBehavior,
22    pub style_slot: Option<String>,
23    pub offset_bars: i32,
24    pub style_by: Option<String>,
25    pub independent_scale: bool,
26}
27
28/// A value emitted by an indicator for one chart bar.
29#[derive(Debug, Clone, Copy, PartialEq)]
30pub enum OutputValue {
31    Number(f64),
32    Boolean(bool),
33}
34
35impl OutputValue {
36    pub const fn value_type(self) -> OutputValueType {
37        match self {
38            Self::Number(_) => OutputValueType::Number,
39            Self::Boolean(_) => OutputValueType::Boolean,
40        }
41    }
42
43    pub fn as_f64(self) -> f64 {
44        match self {
45            Self::Number(value) => value,
46            Self::Boolean(value) => f64::from(value),
47        }
48    }
49
50    pub fn as_number(self) -> Option<f64> {
51        match self {
52            Self::Number(value) => value.is_finite().then_some(value),
53            Self::Boolean(_) => None,
54        }
55    }
56
57    pub fn as_boolean(self) -> Option<bool> {
58        match self {
59            Self::Boolean(value) => Some(value),
60            Self::Number(_) => None,
61        }
62    }
63}
64
65/// A reference to one named output of one indicator instance.
66#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
67pub struct IndicatorOutputRef {
68    pub instance_id: IndicatorInstanceId,
69    pub channel_id: String,
70}
71
72impl IndicatorOutputRef {
73    pub fn new(instance_id: IndicatorInstanceId, channel_id: impl Into<String>) -> Self {
74        Self {
75            instance_id,
76            channel_id: channel_id.into(),
77        }
78    }
79
80    pub fn is_valid(&self) -> bool {
81        !self.channel_id.trim().is_empty()
82    }
83}