git: reset

This commit is contained in:
k
2024-06-23 17:38:53 +02:00
commit a1a576d088
375 changed files with 40952 additions and 0 deletions

View File

@@ -0,0 +1,286 @@
use itertools::Itertools;
use rayon::prelude::*;
use crate::{
datasets::ComputeData,
structs::{AnyBiMap, AnyDateMap, AnyHeightMap, AnyMap, WNaiveDate},
};
use super::MinInitialStates;
pub trait AnyDataset {
fn get_min_initial_states(&self) -> &MinInitialStates;
fn needs_insert(&self, height: usize, date: WNaiveDate) -> bool {
self.needs_insert_height(height) || self.needs_insert_date(date)
}
#[inline(always)]
fn needs_insert_height(&self, height: usize) -> bool {
!self.to_all_inserted_height_map_vec().is_empty()
&& self
.get_min_initial_states()
.inserted
.first_unsafe_height
.unwrap_or(0)
<= height
}
#[inline(always)]
fn needs_insert_date(&self, date: WNaiveDate) -> bool {
!self.to_all_inserted_date_map_vec().is_empty()
&& self
.get_min_initial_states()
.inserted
.first_unsafe_date
.map_or(true, |min_initial_first_unsafe_date| {
min_initial_first_unsafe_date <= date
})
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![]
}
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
vec![]
}
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![]
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
vec![]
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![]
}
fn to_all_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
let mut vec = self.to_inserted_height_map_vec();
vec.append(
&mut self
.to_inserted_bi_map_vec()
.iter()
.map(|bi| bi.get_height())
.collect_vec(),
);
vec
}
fn to_all_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
let mut vec = self.to_inserted_date_map_vec();
vec.append(
&mut self
.to_inserted_bi_map_vec()
.iter()
.map(|bi| bi.get_date())
.collect_vec(),
);
vec
}
fn to_all_inserted_map_vec(&self) -> Vec<&(dyn AnyMap + Send + Sync)> {
let heights = self
.to_all_inserted_height_map_vec()
.into_iter()
.map(|d| d.as_any_map());
let dates = self
.to_all_inserted_date_map_vec()
.into_iter()
.map(|d| d.as_any_map());
heights.chain(dates).collect_vec()
}
#[inline(always)]
fn should_compute(&self, compute_data: &ComputeData) -> bool {
compute_data
.heights
.last()
.map_or(false, |height| self.should_compute_height(*height))
|| compute_data
.dates
.last()
.map_or(false, |date| self.should_compute_date(*date))
}
#[inline(always)]
fn should_compute_height(&self, height: usize) -> bool {
!self.to_all_computed_height_map_vec().is_empty()
&& self
.get_min_initial_states()
.computed
.first_unsafe_height
.unwrap_or(0)
<= height
}
#[inline(always)]
fn should_compute_date(&self, date: WNaiveDate) -> bool {
!self.to_all_computed_date_map_vec().is_empty()
&& self
.get_min_initial_states()
.computed
.first_unsafe_date
.map_or(true, |min_initial_first_unsafe_date| {
min_initial_first_unsafe_date <= date
})
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![]
}
fn to_computed_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
vec![]
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![]
}
fn to_computed_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
vec![]
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![]
}
fn to_all_computed_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
let mut vec = self.to_computed_height_map_vec();
vec.append(
&mut self
.to_computed_bi_map_vec()
.iter()
.map(|bi| bi.get_height())
.collect_vec(),
);
vec
}
fn to_all_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
let mut vec = self.to_computed_date_map_vec();
vec.append(
&mut self
.to_computed_bi_map_vec()
.iter()
.map(|bi| bi.get_date())
.collect_vec(),
);
vec
}
fn to_all_computed_map_vec(&self) -> Vec<&(dyn AnyMap + Send + Sync)> {
let heights = self
.to_all_computed_height_map_vec()
.into_iter()
.map(|d| d.as_any_map());
let dates = self
.to_all_computed_date_map_vec()
.into_iter()
.map(|d| d.as_any_map());
heights.chain(dates).collect_vec()
}
fn to_all_map_vec(&self) -> Vec<&(dyn AnyMap + Send + Sync)> {
let mut inserted = self.to_all_inserted_map_vec();
inserted.append(&mut self.to_all_computed_map_vec());
inserted
}
// #[inline(always)]
// fn is_empty(&self) -> bool {
// self.to_any_map_vec().is_empty()
// }
fn pre_export(&mut self) {
self.to_inserted_mut_height_map_vec()
.into_iter()
.for_each(|map| map.pre_export());
self.to_inserted_mut_date_map_vec()
.into_iter()
.for_each(|map| map.pre_export());
self.to_inserted_mut_bi_map_vec().into_iter().for_each(|d| {
d.as_any_mut_map()
.into_iter()
.for_each(|map| map.pre_export())
});
self.to_computed_mut_height_map_vec()
.into_iter()
.for_each(|map| map.pre_export());
self.to_computed_mut_date_map_vec()
.into_iter()
.for_each(|map| map.pre_export());
self.to_computed_mut_bi_map_vec().into_iter().for_each(|d| {
d.as_any_mut_map()
.into_iter()
.for_each(|map| map.pre_export())
});
}
fn export(&self) -> color_eyre::Result<()> {
self.to_all_map_vec()
.into_par_iter()
.try_for_each(|map| -> color_eyre::Result<()> { map.export() })
}
fn post_export(&mut self) {
self.to_inserted_mut_height_map_vec()
.into_iter()
.for_each(|map| map.post_export());
self.to_inserted_mut_date_map_vec()
.into_iter()
.for_each(|map| map.post_export());
self.to_inserted_mut_bi_map_vec().into_iter().for_each(|d| {
d.as_any_mut_map()
.into_iter()
.for_each(|map| map.post_export())
});
self.to_computed_mut_height_map_vec()
.into_iter()
.for_each(|map| map.post_export());
self.to_computed_mut_date_map_vec()
.into_iter()
.for_each(|map| map.post_export());
self.to_computed_mut_bi_map_vec().into_iter().for_each(|d| {
d.as_any_mut_map()
.into_iter()
.for_each(|map| map.post_export())
});
}
}

View File

@@ -0,0 +1,7 @@
use super::AnyDataset;
pub trait AnyDatasetGroup {
fn as_vec(&self) -> Vec<&(dyn AnyDataset + Send + Sync)>;
fn as_mut_vec(&mut self) -> Vec<&mut dyn AnyDataset>;
}

View File

@@ -0,0 +1,9 @@
use super::{AnyDataset, MinInitialStates};
pub trait AnyDatasets {
fn get_min_initial_states(&self) -> &MinInitialStates;
fn to_any_dataset_vec(&self) -> Vec<&(dyn AnyDataset + Send + Sync)>;
fn to_mut_any_dataset_vec(&mut self) -> Vec<&mut dyn AnyDataset>;
}

View File

@@ -0,0 +1,272 @@
use allocative::Allocative;
use crate::structs::{AnyDateMap, AnyHeightMap, WNaiveDate};
use super::{AnyDataset, AnyDatasets};
#[derive(Default, Debug, Clone, Copy, Allocative)]
pub struct MinInitialStates {
pub inserted: MinInitialState,
pub computed: MinInitialState,
}
impl MinInitialStates {
pub fn consume(&mut self, other: Self) {
self.inserted = other.inserted;
self.computed = other.computed;
}
pub fn compute_from_dataset(dataset: &dyn AnyDataset) -> Self {
Self {
inserted: MinInitialState::compute_from_dataset(dataset, Mode::Inserted),
computed: MinInitialState::compute_from_dataset(dataset, Mode::Computed),
}
}
pub fn compute_from_datasets(datasets: &dyn AnyDatasets) -> Self {
Self {
inserted: MinInitialState::compute_from_datasets(datasets, Mode::Inserted),
computed: MinInitialState::compute_from_datasets(datasets, Mode::Computed),
}
}
}
#[derive(Default, Debug, Clone, Copy, Allocative)]
pub struct MinInitialState {
pub first_unsafe_date: Option<WNaiveDate>,
pub first_unsafe_height: Option<usize>,
pub last_date: Option<WNaiveDate>,
pub last_height: Option<usize>,
}
enum Mode {
Inserted,
Computed,
}
impl MinInitialState {
// pub fn consume(&mut self, other: Self) {
// self.first_unsafe_date = other.first_unsafe_date;
// self.first_unsafe_height = other.first_unsafe_height;
// self.last_date = other.last_date;
// self.last_height = other.last_height;
// }
fn compute_from_datasets(datasets: &dyn AnyDatasets, mode: Mode) -> Self {
match mode {
Mode::Inserted => {
let contains_date_maps = |dataset: &&(dyn AnyDataset + Sync + Send)| {
!dataset.to_all_inserted_date_map_vec().is_empty()
};
let contains_height_maps = |dataset: &&(dyn AnyDataset + Sync + Send)| {
!dataset.to_all_inserted_height_map_vec().is_empty()
};
Self {
first_unsafe_date: Self::min_datasets_date(
datasets,
contains_date_maps,
|dataset| {
dataset
.get_min_initial_states()
.inserted
.first_unsafe_date
.as_ref()
.cloned()
},
),
first_unsafe_height: Self::min_datasets_height(
datasets,
contains_height_maps,
|dataset| {
dataset
.get_min_initial_states()
.inserted
.first_unsafe_height
.as_ref()
.cloned()
},
),
last_date: Self::min_datasets_date(datasets, contains_date_maps, |dataset| {
dataset
.get_min_initial_states()
.inserted
.last_date
.as_ref()
.cloned()
}),
last_height: Self::min_datasets_height(
datasets,
contains_height_maps,
|dataset| {
dataset
.get_min_initial_states()
.inserted
.last_height
.as_ref()
.cloned()
},
),
}
}
Mode::Computed => {
let contains_date_maps = |dataset: &&(dyn AnyDataset + Sync + Send)| {
!dataset.to_all_computed_date_map_vec().is_empty()
};
let contains_height_maps = |dataset: &&(dyn AnyDataset + Sync + Send)| {
!dataset.to_all_computed_height_map_vec().is_empty()
};
Self {
first_unsafe_date: Self::min_datasets_date(
datasets,
contains_date_maps,
|dataset| {
dataset
.get_min_initial_states()
.computed
.first_unsafe_date
.as_ref()
.cloned()
},
),
first_unsafe_height: Self::min_datasets_height(
datasets,
contains_height_maps,
|dataset| {
dataset
.get_min_initial_states()
.computed
.first_unsafe_height
.as_ref()
.cloned()
},
),
last_date: Self::min_datasets_date(datasets, contains_date_maps, |dataset| {
dataset
.get_min_initial_states()
.computed
.last_date
.as_ref()
.cloned()
}),
last_height: Self::min_datasets_height(
datasets,
contains_height_maps,
|dataset| {
dataset
.get_min_initial_states()
.computed
.last_height
.as_ref()
.cloned()
},
),
}
}
}
}
fn min_datasets_date(
datasets: &dyn AnyDatasets,
is_not_empty: impl Fn(&&(dyn AnyDataset + Sync + Send)) -> bool,
map: impl Fn(&(dyn AnyDataset + Sync + Send)) -> Option<WNaiveDate>,
) -> Option<WNaiveDate> {
Self::min_date(
datasets
.to_any_dataset_vec()
.into_iter()
.filter(is_not_empty)
.map(map),
)
}
fn min_datasets_height(
datasets: &dyn AnyDatasets,
is_not_empty: impl Fn(&&(dyn AnyDataset + Sync + Send)) -> bool,
map: impl Fn(&(dyn AnyDataset + Sync + Send)) -> Option<usize>,
) -> Option<usize> {
Self::min_height(
datasets
.to_any_dataset_vec()
.into_iter()
.filter(is_not_empty)
.map(map),
)
}
fn compute_from_dataset(dataset: &dyn AnyDataset, mode: Mode) -> Self {
match mode {
Mode::Inserted => {
let date_vec = dataset.to_all_inserted_date_map_vec();
let height_vec = dataset.to_all_inserted_height_map_vec();
Self {
first_unsafe_date: Self::compute_min_initial_first_unsafe_date_from_dataset(
&date_vec,
),
first_unsafe_height: Self::compute_min_initial_first_unsafe_height_from_dataset(
&height_vec,
),
last_date: Self::compute_min_initial_last_date_from_dataset(&date_vec),
last_height: Self::compute_min_initial_last_height_from_dataset(&height_vec),
}
}
Mode::Computed => {
let date_vec = dataset.to_all_computed_date_map_vec();
let height_vec = dataset.to_all_computed_height_map_vec();
Self {
first_unsafe_date: Self::compute_min_initial_first_unsafe_date_from_dataset(
&date_vec,
),
first_unsafe_height: Self::compute_min_initial_first_unsafe_height_from_dataset(
&height_vec,
),
last_date: Self::compute_min_initial_last_date_from_dataset(&date_vec),
last_height: Self::compute_min_initial_last_height_from_dataset(&height_vec),
}
}
}
}
#[inline(always)]
fn compute_min_initial_last_date_from_dataset(
arr: &[&(dyn AnyDateMap + Sync + Send)],
) -> Option<WNaiveDate> {
Self::min_date(arr.iter().map(|map| map.get_initial_last_date()))
}
#[inline(always)]
fn compute_min_initial_last_height_from_dataset(
arr: &[&(dyn AnyHeightMap + Sync + Send)],
) -> Option<usize> {
Self::min_height(arr.iter().map(|map| map.get_initial_last_height()))
}
#[inline(always)]
fn compute_min_initial_first_unsafe_date_from_dataset(
arr: &[&(dyn AnyDateMap + Sync + Send)],
) -> Option<WNaiveDate> {
Self::min_date(arr.iter().map(|map| map.get_initial_first_unsafe_date()))
}
#[inline(always)]
fn compute_min_initial_first_unsafe_height_from_dataset(
arr: &[&(dyn AnyHeightMap + Sync + Send)],
) -> Option<usize> {
Self::min_height(arr.iter().map(|map| map.get_initial_first_unsafe_height()))
}
#[inline(always)]
fn min_date(iter: impl Iterator<Item = Option<WNaiveDate>>) -> Option<WNaiveDate> {
iter.min().and_then(|opt| opt)
}
#[inline(always)]
fn min_height(iter: impl Iterator<Item = Option<usize>>) -> Option<usize> {
iter.min().and_then(|opt| opt)
}
}

View File

@@ -0,0 +1,9 @@
mod any_dataset;
mod any_dataset_group;
mod any_datasets;
mod min_initial_state;
pub use any_dataset::*;
pub use any_dataset_group::*;
pub use any_datasets::*;
pub use min_initial_state::*;

View File

@@ -0,0 +1,91 @@
use allocative::Allocative;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
structs::{AnyBiMap, BiMap},
};
#[derive(Allocative)]
pub struct AllAddressesMetadataDataset {
min_initial_states: MinInitialStates,
// Inserted
created_addreses: BiMap<u32>,
empty_addresses: BiMap<u32>,
// Computed
new_addresses: BiMap<u32>,
}
impl AllAddressesMetadataDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
// TODO: Shouldn't be (like many others)
created_addreses: BiMap::new_bin(1, &f("created_addresses")),
empty_addresses: BiMap::new_bin(1, &f("empty_addresses")),
new_addresses: BiMap::new_bin(1, &f("new_addresses")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(&mut self, insert_data: &InsertData) {
let &InsertData {
databases,
height,
date,
is_date_last_block,
..
} = insert_data;
let created_addresses = self
.created_addreses
.height
.insert(height, *databases.address_to_address_index.metadata.len);
let empty_addresses = self.empty_addresses.height.insert(
height,
*databases.address_index_to_empty_address_data.metadata.len,
);
if is_date_last_block {
self.created_addreses.date.insert(date, created_addresses);
self.empty_addresses.date.insert(date, empty_addresses);
}
}
pub fn compute(&mut self, &ComputeData { heights, dates }: &ComputeData) {
self.new_addresses
.multi_insert_net_change(heights, dates, &mut self.created_addreses, 1)
}
}
impl AnyDataset for AllAddressesMetadataDataset {
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.created_addreses, &self.empty_addresses]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.created_addreses, &mut self.empty_addresses]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.new_addresses]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.new_addresses]
}
}

View File

