mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-26 15:49:58 -07:00
714 lines
25 KiB
Rust
714 lines
25 KiB
Rust
mod ohlc;
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
use allocative::Allocative;
|
|
use chrono::{Days, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc};
|
|
use color_eyre::eyre::Error;
|
|
|
|
pub use ohlc::*;
|
|
|
|
use crate::{
|
|
price::{Binance, Kraken, Satonomics},
|
|
structs::{
|
|
AnyBiMap, AnyDateMap, BiMap, Date, DateMap, DateMapChunkId, Height, HeightMapChunkId,
|
|
MapKey,
|
|
},
|
|
utils::{ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS},
|
|
};
|
|
|
|
use super::{AnyDataset, ComputeData, MinInitialStates, RatioDataset};
|
|
|
|
#[derive(Allocative)]
|
|
pub struct PriceDatasets {
|
|
min_initial_states: MinInitialStates,
|
|
|
|
kraken_daily: Option<BTreeMap<Date, OHLC>>,
|
|
kraken_1mn: Option<BTreeMap<u32, OHLC>>,
|
|
binance_1mn: Option<BTreeMap<u32, OHLC>>,
|
|
binance_daily: Option<BTreeMap<Date, OHLC>>,
|
|
binance_har: Option<BTreeMap<u32, OHLC>>,
|
|
satonomics_by_height: BTreeMap<HeightMapChunkId, Vec<OHLC>>,
|
|
satonomics_by_date: BTreeMap<DateMapChunkId, BTreeMap<Date, OHLC>>,
|
|
|
|
// Inserted
|
|
pub ohlcs: BiMap<OHLC>,
|
|
|
|
// Computed
|
|
pub closes: BiMap<f32>,
|
|
pub market_cap: BiMap<f32>,
|
|
pub price_1w_sma: BiMap<f32>,
|
|
pub price_1w_sma_ratio: RatioDataset,
|
|
pub price_1m_sma: BiMap<f32>,
|
|
pub price_1m_sma_ratio: RatioDataset,
|
|
pub price_1y_sma: BiMap<f32>,
|
|
pub price_1y_sma_ratio: RatioDataset,
|
|
pub price_2y_sma: BiMap<f32>,
|
|
pub price_2y_sma_ratio: RatioDataset,
|
|
pub price_4y_sma: BiMap<f32>,
|
|
pub price_4y_sma_ratio: RatioDataset,
|
|
pub price_8d_sma: BiMap<f32>,
|
|
pub price_8d_sma_ratio: RatioDataset,
|
|
pub price_13d_sma: BiMap<f32>,
|
|
pub price_13d_sma_ratio: RatioDataset,
|
|
pub price_21d_sma: BiMap<f32>,
|
|
pub price_21d_sma_ratio: RatioDataset,
|
|
pub price_34d_sma: BiMap<f32>,
|
|
pub price_34d_sma_ratio: RatioDataset,
|
|
pub price_55d_sma: BiMap<f32>,
|
|
pub price_55d_sma_ratio: RatioDataset,
|
|
pub price_89d_sma: BiMap<f32>,
|
|
pub price_89d_sma_ratio: RatioDataset,
|
|
pub price_144d_sma: BiMap<f32>,
|
|
pub price_144d_sma_ratio: RatioDataset,
|
|
pub price_200w_sma: BiMap<f32>,
|
|
pub price_200w_sma_ratio: RatioDataset,
|
|
pub price_1d_total_return: DateMap<f32>,
|
|
pub price_1m_total_return: DateMap<f32>,
|
|
pub price_6m_total_return: DateMap<f32>,
|
|
pub price_1y_total_return: DateMap<f32>,
|
|
pub price_2y_total_return: DateMap<f32>,
|
|
pub price_3y_total_return: DateMap<f32>,
|
|
pub price_4y_total_return: DateMap<f32>,
|
|
pub price_6y_total_return: DateMap<f32>,
|
|
pub price_8y_total_return: DateMap<f32>,
|
|
pub price_10y_total_return: DateMap<f32>,
|
|
pub price_4y_compound_return: DateMap<f32>,
|
|
// projection via lowest 4y compound value
|
|
// volatility
|
|
// drawdown
|
|
// sats per dollar
|
|
}
|
|
|
|
impl PriceDatasets {
|
|
pub fn import(datasets_path: &str) -> color_eyre::Result<Self> {
|
|
let price_path = "../price";
|
|
|
|
let f = |s: &str| format!("{datasets_path}/{s}");
|
|
|
|
let mut s = Self {
|
|
min_initial_states: MinInitialStates::default(),
|
|
|
|
binance_1mn: None,
|
|
binance_daily: None,
|
|
binance_har: None,
|
|
kraken_1mn: None,
|
|
kraken_daily: None,
|
|
satonomics_by_height: BTreeMap::default(),
|
|
satonomics_by_date: BTreeMap::default(),
|
|
|
|
ohlcs: BiMap::new_json(1, price_path),
|
|
closes: BiMap::new_bin(1, &f("close")),
|
|
market_cap: BiMap::new_bin(1, &f("market_cap")),
|
|
price_1w_sma: BiMap::new_bin(1, &f("price_1w_sma")),
|
|
price_1w_sma_ratio: RatioDataset::import(datasets_path, "price_1w_sma")?,
|
|
price_1m_sma: BiMap::new_bin(1, &f("price_1m_sma")),
|
|
price_1m_sma_ratio: RatioDataset::import(datasets_path, "price_1m_sma")?,
|
|
price_1y_sma: BiMap::new_bin(1, &f("price_1y_sma")),
|
|
price_1y_sma_ratio: RatioDataset::import(datasets_path, "price_1y_sma")?,
|
|
price_2y_sma: BiMap::new_bin(1, &f("price_2y_sma")),
|
|
price_2y_sma_ratio: RatioDataset::import(datasets_path, "price_2y_sma")?,
|
|
price_4y_sma: BiMap::new_bin(1, &f("price_4y_sma")),
|
|
price_4y_sma_ratio: RatioDataset::import(datasets_path, "price_4y_sma")?,
|
|
price_8d_sma: BiMap::new_bin(1, &f("price_8d_sma")),
|
|
price_8d_sma_ratio: RatioDataset::import(datasets_path, "price_8d_sma")?,
|
|
price_13d_sma: BiMap::new_bin(1, &f("price_13d_sma")),
|
|
price_13d_sma_ratio: RatioDataset::import(datasets_path, "price_13d_sma")?,
|
|
price_21d_sma: BiMap::new_bin(1, &f("price_21d_sma")),
|
|
price_21d_sma_ratio: RatioDataset::import(datasets_path, "price_21d_sma")?,
|
|
price_34d_sma: BiMap::new_bin(1, &f("price_34d_sma")),
|
|
price_34d_sma_ratio: RatioDataset::import(datasets_path, "price_34d_sma")?,
|
|
price_55d_sma: BiMap::new_bin(1, &f("price_55d_sma")),
|
|
price_55d_sma_ratio: RatioDataset::import(datasets_path, "price_55d_sma")?,
|
|
price_89d_sma: BiMap::new_bin(1, &f("price_89d_sma")),
|
|
price_89d_sma_ratio: RatioDataset::import(datasets_path, "price_89d_sma")?,
|
|
price_144d_sma: BiMap::new_bin(1, &f("price_144d_sma")),
|
|
price_144d_sma_ratio: RatioDataset::import(datasets_path, "price_144d_sma")?,
|
|
price_200w_sma: BiMap::new_bin(1, &f("price_200w_sma")),
|
|
price_200w_sma_ratio: RatioDataset::import(datasets_path, "price_200w_sma")?,
|
|
price_1d_total_return: DateMap::new_bin(1, &f("price_1d_total_return")),
|
|
price_1m_total_return: DateMap::new_bin(1, &f("price_1m_total_return")),
|
|
price_6m_total_return: DateMap::new_bin(1, &f("price_6m_total_return")),
|
|
price_1y_total_return: DateMap::new_bin(1, &f("price_1y_total_return")),
|
|
price_2y_total_return: DateMap::new_bin(1, &f("price_2y_total_return")),
|
|
price_3y_total_return: DateMap::new_bin(1, &f("price_3y_total_return")),
|
|
price_4y_total_return: DateMap::new_bin(1, &f("price_4y_total_return")),
|
|
price_6y_total_return: DateMap::new_bin(1, &f("price_6y_total_return")),
|
|
price_8y_total_return: DateMap::new_bin(1, &f("price_8y_total_return")),
|
|
price_10y_total_return: DateMap::new_bin(1, &f("price_10y_total_return")),
|
|
price_4y_compound_return: DateMap::new_bin(1, &f("price_4y_compound_return")),
|
|
};
|
|
|
|
s.min_initial_states
|
|
.consume(MinInitialStates::compute_from_dataset(&s));
|
|
|
|
Ok(s)
|
|
}
|
|
|
|
pub fn compute(&mut self, compute_data: &ComputeData, circulating_supply: &mut BiMap<f64>) {
|
|
let &ComputeData { dates, heights, .. } = compute_data;
|
|
|
|
self.closes
|
|
.multi_insert_simple_transform(heights, dates, &mut self.ohlcs, &|ohlc| ohlc.close);
|
|
|
|
self.market_cap
|
|
.multi_insert_multiply(heights, dates, &mut self.closes, circulating_supply);
|
|
|
|
self.price_1w_sma.multi_insert_simple_average(
|
|
heights,
|
|
dates,
|
|
&mut self.closes,
|
|
ONE_WEEK_IN_DAYS,
|
|
);
|
|
|
|
self.price_1m_sma.multi_insert_simple_average(
|
|
heights,
|
|
dates,
|
|
&mut self.closes,
|
|
ONE_MONTH_IN_DAYS,
|
|
);
|
|
|
|
self.price_1y_sma.multi_insert_simple_average(
|
|
heights,
|
|
dates,
|
|
&mut self.closes,
|
|
ONE_YEAR_IN_DAYS,
|
|
);
|
|
|
|
self.price_2y_sma.multi_insert_simple_average(
|
|
heights,
|
|
dates,
|
|
&mut self.closes,
|
|
2 * ONE_YEAR_IN_DAYS,
|
|
);
|
|
|
|
self.price_4y_sma.multi_insert_simple_average(
|
|
heights,
|
|
dates,
|
|
&mut self.closes,
|
|
4 * ONE_YEAR_IN_DAYS,
|
|
);
|
|
|
|
self.price_8d_sma
|
|
.multi_insert_simple_average(heights, dates, &mut self.closes, 8);
|
|
|
|
self.price_13d_sma
|
|
.multi_insert_simple_average(heights, dates, &mut self.closes, 13);
|
|
|
|
self.price_21d_sma
|
|
.multi_insert_simple_average(heights, dates, &mut self.closes, 21);
|
|
|
|
self.price_34d_sma
|
|
.multi_insert_simple_average(heights, dates, &mut self.closes, 34);
|
|
|
|
self.price_55d_sma
|
|
.multi_insert_simple_average(heights, dates, &mut self.closes, 55);
|
|
|
|
self.price_89d_sma
|
|
.multi_insert_simple_average(heights, dates, &mut self.closes, 89);
|
|
|
|
self.price_144d_sma
|
|
.multi_insert_simple_average(heights, dates, &mut self.closes, 144);
|
|
|
|
self.price_200w_sma.multi_insert_simple_average(
|
|
heights,
|
|
dates,
|
|
&mut self.closes,
|
|
200 * ONE_WEEK_IN_DAYS,
|
|
);
|
|
|
|
self.price_1d_total_return
|
|
.multi_insert_percentage_change(dates, &mut self.closes.date, 1);
|
|
self.price_1m_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
ONE_MONTH_IN_DAYS,
|
|
);
|
|
self.price_6m_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
6 * ONE_MONTH_IN_DAYS,
|
|
);
|
|
self.price_1y_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
ONE_YEAR_IN_DAYS,
|
|
);
|
|
self.price_2y_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
2 * ONE_YEAR_IN_DAYS,
|
|
);
|
|
self.price_3y_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
3 * ONE_YEAR_IN_DAYS,
|
|
);
|
|
self.price_4y_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
4 * ONE_YEAR_IN_DAYS,
|
|
);
|
|
self.price_6y_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
6 * ONE_YEAR_IN_DAYS,
|
|
);
|
|
self.price_8y_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
8 * ONE_YEAR_IN_DAYS,
|
|
);
|
|
self.price_10y_total_return.multi_insert_percentage_change(
|
|
dates,
|
|
&mut self.closes.date,
|
|
10 * ONE_YEAR_IN_DAYS,
|
|
);
|
|
|
|
self.price_4y_compound_return
|
|
.multi_insert_complex_transform(
|
|
dates,
|
|
&mut self.closes.date,
|
|
|(last_value, date, closes)| {
|
|
let previous_value = date
|
|
.checked_sub_days(Days::new(4 * ONE_YEAR_IN_DAYS as u64))
|
|
.and_then(|date| closes.get_or_import(&Date::wrap(date)))
|
|
.unwrap_or_default();
|
|
|
|
(((last_value / previous_value).powf(1.0 / 4.0)) - 1.0) * 100.0
|
|
},
|
|
);
|
|
|
|
self.price_1w_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_1w_sma);
|
|
self.price_1m_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_1m_sma);
|
|
self.price_1y_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_1y_sma);
|
|
self.price_2y_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_2y_sma);
|
|
self.price_4y_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_4y_sma);
|
|
self.price_8d_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_8d_sma);
|
|
self.price_13d_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_13d_sma);
|
|
self.price_21d_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_21d_sma);
|
|
self.price_34d_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_34d_sma);
|
|
self.price_55d_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_55d_sma);
|
|
self.price_89d_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_89d_sma);
|
|
self.price_144d_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_144d_sma);
|
|
self.price_200w_sma_ratio
|
|
.compute(compute_data, &mut self.closes, &mut self.price_200w_sma);
|
|
}
|
|
|
|
pub fn get_date_ohlc(&mut self, date: Date) -> color_eyre::Result<OHLC> {
|
|
if self.ohlcs.date.is_key_safe(date) {
|
|
Ok(self.ohlcs.date.get(&date).unwrap().to_owned())
|
|
} else {
|
|
let ohlc = self
|
|
.get_from_daily_kraken(&date)
|
|
.or_else(|_| self.get_from_daily_binance(&date))
|
|
.or_else(|_| self.get_from_date_satonomics(&date))?;
|
|
|
|
self.ohlcs.date.insert(date, ohlc);
|
|
|
|
Ok(ohlc)
|
|
}
|
|
}
|
|
|
|
fn get_from_date_satonomics(&mut self, date: &Date) -> color_eyre::Result<OHLC> {
|
|
let chunk_id = date.to_chunk_id();
|
|
|
|
#[allow(clippy::map_entry)]
|
|
if !self.satonomics_by_date.contains_key(&chunk_id)
|
|
|| self
|
|
.satonomics_by_date
|
|
.get(&chunk_id)
|
|
.unwrap()
|
|
.last_key_value()
|
|
.unwrap()
|
|
.0
|
|
<= date
|
|
{
|
|
self.satonomics_by_date
|
|
.insert(chunk_id, Satonomics::fetch_date_prices(chunk_id)?);
|
|
}
|
|
|
|
self.satonomics_by_date
|
|
.get(&chunk_id)
|
|
.unwrap()
|
|
.get(date)
|
|
.cloned()
|
|
.ok_or(Error::msg("Couldn't find date in satonomics"))
|
|
}
|
|
|
|
fn get_from_daily_kraken(&mut self, date: &Date) -> color_eyre::Result<OHLC> {
|
|
if self.kraken_daily.is_none()
|
|
|| self
|
|
.kraken_daily
|
|
.as_ref()
|
|
.unwrap()
|
|
.last_key_value()
|
|
.unwrap()
|
|
.0
|
|
< date
|
|
{
|
|
self.kraken_daily.replace(Kraken::fetch_daily_prices()?);
|
|
}
|
|
|
|
self.kraken_daily
|
|
.as_ref()
|
|
.unwrap()
|
|
.get(date)
|
|
.cloned()
|
|
.ok_or(Error::msg("Couldn't find date"))
|
|
}
|
|
|
|
fn get_from_daily_binance(&mut self, date: &Date) -> color_eyre::Result<OHLC> {
|
|
if self.binance_daily.is_none()
|
|
|| self
|
|
.binance_daily
|
|
.as_ref()
|
|
.unwrap()
|
|
.last_key_value()
|
|
.unwrap()
|
|
.0
|
|
<= date
|
|
{
|
|
self.binance_daily.replace(Binance::fetch_daily_prices()?);
|
|
}
|
|
|
|
self.binance_daily
|
|
.as_ref()
|
|
.unwrap()
|
|
.get(date)
|
|
.cloned()
|
|
.ok_or(Error::msg("Couldn't find date"))
|
|
}
|
|
|
|
pub fn get_height_ohlc(
|
|
&mut self,
|
|
height: Height,
|
|
timestamp: u32,
|
|
previous_timestamp: Option<u32>,
|
|
) -> color_eyre::Result<OHLC> {
|
|
if let Some(ohlc) = self.ohlcs.height.get(&height) {
|
|
return Ok(ohlc);
|
|
}
|
|
|
|
let clean_timestamp = |timestamp| {
|
|
let date_time = Utc.timestamp_opt(i64::from(timestamp), 0).unwrap();
|
|
|
|
NaiveDateTime::new(
|
|
date_time.date_naive(),
|
|
NaiveTime::from_hms_opt(date_time.hour(), date_time.minute(), 0).unwrap(),
|
|
)
|
|
.and_utc()
|
|
.timestamp() as u32
|
|
};
|
|
|
|
let timestamp = clean_timestamp(timestamp);
|
|
|
|
if previous_timestamp.is_none() && !height.is_first() {
|
|
panic!("Shouldn't be possible");
|
|
}
|
|
|
|
let previous_timestamp = previous_timestamp.map(clean_timestamp);
|
|
|
|
let ohlc = self
|
|
.get_from_1mn_kraken(timestamp, previous_timestamp)
|
|
.unwrap_or_else(|_| {
|
|
self.get_from_1mn_binance(timestamp, previous_timestamp)
|
|
.unwrap_or_else(|_| {
|
|
self.get_from_har_binance(timestamp, previous_timestamp)
|
|
.unwrap_or_else(|_| {
|
|
self.get_from_height_satonomics(&height)
|
|
.unwrap_or_else(|_| {
|
|
let date = Date::from_timestamp(timestamp);
|
|
|
|
panic!(
|
|
"Can't find the price for: height: {height} - date: {date}
|
|
1mn APIs are limited to the last 16 hours for Binance's and the last 10 hours for Kraken's
|
|
How to fix this:
|
|
1. Go to https://www.binance.com/en/trade/BTC_USDT?type=spot
|
|
2. Select 1mn interval
|
|
3. Open the inspector/dev tools
|
|
4. Go to the Network Tab
|
|
5. Filter URLs by 'uiKlines'
|
|
6. Go back to the chart and scroll until you pass the date mentioned few lines ago
|
|
7. Go back to the dev tools
|
|
8. Export to a har file (if there is no explicit button, click on the cog button)
|
|
9. Move the file to 'parser/imports/binance.har'
|
|
"
|
|
)
|
|
})
|
|
})
|
|
})
|
|
});
|
|
|
|
self.ohlcs.height.insert(height, ohlc);
|
|
|
|
Ok(ohlc)
|
|
}
|
|
|
|
fn get_from_height_satonomics(&mut self, height: &Height) -> color_eyre::Result<OHLC> {
|
|
let chunk_id = height.to_chunk_id();
|
|
|
|
#[allow(clippy::map_entry)]
|
|
if !self.satonomics_by_height.contains_key(&chunk_id)
|
|
|| ((chunk_id.to_usize() + self.satonomics_by_height.get(&chunk_id).unwrap().len())
|
|
<= height.to_usize())
|
|
{
|
|
self.satonomics_by_height
|
|
.insert(chunk_id, Satonomics::fetch_height_prices(chunk_id)?);
|
|
}
|
|
|
|
self.satonomics_by_height
|
|
.get(&chunk_id)
|
|
.unwrap()
|
|
.get(height.to_serialized_key().to_usize())
|
|
.cloned()
|
|
.ok_or(Error::msg("Couldn't find height in satonomics"))
|
|
}
|
|
|
|
fn get_from_1mn_kraken(
|
|
&mut self,
|
|
timestamp: u32,
|
|
previous_timestamp: Option<u32>,
|
|
) -> color_eyre::Result<OHLC> {
|
|
if self.kraken_1mn.is_none()
|
|
|| self
|
|
.kraken_1mn
|
|
.as_ref()
|
|
.unwrap()
|
|
.last_key_value()
|
|
.unwrap()
|
|
.0
|
|
<= ×tamp
|
|
{
|
|
self.kraken_1mn.replace(Kraken::fetch_1mn_prices()?);
|
|
}
|
|
|
|
Self::find_height_ohlc(&self.kraken_1mn, timestamp, previous_timestamp, "kraken 1m")
|
|
}
|
|
|
|
fn get_from_1mn_binance(
|
|
&mut self,
|
|
timestamp: u32,
|
|
previous_timestamp: Option<u32>,
|
|
) -> color_eyre::Result<OHLC> {
|
|
if self.binance_1mn.is_none()
|
|
|| self
|
|
.binance_1mn
|
|
.as_ref()
|
|
.unwrap()
|
|
.last_key_value()
|
|
.unwrap()
|
|
.0
|
|
<= ×tamp
|
|
{
|
|
self.binance_1mn.replace(Binance::fetch_1mn_prices()?);
|
|
}
|
|
|
|
Self::find_height_ohlc(
|
|
&self.binance_1mn,
|
|
timestamp,
|
|
previous_timestamp,
|
|
"binance 1m",
|
|
)
|
|
}
|
|
|
|
fn get_from_har_binance(
|
|
&mut self,
|
|
timestamp: u32,
|
|
previous_timestamp: Option<u32>,
|
|
) -> color_eyre::Result<OHLC> {
|
|
if self.binance_har.is_none() {
|
|
self.binance_har
|
|
.replace(Binance::read_har_file().unwrap_or_default());
|
|
}
|
|
|
|
Self::find_height_ohlc(
|
|
&self.binance_har,
|
|
timestamp,
|
|
previous_timestamp,
|
|
"binance har",
|
|
)
|
|
}
|
|
|
|
fn find_height_ohlc(
|
|
tree: &Option<BTreeMap<u32, OHLC>>,
|
|
timestamp: u32,
|
|
previous_timestamp: Option<u32>,
|
|
name: &str,
|
|
) -> color_eyre::Result<OHLC> {
|
|
let tree = tree.as_ref().unwrap();
|
|
|
|
let err = Error::msg(format!("Couldn't find timestamp in {name}"));
|
|
|
|
let previous_ohlc = previous_timestamp
|
|
.map_or(Some(OHLC::default()), |previous_timestamp| {
|
|
tree.get(&previous_timestamp).cloned()
|
|
});
|
|
|
|
let last_ohlc = tree.get(×tamp);
|
|
|
|
if previous_ohlc.is_none() || last_ohlc.is_none() {
|
|
return Err(err);
|
|
}
|
|
|
|
let previous_ohlc = previous_ohlc.unwrap();
|
|
|
|
let mut final_ohlc = OHLC {
|
|
open: previous_ohlc.close,
|
|
high: previous_ohlc.close,
|
|
low: previous_ohlc.close,
|
|
close: previous_ohlc.close,
|
|
};
|
|
|
|
let start = previous_timestamp.unwrap_or(0);
|
|
let end = timestamp;
|
|
|
|
// Otherwise it's a re-org
|
|
if start < end {
|
|
tree.range(&start..=&end).skip(1).for_each(|(_, ohlc)| {
|
|
if ohlc.high > final_ohlc.high {
|
|
final_ohlc.high = ohlc.high
|
|
}
|
|
|
|
if ohlc.low < final_ohlc.low {
|
|
final_ohlc.low = ohlc.low
|
|
}
|
|
|
|
final_ohlc.close = ohlc.close;
|
|
});
|
|
}
|
|
|
|
Ok(final_ohlc)
|
|
}
|
|
}
|
|
|
|
impl AnyDataset for PriceDatasets {
|
|
fn get_min_initial_states(&self) -> &MinInitialStates {
|
|
&self.min_initial_states
|
|
}
|
|
|
|
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
|
|
vec![&self.ohlcs]
|
|
}
|
|
|
|
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
|
|
vec![&mut self.ohlcs]
|
|
}
|
|
|
|
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
|
|
let mut v = vec![
|
|
&self.closes as &(dyn AnyBiMap + Send + Sync),
|
|
&self.market_cap,
|
|
&self.price_1w_sma,
|
|
&self.price_1m_sma,
|
|
&self.price_1y_sma,
|
|
&self.price_2y_sma,
|
|
&self.price_4y_sma,
|
|
&self.price_8d_sma,
|
|
&self.price_13d_sma,
|
|
&self.price_21d_sma,
|
|
&self.price_34d_sma,
|
|
&self.price_55d_sma,
|
|
&self.price_89d_sma,
|
|
&self.price_144d_sma,
|
|
&self.price_200w_sma,
|
|
];
|
|
|
|
v.append(&mut self.price_1w_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_1m_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_1y_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_2y_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_4y_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_8d_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_13d_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_21d_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_34d_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_55d_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_89d_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_144d_sma_ratio.to_computed_bi_map_vec());
|
|
v.append(&mut self.price_200w_sma_ratio.to_computed_bi_map_vec());
|
|
|
|
v
|
|
}
|
|
|
|
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
|
|
let mut v = vec![
|
|
&mut self.closes as &mut dyn AnyBiMap,
|
|
&mut self.market_cap,
|
|
&mut self.price_1w_sma,
|
|
&mut self.price_1m_sma,
|
|
&mut self.price_1y_sma,
|
|
&mut self.price_2y_sma,
|
|
&mut self.price_4y_sma,
|
|
&mut self.price_8d_sma,
|
|
&mut self.price_13d_sma,
|
|
&mut self.price_21d_sma,
|
|
&mut self.price_34d_sma,
|
|
&mut self.price_55d_sma,
|
|
&mut self.price_89d_sma,
|
|
&mut self.price_144d_sma,
|
|
&mut self.price_200w_sma,
|
|
];
|
|
|
|
v.append(&mut self.price_1w_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_1m_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_1y_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_2y_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_4y_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_8d_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_13d_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_21d_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_34d_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_55d_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_89d_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_144d_sma_ratio.to_computed_mut_bi_map_vec());
|
|
v.append(&mut self.price_200w_sma_ratio.to_computed_mut_bi_map_vec());
|
|
|
|
v
|
|
}
|
|
|
|
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
|
|
vec![
|
|
&self.price_1d_total_return,
|
|
&self.price_1m_total_return,
|
|
&self.price_6m_total_return,
|
|
&self.price_1y_total_return,
|
|
&self.price_2y_total_return,
|
|
&self.price_3y_total_return,
|
|
&self.price_4y_total_return,
|
|
&self.price_6y_total_return,
|
|
&self.price_8y_total_return,
|
|
&self.price_10y_total_return,
|
|
&self.price_4y_compound_return,
|
|
]
|
|
}
|
|
|
|
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
|
|
vec![
|
|
&mut self.price_1d_total_return,
|
|
&mut self.price_1m_total_return,
|
|
&mut self.price_6m_total_return,
|
|
&mut self.price_1y_total_return,
|
|
&mut self.price_2y_total_return,
|
|
&mut self.price_3y_total_return,
|
|
&mut self.price_4y_total_return,
|
|
&mut self.price_6y_total_return,
|
|
&mut self.price_8y_total_return,
|
|
&mut self.price_10y_total_return,
|
|
&mut self.price_4y_compound_return,
|
|
]
|
|
}
|
|
}
|