use crate::common::validate_inputs;
pub use crate::indicator_types::TIndicatorState;
use crate::indicators::homodynediscriminator;
use crate::indicators::msw;
use crate::ring_buffer::fixed_single_buffer::FixedMirrorBuffer;
use crate::types::{DisplayGroup, DisplayType, IndicatorError, IndicatorType, Info};
use serde::{Deserialize, Serialize};
#[cfg(feature = "simd_assets")]
pub use crate::indicators::simd_indicators::adaptivemsw_simd::indicator_by_assets;
#[cfg(feature = "simd_assets")]
pub mod by_assets {
pub use crate::indicators::simd_indicators::adaptivemsw_simd::indicator_by_assets as indicator;
}
pub const INPUTS_WIDTH: usize = 1;
pub const OPTIONS_WIDTH: usize = 0;
pub const INFO: Info = Info {
name: "adaptivemsw",
full_name: "Adaptive MESA Sine Wave",
indicator_type: IndicatorType::Cycle,
inputs: &["real"],
options: &[],
outputs: &["sine", "lead_sine"],
optional_outputs: &["dc_period"],
display_groups: &[
DisplayGroup {
offset: None,
id: "adaptivemsw",
label: "Adaptive MESA Sine Wave",
display_type: DisplayType::Indicator,
outputs: &["sine", "lead_sine"],
},
DisplayGroup {
offset: None,
id: "adaptivemsw_dc_period",
label: "Adaptive MSW Dominant Cycle Period",
display_type: DisplayType::Indicator,
outputs: &["dc_period"],
},
],
};
#[derive(Serialize, Deserialize)]
pub struct State {
pub hd: homodynediscriminator::State,
pub price_buf: FixedMirrorBuffer<f64, 50>,
}
impl State {
pub fn new() -> Self {
Self {
hd: homodynediscriminator::State::new(),
price_buf: FixedMirrorBuffer::new(),
}
}
pub fn init_state(
real: &[f64],
sine_line: &mut [f64],
lead_line: &mut [f64],
dc_period_line: &mut [f64],
) -> Self {
let mut state = Self::new();
let mut i = 0;
while !state.hd.all_buffers_full() {
state.hd.calc(real[i]);
state.price_buf.push(real[i]);
i += 1;
}
let (sine, lead) = unsafe { state.calc_unchecked(real[i]) };
sine_line[0] = sine;
lead_line[0] = lead;
let (_, want_dc) = crate::calc_want_flags!(dc_period_line);
crate::store_optional_outputs!(0, want_dc, dc_period_line => state.hd.smooth_period);
state
}
#[inline(always)]
pub fn calc(&mut self, price: f64) -> (f64, f64) {
let dc = self.hd.calc(price);
self.price_buf.push(price);
if !self.hd.all_buffers_full() {
return (0.0, 0.0);
}
self.apply_dft(dc)
}
#[inline(always)]
pub unsafe fn calc_unchecked(&mut self, price: f64) -> (f64, f64) {
let dc = self.hd.calc_unchecked(price);
self.price_buf.push(price);
self.apply_dft(dc)
}
#[inline(always)]
fn apply_dft(&self, dc: f64) -> (f64, f64) {
let period = ((dc + 0.5) as usize).clamp(6, self.price_buf.len().min(50));
let (cos_tw, sin_tw) = msw::twiddles_for_period(period);
let (rp, ip) =
msw::dot_product_simd::<8>(self.price_buf.get_slice_by_period(period), cos_tw, sin_tw);
msw::phase_from_rp_ip(rp, ip)
}
}
impl Default for State {
fn default() -> Self {
Self::new()
}
}
#[derive(Serialize, Deserialize)]
pub struct IndicatorState {
state: State,
}
impl IndicatorState {
pub fn new(state: State) -> Self {
Self { state }
}
}
impl TIndicatorState<INPUTS_WIDTH> for IndicatorState {
fn batch_indicator(
&mut self,
inputs: &[&[f64]; INPUTS_WIDTH],
optional_outputs: Option<&[bool]>,
) -> Result<Vec<Vec<f64>>, IndicatorError> {
validate_inputs(inputs, 1)?;
let len = inputs[0].len();
let (mut sine_line, mut lead_line) =
(crate::uninit_vec!(f64, len), crate::uninit_vec!(f64, len));
let mut dc_period_line = crate::init_optional_outputs!(
optional_outputs, &[false],
dc_period_line: len
);
cycle(
inputs[0],
&mut self.state,
&mut sine_line,
&mut lead_line,
&mut dc_period_line,
);
Ok(vec![sine_line, lead_line, dc_period_line])
}
}
pub fn min_data(_options: &[f64]) -> usize {
23
}
pub fn output_length(data_len: usize, options: &[f64]) -> usize {
data_len.saturating_sub(min_data(options) - 1)
}
pub fn indicator(
inputs: &[&[f64]; INPUTS_WIDTH],
options: &[f64; OPTIONS_WIDTH],
optional_outputs: Option<&[bool]>,
) -> Result<(Vec<Vec<f64>>, IndicatorState), IndicatorError> {
validate_inputs(inputs, min_data(options))?;
let real = inputs[0];
let capacity = output_length(real.len(), options);
let (mut sine_line, mut lead_line) = (
crate::uninit_vec!(f64, capacity),
crate::uninit_vec!(f64, capacity),
);
let mut dc_period_line = crate::init_optional_outputs!(
optional_outputs, &[false],
dc_period_line: capacity
);
let mut state = State::init_state(real, &mut sine_line, &mut lead_line, &mut dc_period_line);
let real_tail = &real[min_data(options)..];
let (_, want_dc) = crate::calc_want_flags!(dc_period_line);
let dc_tail = if want_dc {
&mut dc_period_line[1..]
} else {
&mut dc_period_line[..]
};
cycle(
real_tail,
&mut state,
&mut sine_line[1..],
&mut lead_line[1..],
dc_tail,
);
Ok((
vec![sine_line, lead_line, dc_period_line],
IndicatorState::new(state),
))
}
fn cycle(
real: &[f64],
state: &mut State,
sine_line: &mut [f64],
lead_line: &mut [f64],
dc_period_line: &mut [f64],
) {
let (has_optional, want_dc) = crate::calc_want_flags!(dc_period_line);
for i in 0..real.len() {
let (sine, lead) = unsafe { state.calc_unchecked(*real.get_unchecked(i)) };
unsafe {
*sine_line.get_unchecked_mut(i) = sine;
*lead_line.get_unchecked_mut(i) = lead;
}
if has_optional {
crate::store_optional_outputs!(i, want_dc, dc_period_line => state.hd.smooth_period);
}
}
}