@@ -0,0 +1,703 @@
use allocative::Allocative;
use itertools::Itertools;
use crate::{
datasets::{
AnyDataset, AnyDatasetGroup, ComputeData, InsertData, MinInitialStates, SubDataset,
},
states::{AddressCohortDurableStates, AddressCohortId},
structs::{AddressSplit, AnyBiMap, AnyDateMap, AnyHeightMap, BiMap, WNaiveDate},
};
use super::cohort_metadata::MetadataDataset;
#[derive(Default, Allocative)]
pub struct CohortDataset {
min_initial_states: MinInitialStates,
split: AddressSplit,
metadata: MetadataDataset,
pub all: SubDataset,
illiquid: SubDataset,
liquid: SubDataset,
highly_liquid: SubDataset,
}
impl CohortDataset {
pub fn import(parent_path: &str, id: AddressCohortId) -> color_eyre::Result<Self> {
let name = id.as_name();
let split = id.as_split();
let folder_path = {
if let Some(name) = name {
format!("{parent_path}/{name}")
} else {
parent_path.to_owned()
}
};
let f = |s: &str| {
if let Some(name) = name {
format!("{parent_path}/{s}/{name}")
} else {
format!("{parent_path}/{s}")
}
};
let mut s = Self {
min_initial_states: MinInitialStates::default(),
split,
metadata: MetadataDataset::import(&folder_path)?,
all: SubDataset::import(&folder_path)?,
illiquid: SubDataset::import(&f("illiquid"))?,
liquid: SubDataset::import(&f("liquid"))?,
highly_liquid: SubDataset::import(&f("highly_liquid"))?,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn sub_datasets_vec(&self) -> Vec<&SubDataset> {
vec![&self.all, &self.illiquid, &self.liquid, &self.highly_liquid]
}
pub fn needs_insert_metadata(&self, height: usize, date: WNaiveDate) -> bool {
self.metadata.needs_insert(height, date)
}
pub fn needs_insert_utxo(&self, height: usize, date: WNaiveDate) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.utxo.needs_insert(height, date))
}
pub fn needs_insert_capitalization(&self, height: usize, date: WNaiveDate) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.capitalization.needs_insert(height, date))
}
pub fn needs_insert_supply(&self, height: usize, date: WNaiveDate) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.supply.needs_insert(height, date))
}
pub fn needs_insert_price_paid(&self, height: usize, date: WNaiveDate) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.price_paid.needs_insert(height, date))
}
fn needs_insert_realized(&self, height: usize, date: WNaiveDate) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.realized.needs_insert(height, date))
}
fn needs_insert_unrealized(&self, height: usize, date: WNaiveDate) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.unrealized.needs_insert(height, date))
}
fn needs_insert_input(&self, height: usize, date: WNaiveDate) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.input.needs_insert(height, date))
}
// fn needs_insert_output(&self, insert_data: &InsertData) -> bool {
// self.sub_datasets_vec()
// .iter()
// .any(|sub| sub.output.needs_insert(height, date))
// }
fn insert_realized_data(&mut self, insert_data: &InsertData) {
let split_realized_state = insert_data
.address_cohorts_realized_states
.as_ref()
.unwrap()
.get(&self.split)
.unwrap();
self.all
.realized
.insert(insert_data, &split_realized_state.all);
self.illiquid
.realized
.insert(insert_data, &split_realized_state.illiquid);
self.liquid
.realized
.insert(insert_data, &split_realized_state.liquid);
self.highly_liquid
.realized
.insert(insert_data, &split_realized_state.highly_liquid);
}
fn insert_metadata(&mut self, insert_data: &InsertData) {
let address_count = insert_data
.states
.address_cohorts_durable_states
.get(&self.split)
.unwrap()
.address_count;
self.metadata.insert(insert_data, address_count);
}
fn insert_supply_data(
&mut self,
insert_data: &InsertData,
liquidity_split_state: &AddressCohortDurableStates,
) {
self.all.supply.insert(
insert_data,
&liquidity_split_state.split_durable_states.all.supply_state,
);
self.illiquid.supply.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.illiquid
.supply_state,
);
self.liquid.supply.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.liquid
.supply_state,
);
self.highly_liquid.supply.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.highly_liquid
.supply_state,
);
}
fn insert_utxo_data(
&mut self,
insert_data: &InsertData,
liquidity_split_state: &AddressCohortDurableStates,
) {
self.all.utxo.insert(
insert_data,
&liquidity_split_state.split_durable_states.all.utxo_state,
);
self.illiquid.utxo.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.illiquid
.utxo_state,
);
self.liquid.utxo.insert(
insert_data,
&liquidity_split_state.split_durable_states.liquid.utxo_state,
);
self.highly_liquid.utxo.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.highly_liquid
.utxo_state,
);
}
fn insert_capitalization_data(
&mut self,
insert_data: &InsertData,
liquidity_split_state: &AddressCohortDurableStates,
) {
self.all.capitalization.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.all
.capitalization_state,
);
self.illiquid.capitalization.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.illiquid
.capitalization_state,
);
self.liquid.capitalization.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.liquid
.capitalization_state,
);
self.highly_liquid.capitalization.insert(
insert_data,
&liquidity_split_state
.split_durable_states
.highly_liquid
.capitalization_state,
);
}
fn insert_unrealized_data(&mut self, insert_data: &InsertData) {
let states = insert_data
.address_cohorts_one_shot_states
.as_ref()
.unwrap()
.get(&self.split)
.unwrap();
self.all.unrealized.insert(
insert_data,
&states.all.unrealized_block_state,
&states.all.unrealized_date_state,
);
self.illiquid.unrealized.insert(
insert_data,
&states.illiquid.unrealized_block_state,
&states.illiquid.unrealized_date_state,
);
self.liquid.unrealized.insert(
insert_data,
&states.liquid.unrealized_block_state,
&states.liquid.unrealized_date_state,
);
self.highly_liquid.unrealized.insert(
insert_data,
&states.highly_liquid.unrealized_block_state,
&states.highly_liquid.unrealized_date_state,
);
}
fn insert_price_paid_data(&mut self, insert_data: &InsertData) {
let states = insert_data
.address_cohorts_one_shot_states
.as_ref()
.unwrap()
.get(&self.split)
.unwrap();
self.all
.price_paid
.insert(insert_data, &states.all.price_paid_state);
self.illiquid
.price_paid
.insert(insert_data, &states.illiquid.price_paid_state);
self.liquid
.price_paid
.insert(insert_data, &states.liquid.price_paid_state);
self.highly_liquid
.price_paid
.insert(insert_data, &states.highly_liquid.price_paid_state);
}
fn insert_input_data(&mut self, insert_data: &InsertData) {
let state = insert_data
.address_cohorts_input_states
.as_ref()
.unwrap()
.get(&self.split)
.unwrap();
self.all.input.insert(insert_data, &state.all);
self.illiquid.input.insert(insert_data, &state.illiquid);
self.liquid.input.insert(insert_data, &state.liquid);
self.highly_liquid
.input
.insert(insert_data, &state.highly_liquid);
}
// fn insert_output_data(&mut self, insert_data: &InsertData) {
// let state = insert_data
// .address_cohorts_output_states
// .as_ref()
// .unwrap()
// .get(&self.split)
// .unwrap();
// self.all.output.insert(insert_data, &state.all);
// self.illiquid.output.insert(insert_data, &state.illiquid);
// self.liquid.output.insert(insert_data, &state.liquid);
// self.highly_liquid
// .output
// .insert(insert_data, &state.highly_liquid);
// }
fn as_vec(&self) -> Vec<&(dyn AnyDataset + Send + Sync)> {
vec![
self.all.as_vec(),
self.illiquid.as_vec(),
self.liquid.as_vec(),
self.highly_liquid.as_vec(),
vec![&self.metadata],
]
.into_iter()
.flatten()
.collect_vec()
}
fn as_mut_vec(&mut self) -> Vec<&mut dyn AnyDataset> {
vec![
self.all.as_mut_vec(),
self.illiquid.as_mut_vec(),
self.liquid.as_mut_vec(),
self.highly_liquid.as_mut_vec(),
vec![&mut self.metadata],
]
.into_iter()
.flatten()
.collect_vec()
}
pub fn insert(&mut self, insert_data: &InsertData) {
if !insert_data.compute_addresses {
return;
}
let liquidity_split_processed_address_state = insert_data
.states
.address_cohorts_durable_states
.get(&self.split);
if liquidity_split_processed_address_state.is_none() {
return; // TODO: Check if should panic instead
}
let liquidity_split_processed_address_state =
liquidity_split_processed_address_state.unwrap();
if self.needs_insert_metadata(insert_data.height, insert_data.date) {
self.insert_metadata(insert_data);
}
if self.needs_insert_utxo(insert_data.height, insert_data.date) {
self.insert_utxo_data(insert_data, liquidity_split_processed_address_state);
}
if self.needs_insert_capitalization(insert_data.height, insert_data.date) {
self.insert_capitalization_data(insert_data, liquidity_split_processed_address_state);
}
if self.needs_insert_supply(insert_data.height, insert_data.date) {
self.insert_supply_data(insert_data, liquidity_split_processed_address_state);
}
if self.needs_insert_realized(insert_data.height, insert_data.date) {
self.insert_realized_data(insert_data);
}
if self.needs_insert_unrealized(insert_data.height, insert_data.date) {
self.insert_unrealized_data(insert_data);
}
if self.needs_insert_price_paid(insert_data.height, insert_data.date) {
self.insert_price_paid_data(insert_data);
}
if self.needs_insert_input(insert_data.height, insert_data.date) {
self.insert_input_data(insert_data);
}
// if self.needs_insert_output(insert_data) {
// self.insert_output_data(insert_data);
// }
}
// pub fn should_compute_metadata(&self, compute_data: &ComputeData) -> bool {
// self.metadata.should_compute(compute_data)
// }
// pub fn should_compute_utxo(&self, compute_data: &ComputeData) -> bool {
// self.sub_datasets_vec()
// .iter()
// .any(|sub| sub.utxo.should_compute(compute_data))
// }
pub fn should_compute_supply(&self, compute_data: &ComputeData) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.supply.should_compute(compute_data))
}
pub fn should_compute_capitalization(&self, compute_data: &ComputeData) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.capitalization.should_compute(compute_data))
}
fn should_compute_realized(&self, compute_data: &ComputeData) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.realized.should_compute(compute_data))
}
fn should_compute_unrealized(&self, compute_data: &ComputeData) -> bool {
self.sub_datasets_vec()
.iter()
.any(|sub| sub.unrealized.should_compute(compute_data))
}
// fn should_compute_input(&self, compute_data: &ComputeData) -> bool {
// self.sub_datasets_vec()
// .iter()
// .any(|sub| sub.input.should_compute(compute_data))
// }
// fn should_compute_output(&self, compute_data: &ComputeData) -> bool {
// self.sub_datasets_vec()
// .iter()
// .any(|sub| sub.output.should_compute(compute_data))
// }
fn compute_supply_data(
&mut self,
compute_data: &ComputeData,
circulating_supply: &mut BiMap<f64>,
) {
self.all.supply.compute(compute_data, circulating_supply);
self.illiquid
.supply
.compute(compute_data, circulating_supply);
self.liquid.supply.compute(compute_data, circulating_supply);
self.highly_liquid
.supply
.compute(compute_data, circulating_supply);
}
fn compute_unrealized_data(
&mut self,
compute_data: &ComputeData,
circulating_supply: &mut BiMap<f64>,
market_cap: &mut BiMap<f32>,
) {
self.all.unrealized.compute(
compute_data,
&mut self.all.supply.supply,
circulating_supply,
market_cap,
);
self.illiquid.unrealized.compute(
compute_data,
&mut self.illiquid.supply.supply,
circulating_supply,
market_cap,
);
self.liquid.unrealized.compute(
compute_data,
&mut self.liquid.supply.supply,
circulating_supply,
market_cap,
);
self.highly_liquid.unrealized.compute(
compute_data,
&mut self.highly_liquid.supply.supply,
circulating_supply,
market_cap,
);
}
fn compute_realized_data(&mut self, compute_data: &ComputeData, market_cap: &mut BiMap<f32>) {
self.all.realized.compute(compute_data, market_cap);
self.illiquid.realized.compute(compute_data, market_cap);
self.liquid.realized.compute(compute_data, market_cap);
self.highly_liquid
.realized
.compute(compute_data, market_cap);
}
fn compute_capitalization_data(&mut self, compute_data: &ComputeData, closes: &mut BiMap<f32>) {
self.all
.capitalization
.compute(compute_data, closes, &mut self.all.supply.supply);
self.illiquid.capitalization.compute(
compute_data,
closes,
&mut self.illiquid.supply.supply,
);
self.liquid
.capitalization
.compute(compute_data, closes, &mut self.liquid.supply.supply);
self.highly_liquid.capitalization.compute(
compute_data,
closes,
&mut self.highly_liquid.supply.supply,
);
}
// fn compute_output_data(&mut self, compute_data: &ComputeData) {
// self.all
// .output
// .compute(compute_data, &mut self.all.supply.total);
// self.illiquid
// .output
// .compute(compute_data, &mut self.illiquid.supply.total);
// self.liquid
// .output
// .compute(compute_data, &mut self.liquid.supply.total);
// self.highly_liquid
// .output
// .compute(compute_data, &mut self.highly_liquid.supply.total);
// }
pub fn compute(
&mut self,
compute_data: &ComputeData,
closes: &mut BiMap<f32>,
circulating_supply: &mut BiMap<f64>,
market_cap: &mut BiMap<f32>,
) {
if self.should_compute_supply(compute_data) {
self.compute_supply_data(compute_data, circulating_supply);
}
if self.should_compute_unrealized(compute_data) {
self.compute_unrealized_data(compute_data, circulating_supply, market_cap);
}
if self.should_compute_realized(compute_data) {
self.compute_realized_data(compute_data, market_cap);
}
// MUST BE after compute_supply
if self.should_compute_capitalization(compute_data) {
self.compute_capitalization_data(compute_data, closes);
}
// if self.should_compute_output(compute_data) {
// self.compute_output_data(compute_data);
// }
}
}
impl AnyDataset for CohortDataset {
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_height_map_vec())
.collect_vec()
}
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_date_map_vec())
.collect_vec()
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_bi_map_vec())
.collect_vec()
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_height_map_vec())
.collect_vec()
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_date_map_vec())
.collect_vec()
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_bi_map_vec())
.collect_vec()
}
fn to_computed_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_height_map_vec())
.collect_vec()
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_date_map_vec())
.collect_vec()
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_bi_map_vec())
.collect_vec()
}
fn to_computed_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_height_map_vec())
.collect_vec()
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_date_map_vec())
.collect_vec()
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_bi_map_vec())
.collect_vec()
}
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
}

View File

@@ -0,0 +1,67 @@
use allocative::Allocative;
use crate::{
datasets::{AnyDataset, InsertData, MinInitialStates},
structs::{AnyBiMap, BiMap},
};
#[derive(Default, Allocative)]
pub struct MetadataDataset {
min_initial_states: MinInitialStates,
// Inserted
address_count: BiMap<usize>,
// pub output: OutputSubDataset,
// Sending addresses
// Receiving addresses
// Active addresses (Unique(Sending + Receiving))
}
impl MetadataDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
address_count: BiMap::new_bin(1, &f("address_count")),
// output: OutputSubDataset::import(parent_path)?,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
date,
is_date_last_block,
..
}: &InsertData,
address_count: usize,
) {
self.address_count.height.insert(height, address_count);
if is_date_last_block {
self.address_count.date.insert(date, address_count);
}
}
}
impl AnyDataset for MetadataDataset {
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.address_count]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.address_count]
}
}

View File

@@ -0,0 +1,151 @@
mod all_metadata;
mod cohort;
mod cohort_metadata;
use allocative::Allocative;
use itertools::Itertools;
use rayon::prelude::*;
use crate::{states::SplitByAddressCohort, structs::BiMap};
use self::{all_metadata::AllAddressesMetadataDataset, cohort::CohortDataset};
use super::{AnyDataset, AnyDatasets, ComputeData, InsertData, MinInitialStates};
#[derive(Allocative)]
pub struct AddressDatasets {
min_initial_states: MinInitialStates,
metadata: AllAddressesMetadataDataset,
pub cohorts: SplitByAddressCohort<CohortDataset>,
}
impl AddressDatasets {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let mut cohorts = SplitByAddressCohort::<CohortDataset>::default();
cohorts
.as_vec()
.into_par_iter()
.map(|(_, id)| (id, CohortDataset::import(parent_path, id)))
.collect::<Vec<_>>()
.into_iter()
.try_for_each(|(id, dataset)| -> color_eyre::Result<()> {
*cohorts.get_mut_from_id(&id) = dataset?;
Ok(())
})?;
let mut s = Self {
min_initial_states: MinInitialStates::default(),
metadata: AllAddressesMetadataDataset::import(parent_path)?,
cohorts,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_datasets(&s));
Ok(s)
}
pub fn insert(&mut self, insert_data: &InsertData) {
self.metadata.insert(insert_data);
self.cohorts
.as_mut_vec()
.into_iter()
.for_each(|(cohort, _)| cohort.insert(insert_data))
}
// pub fn needs_insert_utxo(&self, height: usize, date: WNaiveDate) -> bool {
// self.cohorts
// .as_vec()
// .iter()
// .any(|(dataset, _)| dataset.utxo.needs_insert(height, date))
// }
// pub fn needs_insert_capitalization(&self, height: usize, date: WNaiveDate) -> bool {
// self.cohorts
// .as_vec()
// .iter()
// .any(|(dataset, _)| dataset.capitalization.needs_insert(height, date))
// }
// pub fn needs_insert_supply(&self, height: usize, date: WNaiveDate) -> bool {
// self.cohorts
// .as_vec()
// .iter()
// .any(|(dataset, _)| dataset.supply.needs_insert(height, date))
// }
// pub fn needs_insert_price_paid(&self, height: usize, date: WNaiveDate) -> bool {
// self.cohorts
// .as_vec()
// .iter()
// .any(|(dataset, _)| dataset.price_paid.needs_insert(height, date))
// }
// fn needs_insert_realized(&self, height: usize, date: WNaiveDate) -> bool {
// self.cohorts
// .as_vec()
// .iter()
// .any(|(dataset, _)| dataset.realized.needs_insert(height, date))
// }
// fn needs_insert_unrealized(&self, height: usize, date: WNaiveDate) -> bool {
// self.cohorts
// .as_vec()
// .iter()
// .any(|(dataset, _)| dataset.unrealized.needs_insert(height, date))
// }
// fn needs_insert_input(&self, height: usize, date: WNaiveDate) -> bool {
// self.cohorts
// .as_vec()
// .iter()
// .any(|(dataset, _)| dataset.input.needs_insert(height, date))
// }
pub fn compute(
&mut self,
compute_data: &ComputeData,
closes: &mut BiMap<f32>,
circulating_supply: &mut BiMap<f64>,
market_cap: &mut BiMap<f32>,
) {
self.metadata.compute(compute_data);
self.cohorts
.as_mut_vec()
.into_iter()
.for_each(|(cohort, _)| {
cohort.compute(compute_data, closes, circulating_supply, market_cap)
})
}
}
impl AnyDatasets for AddressDatasets {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_any_dataset_vec(&self) -> Vec<&(dyn AnyDataset + Send + Sync)> {
self.cohorts
.as_vec()
.into_iter()
.map(|(d, _)| d as &(dyn AnyDataset + Send + Sync))
.chain(vec![&self.metadata as &(dyn AnyDataset + Send + Sync)])
.collect_vec()
}
fn to_mut_any_dataset_vec(&mut self) -> Vec<&mut dyn AnyDataset> {
self.cohorts
.as_mut_vec()
.into_iter()
.map(|(d, _)| d as &mut dyn AnyDataset)
.chain(vec![&mut self.metadata as &mut dyn AnyDataset])
.collect_vec()
}
}

