#![allow(clippy::neg_cmp_op_on_partial_ord)]
pub fn sar(high: &[f64], low: &[f64], acceleration: f64, maximum: f64) -> Vec<f64> {
let n = high.len();
let mut out = vec![f64::NAN; n];
if n < 2 {
return out;
}
let af_init = acceleration.min(maximum); let diff_p = high[1] - high[0];
let diff_m = low[0] - low[1];
let minus_dm1 = if diff_m > 0.0 && diff_p < diff_m {
diff_m
} else {
0.0
};
let mut is_long = !(minus_dm1 > 0.0);
let mut af = af_init;
let (mut ep, mut sar) = if is_long {
(high[1], low[0])
} else {
(low[1], high[0])
};
let mut new_low = low[1];
let mut new_high = high[1];
for today in 1..n {
let prev_low = new_low;
let prev_high = new_high;
new_low = low[today];
new_high = high[today];
if is_long {
if new_low <= sar {
is_long = false;
sar = ep.max(prev_high).max(new_high);
out[today] = sar;
af = af_init;
ep = new_low;
sar = (sar + af * (ep - sar)).max(prev_high).max(new_high);
} else {
out[today] = sar;
if new_high > ep {
ep = new_high;
af = (af + af_init).min(maximum);
}
sar = (sar + af * (ep - sar)).min(prev_low).min(new_low);
}
} else if new_high >= sar {
is_long = true;
sar = ep.min(prev_low).min(new_low);
out[today] = sar;
af = af_init;
ep = new_high;
sar = (sar + af * (ep - sar)).min(prev_low).min(new_low);
} else {
out[today] = sar;
if new_low < ep {
ep = new_low;
af = (af + af_init).min(maximum);
}
sar = (sar + af * (ep - sar)).max(prev_high).max(new_high);
}
}
out
}
pub fn sar_final_state(
high: &[f64],
low: &[f64],
acceleration: f64,
maximum: f64,
) -> Option<Vec<f64>> {
let n = high.len();
if n < 2 {
return None;
}
let af_init = acceleration.min(maximum);
let diff_p = high[1] - high[0];
let diff_m = low[0] - low[1];
let minus_dm1 = if diff_m > 0.0 && diff_p < diff_m {
diff_m
} else {
0.0
};
let mut is_long = !(minus_dm1 > 0.0);
let mut af = af_init;
let (mut ep, mut sar) = if is_long {
(high[1], low[0])
} else {
(low[1], high[0])
};
let mut new_low = low[1];
let mut new_high = high[1];
for today in 1..n {
let prev_low = new_low;
let prev_high = new_high;
new_low = low[today];
new_high = high[today];
if is_long {
if new_low <= sar {
is_long = false;
sar = ep.max(prev_high).max(new_high);
af = af_init;
ep = new_low;
sar = (sar + af * (ep - sar)).max(prev_high).max(new_high);
} else {
if new_high > ep {
ep = new_high;
af = (af + af_init).min(maximum);
}
sar = (sar + af * (ep - sar)).min(prev_low).min(new_low);
}
} else if new_high >= sar {
is_long = true;
sar = ep.min(prev_low).min(new_low);
af = af_init;
ep = new_high;
sar = (sar + af * (ep - sar)).min(prev_low).min(new_low);
} else {
if new_low < ep {
ep = new_low;
af = (af + af_init).min(maximum);
}
sar = (sar + af * (ep - sar)).max(prev_high).max(new_high);
}
}
Some(vec![is_long as u8 as f64, af, ep, sar, new_high, new_low])
}
pub fn sar_resume(
high: &[f64],
low: &[f64],
acceleration: f64,
maximum: f64,
from: usize,
state: &[f64],
) -> Option<(Vec<f64>, Vec<f64>)> {
if from < 2 {
return None;
}
let n = high.len();
let af_init = acceleration.min(maximum);
let mut is_long = state[0] != 0.0;
let mut af = state[1];
let mut ep = state[2];
let mut sar = state[3];
let mut new_high = state[4];
let mut new_low = state[5];
let mut out = Vec::with_capacity(n.saturating_sub(from));
for today in from..n {
let prev_low = new_low;
let prev_high = new_high;
new_low = low[today];
new_high = high[today];
if is_long {
if new_low <= sar {
is_long = false;
sar = ep.max(prev_high).max(new_high);
out.push(sar);
af = af_init;
ep = new_low;
sar = (sar + af * (ep - sar)).max(prev_high).max(new_high);
} else {
out.push(sar);
if new_high > ep {
ep = new_high;
af = (af + af_init).min(maximum);
}
sar = (sar + af * (ep - sar)).min(prev_low).min(new_low);
}
} else if new_high >= sar {
is_long = true;
sar = ep.min(prev_low).min(new_low);
out.push(sar);
af = af_init;
ep = new_high;
sar = (sar + af * (ep - sar)).min(prev_low).min(new_low);
} else {
out.push(sar);
if new_low < ep {
ep = new_low;
af = (af + af_init).min(maximum);
}
sar = (sar + af * (ep - sar)).max(prev_high).max(new_high);
}
}
Some((
out,
vec![is_long as u8 as f64, af, ep, sar, new_high, new_low],
))
}
#[allow(clippy::too_many_arguments)]
pub fn sarext(
high: &[f64],
low: &[f64],
start_value: f64,
offset_on_reverse: f64,
accel_init_long: f64,
accel_long: f64,
accel_max_long: f64,
accel_init_short: f64,
accel_short: f64,
accel_max_short: f64,
) -> Vec<f64> {
let n = high.len();
let mut out = vec![f64::NAN; n];
if n < 2 {
return out;
}
let af_long_init = accel_init_long.min(accel_max_long);
let af_short_init = accel_init_short.min(accel_max_short);
let accel_long = accel_long.min(accel_max_long);
let accel_short = accel_short.min(accel_max_short);
let mut is_long = if start_value == 0.0 {
let diff_p = high[1] - high[0];
let diff_m = low[0] - low[1];
let minus_dm1 = if diff_m > 0.0 && diff_p < diff_m {
diff_m
} else {
0.0
};
!(minus_dm1 > 0.0)
} else {
start_value > 0.0
};
let (mut ep, mut sar) = if start_value == 0.0 {
if is_long {
(high[1], low[0])
} else {
(low[1], high[0])
}
} else if start_value > 0.0 {
(high[1], start_value)
} else {
(low[1], start_value.abs())
};
let (mut af_long, mut af_short) = (af_long_init, af_short_init);
let mut new_low = low[1];
let mut new_high = high[1];
for today in 1..n {
let prev_low = new_low;
let prev_high = new_high;
new_low = low[today];
new_high = high[today];
if is_long {
if new_low <= sar {
is_long = false;
sar = ep.max(prev_high).max(new_high);
if offset_on_reverse != 0.0 {
sar += sar * offset_on_reverse;
}
out[today] = -sar;
af_short = af_short_init;
ep = new_low;
sar = (sar + af_short * (ep - sar)).max(prev_high).max(new_high);
} else {
out[today] = sar;
if new_high > ep {
ep = new_high;
af_long = (af_long + accel_long).min(accel_max_long);
}
sar = (sar + af_long * (ep - sar)).min(prev_low).min(new_low);
}
} else if new_high >= sar {
is_long = true;
sar = ep.min(prev_low).min(new_low);
if offset_on_reverse != 0.0 {
sar -= sar * offset_on_reverse;
}
out[today] = sar;
af_long = af_long_init;
ep = new_high;
sar = (sar + af_long * (ep - sar)).min(prev_low).min(new_low);
} else {
out[today] = -sar;
if new_low < ep {
ep = new_low;
af_short = (af_short + accel_short).min(accel_max_short);
}
sar = (sar + af_short * (ep - sar)).max(prev_high).max(new_high);
}
}
out
}
#[allow(clippy::too_many_arguments)]
pub fn sarext_final_state(
high: &[f64],
low: &[f64],
start_value: f64,
offset_on_reverse: f64,
accel_init_long: f64,
accel_long: f64,
accel_max_long: f64,
accel_init_short: f64,
accel_short: f64,
accel_max_short: f64,
) -> Option<Vec<f64>> {
let n = high.len();
if n < 2 {
return None;
}
let af_long_init = accel_init_long.min(accel_max_long);
let af_short_init = accel_init_short.min(accel_max_short);
let accel_long = accel_long.min(accel_max_long);
let accel_short = accel_short.min(accel_max_short);
let mut is_long = if start_value == 0.0 {
let diff_p = high[1] - high[0];
let diff_m = low[0] - low[1];
let minus_dm1 = if diff_m > 0.0 && diff_p < diff_m {
diff_m
} else {
0.0
};
!(minus_dm1 > 0.0)
} else {
start_value > 0.0
};
let (mut ep, mut sar) = if start_value == 0.0 {
if is_long {
(high[1], low[0])
} else {
(low[1], high[0])
}
} else if start_value > 0.0 {
(high[1], start_value)
} else {
(low[1], start_value.abs())
};
let (mut af_long, mut af_short) = (af_long_init, af_short_init);
let mut new_low = low[1];
let mut new_high = high[1];
for today in 1..n {
let prev_low = new_low;
let prev_high = new_high;
new_low = low[today];
new_high = high[today];
if is_long {
if new_low <= sar {
is_long = false;
sar = ep.max(prev_high).max(new_high);
if offset_on_reverse != 0.0 {
sar += sar * offset_on_reverse;
}
af_short = af_short_init;
ep = new_low;
sar = (sar + af_short * (ep - sar)).max(prev_high).max(new_high);
} else {
if new_high > ep {
ep = new_high;
af_long = (af_long + accel_long).min(accel_max_long);
}
sar = (sar + af_long * (ep - sar)).min(prev_low).min(new_low);
}
} else if new_high >= sar {
is_long = true;
sar = ep.min(prev_low).min(new_low);
if offset_on_reverse != 0.0 {
sar -= sar * offset_on_reverse;
}
af_long = af_long_init;
ep = new_high;
sar = (sar + af_long * (ep - sar)).min(prev_low).min(new_low);
} else {
if new_low < ep {
ep = new_low;
af_short = (af_short + accel_short).min(accel_max_short);
}
sar = (sar + af_short * (ep - sar)).max(prev_high).max(new_high);
}
}
Some(vec![
is_long as u8 as f64,
af_long,
af_short,
ep,
sar,
new_high,
new_low,
])
}
#[allow(clippy::too_many_arguments)]
pub fn sarext_resume(
high: &[f64],
low: &[f64],
offset_on_reverse: f64,
accel_init_long: f64,
accel_long: f64,
accel_max_long: f64,
accel_init_short: f64,
accel_short: f64,
accel_max_short: f64,
from: usize,
state: &[f64],
) -> Option<(Vec<f64>, Vec<f64>)> {
if from < 2 {
return None;
}
let n = high.len();
let af_long_init = accel_init_long.min(accel_max_long);
let af_short_init = accel_init_short.min(accel_max_short);
let accel_long = accel_long.min(accel_max_long);
let accel_short = accel_short.min(accel_max_short);
let mut is_long = state[0] != 0.0;
let mut af_long = state[1];
let mut af_short = state[2];
let mut ep = state[3];
let mut sar = state[4];
let mut new_high = state[5];
let mut new_low = state[6];
let mut out = Vec::with_capacity(n.saturating_sub(from));
for today in from..n {
let prev_low = new_low;
let prev_high = new_high;
new_low = low[today];
new_high = high[today];
if is_long {
if new_low <= sar {
is_long = false;
sar = ep.max(prev_high).max(new_high);
if offset_on_reverse != 0.0 {
sar += sar * offset_on_reverse;
}
out.push(-sar);
af_short = af_short_init;
ep = new_low;
sar = (sar + af_short * (ep - sar)).max(prev_high).max(new_high);
} else {
out.push(sar);
if new_high > ep {
ep = new_high;
af_long = (af_long + accel_long).min(accel_max_long);
}
sar = (sar + af_long * (ep - sar)).min(prev_low).min(new_low);
}
} else if new_high >= sar {
is_long = true;
sar = ep.min(prev_low).min(new_low);
if offset_on_reverse != 0.0 {
sar -= sar * offset_on_reverse;
}
out.push(sar);
af_long = af_long_init;
ep = new_high;
sar = (sar + af_long * (ep - sar)).min(prev_low).min(new_low);
} else {
out.push(-sar);
if new_low < ep {
ep = new_low;
af_short = (af_short + accel_short).min(accel_max_short);
}
sar = (sar + af_short * (ep - sar)).max(prev_high).max(new_high);
}
}
Some((
out,
vec![
is_long as u8 as f64,
af_long,
af_short,
ep,
sar,
new_high,
new_low,
],
))
}
pub fn sar_resume_one(
high: &[f64],
low: &[f64],
row: usize,
state: &[f64],
) -> Option<f64> {
if row < 2 || state.len() < 6 || row >= high.len() || row >= low.len() {
return None;
}
let is_long = state[0] != 0.0;
let ep = state[2];
let sar = state[3];
let prev_high = state[4];
let prev_low = state[5];
let new_low = low[row];
let new_high = high[row];
let val = if is_long {
if new_low <= sar {
ep.max(prev_high).max(new_high)
} else {
sar
}
} else if new_high >= sar {
ep.min(prev_low).min(new_low)
} else {
sar
};
Some(val)
}
pub fn sarext_resume_one(
high: &[f64],
low: &[f64],
offset_on_reverse: f64,
row: usize,
state: &[f64],
) -> Option<f64> {
if row < 2 || state.len() < 7 || row >= high.len() || row >= low.len() {
return None;
}
let is_long = state[0] != 0.0;
let ep = state[3];
let sar = state[4];
let prev_high = state[5];
let prev_low = state[6];
let new_low = low[row];
let new_high = high[row];
let val = if is_long {
if new_low <= sar {
let mut sar = ep.max(prev_high).max(new_high);
if offset_on_reverse != 0.0 {
sar += sar * offset_on_reverse;
}
-sar
} else {
sar
}
} else if new_high >= sar {
let mut sar = ep.min(prev_low).min(new_low);
if offset_on_reverse != 0.0 {
sar -= sar * offset_on_reverse;
}
sar
} else {
-sar
};
Some(val)
}