mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-20 23:04:46 -07:00
computer: snapshot
This commit is contained in:
@@ -104,7 +104,10 @@ where
|
||||
Some(("weekindex".to_string(), self.weekindex.to_tree_node())),
|
||||
Some(("monthindex".to_string(), self.monthindex.to_tree_node())),
|
||||
Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())),
|
||||
Some(("semesterindex".to_string(), self.semesterindex.to_tree_node())),
|
||||
Some((
|
||||
"semesterindex".to_string(),
|
||||
self.semesterindex.to_tree_node(),
|
||||
)),
|
||||
Some(("yearindex".to_string(), self.yearindex.to_tree_node())),
|
||||
Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())),
|
||||
]
|
||||
|
||||
163
crates/brk_computer/src/grouped/lazy2_from_height.rs
Normal file
163
crates/brk_computer/src/grouped/lazy2_from_height.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex,
|
||||
Version, WeekIndex, YearIndex,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{AnyExportableVec, BinaryTransform, IterableBoxedVec, LazyVecFrom2};
|
||||
|
||||
use super::{ComputedVecValue, ComputedVecsFromHeight, LazyTransform2Builder};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
/// Lazy binary transform from two `ComputedVecsFromHeight` sources.
|
||||
#[derive(Clone)]
|
||||
pub struct LazyVecsFrom2FromHeight<T, S1T, S2T>
|
||||
where
|
||||
T: ComputedVecValue + PartialOrd + JsonSchema,
|
||||
S1T: ComputedVecValue,
|
||||
S2T: ComputedVecValue,
|
||||
{
|
||||
pub height: LazyVecFrom2<Height, T, Height, S1T, Height, S2T>,
|
||||
pub height_extra: LazyTransform2Builder<Height, T, S1T, S2T>,
|
||||
pub dateindex: LazyTransform2Builder<DateIndex, T, S1T, S2T>,
|
||||
pub weekindex: LazyTransform2Builder<WeekIndex, T, S1T, S2T>,
|
||||
pub difficultyepoch: LazyTransform2Builder<DifficultyEpoch, T, S1T, S2T>,
|
||||
pub monthindex: LazyTransform2Builder<MonthIndex, T, S1T, S2T>,
|
||||
pub quarterindex: LazyTransform2Builder<QuarterIndex, T, S1T, S2T>,
|
||||
pub semesterindex: LazyTransform2Builder<SemesterIndex, T, S1T, S2T>,
|
||||
pub yearindex: LazyTransform2Builder<YearIndex, T, S1T, S2T>,
|
||||
pub decadeindex: LazyTransform2Builder<DecadeIndex, T, S1T, S2T>,
|
||||
}
|
||||
|
||||
impl<T, S1T, S2T> LazyVecsFrom2FromHeight<T, S1T, S2T>
|
||||
where
|
||||
T: ComputedVecValue + JsonSchema + 'static,
|
||||
S1T: ComputedVecValue + JsonSchema,
|
||||
S2T: ComputedVecValue + JsonSchema,
|
||||
{
|
||||
/// Create from two `ComputedVecsFromHeight` sources with explicit height sources.
|
||||
pub fn from_computed<F: BinaryTransform<S1T, S2T, T>>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
height_source1: IterableBoxedVec<Height, S1T>,
|
||||
height_source2: IterableBoxedVec<Height, S2T>,
|
||||
source1: &ComputedVecsFromHeight<S1T>,
|
||||
source2: &ComputedVecsFromHeight<S2T>,
|
||||
) -> Self {
|
||||
let v = version + VERSION;
|
||||
|
||||
Self {
|
||||
height: LazyVecFrom2::transformed::<F>(name, v, height_source1, height_source2),
|
||||
height_extra: LazyTransform2Builder::from_eager::<F>(
|
||||
name,
|
||||
v,
|
||||
&source1.height_extra,
|
||||
&source2.height_extra,
|
||||
),
|
||||
dateindex: LazyTransform2Builder::from_eager::<F>(
|
||||
name,
|
||||
v,
|
||||
&source1.dateindex,
|
||||
&source2.dateindex,
|
||||
),
|
||||
weekindex: LazyTransform2Builder::from_lazy::<F, _, _, _, _>(
|
||||
name,
|
||||
v,
|
||||
&source1.weekindex,
|
||||
&source2.weekindex,
|
||||
),
|
||||
difficultyepoch: LazyTransform2Builder::from_eager::<F>(
|
||||
name,
|
||||
v,
|
||||
&source1.difficultyepoch,
|
||||
&source2.difficultyepoch,
|
||||
),
|
||||
monthindex: LazyTransform2Builder::from_lazy::<F, _, _, _, _>(
|
||||
name,
|
||||
v,
|
||||
&source1.monthindex,
|
||||
&source2.monthindex,
|
||||
),
|
||||
quarterindex: LazyTransform2Builder::from_lazy::<F, _, _, _, _>(
|
||||
name,
|
||||
v,
|
||||
&source1.quarterindex,
|
||||
&source2.quarterindex,
|
||||
),
|
||||
semesterindex: LazyTransform2Builder::from_lazy::<F, _, _, _, _>(
|
||||
name,
|
||||
v,
|
||||
&source1.semesterindex,
|
||||
&source2.semesterindex,
|
||||
),
|
||||
yearindex: LazyTransform2Builder::from_lazy::<F, _, _, _, _>(
|
||||
name,
|
||||
v,
|
||||
&source1.yearindex,
|
||||
&source2.yearindex,
|
||||
),
|
||||
decadeindex: LazyTransform2Builder::from_lazy::<F, _, _, _, _>(
|
||||
name,
|
||||
v,
|
||||
&source1.decadeindex,
|
||||
&source2.decadeindex,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S1T, S2T> Traversable for LazyVecsFrom2FromHeight<T, S1T, S2T>
|
||||
where
|
||||
T: ComputedVecValue + JsonSchema,
|
||||
S1T: ComputedVecValue,
|
||||
S2T: ComputedVecValue,
|
||||
{
|
||||
fn to_tree_node(&self) -> brk_traversable::TreeNode {
|
||||
let height_extra_node = self.height_extra.to_tree_node();
|
||||
brk_traversable::TreeNode::Branch(
|
||||
[
|
||||
Some(("height".to_string(), self.height.to_tree_node())),
|
||||
if height_extra_node.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(("height_extra".to_string(), height_extra_node))
|
||||
},
|
||||
Some(("dateindex".to_string(), self.dateindex.to_tree_node())),
|
||||
Some(("weekindex".to_string(), self.weekindex.to_tree_node())),
|
||||
Some((
|
||||
"difficultyepoch".to_string(),
|
||||
self.difficultyepoch.to_tree_node(),
|
||||
)),
|
||||
Some(("monthindex".to_string(), self.monthindex.to_tree_node())),
|
||||
Some(("quarterindex".to_string(), self.quarterindex.to_tree_node())),
|
||||
Some((
|
||||
"semesterindex".to_string(),
|
||||
self.semesterindex.to_tree_node(),
|
||||
)),
|
||||
Some(("yearindex".to_string(), self.yearindex.to_tree_node())),
|
||||
Some(("decadeindex".to_string(), self.decadeindex.to_tree_node())),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
)
|
||||
.merge_branches()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn iter_any_exportable(&self) -> impl Iterator<Item = &dyn AnyExportableVec> {
|
||||
let mut iter: Box<dyn Iterator<Item = &dyn AnyExportableVec>> =
|
||||
Box::new(self.height.iter_any_exportable());
|
||||
iter = Box::new(iter.chain(self.height_extra.iter_any_exportable()));
|
||||
iter = Box::new(iter.chain(self.dateindex.iter_any_exportable()));
|
||||
iter = Box::new(iter.chain(self.weekindex.iter_any_exportable()));
|
||||
iter = Box::new(iter.chain(self.difficultyepoch.iter_any_exportable()));
|
||||
iter = Box::new(iter.chain(self.monthindex.iter_any_exportable()));
|
||||
iter = Box::new(iter.chain(self.quarterindex.iter_any_exportable()));
|
||||
iter = Box::new(iter.chain(self.semesterindex.iter_any_exportable()));
|
||||
iter = Box::new(iter.chain(self.yearindex.iter_any_exportable()));
|
||||
iter = Box::new(iter.chain(self.decadeindex.iter_any_exportable()));
|
||||
iter
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ mod computed_from_height;
|
||||
mod computed_from_height_strict;
|
||||
mod computed_from_txindex;
|
||||
mod lazy2_from_dateindex;
|
||||
mod lazy2_from_height;
|
||||
mod lazy_from_dateindex;
|
||||
mod lazy_from_height;
|
||||
mod lazy_value_from_dateindex;
|
||||
@@ -40,6 +41,7 @@ pub use lazy_from_height::*;
|
||||
pub use lazy_value_from_dateindex::*;
|
||||
pub use lazy_value_height::*;
|
||||
pub use lazy2_from_dateindex::*;
|
||||
pub use lazy2_from_height::*;
|
||||
// pub use lazy_from_height_strict::*;
|
||||
// pub use lazy_from_txindex::*;
|
||||
pub use price_percentiles::*;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use brk_types::{Bitcoin, Close, Dollars, Sats, StoredF32};
|
||||
use brk_types::{Bitcoin, Close, Dollars, Sats, StoredF32, StoredF64};
|
||||
use vecdb::{BinaryTransform, UnaryTransform};
|
||||
|
||||
/// (Dollars, Dollars) -> Dollars addition
|
||||
@@ -163,3 +163,52 @@ impl<const V: u16> UnaryTransform<Dollars, Dollars> for DollarsTimesTenths<V> {
|
||||
d * (V as f64 / 10.0)
|
||||
}
|
||||
}
|
||||
|
||||
// === Percentage Transforms (a/b × 100) ===
|
||||
|
||||
/// (Bitcoin, Bitcoin) -> StoredF64 percentage (a/b × 100)
|
||||
/// Used for supply ratio calculations like supply_in_profit / total_supply × 100
|
||||
pub struct PercentageBtcF64;
|
||||
|
||||
impl BinaryTransform<Bitcoin, Bitcoin, StoredF64> for PercentageBtcF64 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Bitcoin, denominator: Bitcoin) -> StoredF64 {
|
||||
// Bitcoin / Bitcoin returns StoredF64, so dereference and multiply
|
||||
StoredF64::from(*(numerator / denominator) * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// (Dollars, Dollars) -> StoredF32 percentage (a/b × 100)
|
||||
/// Used for unrealized/realized ratio calculations
|
||||
pub struct PercentageDollarsF32;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, StoredF32> for PercentageDollarsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 {
|
||||
// Dollars / Dollars returns StoredF64, so dereference and multiply
|
||||
StoredF32::from(*(numerator / denominator) * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// (Dollars, Dollars) -> StoredF32 negated percentage (-(a/b × 100))
|
||||
/// Used for negated loss ratio calculations, avoiding lazy-from-lazy chains.
|
||||
pub struct NegPercentageDollarsF32;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, StoredF32> for NegPercentageDollarsF32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> StoredF32 {
|
||||
// Dollars / Dollars returns StoredF64, so dereference and multiply
|
||||
StoredF32::from(-(*(numerator / denominator) * 100.0))
|
||||
}
|
||||
}
|
||||
|
||||
/// (Sats, Sats) -> StoredF64 percentage (a/b × 100)
|
||||
/// Used for supply ratio calculations (equivalent to Bitcoin/Bitcoin since 1e8 cancels)
|
||||
pub struct PercentageSatsF64;
|
||||
|
||||
impl BinaryTransform<Sats, Sats, StoredF64> for PercentageSatsF64 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Sats, denominator: Sats) -> StoredF64 {
|
||||
StoredF64::from((*numerator as f64 / *denominator as f64) * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use rayon::prelude::*;
|
||||
use vecdb::{Exit, GenericStoredVec, IterableVec, TypedVecIterator, VecIndex};
|
||||
|
||||
use crate::{
|
||||
chain, indexes, price, txins,
|
||||
chain, indexes, price,
|
||||
stateful::{
|
||||
address::AddressTypeToAddressCount,
|
||||
compute::write::{process_address_updates, write},
|
||||
@@ -19,14 +19,15 @@ use crate::{
|
||||
},
|
||||
states::{BlockState, Transacted},
|
||||
},
|
||||
txins,
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
use super::{
|
||||
super::{
|
||||
RangeMap,
|
||||
cohorts::{AddressCohorts, DynCohortVecs, UTXOCohorts},
|
||||
vecs::Vecs,
|
||||
RangeMap,
|
||||
},
|
||||
BIP30_DUPLICATE_HEIGHT_1, BIP30_DUPLICATE_HEIGHT_2, BIP30_ORIGINAL_HEIGHT_1,
|
||||
BIP30_ORIGINAL_HEIGHT_2, ComputeContext, FLUSH_INTERVAL, TxInIterators, TxOutIterators,
|
||||
@@ -62,8 +63,6 @@ pub fn process_blocks(
|
||||
ctx.price.is_some()
|
||||
);
|
||||
|
||||
info!("Setting up references...");
|
||||
|
||||
// References to vectors using correct field paths
|
||||
// From indexer.vecs:
|
||||
let height_to_first_txindex = &indexer.vecs.tx.height_to_first_txindex;
|
||||
@@ -97,8 +96,6 @@ pub fn process_blocks(
|
||||
let height_to_price_vec = &ctx.height_to_price;
|
||||
let height_to_timestamp_vec = &ctx.height_to_timestamp;
|
||||
|
||||
info!("Creating iterators...");
|
||||
|
||||
// Create iterators for sequential access
|
||||
let mut height_to_first_txindex_iter = height_to_first_txindex.into_iter();
|
||||
let mut height_to_first_txoutindex_iter = height_to_first_txoutindex.into_iter();
|
||||
@@ -116,12 +113,9 @@ pub fn process_blocks(
|
||||
let mut height_to_price_iter = height_to_price.map(|v| v.into_iter());
|
||||
let mut dateindex_to_price_iter = dateindex_to_price.map(|v| v.into_iter());
|
||||
|
||||
info!("Creating readers...");
|
||||
|
||||
let mut vr = VecsReaders::new(&vecs.any_address_indexes, &vecs.addresses_data);
|
||||
|
||||
// Build txindex -> height lookup map for efficient prev_height computation
|
||||
info!("Building txindex_to_height map...");
|
||||
let mut txindex_to_height: RangeMap<TxIndex, Height> = {
|
||||
let mut map = RangeMap::with_capacity(last_height.to_usize() + 1);
|
||||
for first_txindex in indexer.vecs.tx.height_to_first_txindex.into_iter() {
|
||||
@@ -134,8 +128,6 @@ pub fn process_blocks(
|
||||
let mut txout_iters = TxOutIterators::new(indexer);
|
||||
let mut txin_iters = TxInIterators::new(indexer, txins, &mut txindex_to_height);
|
||||
|
||||
info!("Creating address iterators...");
|
||||
|
||||
// Create iterators for first address indexes per type
|
||||
let mut first_p2a_iter = indexer
|
||||
.vecs
|
||||
@@ -178,8 +170,6 @@ pub fn process_blocks(
|
||||
.height_to_first_p2wshaddressindex
|
||||
.into_iter();
|
||||
|
||||
info!("Recovering running totals...");
|
||||
|
||||
// Track running totals - recover from previous height if resuming
|
||||
let (
|
||||
mut unspendable_supply,
|
||||
@@ -187,28 +177,23 @@ pub fn process_blocks(
|
||||
mut addresstype_to_addr_count,
|
||||
mut addresstype_to_empty_addr_count,
|
||||
) = if starting_height > Height::ZERO {
|
||||
info!("Reading unspendable_supply...");
|
||||
let prev_height = starting_height.decremented().unwrap();
|
||||
let unspendable = vecs
|
||||
.height_to_unspendable_supply
|
||||
.into_iter()
|
||||
.get_unwrap(prev_height);
|
||||
info!("Reading opreturn_supply...");
|
||||
let opreturn = vecs
|
||||
.height_to_opreturn_supply
|
||||
.into_iter()
|
||||
.get_unwrap(prev_height);
|
||||
info!("Reading addresstype_to_addr_count...");
|
||||
let addr_count = AddressTypeToAddressCount::from((
|
||||
&vecs.addresstype_to_height_to_addr_count,
|
||||
starting_height,
|
||||
));
|
||||
info!("Reading addresstype_to_empty_addr_count...");
|
||||
let empty_addr_count = AddressTypeToAddressCount::from((
|
||||
&vecs.addresstype_to_height_to_empty_addr_count,
|
||||
starting_height,
|
||||
));
|
||||
info!("Recovery complete.");
|
||||
(unspendable, opreturn, addr_count, empty_addr_count)
|
||||
} else {
|
||||
(
|
||||
@@ -221,8 +206,6 @@ pub fn process_blocks(
|
||||
|
||||
let mut cache = AddressCache::new();
|
||||
|
||||
info!("Starting main block iteration...");
|
||||
|
||||
// Main block iteration
|
||||
for height in starting_height.to_usize()..=last_height.to_usize() {
|
||||
let height = Height::from(height);
|
||||
|
||||
@@ -53,13 +53,20 @@ impl CohortMetrics {
|
||||
pub fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
let compute_dollars = cfg.compute_dollars();
|
||||
|
||||
let supply = SupplyMetrics::forced_import(cfg)?;
|
||||
|
||||
let unrealized = compute_dollars
|
||||
.then(|| UnrealizedMetrics::forced_import(cfg))
|
||||
.transpose()?;
|
||||
|
||||
let relative = unrealized
|
||||
.as_ref()
|
||||
.map(|u| RelativeMetrics::forced_import(cfg, u, &supply))
|
||||
.transpose()?;
|
||||
|
||||
Ok(Self {
|
||||
filter: cfg.filter.clone(),
|
||||
supply: SupplyMetrics::forced_import(cfg)?,
|
||||
supply,
|
||||
activity: ActivityMetrics::forced_import(cfg)?,
|
||||
realized: compute_dollars
|
||||
.then(|| RealizedMetrics::forced_import(cfg))
|
||||
@@ -67,10 +74,7 @@ impl CohortMetrics {
|
||||
price_paid: compute_dollars
|
||||
.then(|| PricePaidMetrics::forced_import(cfg))
|
||||
.transpose()?,
|
||||
relative: unrealized
|
||||
.as_ref()
|
||||
.map(|u| RelativeMetrics::forced_import(cfg, u))
|
||||
.transpose()?,
|
||||
relative,
|
||||
unrealized,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ use crate::{
|
||||
Indexes,
|
||||
grouped::{
|
||||
ComputedRatioVecsFromDateIndex, ComputedVecsFromDateIndex, ComputedVecsFromHeight,
|
||||
LazyVecsFromHeight, Source, VecBuilderOptions,
|
||||
LazyVecsFrom2FromHeight, LazyVecsFromHeight, PercentageDollarsF32, Source,
|
||||
VecBuilderOptions,
|
||||
},
|
||||
indexes, price,
|
||||
stateful::states::RealizedState,
|
||||
@@ -40,10 +41,13 @@ pub struct RealizedMetrics {
|
||||
pub indexes_to_net_realized_pnl: ComputedVecsFromHeight<Dollars>,
|
||||
pub indexes_to_realized_value: ComputedVecsFromHeight<Dollars>,
|
||||
|
||||
// === Realized vs Realized Cap Ratios ===
|
||||
pub indexes_to_realized_profit_rel_to_realized_cap: ComputedVecsFromHeight<StoredF32>,
|
||||
pub indexes_to_realized_loss_rel_to_realized_cap: ComputedVecsFromHeight<StoredF32>,
|
||||
pub indexes_to_net_realized_pnl_rel_to_realized_cap: ComputedVecsFromHeight<StoredF32>,
|
||||
// === Realized vs Realized Cap Ratios (lazy) ===
|
||||
pub indexes_to_realized_profit_rel_to_realized_cap:
|
||||
LazyVecsFrom2FromHeight<StoredF32, Dollars, Dollars>,
|
||||
pub indexes_to_realized_loss_rel_to_realized_cap:
|
||||
LazyVecsFrom2FromHeight<StoredF32, Dollars, Dollars>,
|
||||
pub indexes_to_net_realized_pnl_rel_to_realized_cap:
|
||||
LazyVecsFrom2FromHeight<StoredF32, Dollars, Dollars>,
|
||||
|
||||
// === Total Realized PnL ===
|
||||
pub indexes_to_total_realized_pnl: LazyVecsFromHeight<Dollars>,
|
||||
@@ -135,21 +139,75 @@ impl RealizedMetrics {
|
||||
&indexes_to_realized_value,
|
||||
);
|
||||
|
||||
// Extract vecs needed for lazy ratio construction
|
||||
let height_to_realized_cap: EagerVec<PcoVec<Height, Dollars>> =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("realized_cap"), cfg.version + v0)?;
|
||||
|
||||
let indexes_to_realized_cap = ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap"),
|
||||
Source::None,
|
||||
cfg.version + v0,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?;
|
||||
|
||||
let height_to_realized_profit: EagerVec<PcoVec<Height, Dollars>> =
|
||||
EagerVec::forced_import(cfg.db, &cfg.name("realized_profit"), cfg.version + v0)?;
|
||||
|
||||
let indexes_to_realized_profit = ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_profit"),
|
||||
Source::None,
|
||||
cfg.version + v0,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?;
|
||||
|
||||
let indexes_to_net_realized_pnl = ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl"),
|
||||
Source::Compute,
|
||||
cfg.version + v0,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?;
|
||||
|
||||
// Construct lazy ratio vecs (before struct assignment to satisfy borrow checker)
|
||||
let indexes_to_realized_profit_rel_to_realized_cap =
|
||||
LazyVecsFrom2FromHeight::from_computed::<PercentageDollarsF32>(
|
||||
&cfg.name("realized_profit_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
height_to_realized_profit.boxed_clone(),
|
||||
height_to_realized_cap.boxed_clone(),
|
||||
&indexes_to_realized_profit,
|
||||
&indexes_to_realized_cap,
|
||||
);
|
||||
|
||||
let indexes_to_realized_loss_rel_to_realized_cap =
|
||||
LazyVecsFrom2FromHeight::from_computed::<PercentageDollarsF32>(
|
||||
&cfg.name("realized_loss_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
height_to_realized_loss.boxed_clone(),
|
||||
height_to_realized_cap.boxed_clone(),
|
||||
&indexes_to_realized_loss,
|
||||
&indexes_to_realized_cap,
|
||||
);
|
||||
|
||||
let indexes_to_net_realized_pnl_rel_to_realized_cap =
|
||||
LazyVecsFrom2FromHeight::from_computed::<PercentageDollarsF32>(
|
||||
&cfg.name("net_realized_pnl_rel_to_realized_cap"),
|
||||
cfg.version + v1,
|
||||
indexes_to_net_realized_pnl.height.as_ref().unwrap().boxed_clone(),
|
||||
height_to_realized_cap.boxed_clone(),
|
||||
&indexes_to_net_realized_pnl,
|
||||
&indexes_to_realized_cap,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
// === Realized Cap ===
|
||||
height_to_realized_cap: EagerVec::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap"),
|
||||
cfg.version + v0,
|
||||
)?,
|
||||
indexes_to_realized_cap: ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap"),
|
||||
Source::None,
|
||||
cfg.version + v0,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
height_to_realized_cap,
|
||||
indexes_to_realized_cap,
|
||||
indexes_to_realized_price: ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_price"),
|
||||
@@ -188,57 +246,18 @@ impl RealizedMetrics {
|
||||
)?,
|
||||
|
||||
// === Realized Profit/Loss ===
|
||||
height_to_realized_profit: EagerVec::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_profit"),
|
||||
cfg.version + v0,
|
||||
)?,
|
||||
indexes_to_realized_profit: ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_profit"),
|
||||
Source::None,
|
||||
cfg.version + v0,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?,
|
||||
height_to_realized_profit,
|
||||
indexes_to_realized_profit,
|
||||
height_to_realized_loss,
|
||||
indexes_to_realized_loss,
|
||||
indexes_to_neg_realized_loss,
|
||||
indexes_to_net_realized_pnl: ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl"),
|
||||
Source::Compute,
|
||||
cfg.version + v0,
|
||||
cfg.indexes,
|
||||
sum_cum,
|
||||
)?,
|
||||
indexes_to_net_realized_pnl,
|
||||
indexes_to_realized_value,
|
||||
|
||||
// === Realized vs Realized Cap Ratios ===
|
||||
indexes_to_realized_profit_rel_to_realized_cap: ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_profit_rel_to_realized_cap"),
|
||||
Source::Compute,
|
||||
cfg.version + v0,
|
||||
cfg.indexes,
|
||||
sum,
|
||||
)?,
|
||||
indexes_to_realized_loss_rel_to_realized_cap: ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("realized_loss_rel_to_realized_cap"),
|
||||
Source::Compute,
|
||||
cfg.version + v0,
|
||||
cfg.indexes,
|
||||
sum,
|
||||
)?,
|
||||
indexes_to_net_realized_pnl_rel_to_realized_cap: ComputedVecsFromHeight::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl_rel_to_realized_cap"),
|
||||
Source::Compute,
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
sum,
|
||||
)?,
|
||||
// === Realized vs Realized Cap Ratios (lazy) ===
|
||||
indexes_to_realized_profit_rel_to_realized_cap,
|
||||
indexes_to_realized_loss_rel_to_realized_cap,
|
||||
indexes_to_net_realized_pnl_rel_to_realized_cap,
|
||||
|
||||
// === Total Realized PnL ===
|
||||
indexes_to_total_realized_pnl,
|
||||
@@ -768,40 +787,6 @@ impl RealizedMetrics {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Ratios relative to realized cap
|
||||
self.indexes_to_realized_profit_rel_to_realized_cap
|
||||
.compute_all(indexes, starting_indexes, exit, |vec| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.height,
|
||||
&self.height_to_realized_profit,
|
||||
&self.height_to_realized_cap,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_realized_loss_rel_to_realized_cap
|
||||
.compute_all(indexes, starting_indexes, exit, |vec| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.height,
|
||||
&self.height_to_realized_loss,
|
||||
&self.height_to_realized_cap,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_net_realized_pnl_rel_to_realized_cap
|
||||
.compute_all(indexes, starting_indexes, exit, |vec| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.height,
|
||||
self.indexes_to_net_realized_pnl.height.u(),
|
||||
&self.height_to_realized_cap,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Net realized PnL cumulative 30d delta
|
||||
self.indexes_to_net_realized_pnl_cumulative_30d_delta
|
||||
.compute_all(starting_indexes, exit, |vec| {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, DateIndex, Dollars, Height, StoredF32, StoredF64, Version};
|
||||
use brk_types::{Bitcoin, DateIndex, Dollars, Height, Sats, StoredF32, StoredF64, Version};
|
||||
use vecdb::{
|
||||
EagerVec, Exit, ImportableVec, IterableCloneableVec, IterableVec, LazyVecFrom1, LazyVecFrom2,
|
||||
Negate, PcoVec,
|
||||
@@ -10,7 +10,8 @@ use crate::{
|
||||
Indexes,
|
||||
grouped::{
|
||||
ComputedVecsFromDateIndex, ComputedVecsFromHeight, LazyVecsFrom2FromDateIndex,
|
||||
LazyVecsFromDateIndex, NegRatio32, Ratio32, Source, VecBuilderOptions,
|
||||
LazyVecsFromDateIndex, NegPercentageDollarsF32, NegRatio32, PercentageDollarsF32,
|
||||
PercentageSatsF64, Ratio32, Source, VecBuilderOptions,
|
||||
},
|
||||
indexes,
|
||||
};
|
||||
@@ -26,8 +27,10 @@ pub struct RelativeMetrics {
|
||||
// === Supply in Profit/Loss Relative to Own Supply ===
|
||||
pub height_to_supply_in_profit_rel_to_own_supply: EagerVec<PcoVec<Height, StoredF64>>,
|
||||
pub height_to_supply_in_loss_rel_to_own_supply: EagerVec<PcoVec<Height, StoredF64>>,
|
||||
pub indexes_to_supply_in_profit_rel_to_own_supply: ComputedVecsFromDateIndex<StoredF64>,
|
||||
pub indexes_to_supply_in_loss_rel_to_own_supply: ComputedVecsFromDateIndex<StoredF64>,
|
||||
pub indexes_to_supply_in_profit_rel_to_own_supply:
|
||||
LazyVecsFrom2FromDateIndex<StoredF64, Sats, Sats>,
|
||||
pub indexes_to_supply_in_loss_rel_to_own_supply:
|
||||
LazyVecsFrom2FromDateIndex<StoredF64, Sats, Sats>,
|
||||
|
||||
// === Supply in Profit/Loss Relative to Circulating Supply ===
|
||||
pub height_to_supply_in_profit_rel_to_circulating_supply:
|
||||
@@ -60,15 +63,15 @@ pub struct RelativeMetrics {
|
||||
pub height_to_net_unrealized_pnl_rel_to_own_market_cap:
|
||||
Option<EagerVec<PcoVec<Height, StoredF32>>>,
|
||||
pub indexes_to_unrealized_profit_rel_to_own_market_cap:
|
||||
Option<ComputedVecsFromDateIndex<StoredF32>>,
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_unrealized_loss_rel_to_own_market_cap:
|
||||
Option<ComputedVecsFromDateIndex<StoredF32>>,
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_neg_unrealized_loss_rel_to_own_market_cap:
|
||||
Option<LazyVecsFromDateIndex<StoredF32>>,
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
pub indexes_to_net_unrealized_pnl_rel_to_own_market_cap:
|
||||
Option<ComputedVecsFromDateIndex<StoredF32>>,
|
||||
Option<LazyVecsFrom2FromDateIndex<StoredF32, Dollars, Dollars>>,
|
||||
|
||||
// === Unrealized vs Own Total Unrealized PnL (optional, lazy from unrealized sources) ===
|
||||
// === Unrealized vs Own Total Unrealized PnL (optional) ===
|
||||
pub height_to_unrealized_profit_rel_to_own_total_unrealized_pnl:
|
||||
Option<LazyVecFrom2<Height, StoredF32, Height, Dollars, Height, Dollars>>,
|
||||
pub height_to_unrealized_loss_rel_to_own_total_unrealized_pnl:
|
||||
@@ -89,7 +92,11 @@ pub struct RelativeMetrics {
|
||||
|
||||
impl RelativeMetrics {
|
||||
/// Import relative metrics from database.
|
||||
pub fn forced_import(cfg: &ImportConfig, unrealized: &UnrealizedMetrics) -> Result<Self> {
|
||||
pub fn forced_import(
|
||||
cfg: &ImportConfig,
|
||||
unrealized: &UnrealizedMetrics,
|
||||
supply: &SupplyMetrics,
|
||||
) -> Result<Self> {
|
||||
let v0 = Version::ZERO;
|
||||
let v1 = Version::ONE;
|
||||
let v2 = Version::new(2);
|
||||
@@ -156,33 +163,6 @@ impl RelativeMetrics {
|
||||
)
|
||||
});
|
||||
|
||||
let indexes_to_unrealized_loss_rel_to_own_market_cap: Option<
|
||||
ComputedVecsFromDateIndex<StoredF32>,
|
||||
> = (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("unrealized_loss_rel_to_own_market_cap"),
|
||||
Source::Compute,
|
||||
cfg.version + v2,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let indexes_to_neg_unrealized_loss_rel_to_own_market_cap =
|
||||
indexes_to_unrealized_loss_rel_to_own_market_cap
|
||||
.as_ref()
|
||||
.map(|source| {
|
||||
LazyVecsFromDateIndex::from_computed::<Negate>(
|
||||
&cfg.name("neg_unrealized_loss_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
source.dateindex.as_ref().map(|v| v.boxed_clone()),
|
||||
source,
|
||||
)
|
||||
});
|
||||
|
||||
// Optional: own total unrealized pnl vecs (lazy from unrealized sources)
|
||||
let height_to_unrealized_profit_rel_to_own_total_unrealized_pnl = extended.then(|| {
|
||||
LazyVecFrom2::transformed::<Ratio32>(
|
||||
@@ -283,22 +263,20 @@ impl RelativeMetrics {
|
||||
cfg.version + v1,
|
||||
)?,
|
||||
indexes_to_supply_in_profit_rel_to_own_supply:
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
cfg.db,
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageSatsF64>(
|
||||
&cfg.name("supply_in_profit_rel_to_own_supply"),
|
||||
Source::Compute,
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
indexes_to_supply_in_loss_rel_to_own_supply: ComputedVecsFromDateIndex::forced_import(
|
||||
cfg.db,
|
||||
&unrealized.indexes_to_supply_in_profit.sats,
|
||||
&supply.indexes_to_supply.sats,
|
||||
),
|
||||
indexes_to_supply_in_loss_rel_to_own_supply: LazyVecsFrom2FromDateIndex::from_computed::<
|
||||
PercentageSatsF64,
|
||||
>(
|
||||
&cfg.name("supply_in_loss_rel_to_own_supply"),
|
||||
Source::Compute,
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)?,
|
||||
&unrealized.indexes_to_supply_in_loss.sats,
|
||||
&supply.indexes_to_supply.sats,
|
||||
),
|
||||
|
||||
// === Supply in Profit/Loss Relative to Circulating Supply ===
|
||||
height_to_supply_in_profit_rel_to_circulating_supply: compute_rel_to_all
|
||||
@@ -401,30 +379,68 @@ impl RelativeMetrics {
|
||||
.transpose()?,
|
||||
indexes_to_unrealized_profit_rel_to_own_market_cap: (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("unrealized_profit_rel_to_own_market_cap"),
|
||||
Source::Compute,
|
||||
cfg.version + v2,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)
|
||||
supply
|
||||
.indexes_to_supply
|
||||
.dollars
|
||||
.as_ref()
|
||||
.map(|supply_dollars| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
&cfg.name("unrealized_profit_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
&unrealized.indexes_to_unrealized_profit,
|
||||
supply_dollars,
|
||||
)
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
indexes_to_unrealized_loss_rel_to_own_market_cap,
|
||||
indexes_to_neg_unrealized_loss_rel_to_own_market_cap,
|
||||
.flatten(),
|
||||
indexes_to_unrealized_loss_rel_to_own_market_cap: (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
supply
|
||||
.indexes_to_supply
|
||||
.dollars
|
||||
.as_ref()
|
||||
.map(|supply_dollars| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
&cfg.name("unrealized_loss_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
&unrealized.indexes_to_unrealized_loss,
|
||||
supply_dollars,
|
||||
)
|
||||
})
|
||||
})
|
||||
.flatten(),
|
||||
indexes_to_neg_unrealized_loss_rel_to_own_market_cap: (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
supply
|
||||
.indexes_to_supply
|
||||
.dollars
|
||||
.as_ref()
|
||||
.map(|supply_dollars| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<NegPercentageDollarsF32>(
|
||||
&cfg.name("neg_unrealized_loss_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
&unrealized.indexes_to_unrealized_loss,
|
||||
supply_dollars,
|
||||
)
|
||||
})
|
||||
})
|
||||
.flatten(),
|
||||
indexes_to_net_unrealized_pnl_rel_to_own_market_cap: (extended && compute_rel_to_all)
|
||||
.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_market_cap"),
|
||||
Source::Compute,
|
||||
cfg.version + v2,
|
||||
cfg.indexes,
|
||||
last,
|
||||
)
|
||||
supply
|
||||
.indexes_to_supply
|
||||
.dollars
|
||||
.as_ref()
|
||||
.map(|supply_dollars| {
|
||||
LazyVecsFrom2FromDateIndex::from_computed::<PercentageDollarsF32>(
|
||||
&cfg.name("net_unrealized_pnl_rel_to_own_market_cap"),
|
||||
cfg.version + v2,
|
||||
&unrealized.indexes_to_net_unrealized_pnl,
|
||||
supply_dollars,
|
||||
)
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
.flatten(),
|
||||
|
||||
// === Unrealized vs Own Total Unrealized PnL (optional) ===
|
||||
height_to_unrealized_profit_rel_to_own_total_unrealized_pnl,
|
||||
@@ -473,6 +489,7 @@ impl RelativeMetrics {
|
||||
}
|
||||
|
||||
// === Supply in Profit/Loss Relative to Own Supply ===
|
||||
// Note: indexes_to_* versions are now lazy (LazyVecsFrom2FromDateIndex)
|
||||
if let Some(unrealized) = unrealized {
|
||||
self.height_to_supply_in_profit_rel_to_own_supply
|
||||
.compute_percentage(
|
||||
@@ -488,46 +505,6 @@ impl RelativeMetrics {
|
||||
&supply.height_to_supply_value.bitcoin,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.indexes_to_supply_in_profit_rel_to_own_supply
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
if let Some(dateindex_vec) = unrealized
|
||||
.indexes_to_supply_in_profit
|
||||
.bitcoin
|
||||
.dateindex
|
||||
.as_ref()
|
||||
&& let Some(supply_dateindex) =
|
||||
supply.indexes_to_supply.bitcoin.dateindex.as_ref()
|
||||
{
|
||||
v.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
dateindex_vec,
|
||||
supply_dateindex,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indexes_to_supply_in_loss_rel_to_own_supply
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
if let Some(dateindex_vec) = unrealized
|
||||
.indexes_to_supply_in_loss
|
||||
.bitcoin
|
||||
.dateindex
|
||||
.as_ref()
|
||||
&& let Some(supply_dateindex) =
|
||||
supply.indexes_to_supply.bitcoin.dateindex.as_ref()
|
||||
{
|
||||
v.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
dateindex_vec,
|
||||
supply_dateindex,
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
|
||||
// === Supply in Profit/Loss Relative to Circulating Supply ===
|
||||
@@ -667,6 +644,7 @@ impl RelativeMetrics {
|
||||
|
||||
// === Unrealized vs Own Market Cap ===
|
||||
// own_market_cap = supply_value.dollars
|
||||
// Note: indexes_to_* versions are now lazy (LazyVecsFrom2FromDateIndex)
|
||||
if let Some(unrealized) = unrealized {
|
||||
if let Some(v) = self
|
||||
.height_to_unrealized_profit_rel_to_own_market_cap
|
||||
@@ -704,67 +682,6 @@ impl RelativeMetrics {
|
||||
exit,
|
||||
)?;
|
||||
}
|
||||
|
||||
// indexes versions
|
||||
if let Some(v) = self
|
||||
.indexes_to_unrealized_profit_rel_to_own_market_cap
|
||||
.as_mut()
|
||||
&& let Some(supply_dollars_dateindex) = supply
|
||||
.indexes_to_supply
|
||||
.dollars
|
||||
.as_ref()
|
||||
.and_then(|d| d.dateindex.as_ref())
|
||||
{
|
||||
v.compute_all(starting_indexes, exit, |vec| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
&unrealized.dateindex_to_unrealized_profit,
|
||||
supply_dollars_dateindex,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
if let Some(v) = self
|
||||
.indexes_to_unrealized_loss_rel_to_own_market_cap
|
||||
.as_mut()
|
||||
&& let Some(supply_dollars_dateindex) = supply
|
||||
.indexes_to_supply
|
||||
.dollars
|
||||
.as_ref()
|
||||
.and_then(|d| d.dateindex.as_ref())
|
||||
{
|
||||
v.compute_all(starting_indexes, exit, |vec| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
&unrealized.dateindex_to_unrealized_loss,
|
||||
supply_dollars_dateindex,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
if let Some(v) = self
|
||||
.indexes_to_net_unrealized_pnl_rel_to_own_market_cap
|
||||
.as_mut()
|
||||
&& let Some(supply_dollars_dateindex) = supply
|
||||
.indexes_to_supply
|
||||
.dollars
|
||||
.as_ref()
|
||||
.and_then(|d| d.dateindex.as_ref())
|
||||
&& let Some(net_pnl_dateindex) =
|
||||
unrealized.indexes_to_net_unrealized_pnl.dateindex.as_ref()
|
||||
{
|
||||
v.compute_all(starting_indexes, exit, |vec| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
net_pnl_dateindex,
|
||||
supply_dollars_dateindex,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Sats, StoredU64, Version};
|
||||
use brk_types::{Height, Sats, StoredU64, SupplyState, Version};
|
||||
use rayon::prelude::*;
|
||||
use vecdb::{
|
||||
AnyStoredVec, AnyVec, EagerVec, Exit, GenericStoredVec, ImportableVec, IterableCloneableVec,
|
||||
@@ -15,7 +15,6 @@ use crate::{
|
||||
LazyValueVecsFromDateIndex, Source, VecBuilderOptions,
|
||||
},
|
||||
indexes, price,
|
||||
stateful::states::SupplyState,
|
||||
};
|
||||
|
||||
use super::ImportConfig;
|
||||
@@ -79,13 +78,16 @@ impl SupplyMetrics {
|
||||
)?;
|
||||
|
||||
// Create lazy supply_half from supply sources
|
||||
let height_to_supply_half_value =
|
||||
LazyHeightValueVecs::from_sources::<HalveSats, HalveSatsToBitcoin, HalfClosePriceTimesSats>(
|
||||
&cfg.name("supply_half"),
|
||||
height_to_supply.boxed_clone(),
|
||||
price_source,
|
||||
cfg.version + v0,
|
||||
);
|
||||
let height_to_supply_half_value = LazyHeightValueVecs::from_sources::<
|
||||
HalveSats,
|
||||
HalveSatsToBitcoin,
|
||||
HalfClosePriceTimesSats,
|
||||
>(
|
||||
&cfg.name("supply_half"),
|
||||
height_to_supply.boxed_clone(),
|
||||
price_source,
|
||||
cfg.version + v0,
|
||||
);
|
||||
|
||||
let indexes_to_supply_half =
|
||||
LazyValueVecsFromDateIndex::from_source::<HalveSats, HalveSatsToBitcoin, HalveDollars>(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_types::{Dollars, Height, LoadedAddressData, Sats};
|
||||
use brk_types::{Dollars, Height, LoadedAddressData, Sats, SupplyState};
|
||||
use vecdb::unlikely;
|
||||
|
||||
use crate::stateful::states::{RealizedState, SupplyState};
|
||||
use crate::stateful::states::RealizedState;
|
||||
|
||||
use super::CohortState;
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use std::ops::{Add, AddAssign, SubAssign};
|
||||
|
||||
use brk_types::{Dollars, Timestamp};
|
||||
use brk_types::{Dollars, SupplyState, Timestamp};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::SupplyState;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct BlockState {
|
||||
#[serde(flatten)]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_types::{Dollars, Height, Sats};
|
||||
use brk_types::{Dollars, Height, Sats, SupplyState};
|
||||
|
||||
use crate::grouped::PERCENTILES_LEN;
|
||||
|
||||
use super::{CachedUnrealizedState, PriceToAmount, RealizedState, SupplyState, UnrealizedState};
|
||||
use super::{CachedUnrealizedState, PriceToAmount, RealizedState, UnrealizedState};
|
||||
|
||||
/// State tracked for each cohort during computation.
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -3,7 +3,6 @@ mod block;
|
||||
mod cohort;
|
||||
mod price_to_amount;
|
||||
mod realized;
|
||||
mod supply;
|
||||
mod transacted;
|
||||
mod unrealized;
|
||||
mod utxo_cohort;
|
||||
@@ -13,7 +12,6 @@ pub use block::*;
|
||||
pub use cohort::*;
|
||||
pub use price_to_amount::*;
|
||||
pub use realized::*;
|
||||
pub use supply::*;
|
||||
pub use transacted::*;
|
||||
pub use unrealized::*;
|
||||
pub use utxo_cohort::*;
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::{
|
||||
};
|
||||
|
||||
use brk_error::{Error, Result};
|
||||
use brk_types::{CentsCompact, Dollars, Height, Sats};
|
||||
use brk_types::{CentsCompact, Dollars, Height, Sats, SupplyState};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use pco::standalone::{simple_decompress, simpler_compress};
|
||||
use rustc_hash::FxHashMap;
|
||||
@@ -18,8 +18,6 @@ use crate::{
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
use super::SupplyState;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PriceToAmount {
|
||||
pathbuf: PathBuf,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use brk_types::{CheckedSub, Dollars};
|
||||
|
||||
use super::SupplyState;
|
||||
use brk_types::{CheckedSub, Dollars, SupplyState};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct RealizedState {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::ops::{Add, AddAssign};
|
||||
|
||||
use brk_grouper::{ByAmountRange, GroupedByType};
|
||||
use brk_types::{OutputType, Sats};
|
||||
|
||||
use super::SupplyState;
|
||||
use brk_types::{OutputType, Sats, SupplyState};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Transacted {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_types::Sats;
|
||||
use brk_types::{Sats, SupplyState};
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
|
||||
use super::{CohortState, RealizedState, SupplyState};
|
||||
use super::{CohortState, RealizedState};
|
||||
|
||||
#[derive(Clone, Deref, DerefMut)]
|
||||
pub struct UTXOCohortState(CohortState);
|
||||
|
||||
@@ -5,7 +5,7 @@ use brk_indexer::Indexer;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
Dollars, EmptyAddressData, EmptyAddressIndex, Height, LoadedAddressData, LoadedAddressIndex,
|
||||
Sats, StoredU64, Version,
|
||||
Sats, StoredU64, SupplyState, Version,
|
||||
};
|
||||
use log::info;
|
||||
use vecdb::{
|
||||
@@ -29,7 +29,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
AddressCohorts, AddressesDataVecs, AnyAddressIndexesVecs, SupplyState, UTXOCohorts,
|
||||
AddressCohorts, AddressesDataVecs, AnyAddressIndexesVecs, UTXOCohorts,
|
||||
address::{AddressTypeToHeightToAddressCount, AddressTypeToIndexesToAddressCount},
|
||||
compute::aggregates,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::{borrow::Cow, collections::BTreeMap};
|
||||
|
||||
use brk_computer::Computer;
|
||||
use brk_indexer::Indexer;
|
||||
@@ -73,7 +73,11 @@ impl<'a> Vecs<'a> {
|
||||
.keys()
|
||||
.map(|i| IndexInfo {
|
||||
index: *i,
|
||||
aliases: i.possible_values(),
|
||||
aliases: i
|
||||
.possible_values()
|
||||
.iter()
|
||||
.map(|v| Cow::Borrowed(*v))
|
||||
.collect(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -116,14 +120,20 @@ impl<'a> Vecs<'a> {
|
||||
.entry(name)
|
||||
.or_default()
|
||||
.insert(index, vec);
|
||||
assert!(prev.is_none(), "Duplicate metric: {name} for index {index:?}");
|
||||
assert!(
|
||||
prev.is_none(),
|
||||
"Duplicate metric: {name} for index {index:?}"
|
||||
);
|
||||
|
||||
let prev = self
|
||||
.index_to_metric_to_vec
|
||||
.entry(index)
|
||||
.or_default()
|
||||
.insert(name, vec);
|
||||
assert!(prev.is_none(), "Duplicate metric: {name} for index {index:?}");
|
||||
assert!(
|
||||
prev.is_none(),
|
||||
"Duplicate metric: {name} for index {index:?}"
|
||||
);
|
||||
}
|
||||
|
||||
pub fn metrics(&'static self, pagination: Pagination) -> PaginatedMetrics {
|
||||
@@ -134,7 +144,10 @@ impl<'a> Vecs<'a> {
|
||||
PaginatedMetrics {
|
||||
current_page: pagination.page(),
|
||||
max_page: len.div_ceil(Pagination::PER_PAGE).saturating_sub(1),
|
||||
metrics: &self.metrics[start..end],
|
||||
metrics: self.metrics[start..end]
|
||||
.iter()
|
||||
.map(|&s| Cow::Borrowed(s))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::sync::Arc;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
use aide::{
|
||||
axum::{ApiRouter, routing::get_with},
|
||||
@@ -71,8 +71,8 @@ impl ApiRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async || -> Json<Health> {
|
||||
Json(Health {
|
||||
status: "healthy",
|
||||
service: "brk",
|
||||
status: Cow::Borrowed("healthy"),
|
||||
service: Cow::Borrowed("brk"),
|
||||
timestamp: jiff::Timestamp::now().to_string(),
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{Formattable, Pco};
|
||||
|
||||
/// Position within a .blk file, encoding file index and byte offset
|
||||
#[derive(Debug, Clone, Copy, Serialize, Pco, JsonSchema)]
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Pco, JsonSchema)]
|
||||
pub struct BlkPosition(u64);
|
||||
|
||||
impl BlkPosition {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Height, Sats, Timestamp};
|
||||
|
||||
/// A single block fees data point.
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BlockFeesEntry {
|
||||
pub avg_height: Height,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::Height;
|
||||
|
||||
/// Difficulty adjustment information.
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DifficultyAdjustment {
|
||||
/// Progress through current difficulty epoch (0-100%)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Server health status
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct Health {
|
||||
pub status: &'static str,
|
||||
pub service: &'static str,
|
||||
pub status: Cow<'static, str>,
|
||||
pub service: Cow<'static, str>,
|
||||
pub timestamp: String,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Hex-encoded string
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(transparent)]
|
||||
pub struct Hex(String);
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::Index;
|
||||
|
||||
/// Information about an available index and its query aliases
|
||||
#[derive(Clone, Copy, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct IndexInfo {
|
||||
/// The canonical index name
|
||||
pub index: Index,
|
||||
|
||||
/// All Accepted query aliases
|
||||
#[schemars(example = vec!["d", "date", "dateindex"])]
|
||||
pub aliases: &'static [&'static str],
|
||||
pub aliases: Vec<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ mod stored_u16;
|
||||
mod stored_u32;
|
||||
mod stored_u64;
|
||||
mod stored_u8;
|
||||
mod supply_state;
|
||||
mod timeperiod;
|
||||
mod timeperiodparam;
|
||||
mod timestamp;
|
||||
@@ -280,6 +281,7 @@ pub use stored_u8::*;
|
||||
pub use stored_u16::*;
|
||||
pub use stored_u32::*;
|
||||
pub use stored_u64::*;
|
||||
pub use supply_state::*;
|
||||
pub use timeperiod::*;
|
||||
pub use timeperiodparam::*;
|
||||
pub use timestamp::*;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{FeeRate, Sats, VSize};
|
||||
|
||||
/// Block info in a mempool.space like format for fee estimation.
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MempoolBlock {
|
||||
/// Total block size in weight units
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A paginated list of available metric names (1000 per page)
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PaginatedMetrics {
|
||||
/// Current page number (0-indexed)
|
||||
#[schemars(example = 0)]
|
||||
@@ -11,5 +13,5 @@ pub struct PaginatedMetrics {
|
||||
#[schemars(example = 21)]
|
||||
pub max_page: usize,
|
||||
/// List of metric names (max 1000 per page)
|
||||
pub metrics: &'static [&'static str],
|
||||
pub metrics: Vec<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{Pool, PoolSlug};
|
||||
|
||||
/// Detailed pool information with statistics across time periods
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PoolDetail {
|
||||
/// Pool information
|
||||
pub pool: PoolDetailInfo,
|
||||
@@ -29,22 +29,22 @@ pub struct PoolDetail {
|
||||
}
|
||||
|
||||
/// Pool information for detail view
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PoolDetailInfo {
|
||||
/// Unique pool identifier
|
||||
pub id: u8,
|
||||
|
||||
/// Pool name
|
||||
pub name: &'static str,
|
||||
pub name: Cow<'static, str>,
|
||||
|
||||
/// Pool website URL
|
||||
pub link: &'static str,
|
||||
pub link: Cow<'static, str>,
|
||||
|
||||
/// Known payout addresses
|
||||
pub addresses: Vec<&'static str>,
|
||||
pub addresses: Vec<Cow<'static, str>>,
|
||||
|
||||
/// Coinbase tag patterns (regexes)
|
||||
pub regexes: Vec<&'static str>,
|
||||
pub regexes: Vec<Cow<'static, str>>,
|
||||
|
||||
/// URL-friendly pool identifier
|
||||
pub slug: PoolSlug,
|
||||
@@ -54,10 +54,10 @@ impl From<&'static Pool> for PoolDetailInfo {
|
||||
fn from(pool: &'static Pool) -> Self {
|
||||
Self {
|
||||
id: pool.unique_id(),
|
||||
name: pool.name,
|
||||
link: pool.link,
|
||||
addresses: pool.addresses.to_vec(),
|
||||
regexes: pool.tags.to_vec(),
|
||||
name: Cow::Borrowed(pool.name),
|
||||
link: Cow::Borrowed(pool.link),
|
||||
addresses: pool.addresses.iter().map(|&s| Cow::Borrowed(s)).collect(),
|
||||
regexes: pool.tags.iter().map(|&s| Cow::Borrowed(s)).collect(),
|
||||
slug: pool.slug(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Pool, PoolSlug};
|
||||
|
||||
/// Basic pool information for listing all pools
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PoolInfo {
|
||||
/// Pool name
|
||||
pub name: &'static str,
|
||||
pub name: Cow<'static, str>,
|
||||
|
||||
/// URL-friendly pool identifier
|
||||
pub slug: PoolSlug,
|
||||
@@ -19,7 +21,7 @@ pub struct PoolInfo {
|
||||
impl From<&'static Pool> for PoolInfo {
|
||||
fn from(pool: &'static Pool) -> Self {
|
||||
Self {
|
||||
name: pool.name,
|
||||
name: Cow::Borrowed(pool.name),
|
||||
slug: pool.slug(),
|
||||
unique_id: pool.unique_id(),
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::PoolStats;
|
||||
|
||||
/// Mining pools response for a time period
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PoolsSummary {
|
||||
/// List of pools sorted by block count descending
|
||||
pub pools: Vec<PoolStats>,
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Pool, PoolSlug};
|
||||
|
||||
/// Mining pool with block statistics for a time period
|
||||
#[derive(Debug, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PoolStats {
|
||||
/// Unique pool identifier
|
||||
#[serde(rename = "poolId")]
|
||||
pub pool_id: u8,
|
||||
|
||||
/// Pool name
|
||||
pub name: &'static str,
|
||||
pub name: Cow<'static, str>,
|
||||
|
||||
/// Pool website URL
|
||||
pub link: &'static str,
|
||||
pub link: Cow<'static, str>,
|
||||
|
||||
/// Number of blocks mined in the time period
|
||||
#[serde(rename = "blockCount")]
|
||||
@@ -39,8 +41,8 @@ impl PoolStats {
|
||||
pub fn new(pool: &'static Pool, block_count: u32, rank: u32, share: f64) -> Self {
|
||||
Self {
|
||||
pool_id: pool.unique_id(),
|
||||
name: pool.name,
|
||||
link: pool.link,
|
||||
name: Cow::Borrowed(pool.name),
|
||||
link: Cow::Borrowed(pool.link),
|
||||
block_count,
|
||||
rank,
|
||||
empty_blocks: 0, // TODO: track empty blocks if needed
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::FeeRate;
|
||||
|
||||
/// Recommended fee rates in sat/vB
|
||||
#[derive(Debug, Default, Clone, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RecommendedFees {
|
||||
/// Fee rate for fastest confirmation (next block)
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
use std::ops::{Add, AddAssign, SubAssign};
|
||||
use std::{
|
||||
fmt,
|
||||
ops::{Add, AddAssign, SubAssign},
|
||||
};
|
||||
|
||||
use brk_types::{CheckedSub, LoadedAddressData, Sats};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{Bytes, Formattable};
|
||||
|
||||
use crate::{CheckedSub, LoadedAddressData, Sats};
|
||||
|
||||
/// Current supply state tracking UTXO count and total value
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct SupplyState {
|
||||
@@ -71,8 +75,8 @@ impl From<&LoadedAddressData> for SupplyState {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SupplyState {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl fmt::Display for SupplyState {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "utxos: {}, value: {}", self.utxo_count, self.value)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{TxStatus, Txid, Vin};
|
||||
|
||||
/// Status of an output indicating whether it has been spent
|
||||
#[derive(Debug, Clone, Serialize, JsonSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct TxOutspend {
|
||||
/// Whether the output has been spent
|
||||
pub spent: bool,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use derive_deref::Deref;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Input index in the spending transaction
|
||||
#[derive(Debug, Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, JsonSchema)]
|
||||
#[derive(
|
||||
Debug, Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema,
|
||||
)]
|
||||
#[schemars(example = 0)]
|
||||
pub struct Vin(u16);
|
||||
|
||||
|
||||
7437
modules/lightweight-charts/5.0.9/dist/typings.d.ts
vendored
7437
modules/lightweight-charts/5.0.9/dist/typings.d.ts
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user