View File

@@ -0,0 +1,61 @@
use allocative::Allocative;
use crate::{
datasets::AnyDataset,
structs::{AnyHeightMap, HeightMap, WNaiveDate},
};
use super::{InsertData, MinInitialStates};
#[derive(Allocative)]
pub struct BlockMetadataDataset {
min_initial_states: MinInitialStates,
// Inserted
pub date: HeightMap<WNaiveDate>,
pub timestamp: HeightMap<u32>,
}
impl BlockMetadataDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
date: HeightMap::new_bin(1, &f("date")),
timestamp: HeightMap::new_bin(1, &f("timestamp")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height, timestamp, ..
}: &InsertData,
) {
self.timestamp.insert(height, timestamp);
self.date
.insert(height, WNaiveDate::from_timestamp(timestamp));
}
}
impl AnyDataset for BlockMetadataDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
vec![&self.date, &self.timestamp]
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
vec![&mut self.date, &mut self.timestamp]
}
}

View File

@@ -0,0 +1,68 @@
use allocative::Allocative;
use crate::{
datasets::AnyDataset,
structs::{AnyBiMap, BiMap},
};
use super::{InsertData, MinInitialStates};
#[derive(Allocative)]
pub struct CoindaysDataset {
min_initial_states: MinInitialStates,
// Inserted
pub coindays_destroyed: BiMap<f32>,
}
impl CoindaysDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
coindays_destroyed: BiMap::new_bin(1, &f("coindays_destroyed")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
satdays_destroyed,
date_blocks_range,
is_date_last_block,
date,
..
}: &InsertData,
) {
self.coindays_destroyed
.height
.insert(height, satdays_destroyed.to_btc() as f32);
if is_date_last_block {
self.coindays_destroyed
.date_insert_sum_range(date, date_blocks_range)
}
}
}
impl AnyDataset for CoindaysDataset {
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.coindays_destroyed]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.coindays_destroyed]
}
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
}

View File

@@ -0,0 +1,594 @@
use allocative::Allocative;
use crate::{
structs::{AnyBiMap, BiMap, DateMap},
utils::{ONE_DAY_IN_DAYS, ONE_YEAR_IN_DAYS, THREE_MONTHS_IN_DAYS, TWO_WEEK_IN_DAYS},
};
use super::{AnyDataset, ComputeData, InsertData, MinInitialStates};
#[derive(Allocative)]
pub struct CointimeDataset {
min_initial_states: MinInitialStates,
// Inserted
pub coinblocks_destroyed: BiMap<f32>,
// Computed
pub active_cap: BiMap<f32>,
pub active_price: BiMap<f32>,
pub active_supply: BiMap<f32>,
pub active_supply_3m_net_change: BiMap<f32>,
pub active_supply_net_change: BiMap<f32>,
pub activity_to_vaultedness_ratio: BiMap<f32>,
pub coinblocks_created: BiMap<f32>,
pub coinblocks_stored: BiMap<f32>,
pub cointime_adjusted_velocity: BiMap<f32>,
pub cointime_adjusted_yearly_inflation_rate: BiMap<f32>,
pub cointime_cap: BiMap<f32>,
pub cointime_price: BiMap<f32>,
pub cointime_value_created: BiMap<f32>,
pub cointime_value_destroyed: BiMap<f32>,
pub cointime_value_stored: BiMap<f32>,
pub concurrent_liveliness: BiMap<f32>,
pub concurrent_liveliness_2w_median: BiMap<f32>,
pub cumulative_coinblocks_created: BiMap<f32>,
pub cumulative_coinblocks_destroyed: BiMap<f32>,
pub cumulative_coinblocks_stored: BiMap<f32>,
pub investor_cap: BiMap<f32>,
pub investorness: BiMap<f32>,
pub liveliness: BiMap<f32>,
pub liveliness_net_change: BiMap<f32>,
pub liveliness_net_change_2w_median: BiMap<f32>,
pub producerness: BiMap<f32>,
pub thermo_cap: BiMap<f32>,
pub thermo_cap_to_investor_cap_ratio: BiMap<f32>,
pub total_cointime_value_created: BiMap<f32>,
pub total_cointime_value_destroyed: BiMap<f32>,
pub total_cointime_value_stored: BiMap<f32>,
pub true_market_deviation: BiMap<f32>,
pub true_market_mean: BiMap<f32>,
pub true_market_net_unrealized_profit_and_loss: BiMap<f32>,
pub vaulted_cap: BiMap<f32>,
pub vaulted_price: BiMap<f32>,
pub vaulted_supply: BiMap<f32>,
pub vaulted_supply_net_change: BiMap<f32>,
pub vaulted_supply_3m_net_change: BiMap<f32>,
pub vaultedness: BiMap<f32>,
pub vaulting_rate: BiMap<f32>,
}
impl CointimeDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
active_cap: BiMap::new_bin(1, &f("active_cap")),
active_price: BiMap::new_bin(1, &f("active_price")),
active_supply: BiMap::new_bin(1, &f("active_supply")),
active_supply_3m_net_change: BiMap::new_bin(1, &f("active_supply_3m_net_change")),
active_supply_net_change: BiMap::new_bin(1, &f("active_supply_net_change")),
activity_to_vaultedness_ratio: BiMap::new_bin(1, &f("activity_to_vaultedness_ratio")),
coinblocks_created: BiMap::new_bin(1, &f("coinblocks_created")),
coinblocks_destroyed: BiMap::new_bin(1, &f("coinblocks_destroyed")),
coinblocks_stored: BiMap::new_bin(1, &f("coinblocks_stored")),
cointime_adjusted_velocity: BiMap::new_bin(1, &f("cointime_adjusted_velocity")),
cointime_adjusted_yearly_inflation_rate: BiMap::new_bin(
1,
&f("cointime_adjusted_yearly_inflation_rate"),
),
cointime_cap: BiMap::new_bin(1, &f("cointime_cap")),
cointime_price: BiMap::new_bin(1, &f("cointime_price")),
cointime_value_created: BiMap::new_bin(1, &f("cointime_value_created")),
cointime_value_destroyed: BiMap::new_bin(1, &f("cointime_value_destroyed")),
cointime_value_stored: BiMap::new_bin(1, &f("cointime_value_stored")),
concurrent_liveliness: BiMap::new_bin(1, &f("concurrent_liveliness")),
concurrent_liveliness_2w_median: BiMap::new_bin(
1,
&f("concurrent_liveliness_2w_median"),
),
cumulative_coinblocks_created: BiMap::new_bin(1, &f("cumulative_coinblocks_created")),
cumulative_coinblocks_destroyed: BiMap::new_bin(
1,
&f("cumulative_coinblocks_destroyed"),
),
cumulative_coinblocks_stored: BiMap::new_bin(1, &f("cumulative_coinblocks_stored")),
investor_cap: BiMap::new_bin(1, &f("investor_cap")),
investorness: BiMap::new_bin(1, &f("investorness")),
liveliness: BiMap::new_bin(1, &f("liveliness")),
liveliness_net_change: BiMap::new_bin(1, &f("liveliness_net_change")),
liveliness_net_change_2w_median: BiMap::new_bin(
1,
&f("liveliness_net_change_2w_median"),
),
producerness: BiMap::new_bin(1, &f("producerness")),
thermo_cap: BiMap::new_bin(1, &f("thermo_cap")),
thermo_cap_to_investor_cap_ratio: BiMap::new_bin(
1,
&f("thermo_cap_to_investor_cap_ratio"),
),
total_cointime_value_created: BiMap::new_bin(1, &f("total_cointime_value_created")),
total_cointime_value_destroyed: BiMap::new_bin(1, &f("total_cointime_value_destroyed")),
total_cointime_value_stored: BiMap::new_bin(1, &f("total_cointime_value_stored")),
true_market_deviation: BiMap::new_bin(1, &f("true_market_deviation")),
true_market_mean: BiMap::new_bin(1, &f("true_market_mean")),
true_market_net_unrealized_profit_and_loss: BiMap::new_bin(
1,
&f("true_market_net_unrealized_profit_and_loss"),
),
vaulted_cap: BiMap::new_bin(1, &f("vaulted_cap")),
vaulted_price: BiMap::new_bin(1, &f("vaulted_price")),
vaulted_supply: BiMap::new_bin(1, &f("vaulted_supply")),
vaulted_supply_3m_net_change: BiMap::new_bin(1, &f("vaulted_supply_3m_net_change")),
vaulted_supply_net_change: BiMap::new_bin(1, &f("vaulted_supply_net_change")),
vaultedness: BiMap::new_bin(1, &f("vaultedness")),
vaulting_rate: BiMap::new_bin(1, &f("vaulting_rate")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
date,
satblocks_destroyed,
date_blocks_range,
is_date_last_block,
..
}: &InsertData,
) {
self.coinblocks_destroyed
.height
.insert(height, satblocks_destroyed.to_btc() as f32);
if is_date_last_block {
self.coinblocks_destroyed
.date_insert_sum_range(date, date_blocks_range);
}
}
#[allow(clippy::too_many_arguments)]
pub fn compute(
&mut self,
&ComputeData { heights, dates }: &ComputeData,
first_height: &mut DateMap<usize>,
last_height: &mut DateMap<usize>,
closes: &mut BiMap<f32>,
circulating_supply: &mut BiMap<f64>,
realized_cap: &mut BiMap<f32>,
realized_price: &mut BiMap<f32>,
yearly_inflation_rate: &mut BiMap<f64>,
annualized_transaction_volume: &mut BiMap<f32>,
cumulative_subsidy_in_dollars: &mut BiMap<f32>,
) {
self.cumulative_coinblocks_destroyed
.multi_insert_cumulative(heights, dates, &mut self.coinblocks_destroyed);
self.coinblocks_created
.height
.multi_insert_simple_transform(
heights,
&mut circulating_supply.height,
|circulating_supply| circulating_supply as f32,
);
self.coinblocks_created
.multi_date_insert_sum_range(dates, first_height, last_height);
self.cumulative_coinblocks_created.multi_insert_cumulative(
heights,
dates,
&mut self.coinblocks_created,
);
self.coinblocks_stored.height.multi_insert_subtract(
heights,
&mut self.coinblocks_created.height,
&mut self.coinblocks_destroyed.height,
);
self.coinblocks_stored
.multi_date_insert_sum_range(dates, first_height, last_height);
self.cumulative_coinblocks_stored.multi_insert_cumulative(
heights,
dates,
&mut self.coinblocks_stored,
);
self.liveliness.multi_insert_divide(
heights,
dates,
&mut self.cumulative_coinblocks_destroyed,
&mut self.cumulative_coinblocks_created,
);
self.vaultedness.multi_insert_simple_transform(
heights,
dates,
&mut self.liveliness,
&|liveliness| 1.0 - liveliness,
);
self.activity_to_vaultedness_ratio.multi_insert_divide(
heights,
dates,
&mut self.liveliness,
&mut self.vaultedness,
);
self.concurrent_liveliness.multi_insert_divide(
heights,
dates,
&mut self.coinblocks_destroyed,
&mut self.coinblocks_created,
);
self.concurrent_liveliness_2w_median.multi_insert_median(
heights,
dates,
&mut self.concurrent_liveliness,
Some(TWO_WEEK_IN_DAYS),
);
self.liveliness_net_change.multi_insert_net_change(
heights,
dates,
&mut self.liveliness,
ONE_DAY_IN_DAYS,
);
self.liveliness_net_change_2w_median
.multi_insert_net_change(heights, dates, &mut self.liveliness, TWO_WEEK_IN_DAYS);
self.vaulted_supply.multi_insert_multiply(
heights,
dates,
&mut self.vaultedness,
circulating_supply,
);
self.vaulted_supply_net_change.multi_insert_net_change(
heights,
dates,
&mut self.vaulted_supply,
ONE_DAY_IN_DAYS,
);
self.vaulted_supply_3m_net_change.multi_insert_net_change(
heights,
dates,
&mut self.vaulted_supply,
THREE_MONTHS_IN_DAYS,
);
self.vaulting_rate.multi_insert_simple_transform(
heights,
dates,
&mut self.vaulted_supply,
&|vaulted_supply| vaulted_supply * ONE_YEAR_IN_DAYS as f32,
);
self.active_supply.multi_insert_multiply(
heights,
dates,
&mut self.liveliness,
circulating_supply,
);
self.active_supply_net_change.multi_insert_net_change(
heights,
dates,
&mut self.active_supply,
ONE_DAY_IN_DAYS,
);
self.active_supply_3m_net_change.multi_insert_net_change(
heights,
dates,
&mut self.active_supply,
THREE_MONTHS_IN_DAYS,
);
// TODO: Do these
// let min_vaulted_supply = ;
// let max_active_supply = ;
self.cointime_adjusted_yearly_inflation_rate
.multi_insert_multiply(
heights,
dates,
&mut self.activity_to_vaultedness_ratio,
yearly_inflation_rate,
);
self.cointime_adjusted_velocity.multi_insert_divide(
heights,
dates,
annualized_transaction_volume,
&mut self.active_supply,
);
// TODO:
// const activeSupplyChangeFromTransactions90dChange =
// createNetChangeLazyDataset(activeSupplyChangeFromTransactions, 90);
// const activeSupplyChangeFromIssuance = createMultipliedLazyDataset(
// lastSubsidy,
// liveliness,
// );
self.thermo_cap.multi_insert_simple_transform(
heights,
dates,
cumulative_subsidy_in_dollars,
&|cumulative_subsidy_in_dollars| cumulative_subsidy_in_dollars,
);
self.investor_cap
.multi_insert_subtract(heights, dates, realized_cap, &mut self.thermo_cap);
self.thermo_cap_to_investor_cap_ratio.multi_insert_divide(
heights,
dates,
&mut self.thermo_cap,
&mut self.investor_cap,
);
// TODO:
// const activeSupplyChangeFromIssuance90dChange = createNetChangeLazyDataset(
// activeSupplyChangeFromIssuance,
// 90,
// );
self.active_price
.multi_insert_divide(heights, dates, realized_price, &mut self.liveliness);
self.active_cap.height.multi_insert_multiply(
heights,
&mut self.active_supply.height,
&mut closes.height,
);
self.active_cap.date.multi_insert_multiply(
dates,
&mut self.active_supply.date,
&mut closes.date,
);
self.vaulted_price.multi_insert_divide(
heights,
dates,
realized_price,
&mut self.vaultedness,
);
self.vaulted_cap.height.multi_insert_multiply(
heights,
&mut self.vaulted_supply.height,
&mut closes.height,
);
self.vaulted_cap.date.multi_insert_multiply(
dates,
&mut self.vaulted_supply.date,
&mut closes.date,
);
self.true_market_mean.multi_insert_divide(
heights,
dates,
&mut self.investor_cap,
&mut self.active_supply,
);
self.true_market_deviation.multi_insert_divide(
heights,
dates,
&mut self.active_cap,
&mut self.investor_cap,
);
self.true_market_net_unrealized_profit_and_loss
.height
.multi_insert_complex_transform(
heights,
&mut self.active_cap.height,
|(active_cap, height)| {
let investor_cap = self.investor_cap.height.get(height).unwrap();
(active_cap - investor_cap) / active_cap
},
);
self.true_market_net_unrealized_profit_and_loss
.date
.multi_insert_complex_transform(
dates,
&mut self.active_cap.date,
|(active_cap, date, _)| {
let investor_cap = self.investor_cap.date.get(date).unwrap();
(active_cap - investor_cap) / active_cap
},
);
self.investorness
.multi_insert_divide(heights, dates, &mut self.investor_cap, realized_cap);
self.producerness
.multi_insert_divide(heights, dates, &mut self.thermo_cap, realized_cap);
self.cointime_value_destroyed.height.multi_insert_multiply(
heights,
&mut self.coinblocks_destroyed.height,
&mut closes.height,
);
self.cointime_value_destroyed.date.multi_insert_multiply(
dates,
&mut self.coinblocks_destroyed.date,
&mut closes.date,
);
self.cointime_value_created.height.multi_insert_multiply(
heights,
&mut self.coinblocks_created.height,
&mut closes.height,
);
self.cointime_value_created.date.multi_insert_multiply(
dates,
&mut self.coinblocks_created.date,
&mut closes.date,
);
self.cointime_value_stored.height.multi_insert_multiply(
heights,
&mut self.coinblocks_stored.height,
&mut closes.height,
);
self.cointime_value_stored.date.multi_insert_multiply(
dates,
&mut self.coinblocks_stored.date,
&mut closes.date,
);
self.total_cointime_value_created.multi_insert_cumulative(
heights,
dates,
&mut self.cointime_value_created,
);
self.total_cointime_value_destroyed.multi_insert_cumulative(
heights,
dates,
&mut self.cointime_value_destroyed,
);
self.total_cointime_value_stored.multi_insert_cumulative(
heights,
dates,
&mut self.cointime_value_stored,
);
self.cointime_price.multi_insert_divide(
heights,
dates,
&mut self.total_cointime_value_destroyed,
&mut self.cumulative_coinblocks_stored,
);
self.cointime_cap.multi_insert_multiply(
heights,
dates,
&mut self.cointime_price,
circulating_supply,
);
}
}
impl AnyDataset for CointimeDataset {
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.coinblocks_destroyed]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.coinblocks_destroyed]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.active_cap,
&self.active_price,
&self.active_supply,
&self.active_supply_3m_net_change,
&self.active_supply_net_change,
&self.activity_to_vaultedness_ratio,
&self.coinblocks_created,
&self.coinblocks_stored,
&self.cointime_adjusted_velocity,
&self.cointime_adjusted_yearly_inflation_rate,
&self.cointime_cap,
&self.cointime_price,
&self.cointime_value_created,
&self.cointime_value_destroyed,
&self.cointime_value_stored,
&self.concurrent_liveliness,
&self.concurrent_liveliness_2w_median,
&self.cumulative_coinblocks_created,
&self.cumulative_coinblocks_destroyed,
&self.cumulative_coinblocks_stored,
&self.investor_cap,
&self.investorness,
&self.liveliness,
&self.liveliness_net_change,
&self.liveliness_net_change_2w_median,
&self.producerness,
&self.thermo_cap,
&self.thermo_cap_to_investor_cap_ratio,
&self.total_cointime_value_created,
&self.total_cointime_value_destroyed,
&self.total_cointime_value_stored,
&self.true_market_deviation,
&self.true_market_mean,
&self.true_market_net_unrealized_profit_and_loss,
&self.vaulted_cap,
&self.vaulted_price,
&self.vaulted_supply,
&self.vaulted_supply_net_change,
&self.vaulted_supply_3m_net_change,
&self.vaultedness,
&self.vaulting_rate,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.active_cap,
&mut self.active_price,
&mut self.active_supply,
&mut self.active_supply_3m_net_change,
&mut self.active_supply_net_change,
&mut self.activity_to_vaultedness_ratio,
&mut self.coinblocks_created,
&mut self.coinblocks_stored,
&mut self.cointime_adjusted_velocity,
&mut self.cointime_adjusted_yearly_inflation_rate,
&mut self.cointime_cap,
&mut self.cointime_price,
&mut self.cointime_value_created,
&mut self.cointime_value_destroyed,
&mut self.cointime_value_stored,
&mut self.concurrent_liveliness,
&mut self.concurrent_liveliness_2w_median,
&mut self.cumulative_coinblocks_created,
&mut self.cumulative_coinblocks_destroyed,
&mut self.cumulative_coinblocks_stored,
&mut self.investor_cap,
&mut self.investorness,
&mut self.liveliness,
&mut self.liveliness_net_change,
&mut self.liveliness_net_change_2w_median,
&mut self.producerness,
&mut self.thermo_cap,
&mut self.thermo_cap_to_investor_cap_ratio,
&mut self.total_cointime_value_created,
&mut self.total_cointime_value_destroyed,
&mut self.total_cointime_value_stored,
&mut self.true_market_deviation,
&mut self.true_market_mean,
&mut self.true_market_net_unrealized_profit_and_loss,
&mut self.vaulted_cap,
&mut self.vaulted_price,
&mut self.vaulted_supply,
&mut self.vaulted_supply_net_change,
&mut self.vaulted_supply_3m_net_change,
&mut self.vaultedness,
&mut self.vaulting_rate,
]
}
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
}

