use chrono::TimeDelta;
use paft::market::responses::history::Candle;
#[must_use]
pub fn estimate_step_seconds(mut candles: Vec<Candle>) -> Option<i64> {
if candles.len() < 2 {
return None;
}
candles.sort_by_key(|c| c.ts);
let mut deltas: Vec<i64> = Vec::with_capacity(candles.len().saturating_sub(1));
let mut last = candles[0].ts;
for c in candles.into_iter().skip(1) {
let dt: TimeDelta = c.ts - last;
if dt > TimeDelta::zero() {
deltas.push(dt.num_seconds());
last = c.ts;
}
}
if deltas.is_empty() {
return None;
}
deltas.sort_unstable();
let mut best_delta: i64 = deltas[0];
let mut best_count: usize = 0;
let mut num_best_candidates: usize = 0;
let mut cur_delta: i64 = deltas[0];
let mut cur_count: usize = 1;
for &d in deltas.iter().skip(1) {
if d == cur_delta {
cur_count += 1;
continue;
}
if cur_count > best_count {
best_count = cur_count;
best_delta = cur_delta;
num_best_candidates = 1;
} else if cur_count == best_count {
num_best_candidates = num_best_candidates.saturating_add(1);
}
cur_delta = d;
cur_count = 1;
}
if cur_count > best_count {
best_delta = cur_delta;
num_best_candidates = 1;
} else if cur_count == best_count {
num_best_candidates = num_best_candidates.saturating_add(1);
}
if num_best_candidates == 1 {
return Some(best_delta);
}
let mid = deltas.len() / 2;
if deltas.len() % 2 == 1 {
Some(deltas[mid])
} else {
Some(deltas[mid - 1])
}
}
#[must_use]
pub fn is_subdaily(candles: &[Candle]) -> bool {
const DAY: i64 = 86_400;
if candles.len() < 2 {
return false;
}
let mut ts: Vec<_> = candles.iter().map(|c| c.ts).collect();
ts.sort();
let mut deltas: Vec<i64> = Vec::with_capacity(ts.len().saturating_sub(1));
let mut last = ts[0];
for &cur in ts.iter().skip(1) {
let dt: TimeDelta = cur - last;
if dt > TimeDelta::zero() {
deltas.push(dt.num_seconds());
last = cur;
}
}
if deltas.is_empty() {
return false;
}
let total: usize = deltas.len();
let subdaily: usize = deltas.iter().filter(|&&d| d > 0 && d < DAY).count();
let min_count: usize = 3;
let min_ratio_num: usize = 3; let min_ratio_den: usize = 5;
if subdaily < min_count {
return false;
}
subdaily.saturating_mul(min_ratio_den) >= total.saturating_mul(min_ratio_num)
}