View File

@@ -0,0 +1,52 @@
use allocative::Allocative;
use crate::structs::{AnyBiMap, BiMap};
use super::{AnyDataset, ComputeData, MinInitialStates};
#[derive(Allocative)]
pub struct ConstantDataset {
min_initial_states: MinInitialStates,
// Computed
pub _50: BiMap<u16>,
pub _100: BiMap<u16>,
}
impl ConstantDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
_50: BiMap::new_bin(1, &f("50")),
_100: BiMap::new_bin(1, &f("100")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn compute(&mut self, &ComputeData { heights, dates }: &ComputeData) {
self._50.multi_insert_const(heights, dates, 50);
self._100.multi_insert_const(heights, dates, 100);
}
}
impl AnyDataset for ConstantDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self._50, &self._100]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self._50, &mut self._100]
}
}

View File

@@ -0,0 +1,63 @@
use allocative::Allocative;
use crate::{
datasets::AnyDataset,
structs::{AnyDateMap, DateMap},
};
use super::{InsertData, MinInitialStates};
#[derive(Allocative)]
pub struct DateMetadataDataset {
min_initial_states: MinInitialStates,
// Inserted
pub first_height: DateMap<usize>,
pub last_height: DateMap<usize>,
}
impl DateMetadataDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
first_height: DateMap::new_bin(1, &f("first_height")),
last_height: DateMap::new_bin(1, &f("last_height")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
date,
date_first_height,
height,
..
}: &InsertData,
) {
self.first_height.insert(date, date_first_height);
self.last_height.insert(date, height);
}
}
impl AnyDataset for DateMetadataDataset {
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![&self.first_height, &self.last_height]
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![&mut self.first_height, &mut self.last_height]
}
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
}

View File

@@ -0,0 +1,643 @@
use allocative::Allocative;
use crate::{
bitcoin::TARGET_BLOCKS_PER_DAY,
datasets::AnyDataset,
structs::{AnyBiMap, AnyDateMap, AnyHeightMap, BiMap, DateMap, HeightMap, WAmount},
utils::{BYTES_IN_MB, ONE_DAY_IN_DAYS, ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS},
};
use super::{ComputeData, InsertData, MinInitialStates};
#[derive(Allocative)]
pub struct MiningDataset {
min_initial_states: MinInitialStates,
// Inserted
pub blocks_mined: DateMap<usize>,
pub total_blocks_mined: DateMap<usize>,
pub coinbase: BiMap<f64>,
pub coinbase_in_dollars: BiMap<f32>,
pub fees: BiMap<f64>,
pub fees_in_dollars: BiMap<f32>,
// Raw
// pub average_fee_paid: BiMap<f32>,
// pub max_fee_paid: BiMap<f32>,
// pub _90th_percentile_fee_paid: BiMap<f32>,
// pub _75th_percentile_fee_paid: BiMap<f32>,
// pub median_fee_paid: BiMap<f32>,
// pub _25th_percentile_fee_paid: BiMap<f32>,
// pub _10th_percentile_fee_paid: BiMap<f32>,
// pub min_fee_paid: BiMap<f32>,
// sat/vB
// pub average_fee_price: BiMap<f32>,
// pub max_fee_price: BiMap<f32>,
// pub _90th_percentile_fee_price: BiMap<f32>,
// pub _75th_percentile_fee_price: BiMap<f32>,
// pub median_fee_price: BiMap<f32>,
// pub _25th_percentile_fee_price: BiMap<f32>,
// pub _10th_percentile_fee_price: BiMap<f32>,
// pub min_fee_price: BiMap<f32>,
// -
pub subsidy: BiMap<f64>,
pub subsidy_in_dollars: BiMap<f32>,
pub last_coinbase: DateMap<f64>,
pub last_coinbase_in_dollars: DateMap<f32>,
pub last_fees: DateMap<f64>,
pub last_fees_in_dollars: DateMap<f32>,
pub last_subsidy: DateMap<f64>,
pub last_subsidy_in_dollars: DateMap<f32>,
pub difficulty: BiMap<f64>,
pub block_size: HeightMap<f32>, // in MB
pub block_weight: HeightMap<f32>, // in MB
pub block_vbytes: HeightMap<u64>,
pub block_interval: HeightMap<u32>, // in ms
// Computed
pub annualized_issuance: BiMap<f64>, // Same as subsidy_1y_sum
pub blocks_mined_1d_target: DateMap<usize>,
pub blocks_mined_1m_sma: DateMap<f32>,
pub blocks_mined_1m_sum: DateMap<usize>,
pub blocks_mined_1m_target: DateMap<usize>,
pub blocks_mined_1w_sma: DateMap<f32>,
pub blocks_mined_1w_sum: DateMap<usize>,
pub blocks_mined_1w_target: DateMap<usize>,
pub blocks_mined_1y_sum: DateMap<usize>,
pub blocks_mined_1y_target: DateMap<usize>,
pub cumulative_block_size: BiMap<f32>,
pub subsidy_1y_sum: DateMap<f64>,
pub subsidy_in_dollars_1y_sum: DateMap<f64>,
pub cumulative_subsidy: BiMap<f64>,
pub cumulative_subsidy_in_dollars: BiMap<f32>,
pub coinbase_1y_sum: DateMap<f64>,
pub coinbase_in_dollars_1y_sum: DateMap<f64>,
pub coinbase_in_dollars_1y_sma: DateMap<f32>,
pub cumulative_coinbase: BiMap<f64>,
pub cumulative_coinbase_in_dollars: BiMap<f32>,
pub fees_1y_sum: DateMap<f64>,
pub fees_in_dollars_1y_sum: DateMap<f64>,
pub cumulative_fees: BiMap<f64>,
pub cumulative_fees_in_dollars: BiMap<f32>,
pub yearly_inflation_rate: BiMap<f64>,
pub subsidy_to_coinbase_ratio: BiMap<f64>,
pub fees_to_coinbase_ratio: BiMap<f64>,
pub hash_rate: DateMap<f64>,
pub hash_rate_1w_sma: DateMap<f32>,
pub hash_rate_1m_sma: DateMap<f32>,
pub hash_rate_2m_sma: DateMap<f32>,
pub hash_price: DateMap<f64>,
pub difficulty_adjustment: DateMap<f64>,
pub puell_multiple: DateMap<f32>,
// pub average_block_size: DateMap<f32>, // in MB
// pub average_block_weight: DateMap<f32>, // in MB
// pub average_block_vbytes: DateMap<u64>,
// pub average_block_interval: DateMap<u32>, // in ms
// pub blocks_size: DateMap<f32>,
// pub average_block_size: DateMap<f32>,
// pub median_block_size: DateMap<f32>,
// pub average_block_weight: DateMap<f32>,
// pub median_block_weight: DateMap<f32>,
// pub average_block_interval: DateMap<u32>,
// pub median_block_interval: DateMap<u32>,
// pub hash_price_in_dollars: DateMap<f64>,
// pub hash_price_30d_volatility: BiMap<f32>,
// difficulty_adjustment
// next_difficulty_adjustment
// op return fees
// inscriptions fees
// until adjustement
// until halving in days
// until halving in blocks
}
impl MiningDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
total_blocks_mined: DateMap::new_bin(1, &f("total_blocks_mined")),
blocks_mined: DateMap::new_bin(1, &f("blocks_mined")),
coinbase: BiMap::new_bin(1, &f("coinbase")),
coinbase_in_dollars: BiMap::new_bin(1, &f("coinbase_in_dollars")),
coinbase_1y_sum: DateMap::new_bin(1, &f("coinbase_1y_sum")),
coinbase_in_dollars_1y_sum: DateMap::new_bin(1, &f("coinbase_in_dollars_1y_sum")),
coinbase_in_dollars_1y_sma: DateMap::new_bin(1, &f("coinbase_in_dollars_1y_sma")),
cumulative_coinbase: BiMap::new_bin(1, &f("cumulative_coinbase")),
cumulative_coinbase_in_dollars: BiMap::new_bin(1, &f("cumulative_coinbase_in_dollars")),
fees: BiMap::new_bin(1, &f("fees")),
fees_in_dollars: BiMap::new_bin(1, &f("fees_in_dollars")),
fees_1y_sum: DateMap::new_bin(1, &f("fees_1y_sum")),
fees_in_dollars_1y_sum: DateMap::new_bin(1, &f("fees_in_dollars_1y_sum")),
cumulative_fees: BiMap::new_bin(1, &f("cumulative_fees")),
cumulative_fees_in_dollars: BiMap::new_bin(1, &f("cumulative_fees_in_dollars")),
subsidy: BiMap::new_bin(1, &f("subsidy")),
subsidy_in_dollars: BiMap::new_bin(1, &f("subsidy_in_dollars")),
subsidy_1y_sum: DateMap::new_bin(1, &f("subsidy_1y_sum")),
subsidy_in_dollars_1y_sum: DateMap::new_bin(1, &f("subsidy_in_dollars_1y_sum")),
cumulative_subsidy: BiMap::new_bin(1, &f("cumulative_subsidy")),
cumulative_subsidy_in_dollars: BiMap::new_bin(1, &f("cumulative_subsidy_in_dollars")),
subsidy_to_coinbase_ratio: BiMap::new_bin(1, &f("subsidy_to_coinbase_ratio")),
fees_to_coinbase_ratio: BiMap::new_bin(1, &f("fees_to_coinbase_ratio")),
annualized_issuance: BiMap::new_bin(1, &f("annualized_issuance")),
yearly_inflation_rate: BiMap::new_bin(1, &f("yearly_inflation_rate")),
last_subsidy: DateMap::new_bin(1, &f("last_subsidy")),
last_subsidy_in_dollars: DateMap::new_bin(1, &f("last_subsidy_in_dollars")),
last_coinbase: DateMap::new_bin(1, &f("last_coinbase")),
last_coinbase_in_dollars: DateMap::new_bin(1, &f("last_coinbase_in_dollars")),
last_fees: DateMap::new_bin(1, &f("last_fees")),
last_fees_in_dollars: DateMap::new_bin(1, &f("last_fees_in_dollars")),
blocks_mined_1d_target: DateMap::new_bin(1, &f("blocks_mined_1d_target")),
blocks_mined_1w_sma: DateMap::new_bin(1, &f("blocks_mined_1w_sma")),
blocks_mined_1m_sma: DateMap::new_bin(1, &f("blocks_mined_1m_sma")),
blocks_mined_1w_sum: DateMap::new_bin(1, &f("blocks_mined_1w_sum")),
blocks_mined_1m_sum: DateMap::new_bin(1, &f("blocks_mined_1m_sum")),
blocks_mined_1y_sum: DateMap::new_bin(1, &f("blocks_mined_1y_sum")),
blocks_mined_1w_target: DateMap::new_bin(1, &f("blocks_mined_1w_target")),
blocks_mined_1m_target: DateMap::new_bin(1, &f("blocks_mined_1m_target")),
blocks_mined_1y_target: DateMap::new_bin(1, &f("blocks_mined_1y_target")),
difficulty: BiMap::new_bin(1, &f("difficulty")),
difficulty_adjustment: DateMap::new_bin(1, &f("difficulty_adjustment")),
block_size: HeightMap::new_bin(1, &f("block_size")),
cumulative_block_size: BiMap::new_bin(1, &f("cumulative_block_size")),
block_weight: HeightMap::new_bin(1, &f("block_weight")),
block_vbytes: HeightMap::new_bin(1, &f("block_vbytes")),
block_interval: HeightMap::new_bin(1, &f("block_interval")),
hash_rate: DateMap::new_bin(1, &f("hash_rate")),
hash_rate_1w_sma: DateMap::new_bin(1, &f("hash_rate_1w_sma")),
hash_rate_1m_sma: DateMap::new_bin(1, &f("hash_rate_1m_sma")),
hash_rate_2m_sma: DateMap::new_bin(1, &f("hash_rate_2m_sma")),
hash_price: DateMap::new_bin(1, &f("hash_price")),
puell_multiple: DateMap::new_bin(1, &f("puell_multiple")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
date_first_height,
height,
coinbase,
fees,
date_blocks_range,
is_date_last_block,
block_price,
date,
difficulty,
block_size,
block_vbytes,
block_weight,
block_interval,
..
}: &InsertData,
) {
self.coinbase.height.insert(height, coinbase.to_btc());
let coinbase_in_dollars = self
.coinbase_in_dollars
.height
.insert(height, (block_price * coinbase).to_dollar() as f32);
let sumed_fees = WAmount::from_sat(fees.iter().map(|amount| amount.to_sat()).sum());
self.fees.height.insert(height, sumed_fees.to_btc());
let sumed_fees_in_dollars = self
.fees_in_dollars
.height
.insert(height, (block_price * sumed_fees).to_dollar() as f32);
let subsidy = coinbase - sumed_fees;
self.subsidy.height.insert(height, subsidy.to_btc());
let subsidy_in_dollars = self
.subsidy_in_dollars
.height
.insert(height, (block_price * subsidy).to_dollar() as f32);
self.difficulty.height.insert(height, difficulty);
self.block_size
.insert(height, block_size as f32 / BYTES_IN_MB as f32);
self.block_weight
.insert(height, block_weight as f32 / BYTES_IN_MB as f32);
self.block_vbytes.insert(height, block_vbytes);
self.block_interval.insert(height, block_interval);
if is_date_last_block {
self.coinbase.date_insert_sum_range(date, date_blocks_range);
self.coinbase_in_dollars
.date_insert_sum_range(date, date_blocks_range);
self.fees.date_insert_sum_range(date, date_blocks_range);
self.fees_in_dollars
.date_insert_sum_range(date, date_blocks_range);
self.subsidy.date_insert_sum_range(date, date_blocks_range);
self.subsidy_in_dollars
.date_insert_sum_range(date, date_blocks_range);
self.last_coinbase.insert(date, coinbase.to_btc());
self.last_coinbase_in_dollars
.insert(date, coinbase_in_dollars);
self.last_subsidy.insert(date, subsidy.to_btc());
self.last_subsidy_in_dollars
.insert(date, subsidy_in_dollars);
self.last_fees.insert(date, sumed_fees.to_btc());
self.last_fees_in_dollars
.insert(date, sumed_fees_in_dollars);
let total_blocks_mined = self.total_blocks_mined.insert(date, height + 1);
self.blocks_mined
.insert(date, total_blocks_mined - date_first_height);
self.difficulty.date.insert(date, difficulty);
}
}
pub fn compute(
&mut self,
&ComputeData { heights, dates }: &ComputeData,
last_height: &mut DateMap<usize>,
) {
self.blocks_mined_1w_sum.multi_insert_last_x_sum(
dates,
&mut self.blocks_mined,
ONE_WEEK_IN_DAYS,
);
self.blocks_mined_1m_sum.multi_insert_last_x_sum(
dates,
&mut self.blocks_mined,
ONE_MONTH_IN_DAYS,
);
self.blocks_mined_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.blocks_mined,
ONE_YEAR_IN_DAYS,
);
self.subsidy_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.subsidy.date,
ONE_YEAR_IN_DAYS,
);
self.subsidy_in_dollars_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.subsidy_in_dollars.date,
ONE_YEAR_IN_DAYS,
);
self.cumulative_subsidy
.multi_insert_cumulative(heights, dates, &mut self.subsidy);
self.cumulative_subsidy_in_dollars.multi_insert_cumulative(
heights,
dates,
&mut self.subsidy_in_dollars,
);
self.fees_1y_sum
.multi_insert_last_x_sum(dates, &mut self.fees.date, ONE_YEAR_IN_DAYS);
self.fees_in_dollars_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.fees_in_dollars.date,
ONE_YEAR_IN_DAYS,
);
self.cumulative_fees
.multi_insert_cumulative(heights, dates, &mut self.fees);
self.cumulative_fees_in_dollars.multi_insert_cumulative(
heights,
dates,
&mut self.fees_in_dollars,
);
self.coinbase_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.coinbase.date,
ONE_YEAR_IN_DAYS,
);
self.coinbase_in_dollars_1y_sum.multi_insert_last_x_sum(
dates,
&mut self.coinbase_in_dollars.date,
ONE_YEAR_IN_DAYS,
);
self.coinbase_in_dollars_1y_sma.multi_insert_simple_average(
dates,
&mut self.coinbase_in_dollars.date,
ONE_YEAR_IN_DAYS,
);
self.cumulative_coinbase
.multi_insert_cumulative(heights, dates, &mut self.coinbase);
self.cumulative_coinbase_in_dollars.multi_insert_cumulative(
heights,
dates,
&mut self.coinbase_in_dollars,
);
self.subsidy_to_coinbase_ratio.multi_insert_percentage(
heights,
dates,
&mut self.subsidy,
&mut self.coinbase,
);
self.fees_to_coinbase_ratio.multi_insert_percentage(
heights,
dates,
&mut self.fees,
&mut self.coinbase,
);
self.annualized_issuance.multi_insert_last_x_sum(
heights,
dates,
&mut self.subsidy,
ONE_YEAR_IN_DAYS,
);
self.yearly_inflation_rate.multi_insert_percentage(
heights,
dates,
&mut self.annualized_issuance,
&mut self.cumulative_subsidy,
);
self.blocks_mined_1d_target
.multi_insert_const(dates, TARGET_BLOCKS_PER_DAY);
self.blocks_mined_1w_target
.multi_insert_const(dates, ONE_WEEK_IN_DAYS * TARGET_BLOCKS_PER_DAY);
self.blocks_mined_1m_target
.multi_insert_const(dates, ONE_MONTH_IN_DAYS * TARGET_BLOCKS_PER_DAY);
self.blocks_mined_1y_target
.multi_insert_const(dates, ONE_YEAR_IN_DAYS * TARGET_BLOCKS_PER_DAY);
self.blocks_mined_1w_sma.multi_insert_simple_average(
dates,
&mut self.blocks_mined,
ONE_WEEK_IN_DAYS,
);
self.blocks_mined_1m_sma.multi_insert_simple_average(
dates,
&mut self.blocks_mined,
ONE_MONTH_IN_DAYS,
);
self.cumulative_block_size
.height
.multi_insert_cumulative(heights, &mut self.block_size);
self.cumulative_block_size.date.multi_insert_last(
dates,
&mut self.cumulative_block_size.height,
last_height,
);
// https://hashrateindex.com/blog/what-is-bitcoins-hashrate/
self.hash_rate.multi_insert(dates, |date| {
let blocks_mined = self.blocks_mined.get_or_import(date).unwrap();
let difficulty = self.difficulty.date.get_or_import(date).unwrap();
((blocks_mined as f64 / TARGET_BLOCKS_PER_DAY as f64) * difficulty * 2.0_f64.powi(32))
/ 600.0
/ 1_000_000_000_000_000_000.0
});
self.hash_rate_1w_sma.multi_insert_simple_average(
dates,
&mut self.hash_rate,
ONE_WEEK_IN_DAYS,
);
self.hash_rate_1m_sma.multi_insert_simple_average(
dates,
&mut self.hash_rate,
ONE_MONTH_IN_DAYS,
);
self.hash_rate_2m_sma.multi_insert_simple_average(
dates,
&mut self.hash_rate,
2 * ONE_MONTH_IN_DAYS,
);
self.hash_price.multi_insert(dates, |date| {
let coinbase_in_dollars = self.coinbase_in_dollars.date.get_or_import(date).unwrap();
let hashrate = self.hash_rate.get_or_import(date).unwrap();
coinbase_in_dollars as f64 / hashrate / 1_000.0
});
self.puell_multiple.multi_insert_divide(
dates,
&mut self.coinbase_in_dollars.date,
&mut self.coinbase_in_dollars_1y_sma,
);
self.difficulty_adjustment.multi_insert_percentage_change(
dates,
&mut self.difficulty.date,
ONE_DAY_IN_DAYS,
);
}
}
impl AnyDataset for MiningDataset {
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.coinbase,
&self.coinbase_in_dollars,
&self.fees,
&self.fees_in_dollars,
&self.subsidy,
&self.subsidy_in_dollars,
&self.difficulty,
]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.coinbase,
&mut self.coinbase_in_dollars,
&mut self.fees,
&mut self.fees_in_dollars,
&mut self.subsidy,
&mut self.subsidy_in_dollars,
&mut self.difficulty,
]
}
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![
&self.total_blocks_mined,
&self.blocks_mined,
&self.last_subsidy,
&self.last_subsidy_in_dollars,
&self.last_coinbase,
&self.last_coinbase_in_dollars,
&self.last_fees,
&self.last_fees_in_dollars,
]
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![
&mut self.total_blocks_mined,
&mut self.blocks_mined,
&mut self.last_subsidy,
&mut self.last_subsidy_in_dollars,
&mut self.last_coinbase,
&mut self.last_coinbase_in_dollars,
&mut self.last_fees,
&mut self.last_fees_in_dollars,
]
}
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
vec![
&self.block_size,
&self.block_weight,
&self.block_vbytes,
&self.block_interval,
]
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
vec![
&mut self.block_size,
&mut self.block_weight,
&mut self.block_vbytes,
&mut self.block_interval,
]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.cumulative_coinbase,
&self.cumulative_coinbase_in_dollars,
&self.cumulative_fees,
&self.cumulative_fees_in_dollars,
&self.cumulative_subsidy,
&self.cumulative_subsidy_in_dollars,
&self.annualized_issuance,
&self.yearly_inflation_rate,
&self.cumulative_block_size,
&self.subsidy_to_coinbase_ratio,
&self.fees_to_coinbase_ratio,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.cumulative_coinbase,
&mut self.cumulative_coinbase_in_dollars,
&mut self.cumulative_fees,
&mut self.cumulative_fees_in_dollars,
&mut self.cumulative_subsidy,
&mut self.cumulative_subsidy_in_dollars,
&mut self.annualized_issuance,
&mut self.yearly_inflation_rate,
&mut self.cumulative_block_size,
&mut self.subsidy_to_coinbase_ratio,
&mut self.fees_to_coinbase_ratio,
]
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![
&self.blocks_mined_1d_target,
&self.blocks_mined_1w_sma,
&self.blocks_mined_1m_sma,
&self.blocks_mined_1w_sum,
&self.blocks_mined_1m_sum,
&self.blocks_mined_1y_sum,
&self.blocks_mined_1w_target,
&self.blocks_mined_1m_target,
&self.blocks_mined_1y_target,
&self.subsidy_1y_sum,
&self.subsidy_in_dollars_1y_sum,
&self.coinbase_1y_sum,
&self.coinbase_in_dollars_1y_sum,
&self.coinbase_in_dollars_1y_sma,
&self.fees_1y_sum,
&self.fees_in_dollars_1y_sum,
&self.hash_rate,
&self.hash_rate_1w_sma,
&self.hash_rate_1m_sma,
&self.hash_rate_2m_sma,
&self.hash_price,
&self.puell_multiple,
&self.difficulty_adjustment,
]
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
vec![
&mut self.blocks_mined_1d_target,
&mut self.blocks_mined_1w_sma,
&mut self.blocks_mined_1m_sma,
&mut self.blocks_mined_1w_sum,
&mut self.blocks_mined_1m_sum,
&mut self.blocks_mined_1y_sum,
&mut self.blocks_mined_1w_target,
&mut self.blocks_mined_1m_target,
&mut self.blocks_mined_1y_target,
&mut self.subsidy_1y_sum,
&mut self.subsidy_in_dollars_1y_sum,
&mut self.coinbase_1y_sum,
&mut self.coinbase_in_dollars_1y_sum,
&mut self.coinbase_in_dollars_1y_sma,
&mut self.fees_1y_sum,
&mut self.fees_in_dollars_1y_sum,
&mut self.hash_rate,
&mut self.hash_rate_1w_sma,
&mut self.hash_rate_1m_sma,
&mut self.hash_rate_2m_sma,
&mut self.hash_price,
&mut self.puell_multiple,
&mut self.difficulty_adjustment,
]
}
}

340
parser/src/datasets/mod.rs Normal file
View File

@@ -0,0 +1,340 @@
use std::{collections::BTreeMap, ops::RangeInclusive};
use allocative::Allocative;
use itertools::Itertools;
use rayon::prelude::*;
mod _traits;
mod address;
mod block_metadata;
mod coindays;
mod cointime;
mod constant;
mod date_metadata;
mod mining;
mod price;
mod subs;
mod transaction;
mod utxo;
pub use _traits::*;
pub use address::*;
pub use block_metadata::*;
pub use coindays::*;
pub use cointime::*;
pub use constant::*;
pub use date_metadata::*;
pub use mining::*;
pub use price::*;
pub use subs::*;
pub use transaction::*;
pub use utxo::*;
use crate::{
databases::Databases,
io::Json,
states::{
AddressCohortsInputStates,
AddressCohortsOneShotStates,
AddressCohortsRealizedStates,
States,
UTXOCohortsOneShotStates,
// UTXOCohortsReceivedStates,
UTXOCohortsSentStates,
},
structs::{Price, WAmount, WNaiveDate},
};
pub struct InsertData<'a> {
pub address_cohorts_input_states: &'a Option<AddressCohortsInputStates>,
pub address_cohorts_one_shot_states: &'a Option<AddressCohortsOneShotStates>,
pub address_cohorts_realized_states: &'a Option<AddressCohortsRealizedStates>,
pub amount_sent: WAmount,
pub block_interval: u32,
pub block_price: Price,
pub block_size: usize,
pub block_vbytes: u64,
pub block_weight: u64,
pub coinbase: WAmount,
pub compute_addresses: bool,
pub databases: &'a Databases,
pub date: WNaiveDate,
pub date_blocks_range: &'a RangeInclusive<usize>,
pub date_first_height: usize,
pub difficulty: f64,
pub fees: &'a Vec<WAmount>,
pub height: usize,
pub is_date_last_block: bool,
pub satblocks_destroyed: WAmount,
pub satdays_destroyed: WAmount,
pub states: &'a States,
pub timestamp: u32,
pub transaction_count: usize,
pub utxo_cohorts_one_shot_states: &'a UTXOCohortsOneShotStates,
// pub utxo_cohorts_received_states: &'a UTXOCohortsReceivedStates,
pub utxo_cohorts_sent_states: &'a UTXOCohortsSentStates,
}
pub struct ComputeData<'a> {
pub heights: &'a [usize],
pub dates: &'a [WNaiveDate],
}
#[derive(Allocative)]
pub struct AllDatasets {
min_initial_states: MinInitialStates,
pub constant: ConstantDataset,
pub address: AddressDatasets,
pub block_metadata: BlockMetadataDataset,
pub coindays: CoindaysDataset,
pub cointime: CointimeDataset,
pub date_metadata: DateMetadataDataset,
pub mining: MiningDataset,
pub price: PriceDatasets,
pub transaction: TransactionDataset,
pub utxo: UTXODatasets,
}
impl AllDatasets {
pub fn import() -> color_eyre::Result<Self> {
let path = "../datasets";
let price = PriceDatasets::import(path)?;
let constant = ConstantDataset::import(path)?;
let date_metadata = DateMetadataDataset::import(path)?;
let cointime = CointimeDataset::import(path)?;
let coindays = CoindaysDataset::import(path)?;
let mining = MiningDataset::import(path)?;
let block_metadata = BlockMetadataDataset::import(path)?;
let transaction = TransactionDataset::import(path)?;
let address = AddressDatasets::import(path)?;
let utxo = UTXODatasets::import(path)?;
let mut s = Self {
min_initial_states: MinInitialStates::default(),
address,
block_metadata,
cointime,
coindays,
constant,
date_metadata,
price,
mining,
transaction,
utxo,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_datasets(&s));
s.export_path_to_type()?;
Ok(s)
}
pub fn insert(&mut self, insert_data: InsertData) {
self.address.insert(&insert_data);
self.utxo.insert(&insert_data);
if self
.block_metadata
.needs_insert(insert_data.height, insert_data.date)
{
self.block_metadata.insert(&insert_data);
}
if self
.date_metadata
.needs_insert(insert_data.height, insert_data.date)
{
self.date_metadata.insert(&insert_data);
}
if self
.coindays
.needs_insert(insert_data.height, insert_data.date)
{
self.coindays.insert(&insert_data);
}
if self
.mining
.needs_insert(insert_data.height, insert_data.date)
{
self.mining.insert(&insert_data);
}
if self
.transaction
.needs_insert(insert_data.height, insert_data.date)
{
self.transaction.insert(&insert_data);
}
if self
.cointime
.needs_insert(insert_data.height, insert_data.date)
{
self.cointime.insert(&insert_data);
}
}
pub fn compute(&mut self, compute_data: ComputeData) {
if self.constant.should_compute(&compute_data) {
self.constant.compute(&compute_data);
}
if self.mining.should_compute(&compute_data) {
self.mining
.compute(&compute_data, &mut self.date_metadata.last_height);
}
// No compute needed for now
self.price
.compute(&compute_data, &mut self.mining.cumulative_subsidy);
self.address.compute(
&compute_data,
&mut self.price.closes,
&mut self.mining.cumulative_subsidy,
&mut self.price.market_cap,
);
self.utxo.compute(
&compute_data,
&mut self.price.closes,
&mut self.mining.cumulative_subsidy,
&mut self.price.market_cap,
);
// No compute needed for now
// if self.block_metadata.should_compute(height, date) {
// self.block_metadata.compute(&compute_data);
// }
// No compute needed for now
// if self.date_metadata.should_compute(height, date) {
// self.date_metadata.compute(&compute_data);
// }
// No compute needed for now
// if self.coindays.should_compute(height, date) {
// self.coindays.compute(&compute_data);
// }
if self.transaction.should_compute(&compute_data) {
self.transaction.compute(
&compute_data,
&mut self.mining.cumulative_subsidy,
&mut self.mining.block_interval,
);
}
if self.cointime.should_compute(&compute_data) {
self.cointime.compute(
&compute_data,
&mut self.date_metadata.first_height,
&mut self.date_metadata.last_height,
&mut self.price.closes,
&mut self.mining.cumulative_subsidy,
&mut self.address.cohorts.all.all.capitalization.realized_cap,
&mut self.address.cohorts.all.all.capitalization.realized_price,
&mut self.mining.yearly_inflation_rate,
&mut self.transaction.annualized_volume,
&mut self.mining.cumulative_subsidy_in_dollars,
);
}
}
pub fn export_path_to_type(&self) -> color_eyre::Result<()> {
let path_to_type: BTreeMap<&str, &str> = self
.to_any_dataset_vec()
.into_iter()
.flat_map(|dataset| {
dataset
.to_all_map_vec()
.into_iter()
.flat_map(|map| map.exported_path_with_t_name())
})
.collect();
Json::export("../datasets/disk_path_to_type.json", &path_to_type)
}
pub fn export(&mut self) -> color_eyre::Result<()> {
self.to_mut_any_dataset_vec()
.into_iter()
.for_each(|dataset| dataset.pre_export());
self.to_any_dataset_vec()
.into_par_iter()
.try_for_each(|dataset| -> color_eyre::Result<()> { dataset.export() })?;
self.to_mut_any_dataset_vec()
.into_iter()
.for_each(|dataset| dataset.post_export());
Ok(())
}
}
impl AnyDatasets for AllDatasets {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_any_dataset_vec(&self) -> Vec<&(dyn AnyDataset + Send + Sync)> {
vec![
vec![
&self.price as &(dyn AnyDataset + Send + Sync),
&self.constant,
],
self.address.to_any_dataset_vec(),
self.utxo.to_any_dataset_vec(),
vec![
&self.mining,
&self.transaction,
&self.block_metadata,
&self.date_metadata,
&self.cointime,
&self.coindays,
],
]
.into_iter()
.flatten()
.collect_vec()
}
fn to_mut_any_dataset_vec(&mut self) -> Vec<&mut dyn AnyDataset> {
vec![
vec![&mut self.price as &mut dyn AnyDataset, &mut self.constant],
self.address.to_mut_any_dataset_vec(),
self.utxo.to_mut_any_dataset_vec(),
vec![
&mut self.mining,
&mut self.transaction,
&mut self.block_metadata,
&mut self.date_metadata,
&mut self.cointime,
&mut self.coindays,
],
]
.into_iter()
.flatten()
.collect_vec()
}
}

View File

@@ -0,0 +1,493 @@
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},
structs::{AnyBiMap, AnyDateMap, BiMap, DateMap, WNaiveDate},
utils::{ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS},
};
use super::{AnyDataset, ComputeData, MinInitialStates};
#[derive(Allocative)]
pub struct PriceDatasets {
min_initial_states: MinInitialStates,
kraken_daily: Option<BTreeMap<WNaiveDate, OHLC>>,
kraken_1mn: Option<BTreeMap<u32, OHLC>>,
binance_1mn: Option<BTreeMap<u32, OHLC>>,
binance_har: Option<BTreeMap<u32, OHLC>>,
// Inserted
pub ohlcs: BiMap<OHLC>,
// Computed
pub closes: BiMap<f32>,
pub market_cap: BiMap<f32>,
pub price_1w_sma: DateMap<f32>,
pub price_1m_sma: DateMap<f32>,
pub price_1y_sma: DateMap<f32>,
pub price_2y_sma: DateMap<f32>,
pub price_4y_sma: DateMap<f32>,
pub price_8d_sma: DateMap<f32>,
pub price_13d_sma: DateMap<f32>,
pub price_21d_sma: DateMap<f32>,
pub price_34d_sma: DateMap<f32>,
pub price_55d_sma: DateMap<f32>,
pub price_89d_sma: DateMap<f32>,
pub price_144d_sma: DateMap<f32>,
pub price_200w_sma: DateMap<f32>,
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_har: None,
kraken_1mn: None,
kraken_daily: None,
ohlcs: BiMap::new_json(1, &format!("{price_path}/ohlc")),
closes: BiMap::new_json(1, &f("close")),
market_cap: BiMap::new_bin(1, &f("market_cap")),
price_1w_sma: DateMap::new_bin(1, &f("price_1w_sma")),
price_1m_sma: DateMap::new_bin(1, &f("price_1m_sma")),
price_1y_sma: DateMap::new_bin(1, &f("price_1y_sma")),
price_2y_sma: DateMap::new_bin(1, &f("price_2y_sma")),
price_4y_sma: DateMap::new_bin(1, &f("price_4y_sma")),
price_8d_sma: DateMap::new_bin(1, &f("price_8d_sma")),
price_13d_sma: DateMap::new_bin(1, &f("price_13d_sma")),
price_21d_sma: DateMap::new_bin(1, &f("price_21d_sma")),
price_34d_sma: DateMap::new_bin(1, &f("price_34d_sma")),
price_55d_sma: DateMap::new_bin(1, &f("price_55d_sma")),
price_89d_sma: DateMap::new_bin(1, &f("price_89d_sma")),
price_144d_sma: DateMap::new_bin(1, &f("price_144d_sma")),
price_200w_sma: DateMap::new_bin(1, &f("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,
&ComputeData { dates, heights }: &ComputeData,
circulating_supply: &mut BiMap<f64>,
) {
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(
dates,
&mut self.closes.date,
ONE_WEEK_IN_DAYS,
);
self.price_1m_sma.multi_insert_simple_average(
dates,
&mut self.closes.date,
ONE_MONTH_IN_DAYS,
);
self.price_1y_sma.multi_insert_simple_average(
dates,
&mut self.closes.date,
ONE_YEAR_IN_DAYS,
);
self.price_2y_sma.multi_insert_simple_average(
dates,
&mut self.closes.date,
2 * ONE_YEAR_IN_DAYS,
);
self.price_4y_sma.multi_insert_simple_average(
dates,
&mut self.closes.date,
4 * ONE_YEAR_IN_DAYS,
);
self.price_8d_sma
.multi_insert_simple_average(dates, &mut self.closes.date, 8);
self.price_13d_sma
.multi_insert_simple_average(dates, &mut self.closes.date, 13);
self.price_21d_sma
.multi_insert_simple_average(dates, &mut self.closes.date, 21);
self.price_34d_sma
.multi_insert_simple_average(dates, &mut self.closes.date, 34);
self.price_55d_sma
.multi_insert_simple_average(dates, &mut self.closes.date, 55);
self.price_89d_sma
.multi_insert_simple_average(dates, &mut self.closes.date, 89);
self.price_144d_sma
.multi_insert_simple_average(dates, &mut self.closes.date, 144);
self.price_200w_sma.multi_insert_simple_average(
dates,
&mut self.closes.date,
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(&WNaiveDate::wrap(date)))
.unwrap_or_default();
(((last_value / previous_value).powf(1.0 / 4.0)) - 1.0) * 100.0
},
);
}
pub fn get_date_ohlc(&mut self, date: WNaiveDate) -> color_eyre::Result<OHLC> {
if self.ohlcs.date.is_date_safe(date) {
Ok(self.ohlcs.date.get(&date).unwrap().to_owned())
} else {
let ohlc = self.get_from_daily_kraken(&date)?;
self.ohlcs.date.insert(date, ohlc);
Ok(ohlc)
}
}
fn get_from_daily_kraken(&mut self, date: &WNaiveDate) -> color_eyre::Result<OHLC> {
if self.kraken_daily.is_none() {
self.kraken_daily.replace(
Kraken::fetch_daily_prices()
.unwrap_or_else(|_| Binance::fetch_daily_prices().unwrap()),
);
}
self.kraken_daily
.as_ref()
.unwrap()
.get(date)
.cloned()
.ok_or(Error::msg("Couldn't find date in daily kraken"))
}
pub fn get_height_ohlc(
&mut self,
height: usize,
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 > 0 {
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(|_| {
let date = WNaiveDate::from_timestamp(timestamp);
panic!(
"Can't find price for {height} - {timestamp} - {date}, please update binance.har file"
)
}))
});
self.ohlcs.height.insert(height, ohlc);
Ok(ohlc)
}
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.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.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()?);
}
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(&timestamp);
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)> {
vec![&self.closes, &self.market_cap]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.closes, &mut self.market_cap]
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
vec![
&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,
&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_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,
&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,
]
}
}

View File

@@ -0,0 +1,12 @@
use allocative::Allocative;
use bincode::{Decode, Encode};
use serde::{Deserialize, Serialize};
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Default, Deserialize, Serialize, Encode, Decode, Clone, Copy, Allocative)]
pub struct OHLC {
pub open: f32,
pub high: f32,
pub low: f32,
pub close: f32,
}

View File

@@ -0,0 +1,121 @@
use allocative::Allocative;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::CapitalizationState,
structs::{AnyBiMap, BiMap},
utils::ONE_MONTH_IN_DAYS,
};
#[derive(Default, Allocative)]
pub struct CapitalizationDataset {
min_initial_states: MinInitialStates,
// Inserted
pub realized_cap: BiMap<f32>,
// Computed
pub realized_price: BiMap<f32>,
mvrv: BiMap<f32>,
realized_cap_1m_net_change: BiMap<f32>,
}
impl CapitalizationDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
realized_cap: BiMap::new_bin(1, &f("realized_cap")),
realized_cap_1m_net_change: BiMap::new_bin(1, &f("realized_cap_1m_net_change")),
realized_price: BiMap::new_bin(1, &f("realized_price")),
mvrv: BiMap::new_bin(1, &f("mvrv")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
is_date_last_block,
date,
..
}: &InsertData,
state: &CapitalizationState,
) {
let realized_cap = self
.realized_cap
.height
.insert(height, state.realized_cap.to_dollar() as f32);
if is_date_last_block {
self.realized_cap.date.insert(date, realized_cap);
}
}
pub fn compute(
&mut self,
&ComputeData { heights, dates }: &ComputeData,
closes: &mut BiMap<f32>,
cohort_supply: &mut BiMap<f64>,
) {
self.realized_price.multi_insert_divide(
heights,
dates,
&mut self.realized_cap,
cohort_supply,
);
self.mvrv.height.multi_insert_divide(
heights,
&mut closes.height,
&mut self.realized_price.height,
);
self.mvrv
.date
.multi_insert_divide(dates, &mut closes.date, &mut self.realized_price.date);
self.realized_cap_1m_net_change.multi_insert_net_change(
heights,
dates,
&mut self.realized_cap,
ONE_MONTH_IN_DAYS,
)
}
}
impl AnyDataset for CapitalizationDataset {
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.realized_cap]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.realized_cap]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.realized_price,
&self.mvrv,
&self.realized_cap_1m_net_change,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.realized_price,
&mut self.mvrv,
&mut self.realized_cap_1m_net_change,
]
}
}

View File

@@ -0,0 +1,70 @@
use allocative::Allocative;
use crate::{
datasets::{AnyDataset, InsertData, MinInitialStates},
states::InputState,
structs::{AnyBiMap, BiMap},
};
#[derive(Default, Allocative)]
pub struct InputSubDataset {
min_initial_states: MinInitialStates,
pub count: BiMap<u64>,
pub volume: BiMap<f64>,
// add inputs_per_second
}
impl InputSubDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
count: BiMap::new_bin(1, &f("input_count")),
volume: BiMap::new_bin(1, &f("input_volume")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
date,
is_date_last_block,
date_blocks_range,
..
}: &InsertData,
state: &InputState,
) {
let count = self.count.height.insert(height, state.count.round() as u64);
self.volume.height.insert(height, state.volume.to_btc());
if is_date_last_block {
self.count.date.insert(date, count);
self.volume.date_insert_sum_range(date, date_blocks_range);
}
}
}
impl AnyDataset for InputSubDataset {
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.count, &self.volume]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.count, &mut self.volume]
}
}

View File

@@ -0,0 +1,80 @@
use allocative::Allocative;
mod capitalization;
mod input;
// mod output;
mod price_paid;
mod realized;
mod supply;
mod unrealized;
mod utxo;
pub use capitalization::*;
pub use input::*;
// pub use output::*;
pub use price_paid::*;
pub use realized::*;
pub use supply::*;
pub use unrealized::*;
pub use utxo::*;
use crate::datasets::AnyDataset;
use super::AnyDatasetGroup;
#[derive(Default, Allocative)]
pub struct SubDataset {
pub capitalization: CapitalizationDataset,
pub input: InputSubDataset,
// pub output: OutputSubDataset,
pub price_paid: PricePaidSubDataset,
pub realized: RealizedSubDataset,
pub supply: SupplySubDataset,
pub unrealized: UnrealizedSubDataset,
pub utxo: UTXOSubDataset,
}
impl SubDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let s = Self {
capitalization: CapitalizationDataset::import(parent_path)?,
input: InputSubDataset::import(parent_path)?,
// output: OutputSubDataset::import(parent_path)?,
price_paid: PricePaidSubDataset::import(parent_path)?,
realized: RealizedSubDataset::import(parent_path)?,
supply: SupplySubDataset::import(parent_path)?,
unrealized: UnrealizedSubDataset::import(parent_path)?,
utxo: UTXOSubDataset::import(parent_path)?,
};
Ok(s)
}
}
impl AnyDatasetGroup for SubDataset {
fn as_vec(&self) -> Vec<&(dyn AnyDataset + Send + Sync)> {
vec![
&self.capitalization,
&self.price_paid,
&self.realized,
&self.supply,
&self.unrealized,
&self.utxo,
&self.input,
// &self.output,
]
}
fn as_mut_vec(&mut self) -> Vec<&mut dyn AnyDataset> {
vec![
&mut self.capitalization,
&mut self.price_paid,
&mut self.realized,
&mut self.supply,
&mut self.unrealized,
&mut self.utxo,
&mut self.input,
// &mut self.output,
]
}
}

View File

@@ -0,0 +1,103 @@
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::OutputState,
structs::{AnyBiMap, BiMap},
utils::ONE_YEAR_IN_DAYS,
};
pub struct OutputSubDataset {
min_initial_states: MinInitialStates,
// Inserted
pub count: BiMap<f32>,
pub volume: BiMap<f32>,
// Computed
pub annualized_volume: BiMap<f32>,
pub velocity: BiMap<f32>,
// add outputs_per_second
}
impl OutputSubDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
count: BiMap::new_bin(1, &f("output_count")),
volume: BiMap::new_bin(1, &f("output_volume")),
annualized_volume: BiMap::new_bin(1, &f("annualized_output_volume")),
velocity: BiMap::new_bin(1, &f("output_velocity")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
date,
is_date_last_block,
date_blocks_range,
..
}: &InsertData,
state: &OutputState,
) {
let count = self.count.height.insert(height, state.count);
self.volume.height.insert(height, state.volume);
if is_date_last_block {
self.count.date.insert(date, count);
self.volume.date_insert_sum_range(date, date_blocks_range);
}
}
pub fn compute(
&mut self,
&ComputeData { heights, dates }: &ComputeData,
cohort_supply: &mut BiMap<f32>,
) {
self.annualized_volume.multi_insert_last_x_sum(
heights,
dates,
&mut self.volume,
ONE_YEAR_IN_DAYS,
);
self.velocity.multi_insert_divide(
heights,
dates,
&mut self.annualized_volume,
cohort_supply,
);
}
}
impl AnyDataset for OutputSubDataset {
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.count, &self.volume]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.count, &mut self.volume]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![&self.annualized_volume, &self.velocity]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.annualized_volume, &mut self.velocity]
}
}

View File

@@ -0,0 +1,293 @@
use allocative::Allocative;
use itertools::Itertools;
use crate::{
datasets::{AnyDataset, InsertData, MinInitialStates},
states::PricePaidState,
structs::{AnyBiMap, BiMap, WNaiveDate},
};
#[derive(Default, Allocative)]
pub struct PricePaidSubDataset {
min_initial_states: MinInitialStates,
// Inserted
pp_median: BiMap<f32>,
pp_95p: BiMap<f32>,
pp_90p: BiMap<f32>,
pp_85p: BiMap<f32>,
pp_80p: BiMap<f32>,
pp_75p: BiMap<f32>,
pp_70p: BiMap<f32>,
pp_65p: BiMap<f32>,
pp_60p: BiMap<f32>,
pp_55p: BiMap<f32>,
pp_45p: BiMap<f32>,
pp_40p: BiMap<f32>,
pp_35p: BiMap<f32>,
pp_30p: BiMap<f32>,
pp_25p: BiMap<f32>,
pp_20p: BiMap<f32>,
pp_15p: BiMap<f32>,
pp_10p: BiMap<f32>,
pp_05p: BiMap<f32>,
}
impl PricePaidSubDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
pp_median: BiMap::new_bin(1, &f("median_price_paid")),
pp_95p: BiMap::new_bin(1, &f("95p_price_paid")),
pp_90p: BiMap::new_bin(1, &f("90p_price_paid")),
pp_85p: BiMap::new_bin(1, &f("85p_price_paid")),
pp_80p: BiMap::new_bin(1, &f("80p_price_paid")),
pp_75p: BiMap::new_bin(1, &f("75p_price_paid")),
pp_70p: BiMap::new_bin(1, &f("70p_price_paid")),
pp_65p: BiMap::new_bin(1, &f("65p_price_paid")),
pp_60p: BiMap::new_bin(1, &f("60p_price_paid")),
pp_55p: BiMap::new_bin(1, &f("55p_price_paid")),
pp_45p: BiMap::new_bin(1, &f("45p_price_paid")),
pp_40p: BiMap::new_bin(1, &f("40p_price_paid")),
pp_35p: BiMap::new_bin(1, &f("35p_price_paid")),
pp_30p: BiMap::new_bin(1, &f("30p_price_paid")),
pp_25p: BiMap::new_bin(1, &f("25p_price_paid")),
pp_20p: BiMap::new_bin(1, &f("20p_price_paid")),
pp_15p: BiMap::new_bin(1, &f("15p_price_paid")),
pp_10p: BiMap::new_bin(1, &f("10p_price_paid")),
pp_05p: BiMap::new_bin(1, &f("05p_price_paid")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
is_date_last_block,
date,
..
}: &InsertData,
state: &PricePaidState,
) {
let PricePaidState {
pp_05p,
pp_10p,
pp_15p,
pp_20p,
pp_25p,
pp_30p,
pp_35p,
pp_40p,
pp_45p,
pp_median,
pp_55p,
pp_60p,
pp_65p,
pp_70p,
pp_75p,
pp_80p,
pp_85p,
pp_90p,
pp_95p,
..
} = state;
// Check if iter was empty
if pp_05p.is_none() {
self.insert_height_default(height);
if is_date_last_block {
self.insert_date_default(date);
}
return;
}
let pp_05p = self
.pp_05p
.height
.insert(height, pp_05p.unwrap().to_dollar() as f32);
let pp_10p = self
.pp_10p
.height
.insert(height, pp_10p.unwrap().to_dollar() as f32);
let pp_15p = self
.pp_15p
.height
.insert(height, pp_15p.unwrap().to_dollar() as f32);
let pp_20p = self
.pp_20p
.height
.insert(height, pp_20p.unwrap().to_dollar() as f32);
let pp_25p = self
.pp_25p
.height
.insert(height, pp_25p.unwrap().to_dollar() as f32);
let pp_30p = self
.pp_30p
.height
.insert(height, pp_30p.unwrap().to_dollar() as f32);
let pp_35p = self
.pp_35p
.height
.insert(height, pp_35p.unwrap().to_dollar() as f32);
let pp_40p = self
.pp_40p
.height
.insert(height, pp_40p.unwrap().to_dollar() as f32);
let pp_45p = self
.pp_45p
.height
.insert(height, pp_45p.unwrap().to_dollar() as f32);
let pp_median = self
.pp_median
.height
.insert(height, pp_median.unwrap().to_dollar() as f32);
let pp_55p = self
.pp_55p
.height
.insert(height, pp_55p.unwrap().to_dollar() as f32);
let pp_60p = self
.pp_60p
.height
.insert(height, pp_60p.unwrap().to_dollar() as f32);
let pp_65p = self
.pp_65p
.height
.insert(height, pp_65p.unwrap().to_dollar() as f32);
let pp_70p = self
.pp_70p
.height
.insert(height, pp_70p.unwrap().to_dollar() as f32);
let pp_75p = self
.pp_75p
.height
.insert(height, pp_75p.unwrap().to_dollar() as f32);
let pp_80p = self
.pp_80p
.height
.insert(height, pp_80p.unwrap().to_dollar() as f32);
let pp_85p = self
.pp_85p
.height
.insert(height, pp_85p.unwrap().to_dollar() as f32);
let pp_90p = self
.pp_90p
.height
.insert(height, pp_90p.unwrap().to_dollar() as f32);
let pp_95p = self
.pp_95p
.height
.insert(height, pp_95p.unwrap().to_dollar() as f32);
if is_date_last_block {
self.pp_05p.date.insert(date, pp_05p);
self.pp_10p.date.insert(date, pp_10p);
self.pp_15p.date.insert(date, pp_15p);
self.pp_20p.date.insert(date, pp_20p);
self.pp_25p.date.insert(date, pp_25p);
self.pp_30p.date.insert(date, pp_30p);
self.pp_35p.date.insert(date, pp_35p);
self.pp_40p.date.insert(date, pp_40p);
self.pp_45p.date.insert(date, pp_45p);
self.pp_median.date.insert(date, pp_median);
self.pp_55p.date.insert(date, pp_55p);
self.pp_60p.date.insert(date, pp_60p);
self.pp_65p.date.insert(date, pp_65p);
self.pp_70p.date.insert(date, pp_70p);
self.pp_75p.date.insert(date, pp_75p);
self.pp_80p.date.insert(date, pp_80p);
self.pp_85p.date.insert(date, pp_85p);
self.pp_90p.date.insert(date, pp_90p);
self.pp_95p.date.insert(date, pp_95p);
}
}
fn insert_height_default(&mut self, height: usize) {
self.inserted_as_mut_vec().into_iter().for_each(|bi| {
bi.height.insert_default(height);
})
}
fn insert_date_default(&mut self, date: WNaiveDate) {
self.inserted_as_mut_vec().into_iter().for_each(|bi| {
bi.date.insert_default(date);
})
}
pub fn inserted_as_vec(&self) -> Vec<&BiMap<f32>> {
vec![
&self.pp_95p,
&self.pp_90p,
&self.pp_85p,
&self.pp_80p,
&self.pp_75p,
&self.pp_70p,
&self.pp_65p,
&self.pp_60p,
&self.pp_55p,
&self.pp_median,
&self.pp_45p,
&self.pp_40p,
&self.pp_35p,
&self.pp_30p,
&self.pp_25p,
&self.pp_20p,
&self.pp_15p,
&self.pp_10p,
&self.pp_05p,
]
}
pub fn inserted_as_mut_vec(&mut self) -> Vec<&mut BiMap<f32>> {
vec![
&mut self.pp_95p,
&mut self.pp_90p,
&mut self.pp_85p,
&mut self.pp_80p,
&mut self.pp_75p,
&mut self.pp_70p,
&mut self.pp_65p,
&mut self.pp_60p,
&mut self.pp_55p,
&mut self.pp_median,
&mut self.pp_45p,
&mut self.pp_40p,
&mut self.pp_35p,
&mut self.pp_30p,
&mut self.pp_25p,
&mut self.pp_20p,
&mut self.pp_15p,
&mut self.pp_10p,
&mut self.pp_05p,
]
}
}
impl AnyDataset for PricePaidSubDataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.inserted_as_vec()
.into_iter()
.map(|dataset| dataset as &(dyn AnyBiMap + Send + Sync))
.collect_vec()
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.inserted_as_mut_vec()
.into_iter()
.map(|dataset| dataset as &mut dyn AnyBiMap)
.collect_vec()
}
}

View File

@@ -0,0 +1,178 @@
use allocative::Allocative;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::RealizedState,
structs::{AnyBiMap, BiMap},
utils::ONE_MONTH_IN_DAYS,
};
/// TODO: Fix fees not taken into account ?
#[derive(Default, Allocative)]
pub struct RealizedSubDataset {
min_initial_states: MinInitialStates,
// Inserted
realized_profit: BiMap<f32>,
realized_loss: BiMap<f32>,
// Computed
negative_realized_loss: BiMap<f32>,
net_realized_profit_and_loss: BiMap<f32>,
net_realized_profit_and_loss_to_market_cap_ratio: BiMap<f32>,
cumulative_realized_profit: BiMap<f32>,
cumulative_realized_loss: BiMap<f32>,
cumulative_net_realized_profit_and_loss: BiMap<f32>,
cumulative_net_realized_profit_and_loss_1m_net_change: BiMap<f32>,
}
impl RealizedSubDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
realized_profit: BiMap::new_bin(1, &f("realized_profit")),
realized_loss: BiMap::new_bin(1, &f("realized_loss")),
negative_realized_loss: BiMap::new_bin(2, &f("negative_realized_loss")),
net_realized_profit_and_loss: BiMap::new_bin(1, &f("net_realized_profit_and_loss")),
net_realized_profit_and_loss_to_market_cap_ratio: BiMap::new_bin(
1,
&f("net_realized_profit_and_loss_to_market_cap_ratio"),
),
cumulative_realized_profit: BiMap::new_bin(1, &f("cumulative_realized_profit")),
cumulative_realized_loss: BiMap::new_bin(1, &f("cumulative_realized_loss")),
cumulative_net_realized_profit_and_loss: BiMap::new_bin(
1,
&f("cumulative_net_realized_profit_and_loss"),
),
cumulative_net_realized_profit_and_loss_1m_net_change: BiMap::new_bin(
1,
&f("cumulative_net_realized_profit_and_loss_1m_net_change"),
),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
date,
is_date_last_block,
date_blocks_range,
..
}: &InsertData,
height_state: &RealizedState,
) {
self.realized_profit
.height
.insert(height, height_state.realized_profit.to_dollar() as f32);
self.realized_loss
.height
.insert(height, height_state.realized_loss.to_dollar() as f32);
if is_date_last_block {
self.realized_profit
.date_insert_sum_range(date, date_blocks_range);
self.realized_loss
.date_insert_sum_range(date, date_blocks_range);
}
}
pub fn compute(
&mut self,
&ComputeData { heights, dates }: &ComputeData,
market_cap: &mut BiMap<f32>,
) {
self.negative_realized_loss.multi_insert_simple_transform(
heights,
dates,
&mut self.realized_loss,
&|v| v * -1.0,
);
self.net_realized_profit_and_loss.multi_insert_subtract(
heights,
dates,
&mut self.realized_profit,
&mut self.realized_loss,
);
self.net_realized_profit_and_loss_to_market_cap_ratio
.multi_insert_divide(
heights,
dates,
&mut self.net_realized_profit_and_loss,
market_cap,
);
self.cumulative_realized_profit.multi_insert_cumulative(
heights,
dates,
&mut self.realized_profit,
);
self.cumulative_realized_loss.multi_insert_cumulative(
heights,
dates,
&mut self.realized_loss,
);
self.cumulative_net_realized_profit_and_loss
.multi_insert_cumulative(heights, dates, &mut self.net_realized_profit_and_loss);
self.cumulative_net_realized_profit_and_loss_1m_net_change
.multi_insert_net_change(
heights,
dates,
&mut self.cumulative_net_realized_profit_and_loss,
ONE_MONTH_IN_DAYS,
);
}
}
impl AnyDataset for RealizedSubDataset {
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.realized_loss, &self.realized_profit]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.realized_loss, &mut self.realized_profit]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.negative_realized_loss,
&self.net_realized_profit_and_loss,
&self.net_realized_profit_and_loss_to_market_cap_ratio,
&self.cumulative_realized_profit,
&self.cumulative_realized_loss,
&self.cumulative_net_realized_profit_and_loss,
&self.cumulative_net_realized_profit_and_loss_1m_net_change,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.negative_realized_loss,
&mut self.net_realized_profit_and_loss,
&mut self.net_realized_profit_and_loss_to_market_cap_ratio,
&mut self.cumulative_realized_profit,
&mut self.cumulative_realized_loss,
&mut self.cumulative_net_realized_profit_and_loss,
&mut self.cumulative_net_realized_profit_and_loss_1m_net_change,
]
}
}

View File

@@ -0,0 +1,114 @@
use allocative::Allocative;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::SupplyState,
structs::{AnyBiMap, BiMap},
};
#[derive(Default, Allocative)]
pub struct SupplySubDataset {
min_initial_states: MinInitialStates,
// Inserted
pub supply: BiMap<f64>,
// Computed
pub supply_to_circulating_supply_ratio: BiMap<f64>,
pub halved_supply: BiMap<f64>,
pub halved_supply_to_circulating_supply_ratio: BiMap<f64>,
}
impl SupplySubDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
supply: BiMap::new_bin(1, &f("supply")),
supply_to_circulating_supply_ratio: BiMap::new_bin(
1,
&f("supply_to_circulating_supply_ratio"),
),
halved_supply: BiMap::new_bin(1, &f("halved_supply")),
halved_supply_to_circulating_supply_ratio: BiMap::new_bin(
1,
&f("halved_supply_to_circulating_supply_ratio"),
),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
date,
is_date_last_block,
..
}: &InsertData,
state: &SupplyState,
) {
let total_supply = self.supply.height.insert(height, state.supply.to_btc());
if is_date_last_block {
self.supply.date.insert(date, total_supply);
}
}
#[allow(unused_variables)]
pub fn compute(
&mut self,
&ComputeData { heights, dates }: &ComputeData,
circulating_supply: &mut BiMap<f64>,
) {
self.supply_to_circulating_supply_ratio
.multi_insert_percentage(heights, dates, &mut self.supply, circulating_supply);
self.halved_supply
.multi_insert_simple_transform(heights, dates, &mut self.supply, &|v| v / 2.0);
self.halved_supply_to_circulating_supply_ratio
.multi_insert_simple_transform(
heights,
dates,
&mut self.supply_to_circulating_supply_ratio,
&|v| v / 2.0,
);
}
}
impl AnyDataset for SupplySubDataset {
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.supply]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.supply]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.supply_to_circulating_supply_ratio,
&self.halved_supply,
&self.halved_supply_to_circulating_supply_ratio,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.supply_to_circulating_supply_ratio,
&mut self.halved_supply,
&mut self.halved_supply_to_circulating_supply_ratio,
]
}
}

View File

@@ -0,0 +1,211 @@
use allocative::Allocative;
use crate::{
datasets::{AnyDataset, ComputeData, InsertData, MinInitialStates},
states::UnrealizedState,
structs::{AnyBiMap, BiMap},
};
#[derive(Default, Allocative)]
pub struct UnrealizedSubDataset {
min_initial_states: MinInitialStates,
// Inserted
supply_in_profit: BiMap<f64>,
unrealized_profit: BiMap<f32>,
unrealized_loss: BiMap<f32>,
// Computed
supply_in_loss: BiMap<f64>,
negative_unrealized_loss: BiMap<f32>,
net_unrealized_profit_and_loss: BiMap<f32>,
net_unrealized_profit_and_loss_to_market_cap_ratio: BiMap<f32>,
supply_in_profit_to_own_supply_ratio: BiMap<f64>,
supply_in_profit_to_circulating_supply_ratio: BiMap<f64>,
supply_in_loss_to_own_supply_ratio: BiMap<f64>,
supply_in_loss_to_circulating_supply_ratio: BiMap<f64>,
}
impl UnrealizedSubDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
supply_in_profit: BiMap::new_bin(1, &f("supply_in_profit")),
supply_in_loss: BiMap::new_bin(1, &f("supply_in_loss")),
unrealized_profit: BiMap::new_bin(1, &f("unrealized_profit")),
unrealized_loss: BiMap::new_bin(1, &f("unrealized_loss")),
negative_unrealized_loss: BiMap::new_bin(1, &f("negative_unrealized_loss")),
net_unrealized_profit_and_loss: BiMap::new_bin(1, &f("net_unrealized_profit_and_loss")),
net_unrealized_profit_and_loss_to_market_cap_ratio: BiMap::new_bin(
1,
&f("net_unrealized_profit_and_loss_to_market_cap_ratio"),
),
supply_in_profit_to_own_supply_ratio: BiMap::new_bin(
1,
&f("supply_in_profit_to_own_supply_ratio"),
),
supply_in_profit_to_circulating_supply_ratio: BiMap::new_bin(
1,
&f("supply_in_profit_to_circulating_supply_ratio"),
),
supply_in_loss_to_own_supply_ratio: BiMap::new_bin(
1,
&f("supply_in_loss_to_own_supply_ratio"),
),
supply_in_loss_to_circulating_supply_ratio: BiMap::new_bin(
1,
&f("supply_in_loss_to_circulating_supply_ratio"),
),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
date,
is_date_last_block,
..
}: &InsertData,
block_state: &UnrealizedState,
date_state: &Option<UnrealizedState>,
) {
self.supply_in_profit
.height
.insert(height, block_state.supply_in_profit.to_btc());
self.unrealized_profit
.height
.insert(height, block_state.unrealized_profit.to_dollar() as f32);
self.unrealized_loss
.height
.insert(height, block_state.unrealized_loss.to_dollar() as f32);
if is_date_last_block {
let date_state = date_state.as_ref().unwrap();
self.supply_in_profit
.date
.insert(date, date_state.supply_in_profit.to_btc());
self.unrealized_profit
.date
.insert(date, date_state.unrealized_profit.to_dollar() as f32);
self.unrealized_loss
.date
.insert(date, date_state.unrealized_loss.to_dollar() as f32);
}
}
pub fn compute(
&mut self,
&ComputeData { heights, dates }: &ComputeData,
own_supply: &mut BiMap<f64>,
circulating_supply: &mut BiMap<f64>,
market_cap: &mut BiMap<f32>,
) {
self.supply_in_loss.multi_insert_subtract(
heights,
dates,
own_supply,
&mut self.supply_in_profit,
);
self.negative_unrealized_loss.multi_insert_simple_transform(
heights,
dates,
&mut self.unrealized_loss,
&|v| v * -1.0,
);
self.net_unrealized_profit_and_loss.multi_insert_subtract(
heights,
dates,
&mut self.unrealized_profit,
&mut self.unrealized_loss,
);
self.net_unrealized_profit_and_loss_to_market_cap_ratio
.multi_insert_divide(
heights,
dates,
&mut self.net_unrealized_profit_and_loss,
market_cap,
);
self.supply_in_profit_to_own_supply_ratio
.multi_insert_percentage(heights, dates, &mut self.supply_in_profit, own_supply);
self.supply_in_profit_to_circulating_supply_ratio
.multi_insert_percentage(
heights,
dates,
&mut self.supply_in_profit,
circulating_supply,
);
self.supply_in_loss_to_own_supply_ratio
.multi_insert_percentage(heights, dates, &mut self.supply_in_loss, own_supply);
self.supply_in_loss_to_circulating_supply_ratio
.multi_insert_percentage(heights, dates, &mut self.supply_in_loss, circulating_supply);
}
}
impl AnyDataset for UnrealizedSubDataset {
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.supply_in_profit,
&self.unrealized_profit,
&self.unrealized_loss,
]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.supply_in_profit,
&mut self.unrealized_profit,
&mut self.unrealized_loss,
]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.supply_in_loss,
&self.negative_unrealized_loss,
&self.net_unrealized_profit_and_loss,
&self.net_unrealized_profit_and_loss_to_market_cap_ratio,
&self.supply_in_profit_to_own_supply_ratio,
&self.supply_in_profit_to_circulating_supply_ratio,
&self.supply_in_loss_to_own_supply_ratio,
&self.supply_in_loss_to_circulating_supply_ratio,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.supply_in_loss,
&mut self.negative_unrealized_loss,
&mut self.net_unrealized_profit_and_loss,
&mut self.net_unrealized_profit_and_loss_to_market_cap_ratio,
&mut self.supply_in_profit_to_own_supply_ratio,
&mut self.supply_in_profit_to_circulating_supply_ratio,
&mut self.supply_in_loss_to_own_supply_ratio,
&mut self.supply_in_loss_to_circulating_supply_ratio,
]
}
}

View File

@@ -0,0 +1,63 @@
use allocative::Allocative;
use crate::{
datasets::{AnyDataset, InsertData, MinInitialStates},
states::UTXOState,
structs::{AnyBiMap, BiMap},
};
#[derive(Default, Allocative)]
pub struct UTXOSubDataset {
min_initial_states: MinInitialStates,
// Inserted
count: BiMap<usize>,
}
impl UTXOSubDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
count: BiMap::new_bin(1, &f("utxo_count")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
is_date_last_block,
date,
..
}: &InsertData,
state: &UTXOState,
) {
let count = self.count.height.insert(height, state.count);
if is_date_last_block {
self.count.date.insert(date, count);
}
}
}
impl AnyDataset for UTXOSubDataset {
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.count]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![&mut self.count]
}
}

View File

@@ -0,0 +1,257 @@
use allocative::Allocative;
use crate::{
datasets::InsertData,
structs::{AnyBiMap, BiMap, HeightMap},
utils::{ONE_DAY_IN_S, ONE_MONTH_IN_DAYS, ONE_WEEK_IN_DAYS, ONE_YEAR_IN_DAYS},
};
use super::{AnyDataset, ComputeData, MinInitialStates};
#[derive(Allocative)]
pub struct TransactionDataset {
min_initial_states: MinInitialStates,
// Inserted
pub count: BiMap<usize>,
pub volume: BiMap<f64>,
pub volume_in_dollars: BiMap<f32>,
// Average sent
// Average sent in dollars
// Median sent
// Median sent in dollars
// Min
// Max
// 10th 25th 75th 90th percentiles
// type
// version
// Computed
pub count_1w_sma: BiMap<f32>,
pub count_1m_sma: BiMap<f32>,
pub volume_1w_sma: BiMap<f32>,
pub volume_1m_sma: BiMap<f32>,
pub volume_in_dollars_1w_sma: BiMap<f32>,
pub volume_in_dollars_1m_sma: BiMap<f32>,
pub annualized_volume: BiMap<f32>,
pub annualized_volume_in_dollars: BiMap<f32>,
pub velocity: BiMap<f32>,
pub transactions_per_second: BiMap<f32>,
pub transactions_per_second_1w_sma: BiMap<f32>,
pub transactions_per_second_1m_sma: BiMap<f32>,
}
impl TransactionDataset {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let f = |s: &str| format!("{parent_path}/{s}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
count: BiMap::new_bin(1, &f("transaction_count")),
count_1w_sma: BiMap::new_bin(1, &f("transaction_count_1w_sma")),
count_1m_sma: BiMap::new_bin(1, &f("transaction_count_1m_sma")),
volume: BiMap::new_bin(1, &f("transaction_volume")),
volume_1w_sma: BiMap::new_bin(1, &f("transaction_volume_1w_sma")),
volume_1m_sma: BiMap::new_bin(1, &f("transaction_volume_1m_sma")),
volume_in_dollars: BiMap::new_bin(1, &f("transaction_volume_in_dollars")),
volume_in_dollars_1w_sma: BiMap::new_bin(1, &f("transaction_volume_in_dollars_1w_sma")),
volume_in_dollars_1m_sma: BiMap::new_bin(1, &f("transaction_volume_in_dollars_1m_sma")),
annualized_volume: BiMap::new_bin(1, &f("annualized_transaction_volume")),
annualized_volume_in_dollars: BiMap::new_bin(
2,
&f("annualized_transaction_volume_in_dollars"),
),
velocity: BiMap::new_bin(1, &f("transaction_velocity")),
transactions_per_second: BiMap::new_bin(1, &f("transactions_per_second")),
transactions_per_second_1w_sma: BiMap::new_bin(1, &f("transactions_per_second_1w_sma")),
transactions_per_second_1m_sma: BiMap::new_bin(1, &f("transactions_per_second_1m_sma")),
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(
&mut self,
&InsertData {
height,
date,
amount_sent,
transaction_count,
is_date_last_block,
date_blocks_range,
block_price,
..
}: &InsertData,
) {
self.count.height.insert(height, transaction_count);
self.volume.height.insert(height, amount_sent.to_btc());
self.volume_in_dollars
.height
.insert(height, (block_price * amount_sent).to_dollar() as f32);
if is_date_last_block {
self.count.date_insert_sum_range(date, date_blocks_range);
self.volume.date_insert_sum_range(date, date_blocks_range);
self.volume_in_dollars
.date_insert_sum_range(date, date_blocks_range);
}
}
pub fn compute(
&mut self,
&ComputeData { heights, dates }: &ComputeData,
circulating_supply: &mut BiMap<f64>,
block_interval: &mut HeightMap<u32>,
) {
self.count_1w_sma.multi_insert_simple_average(
heights,
dates,
&mut self.count,
ONE_WEEK_IN_DAYS,
);
self.count_1m_sma.multi_insert_simple_average(
heights,
dates,
&mut self.count,
ONE_MONTH_IN_DAYS,
);
self.volume_1w_sma.multi_insert_simple_average(
heights,
dates,
&mut self.volume,
ONE_WEEK_IN_DAYS,
);
self.volume_1m_sma.multi_insert_simple_average(
heights,
dates,
&mut self.volume,
ONE_MONTH_IN_DAYS,
);
self.volume_in_dollars_1w_sma.multi_insert_simple_average(
heights,
dates,
&mut self.volume_in_dollars,
ONE_WEEK_IN_DAYS,
);
self.volume_in_dollars_1m_sma.multi_insert_simple_average(
heights,
dates,
&mut self.volume_in_dollars,
ONE_MONTH_IN_DAYS,
);
self.annualized_volume.multi_insert_last_x_sum(
heights,
dates,
&mut self.volume,
ONE_YEAR_IN_DAYS,
);
self.annualized_volume_in_dollars.multi_insert_last_x_sum(
heights,
dates,
&mut self.volume_in_dollars,
ONE_YEAR_IN_DAYS,
);
self.velocity.multi_insert_divide(
heights,
dates,
&mut self.annualized_volume,
circulating_supply,
);
self.transactions_per_second.height.multi_insert_divide(
heights,
&mut self.count.height,
block_interval,
);
self.transactions_per_second
.date
.multi_insert_simple_transform(dates, &mut self.count.date, |count| {
count as f32 / ONE_DAY_IN_S as f32
});
self.transactions_per_second_1w_sma
.multi_insert_simple_average(
heights,
dates,
&mut self.transactions_per_second,
ONE_WEEK_IN_DAYS,
);
self.transactions_per_second_1m_sma
.multi_insert_simple_average(
heights,
dates,
&mut self.transactions_per_second,
ONE_MONTH_IN_DAYS,
);
}
}
impl AnyDataset for TransactionDataset {
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.count, &self.volume, &self.volume_in_dollars]
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.count,
&mut self.volume,
&mut self.volume_in_dollars,
]
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
vec![
&self.count_1w_sma,
&self.count_1m_sma,
&self.volume_1w_sma,
&self.volume_1m_sma,
&self.volume_in_dollars_1w_sma,
&self.volume_in_dollars_1m_sma,
&self.annualized_volume,
&self.annualized_volume_in_dollars,
&self.velocity,
&self.transactions_per_second,
&self.transactions_per_second_1w_sma,
&self.transactions_per_second_1m_sma,
]
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
vec![
&mut self.count_1w_sma,
&mut self.count_1m_sma,
&mut self.volume_1w_sma,
&mut self.volume_1m_sma,
&mut self.volume_in_dollars_1w_sma,
&mut self.volume_in_dollars_1m_sma,
&mut self.annualized_volume,
&mut self.annualized_volume_in_dollars,
&mut self.velocity,
&mut self.transactions_per_second,
&mut self.transactions_per_second_1w_sma,
&mut self.transactions_per_second_1m_sma,
]
}
}

View File

@@ -0,0 +1,287 @@
use allocative::Allocative;
use itertools::Itertools;
use crate::{
datasets::{
AnyDataset, AnyDatasetGroup, ComputeData, InsertData, MinInitialStates, SubDataset,
},
states::UTXOCohortId,
structs::{AnyBiMap, AnyDateMap, AnyHeightMap, BiMap, WNaiveDate},
};
#[derive(Default, Allocative)]
pub struct UTXODataset {
id: UTXOCohortId,
min_initial_states: MinInitialStates,
pub subs: SubDataset,
}
impl UTXODataset {
pub fn import(parent_path: &str, id: UTXOCohortId) -> color_eyre::Result<Self> {
let name = id.name();
let folder_path = format!("{parent_path}/{name}");
let mut s = Self {
min_initial_states: MinInitialStates::default(),
id,
subs: SubDataset::import(&folder_path)?,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_dataset(&s));
Ok(s)
}
pub fn insert(&mut self, insert_data: &InsertData) {
let &InsertData {
states,
utxo_cohorts_one_shot_states,
// utxo_cohorts_received_states,
utxo_cohorts_sent_states,
..
} = insert_data;
if self.needs_insert_supply(insert_data.height, insert_data.date) {
self.subs.supply.insert(
insert_data,
&states
.utxo_cohorts_durable_states
.get(&self.id)
.durable_states
.supply_state,
);
}
if self.needs_insert_utxo(insert_data.height, insert_data.date) {
self.subs.utxo.insert(
insert_data,
&states
.utxo_cohorts_durable_states
.get(&self.id)
.durable_states
.utxo_state,
);
}
if self.needs_insert_capitalization(insert_data.height, insert_data.date) {
self.subs.capitalization.insert(
insert_data,
&states
.utxo_cohorts_durable_states
.get(&self.id)
.durable_states
.capitalization_state,
);
}
if self.needs_insert_unrealized(insert_data.height, insert_data.date) {
self.subs.unrealized.insert(
insert_data,
&utxo_cohorts_one_shot_states
.get(&self.id)
.unrealized_block_state,
&utxo_cohorts_one_shot_states
.get(&self.id)
.unrealized_date_state,
);
}
if self.needs_insert_price_paid(insert_data.height, insert_data.date) {
self.subs.price_paid.insert(
insert_data,
&utxo_cohorts_one_shot_states.get(&self.id).price_paid_state,
);
}
if self.needs_insert_realized(insert_data.height, insert_data.date) {
self.subs.realized.insert(
insert_data,
&utxo_cohorts_sent_states.get(&self.id).realized,
);
}
if self.needs_insert_input(insert_data.height, insert_data.date) {
self.subs
.input
.insert(insert_data, &utxo_cohorts_sent_states.get(&self.id).input);
}
// TODO: move output from common to address
// if self.subs.output.needs_insert(insert_data) {
// self.subs
// .output
// .insert(insert_data, utxo_cohorts_received_states.get(&self.id));
// }
}
pub fn needs_insert_utxo(&self, height: usize, date: WNaiveDate) -> bool {
self.subs.utxo.needs_insert(height, date)
}
pub fn needs_insert_capitalization(&self, height: usize, date: WNaiveDate) -> bool {
self.subs.capitalization.needs_insert(height, date)
}
pub fn needs_insert_supply(&self, height: usize, date: WNaiveDate) -> bool {
self.subs.supply.needs_insert(height, date)
}
pub fn needs_insert_price_paid(&self, height: usize, date: WNaiveDate) -> bool {
self.subs.price_paid.needs_insert(height, date)
}
pub fn needs_insert_realized(&self, height: usize, date: WNaiveDate) -> bool {
self.subs.realized.needs_insert(height, date)
}
pub fn needs_insert_unrealized(&self, height: usize, date: WNaiveDate) -> bool {
self.subs.unrealized.needs_insert(height, date)
}
pub fn needs_insert_input(&self, height: usize, date: WNaiveDate) -> bool {
self.subs.input.needs_insert(height, date)
}
pub fn compute(
&mut self,
compute_data: &ComputeData,
closes: &mut BiMap<f32>,
circulating_supply: &mut BiMap<f64>,
market_cap: &mut BiMap<f32>,
) {
if self.subs.supply.should_compute(compute_data) {
self.subs.supply.compute(compute_data, circulating_supply);
}
if self.subs.unrealized.should_compute(compute_data) {
self.subs.unrealized.compute(
compute_data,
&mut self.subs.supply.supply,
circulating_supply,
market_cap,
);
}
if self.subs.realized.should_compute(compute_data) {
self.subs.realized.compute(compute_data, market_cap);
}
if self.subs.capitalization.should_compute(compute_data) {
self.subs
.capitalization
.compute(compute_data, closes, &mut self.subs.supply.supply);
}
// if self.subs.output.should_compute(compute_data) {
// self.subs
// .output
// .compute(compute_data, &mut self.subs.supply.total);
// }
}
}
impl AnyDataset for UTXODataset {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_inserted_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_height_map_vec())
.collect_vec()
}
fn to_inserted_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_date_map_vec())
.collect_vec()
}
fn to_inserted_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_inserted_bi_map_vec())
.collect_vec()
}
fn to_inserted_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_height_map_vec())
.collect_vec()
}
fn to_inserted_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_date_map_vec())
.collect_vec()
}
fn to_inserted_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_inserted_mut_bi_map_vec())
.collect_vec()
}
fn to_computed_height_map_vec(&self) -> Vec<&(dyn AnyHeightMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_height_map_vec())
.collect_vec()
}
fn to_computed_date_map_vec(&self) -> Vec<&(dyn AnyDateMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_date_map_vec())
.collect_vec()
}
fn to_computed_bi_map_vec(&self) -> Vec<&(dyn AnyBiMap + Send + Sync)> {
self.subs
.as_vec()
.into_iter()
.flat_map(|d| d.to_computed_bi_map_vec())
.collect_vec()
}
fn to_computed_mut_height_map_vec(&mut self) -> Vec<&mut dyn AnyHeightMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_height_map_vec())
.collect_vec()
}
fn to_computed_mut_date_map_vec(&mut self) -> Vec<&mut dyn AnyDateMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_date_map_vec())
.collect_vec()
}
fn to_computed_mut_bi_map_vec(&mut self) -> Vec<&mut dyn AnyBiMap> {
self.subs
.as_mut_vec()
.into_iter()
.flat_map(|d| d.to_computed_mut_bi_map_vec())
.collect_vec()
}
}

View File

@@ -0,0 +1,162 @@
mod dataset;
use allocative::Allocative;
use dataset::*;
use rayon::prelude::*;
use itertools::Itertools;
use crate::{
datasets::AnyDatasets,
states::{SplitByUTXOCohort, UTXOCohortId},
structs::{BiMap, WNaiveDate},
};
use super::{AnyDataset, ComputeData, InsertData, MinInitialStates};
#[derive(Allocative)]
pub struct UTXODatasets {
min_initial_states: MinInitialStates,
cohorts: SplitByUTXOCohort<UTXODataset>,
}
impl UTXODatasets {
pub fn import(parent_path: &str) -> color_eyre::Result<Self> {
let mut cohorts = SplitByUTXOCohort::<UTXODataset>::default();
cohorts
.as_vec()
.into_par_iter()
.map(|(_, id)| (id, UTXODataset::import(parent_path, id)))
.collect::<Vec<_>>()
.into_iter()
.try_for_each(|(id, dataset)| -> color_eyre::Result<()> {
*cohorts.get_mut(&id) = dataset?;
Ok(())
})?;
let mut s = Self {
min_initial_states: MinInitialStates::default(),
cohorts,
};
s.min_initial_states
.consume(MinInitialStates::compute_from_datasets(&s));
Ok(s)
}
pub fn insert(&mut self, insert_data: &InsertData) {
self.cohorts
.as_mut_vec()
.into_iter()
.for_each(|(cohort, _)| cohort.insert(insert_data))
}
pub fn needs_durable_states(&self, height: usize, date: WNaiveDate) -> bool {
let needs_insert_utxo = self.needs_insert_utxo(height, date);
let needs_insert_capitalization = self.needs_insert_capitalization(height, date);
let needs_insert_supply = self.needs_insert_supply(height, date);
let needs_one_shot_states = self.needs_one_shot_states(height, date);
needs_insert_utxo
|| needs_insert_capitalization
|| needs_insert_supply
|| needs_one_shot_states
}
pub fn needs_one_shot_states(&self, height: usize, date: WNaiveDate) -> bool {
self.needs_insert_price_paid(height, date) || self.needs_insert_unrealized(height, date)
}
pub fn needs_sent_states(&self, height: usize, date: WNaiveDate) -> bool {
self.needs_insert_input(height, date) || self.needs_insert_realized(height, date)
}
pub fn needs_insert_utxo(&self, height: usize, date: WNaiveDate) -> bool {
self.as_vec()
.iter()
.any(|(dataset, _)| dataset.needs_insert_utxo(height, date))
}
pub fn needs_insert_capitalization(&self, height: usize, date: WNaiveDate) -> bool {
self.as_vec()
.iter()
.any(|(dataset, _)| dataset.needs_insert_capitalization(height, date))
}
pub fn needs_insert_supply(&self, height: usize, date: WNaiveDate) -> bool {
self.as_vec()
.iter()
.any(|(dataset, _)| dataset.needs_insert_supply(height, date))
}
pub fn needs_insert_price_paid(&self, height: usize, date: WNaiveDate) -> bool {
self.as_vec()
.iter()
.any(|(dataset, _)| dataset.needs_insert_price_paid(height, date))
}
pub fn needs_insert_realized(&self, height: usize, date: WNaiveDate) -> bool {
self.as_vec()
.iter()
.any(|(dataset, _)| dataset.needs_insert_realized(height, date))
}
pub fn needs_insert_unrealized(&self, height: usize, date: WNaiveDate) -> bool {
self.as_vec()
.iter()
.any(|(dataset, _)| dataset.needs_insert_unrealized(height, date))
}
pub fn needs_insert_input(&self, height: usize, date: WNaiveDate) -> bool {
self.as_vec()
.iter()
.any(|(dataset, _)| dataset.needs_insert_input(height, date))
}
pub fn compute(
&mut self,
compute_data: &ComputeData,
closes: &mut BiMap<f32>,
circulating_supply: &mut BiMap<f64>,
market_cap: &mut BiMap<f32>,
) {
self.cohorts
.as_mut_vec()
.into_iter()
.for_each(|(cohort, _)| {
cohort.compute(compute_data, closes, circulating_supply, market_cap)
})
}
fn as_vec(&self) -> Vec<(&UTXODataset, UTXOCohortId)> {
self.cohorts.as_vec()
}
fn as_mut_vec(&mut self) -> Vec<(&mut UTXODataset, UTXOCohortId)> {
self.cohorts.as_mut_vec()
}
}
impl AnyDatasets for UTXODatasets {
fn get_min_initial_states(&self) -> &MinInitialStates {
&self.min_initial_states
}
fn to_any_dataset_vec(&self) -> Vec<&(dyn AnyDataset + Send + Sync)> {
self.as_vec()
.into_iter()
.map(|(dataset, _)| dataset as &(dyn AnyDataset + Send + Sync))
.collect_vec()
}
fn to_mut_any_dataset_vec(&mut self) -> Vec<&mut dyn AnyDataset> {
self.as_mut_vec()
.into_iter()
.map(|(dataset, _)| dataset as &mut dyn AnyDataset)
.collect_vec()
}
}