mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-23 22:29:59 -07:00
global: snapshot
This commit is contained in:
@@ -1074,12 +1074,12 @@ pub struct CapGrossInvestorLossMvrvNetPeakPriceProfitSellSoprPattern {
|
||||
pub cap: CentsDeltaToUsdPattern,
|
||||
pub gross_pnl: BaseCumulativeSumPattern3,
|
||||
pub investor: PricePattern,
|
||||
pub loss: BaseCapitulationCumulativeNegativeSumToValuePattern,
|
||||
pub loss: BaseCumulativeNegativeSumToPattern,
|
||||
pub mvrv: SeriesPattern1<StoredF32>,
|
||||
pub net_pnl: BaseChangeCumulativeDeltaSumToPattern,
|
||||
pub peak_regret: BaseCumulativeSumToPattern,
|
||||
pub price: BpsCentsPercentilesRatioSatsSmaStdUsdPattern,
|
||||
pub profit: BaseCumulativeDistributionSumToValuePattern,
|
||||
pub profit: BaseCumulativeSumToPattern,
|
||||
pub profit_to_loss_ratio: _1m1w1y24hPattern<StoredF64>,
|
||||
pub sell_side_risk_ratio: _1m1w1y24hPattern6,
|
||||
pub sopr: AdjustedRatioValuePattern,
|
||||
@@ -1254,18 +1254,6 @@ impl AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BaseCapitulationCumulativeNegativeSumToValuePattern {
|
||||
pub base: CentsUsdPattern2,
|
||||
pub capitulation_flow: SeriesPattern1<Dollars>,
|
||||
pub cumulative: CentsUsdPattern2,
|
||||
pub negative: BaseSumPattern,
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
pub value_created: BaseCumulativeSumPattern<Cents>,
|
||||
pub value_destroyed: BaseCumulativeSumPattern<Cents>,
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BpsCentsPercentilesRatioSatsSmaStdUsdPattern {
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
@@ -1358,17 +1346,6 @@ impl _1m1w1y24hBpsPercentRatioPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BaseCumulativeDistributionSumToValuePattern {
|
||||
pub base: CentsUsdPattern2,
|
||||
pub cumulative: CentsUsdPattern2,
|
||||
pub distribution_flow: SeriesPattern1<Dollars>,
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
pub value_created: BaseCumulativeSumPattern<Cents>,
|
||||
pub value_destroyed: BaseCumulativeSumPattern<Cents>,
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CapLossMvrvNetPriceProfitSoprPattern {
|
||||
pub cap: CentsDeltaUsdPattern,
|
||||
@@ -1688,6 +1665,15 @@ impl BaseCumulativeInSumPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BaseCumulativeNegativeSumToPattern {
|
||||
pub base: CentsUsdPattern2,
|
||||
pub cumulative: CentsUsdPattern2,
|
||||
pub negative: BaseSumPattern,
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BpsCentsRatioSatsUsdPattern {
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
@@ -6332,7 +6318,7 @@ impl SeriesTree_Cohorts_Utxo_All_Activity {
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_All_Realized {
|
||||
pub cap: CentsDeltaToUsdPattern,
|
||||
pub profit: SeriesTree_Cohorts_Utxo_All_Realized_Profit,
|
||||
pub profit: BaseCumulativeSumToPattern,
|
||||
pub loss: SeriesTree_Cohorts_Utxo_All_Realized_Loss,
|
||||
pub price: SeriesTree_Cohorts_Utxo_All_Realized_Price,
|
||||
pub mvrv: SeriesPattern1<StoredF32>,
|
||||
@@ -6349,7 +6335,7 @@ impl SeriesTree_Cohorts_Utxo_All_Realized {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
cap: CentsDeltaToUsdPattern::new(client.clone(), "realized_cap".to_string()),
|
||||
profit: SeriesTree_Cohorts_Utxo_All_Realized_Profit::new(client.clone(), format!("{base_path}_profit")),
|
||||
profit: BaseCumulativeSumToPattern::new(client.clone(), "realized_profit".to_string()),
|
||||
loss: SeriesTree_Cohorts_Utxo_All_Realized_Loss::new(client.clone(), format!("{base_path}_loss")),
|
||||
price: SeriesTree_Cohorts_Utxo_All_Realized_Price::new(client.clone(), format!("{base_path}_price")),
|
||||
mvrv: SeriesPattern1::new(client.clone(), "mvrv".to_string()),
|
||||
@@ -6364,31 +6350,6 @@ impl SeriesTree_Cohorts_Utxo_All_Realized {
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_All_Realized_Profit {
|
||||
pub base: CentsUsdPattern2,
|
||||
pub cumulative: CentsUsdPattern2,
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
pub value_created: BaseCumulativeSumPattern<Cents>,
|
||||
pub value_destroyed: BaseCumulativeSumPattern<Cents>,
|
||||
pub distribution_flow: SeriesPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_All_Realized_Profit {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
base: CentsUsdPattern2::new(client.clone(), "realized_profit".to_string()),
|
||||
cumulative: CentsUsdPattern2::new(client.clone(), "realized_profit_cumulative".to_string()),
|
||||
sum: _1m1w1y24hPattern4::new(client.clone(), "realized_profit_sum".to_string()),
|
||||
to_rcap: BpsPercentRatioPattern4::new(client.clone(), "realized_profit_to_rcap".to_string()),
|
||||
value_created: BaseCumulativeSumPattern::new(client.clone(), "profit_value_created".to_string()),
|
||||
value_destroyed: BaseCumulativeSumPattern::new(client.clone(), "profit_value_destroyed".to_string()),
|
||||
distribution_flow: SeriesPattern1::new(client.clone(), "distribution_flow".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_All_Realized_Loss {
|
||||
pub base: CentsUsdPattern2,
|
||||
@@ -6396,9 +6357,6 @@ pub struct SeriesTree_Cohorts_Utxo_All_Realized_Loss {
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub negative: BaseSumPattern,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
pub value_created: BaseCumulativeSumPattern<Cents>,
|
||||
pub value_destroyed: BaseCumulativeSumPattern<Cents>,
|
||||
pub capitulation_flow: SeriesPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_All_Realized_Loss {
|
||||
@@ -6409,9 +6367,6 @@ impl SeriesTree_Cohorts_Utxo_All_Realized_Loss {
|
||||
sum: _1m1w1y24hPattern4::new(client.clone(), "realized_loss_sum".to_string()),
|
||||
negative: BaseSumPattern::new(client.clone(), "neg_realized_loss".to_string()),
|
||||
to_rcap: BpsPercentRatioPattern4::new(client.clone(), "realized_loss_to_rcap".to_string()),
|
||||
value_created: BaseCumulativeSumPattern::new(client.clone(), "loss_value_created".to_string()),
|
||||
value_destroyed: BaseCumulativeSumPattern::new(client.clone(), "loss_value_destroyed".to_string()),
|
||||
capitulation_flow: SeriesPattern1::new(client.clone(), "capitulation_flow".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6827,7 +6782,7 @@ impl SeriesTree_Cohorts_Utxo_Sth_Activity {
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Sth_Realized {
|
||||
pub cap: CentsDeltaToUsdPattern,
|
||||
pub profit: SeriesTree_Cohorts_Utxo_Sth_Realized_Profit,
|
||||
pub profit: BaseCumulativeSumToPattern,
|
||||
pub loss: SeriesTree_Cohorts_Utxo_Sth_Realized_Loss,
|
||||
pub price: SeriesTree_Cohorts_Utxo_Sth_Realized_Price,
|
||||
pub mvrv: SeriesPattern1<StoredF32>,
|
||||
@@ -6844,7 +6799,7 @@ impl SeriesTree_Cohorts_Utxo_Sth_Realized {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
cap: CentsDeltaToUsdPattern::new(client.clone(), "sth_realized_cap".to_string()),
|
||||
profit: SeriesTree_Cohorts_Utxo_Sth_Realized_Profit::new(client.clone(), format!("{base_path}_profit")),
|
||||
profit: BaseCumulativeSumToPattern::new(client.clone(), "sth_realized_profit".to_string()),
|
||||
loss: SeriesTree_Cohorts_Utxo_Sth_Realized_Loss::new(client.clone(), format!("{base_path}_loss")),
|
||||
price: SeriesTree_Cohorts_Utxo_Sth_Realized_Price::new(client.clone(), format!("{base_path}_price")),
|
||||
mvrv: SeriesPattern1::new(client.clone(), "sth_mvrv".to_string()),
|
||||
@@ -6859,31 +6814,6 @@ impl SeriesTree_Cohorts_Utxo_Sth_Realized {
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Sth_Realized_Profit {
|
||||
pub base: CentsUsdPattern2,
|
||||
pub cumulative: CentsUsdPattern2,
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
pub value_created: BaseCumulativeSumPattern<Cents>,
|
||||
pub value_destroyed: BaseCumulativeSumPattern<Cents>,
|
||||
pub distribution_flow: SeriesPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Sth_Realized_Profit {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
base: CentsUsdPattern2::new(client.clone(), "sth_realized_profit".to_string()),
|
||||
cumulative: CentsUsdPattern2::new(client.clone(), "sth_realized_profit_cumulative".to_string()),
|
||||
sum: _1m1w1y24hPattern4::new(client.clone(), "sth_realized_profit_sum".to_string()),
|
||||
to_rcap: BpsPercentRatioPattern4::new(client.clone(), "sth_realized_profit_to_rcap".to_string()),
|
||||
value_created: BaseCumulativeSumPattern::new(client.clone(), "sth_profit_value_created".to_string()),
|
||||
value_destroyed: BaseCumulativeSumPattern::new(client.clone(), "sth_profit_value_destroyed".to_string()),
|
||||
distribution_flow: SeriesPattern1::new(client.clone(), "sth_distribution_flow".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Sth_Realized_Loss {
|
||||
pub base: CentsUsdPattern2,
|
||||
@@ -6891,9 +6821,6 @@ pub struct SeriesTree_Cohorts_Utxo_Sth_Realized_Loss {
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub negative: BaseSumPattern,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
pub value_created: BaseCumulativeSumPattern<Cents>,
|
||||
pub value_destroyed: BaseCumulativeSumPattern<Cents>,
|
||||
pub capitulation_flow: SeriesPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Sth_Realized_Loss {
|
||||
@@ -6904,9 +6831,6 @@ impl SeriesTree_Cohorts_Utxo_Sth_Realized_Loss {
|
||||
sum: _1m1w1y24hPattern4::new(client.clone(), "sth_realized_loss_sum".to_string()),
|
||||
negative: BaseSumPattern::new(client.clone(), "sth_neg_realized_loss".to_string()),
|
||||
to_rcap: BpsPercentRatioPattern4::new(client.clone(), "sth_realized_loss_to_rcap".to_string()),
|
||||
value_created: BaseCumulativeSumPattern::new(client.clone(), "sth_loss_value_created".to_string()),
|
||||
value_destroyed: BaseCumulativeSumPattern::new(client.clone(), "sth_loss_value_destroyed".to_string()),
|
||||
capitulation_flow: SeriesPattern1::new(client.clone(), "sth_capitulation_flow".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7265,7 +7189,7 @@ impl SeriesTree_Cohorts_Utxo_Lth_Activity {
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Lth_Realized {
|
||||
pub cap: CentsDeltaToUsdPattern,
|
||||
pub profit: SeriesTree_Cohorts_Utxo_Lth_Realized_Profit,
|
||||
pub profit: BaseCumulativeSumToPattern,
|
||||
pub loss: SeriesTree_Cohorts_Utxo_Lth_Realized_Loss,
|
||||
pub price: SeriesTree_Cohorts_Utxo_Lth_Realized_Price,
|
||||
pub mvrv: SeriesPattern1<StoredF32>,
|
||||
@@ -7282,7 +7206,7 @@ impl SeriesTree_Cohorts_Utxo_Lth_Realized {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
cap: CentsDeltaToUsdPattern::new(client.clone(), "lth_realized_cap".to_string()),
|
||||
profit: SeriesTree_Cohorts_Utxo_Lth_Realized_Profit::new(client.clone(), format!("{base_path}_profit")),
|
||||
profit: BaseCumulativeSumToPattern::new(client.clone(), "lth_realized_profit".to_string()),
|
||||
loss: SeriesTree_Cohorts_Utxo_Lth_Realized_Loss::new(client.clone(), format!("{base_path}_loss")),
|
||||
price: SeriesTree_Cohorts_Utxo_Lth_Realized_Price::new(client.clone(), format!("{base_path}_price")),
|
||||
mvrv: SeriesPattern1::new(client.clone(), "lth_mvrv".to_string()),
|
||||
@@ -7297,31 +7221,6 @@ impl SeriesTree_Cohorts_Utxo_Lth_Realized {
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Lth_Realized_Profit {
|
||||
pub base: CentsUsdPattern2,
|
||||
pub cumulative: CentsUsdPattern2,
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
pub value_created: BaseCumulativeSumPattern<Cents>,
|
||||
pub value_destroyed: BaseCumulativeSumPattern<Cents>,
|
||||
pub distribution_flow: SeriesPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Lth_Realized_Profit {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
base: CentsUsdPattern2::new(client.clone(), "lth_realized_profit".to_string()),
|
||||
cumulative: CentsUsdPattern2::new(client.clone(), "lth_realized_profit_cumulative".to_string()),
|
||||
sum: _1m1w1y24hPattern4::new(client.clone(), "lth_realized_profit_sum".to_string()),
|
||||
to_rcap: BpsPercentRatioPattern4::new(client.clone(), "lth_realized_profit_to_rcap".to_string()),
|
||||
value_created: BaseCumulativeSumPattern::new(client.clone(), "lth_profit_value_created".to_string()),
|
||||
value_destroyed: BaseCumulativeSumPattern::new(client.clone(), "lth_profit_value_destroyed".to_string()),
|
||||
distribution_flow: SeriesPattern1::new(client.clone(), "lth_distribution_flow".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Lth_Realized_Loss {
|
||||
pub base: CentsUsdPattern2,
|
||||
@@ -7329,9 +7228,6 @@ pub struct SeriesTree_Cohorts_Utxo_Lth_Realized_Loss {
|
||||
pub sum: _1m1w1y24hPattern4,
|
||||
pub negative: BaseSumPattern,
|
||||
pub to_rcap: BpsPercentRatioPattern4,
|
||||
pub value_created: BaseCumulativeSumPattern<Cents>,
|
||||
pub value_destroyed: BaseCumulativeSumPattern<Cents>,
|
||||
pub capitulation_flow: SeriesPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Lth_Realized_Loss {
|
||||
@@ -7342,9 +7238,6 @@ impl SeriesTree_Cohorts_Utxo_Lth_Realized_Loss {
|
||||
sum: _1m1w1y24hPattern4::new(client.clone(), "lth_realized_loss_sum".to_string()),
|
||||
negative: BaseSumPattern::new(client.clone(), "lth_neg_realized_loss".to_string()),
|
||||
to_rcap: BpsPercentRatioPattern4::new(client.clone(), "lth_realized_loss_to_rcap".to_string()),
|
||||
value_created: BaseCumulativeSumPattern::new(client.clone(), "lth_loss_value_created".to_string()),
|
||||
value_destroyed: BaseCumulativeSumPattern::new(client.clone(), "lth_loss_value_destroyed".to_string()),
|
||||
capitulation_flow: SeriesPattern1::new(client.clone(), "lth_capitulation_flow".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,9 +542,9 @@ impl UTXOCohorts<Rw> {
|
||||
.metrics
|
||||
.realized
|
||||
.minimal
|
||||
.sopr
|
||||
.value_created
|
||||
.transfer_volume
|
||||
.base
|
||||
.cents
|
||||
.height
|
||||
.read_only_clone();
|
||||
let under_1h_value_destroyed = self
|
||||
@@ -552,7 +552,6 @@ impl UTXOCohorts<Rw> {
|
||||
.under_1h
|
||||
.metrics
|
||||
.realized
|
||||
.minimal
|
||||
.sopr
|
||||
.value_destroyed
|
||||
.base
|
||||
|
||||
@@ -128,8 +128,8 @@ impl AllCohortMetrics {
|
||||
|
||||
self.asopr.compute_rest_part2(
|
||||
starting_indexes,
|
||||
&self.realized.minimal.sopr.value_created.base.height,
|
||||
&self.realized.minimal.sopr.value_destroyed.base.height,
|
||||
&self.realized.minimal.transfer_volume.base.cents.height,
|
||||
&self.realized.core.sopr.value_destroyed.base.height,
|
||||
under_1h_value_created,
|
||||
under_1h_value_destroyed,
|
||||
exit,
|
||||
|
||||
@@ -114,7 +114,7 @@ impl CoreCohortMetrics {
|
||||
.compute_sent_profitability(prices, starting_indexes, exit)?;
|
||||
|
||||
self.realized
|
||||
.compute_rest_part1(starting_indexes, exit)?;
|
||||
.compute_rest_part1(prices, starting_indexes, exit)?;
|
||||
|
||||
self.unrealized.compute_rest(starting_indexes, exit)?;
|
||||
|
||||
|
||||
@@ -80,8 +80,8 @@ impl ExtendedAdjustedCohortMetrics {
|
||||
|
||||
self.asopr.compute_rest_part2(
|
||||
starting_indexes,
|
||||
&self.inner.realized.minimal.sopr.value_created.base.height,
|
||||
&self.inner.realized.minimal.sopr.value_destroyed.base.height,
|
||||
&self.inner.realized.minimal.transfer_volume.base.cents.height,
|
||||
&self.inner.realized.core.sopr.value_destroyed.base.height,
|
||||
under_1h_value_created,
|
||||
under_1h_value_destroyed,
|
||||
exit,
|
||||
|
||||
@@ -90,7 +90,7 @@ impl MinimalCohortMetrics {
|
||||
) -> Result<()> {
|
||||
self.supply.compute(prices, starting_indexes.height, exit)?;
|
||||
self.realized
|
||||
.compute_rest_part1(starting_indexes, exit)?;
|
||||
.compute_rest_part1(prices, starting_indexes, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ impl TypeCohortMetrics {
|
||||
) -> Result<()> {
|
||||
self.supply.compute(prices, starting_indexes.height, exit)?;
|
||||
self.realized
|
||||
.compute_rest_part1(starting_indexes, exit)?;
|
||||
.compute_rest_part1(prices, starting_indexes, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
AmountPerBlock, AmountPerBlockCumulative, AmountPerBlockCumulativeWithSums,
|
||||
CachedWindowStarts, CentsType, PerBlock,
|
||||
PerBlockCumulative, PerBlockCumulativeWithSums,
|
||||
FiatPerBlock, FiatPerBlockCumulativeWithSums, NumericValue,
|
||||
PercentPerBlock, PercentRollingWindows, Price,
|
||||
CachedWindowStarts, CentsType, FiatPerBlock, FiatPerBlockCumulativeWithSums, NumericValue,
|
||||
PerBlock, PerBlockCumulativeWithSums, PercentPerBlock, PercentRollingWindows, Price,
|
||||
PriceWithRatioExtendedPerBlock, PriceWithRatioPerBlock, RatioPerBlock,
|
||||
RollingWindow24hPerBlock, RollingWindows, RollingWindowsFrom1w,
|
||||
},
|
||||
@@ -56,11 +54,6 @@ impl<T: NumericValue + JsonSchema> ConfigImport for PerBlock<T> {
|
||||
Self::forced_import(cfg.db, &cfg.name(suffix), cfg.version + offset, cfg.indexes)
|
||||
}
|
||||
}
|
||||
impl<T: NumericValue + JsonSchema> ConfigImport for PerBlockCumulative<T> {
|
||||
fn config_import(cfg: &ImportConfig, suffix: &str, offset: Version) -> Result<Self> {
|
||||
Self::forced_import(cfg.db, &cfg.name(suffix), cfg.version + offset, cfg.indexes)
|
||||
}
|
||||
}
|
||||
impl<T, C> ConfigImport for PerBlockCumulativeWithSums<T, C>
|
||||
where
|
||||
T: NumericValue + JsonSchema + Into<C>,
|
||||
|
||||
@@ -228,7 +228,7 @@ pub trait CohortMetricsBase:
|
||||
.compute_sent_profitability(prices, starting_indexes, exit)?;
|
||||
|
||||
self.realized_mut()
|
||||
.compute_rest_part1(starting_indexes, exit)?;
|
||||
.compute_rest_part1(prices, starting_indexes, exit)?;
|
||||
|
||||
self.unrealized_mut()
|
||||
.compute_rest(prices, starting_indexes, exit)?;
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
#[derive(Traversable)]
|
||||
pub struct AdjustedSopr<M: StorageMode = Rw> {
|
||||
pub ratio: RollingWindows<StoredF64, M>,
|
||||
pub value_created: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
pub transfer_volume: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
pub value_destroyed: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ impl AdjustedSopr {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
ratio: cfg.import("asopr", Version::ONE)?,
|
||||
value_created: cfg.import("adj_value_created", Version::ONE)?,
|
||||
transfer_volume: cfg.import("adj_value_created", Version::ONE)?,
|
||||
value_destroyed: cfg.import("adj_value_destroyed", Version::ONE)?,
|
||||
})
|
||||
}
|
||||
@@ -28,17 +28,16 @@ impl AdjustedSopr {
|
||||
pub(crate) fn compute_rest_part2(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
base_value_created: &impl ReadableVec<Height, Cents>,
|
||||
base_transfer_volume: &impl ReadableVec<Height, Cents>,
|
||||
base_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_transfer_volume: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
// Compute value_created = base.value_created - under_1h.value_created
|
||||
self.value_created.base.height.compute_subtract(
|
||||
self.transfer_volume.base.height.compute_subtract(
|
||||
starting_indexes.height,
|
||||
base_value_created,
|
||||
under_1h_value_created,
|
||||
base_transfer_volume,
|
||||
under_1h_transfer_volume,
|
||||
exit,
|
||||
)?;
|
||||
self.value_destroyed.base.height.compute_subtract(
|
||||
@@ -48,23 +47,21 @@ impl AdjustedSopr {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Cumulatives (rolling sums are lazy)
|
||||
self.value_created
|
||||
self.transfer_volume
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
self.value_destroyed
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
|
||||
// SOPR ratios from lazy rolling sums
|
||||
for ((sopr, vc), vd) in self
|
||||
for ((sopr, tv), vd) in self
|
||||
.ratio
|
||||
.as_mut_array()
|
||||
.into_iter()
|
||||
.zip(self.value_created.sum.as_array())
|
||||
.zip(self.transfer_volume.sum.as_array())
|
||||
.zip(self.value_destroyed.sum.as_array())
|
||||
{
|
||||
sopr.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&vc.height,
|
||||
&tv.height,
|
||||
&vd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -3,14 +3,14 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Dollars, Height, Indexes, StoredF64, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{
|
||||
AnyStoredVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode,
|
||||
AnyStoredVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, WritableVec,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
distribution::state::{CohortState, CostBasisOps, RealizedOps},
|
||||
internal::{
|
||||
FiatPerBlockCumulativeWithSumsAndDeltas, LazyPerBlock, NegCentsUnsignedToDollars,
|
||||
RatioCents64, RollingWindow24hPerBlock, Windows,
|
||||
PerBlockCumulativeWithSums, RatioCents64, RollingWindow24hPerBlock, Windows,
|
||||
},
|
||||
prices,
|
||||
};
|
||||
@@ -28,6 +28,7 @@ pub struct NegRealizedLoss {
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedSoprCore<M: StorageMode = Rw> {
|
||||
pub value_destroyed: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
pub ratio: RollingWindow24hPerBlock<StoredF64, M>,
|
||||
}
|
||||
|
||||
@@ -80,11 +81,20 @@ impl RealizedCore {
|
||||
cfg.cached_starts,
|
||||
)?;
|
||||
|
||||
let value_destroyed = PerBlockCumulativeWithSums::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("value_destroyed"),
|
||||
cfg.version + v1,
|
||||
cfg.indexes,
|
||||
cfg.cached_starts,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
minimal,
|
||||
neg_loss,
|
||||
net_pnl,
|
||||
sopr: RealizedSoprCore {
|
||||
value_destroyed,
|
||||
ratio: cfg.import("sopr", v1)?,
|
||||
},
|
||||
})
|
||||
@@ -97,10 +107,13 @@ impl RealizedCore {
|
||||
#[inline(always)]
|
||||
pub(crate) fn push_state(&mut self, state: &CohortState<impl RealizedOps, impl CostBasisOps>) {
|
||||
self.minimal.push_state(state);
|
||||
self.sopr.value_destroyed.base.height.push(state.realized.value_destroyed());
|
||||
}
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
self.minimal.collect_vecs_mut()
|
||||
let mut vecs = self.minimal.collect_vecs_mut();
|
||||
vecs.push(&mut self.sopr.value_destroyed.base.height);
|
||||
vecs
|
||||
}
|
||||
|
||||
pub(crate) fn compute_from_stateful(
|
||||
@@ -113,16 +126,22 @@ impl RealizedCore {
|
||||
self.minimal
|
||||
.compute_from_stateful(starting_indexes, &minimal_refs, exit)?;
|
||||
|
||||
sum_others!(self, starting_indexes, others, exit; sopr.value_destroyed.base.height);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rest_part1(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.minimal
|
||||
.compute_rest_part1(starting_indexes, exit)?;
|
||||
.compute_rest_part1(prices, starting_indexes, exit)?;
|
||||
|
||||
self.sopr
|
||||
.value_destroyed
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
|
||||
self.net_pnl.base.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
@@ -158,8 +177,8 @@ impl RealizedCore {
|
||||
._24h
|
||||
.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&self.minimal.sopr.value_created.sum._24h.height,
|
||||
&self.minimal.sopr.value_destroyed.sum._24h.height,
|
||||
&self.minimal.transfer_volume.sum._24h.cents.height,
|
||||
&self.sopr.value_destroyed.sum._24h.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use brk_types::{
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{
|
||||
AnyStoredVec, AnyVec, BytesVec, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode,
|
||||
AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode,
|
||||
WritableVec,
|
||||
};
|
||||
|
||||
@@ -14,9 +14,8 @@ use crate::{
|
||||
blocks,
|
||||
distribution::state::{WithCapital, CohortState, CostBasisData, RealizedState},
|
||||
internal::{
|
||||
CentsUnsignedToDollars,
|
||||
PerBlockCumulativeWithSums, FiatPerBlockCumulativeWithSums,
|
||||
LazyPerBlock, PercentPerBlock, PercentRollingWindows,
|
||||
FiatPerBlockCumulativeWithSums,
|
||||
PercentPerBlock, PercentRollingWindows,
|
||||
PriceWithRatioExtendedPerBlock, RatioCents64, RatioCentsBp32,
|
||||
RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32, RatioDollarsBp32,
|
||||
RatioPerBlockPercentiles, RatioPerBlockStdDevBands, RatioSma, RollingWindows,
|
||||
@@ -30,19 +29,13 @@ use crate::distribution::metrics::ImportConfig;
|
||||
use super::RealizedCore;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedProfit<M: StorageMode = Rw> {
|
||||
pub struct RealizedProfitFull<M: StorageMode = Rw> {
|
||||
pub to_rcap: PercentPerBlock<BasisPoints32, M>,
|
||||
pub value_created: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
pub value_destroyed: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
pub distribution_flow: LazyPerBlock<Dollars, Cents>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedLoss<M: StorageMode = Rw> {
|
||||
pub struct RealizedLossFull<M: StorageMode = Rw> {
|
||||
pub to_rcap: PercentPerBlock<BasisPoints32, M>,
|
||||
pub value_created: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
pub value_destroyed: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
pub capitulation_flow: LazyPerBlock<Dollars, Cents>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -81,8 +74,8 @@ pub struct RealizedFull<M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub core: RealizedCore<M>,
|
||||
|
||||
pub profit: RealizedProfit<M>,
|
||||
pub loss: RealizedLoss<M>,
|
||||
pub profit: RealizedProfitFull<M>,
|
||||
pub loss: RealizedLossFull<M>,
|
||||
pub gross_pnl: FiatPerBlockCumulativeWithSums<Cents, M>,
|
||||
pub sell_side_risk_ratio: PercentRollingWindows<BasisPoints32, M>,
|
||||
pub net_pnl: RealizedNetPnl<M>,
|
||||
@@ -112,36 +105,11 @@ impl RealizedFull {
|
||||
|
||||
let core = RealizedCore::forced_import(cfg)?;
|
||||
|
||||
// Profit
|
||||
let profit_value_destroyed: PerBlockCumulativeWithSums<Cents, Cents> =
|
||||
cfg.import("profit_value_destroyed", v1)?;
|
||||
let profit_flow = LazyPerBlock::from_computed::<CentsUnsignedToDollars>(
|
||||
&cfg.name("distribution_flow"),
|
||||
cfg.version,
|
||||
profit_value_destroyed.base.height.read_only_boxed_clone(),
|
||||
&profit_value_destroyed.base,
|
||||
);
|
||||
let profit = RealizedProfit {
|
||||
let profit = RealizedProfitFull {
|
||||
to_rcap: cfg.import("realized_profit_to_rcap", Version::new(2))?,
|
||||
value_created: cfg.import("profit_value_created", v1)?,
|
||||
value_destroyed: profit_value_destroyed,
|
||||
distribution_flow: profit_flow,
|
||||
};
|
||||
|
||||
// Loss
|
||||
let loss_value_destroyed: PerBlockCumulativeWithSums<Cents, Cents> =
|
||||
cfg.import("loss_value_destroyed", v1)?;
|
||||
let capitulation_flow = LazyPerBlock::from_computed::<CentsUnsignedToDollars>(
|
||||
&cfg.name("capitulation_flow"),
|
||||
cfg.version,
|
||||
loss_value_destroyed.base.height.read_only_boxed_clone(),
|
||||
&loss_value_destroyed.base,
|
||||
);
|
||||
let loss = RealizedLoss {
|
||||
let loss = RealizedLossFull {
|
||||
to_rcap: cfg.import("realized_loss_to_rcap", Version::new(2))?,
|
||||
value_created: cfg.import("loss_value_created", v1)?,
|
||||
value_destroyed: loss_value_destroyed,
|
||||
capitulation_flow,
|
||||
};
|
||||
|
||||
// Gross PnL
|
||||
@@ -216,15 +184,7 @@ impl RealizedFull {
|
||||
}
|
||||
|
||||
pub(crate) fn min_stateful_len(&self) -> usize {
|
||||
self.profit
|
||||
.value_created
|
||||
.base
|
||||
.height
|
||||
.len()
|
||||
.min(self.profit.value_destroyed.base.height.len())
|
||||
.min(self.loss.value_created.base.height.len())
|
||||
.min(self.loss.value_destroyed.base.height.len())
|
||||
.min(self.investor.price.cents.height.len())
|
||||
self.investor.price.cents.height.len()
|
||||
.min(self.cap_raw.len())
|
||||
.min(self.investor.cap_raw.len())
|
||||
.min(self.peak_regret.value.base.cents.height.len())
|
||||
@@ -236,26 +196,6 @@ impl RealizedFull {
|
||||
state: &CohortState<RealizedState, CostBasisData<WithCapital>>,
|
||||
) {
|
||||
self.core.push_state(state);
|
||||
self.profit
|
||||
.value_created
|
||||
.base
|
||||
.height
|
||||
.push(state.realized.profit_value_created());
|
||||
self.profit
|
||||
.value_destroyed
|
||||
.base
|
||||
.height
|
||||
.push(state.realized.profit_value_destroyed());
|
||||
self.loss
|
||||
.value_created
|
||||
.base
|
||||
.height
|
||||
.push(state.realized.loss_value_created());
|
||||
self.loss
|
||||
.value_destroyed
|
||||
.base
|
||||
.height
|
||||
.push(state.realized.loss_value_destroyed());
|
||||
self.investor
|
||||
.price
|
||||
.cents
|
||||
@@ -276,10 +216,6 @@ impl RealizedFull {
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
let mut vecs = self.core.collect_vecs_mut();
|
||||
vecs.push(&mut self.profit.value_created.base.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.profit.value_destroyed.base.height);
|
||||
vecs.push(&mut self.loss.value_created.base.height);
|
||||
vecs.push(&mut self.loss.value_destroyed.base.height);
|
||||
vecs.push(&mut self.investor.price.cents.height);
|
||||
vecs.push(&mut self.cap_raw as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.investor.cap_raw as &mut dyn AnyStoredVec);
|
||||
@@ -304,26 +240,6 @@ impl RealizedFull {
|
||||
&mut self,
|
||||
accum: &RealizedFullAccum,
|
||||
) {
|
||||
self.profit
|
||||
.value_created
|
||||
.base
|
||||
.height
|
||||
.push(accum.profit_value_created());
|
||||
self.profit
|
||||
.value_destroyed
|
||||
.base
|
||||
.height
|
||||
.push(accum.profit_value_destroyed());
|
||||
self.loss
|
||||
.value_created
|
||||
.base
|
||||
.height
|
||||
.push(accum.loss_value_created());
|
||||
self.loss
|
||||
.value_destroyed
|
||||
.base
|
||||
.height
|
||||
.push(accum.loss_value_destroyed());
|
||||
self.cap_raw
|
||||
.push(accum.cap_raw);
|
||||
self.investor
|
||||
@@ -354,11 +270,12 @@ impl RealizedFull {
|
||||
|
||||
pub(crate) fn compute_rest_part1(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.core
|
||||
.compute_rest_part1(starting_indexes, exit)?;
|
||||
.compute_rest_part1(prices, starting_indexes, exit)?;
|
||||
|
||||
self.peak_regret
|
||||
.value
|
||||
@@ -388,12 +305,12 @@ impl RealizedFull {
|
||||
.ratio_extended
|
||||
.as_mut_array()
|
||||
.into_iter()
|
||||
.zip(self.core.minimal.sopr.value_created.sum.as_array()[1..].iter())
|
||||
.zip(self.core.minimal.sopr.value_destroyed.sum.as_array()[1..].iter())
|
||||
.zip(self.core.minimal.transfer_volume.sum.0.as_array()[1..].iter())
|
||||
.zip(self.core.sopr.value_destroyed.sum.as_array()[1..].iter())
|
||||
{
|
||||
sopr.compute_binary::<Cents, Cents, RatioCents64>(
|
||||
starting_indexes.height,
|
||||
&vc.height,
|
||||
&vc.cents.height,
|
||||
&vd.height,
|
||||
exit,
|
||||
)?;
|
||||
@@ -425,20 +342,6 @@ impl RealizedFull {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Profit/loss value created/destroyed cumulatives (rolling sums are lazy)
|
||||
self.profit
|
||||
.value_created
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
self.profit
|
||||
.value_destroyed
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
self.loss
|
||||
.value_created
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
self.loss
|
||||
.value_destroyed
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
|
||||
// Gross PnL
|
||||
self.gross_pnl.base.cents.height.compute_add(
|
||||
starting_indexes.height,
|
||||
@@ -554,10 +457,6 @@ impl RealizedFull {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RealizedFullAccum {
|
||||
profit_value_created: CentsSats,
|
||||
profit_value_destroyed: CentsSats,
|
||||
loss_value_created: CentsSats,
|
||||
loss_value_destroyed: CentsSats,
|
||||
pub(crate) cap_raw: CentsSats,
|
||||
pub(crate) investor_cap_raw: CentsSquaredSats,
|
||||
peak_regret: CentsSats,
|
||||
@@ -565,31 +464,11 @@ pub struct RealizedFullAccum {
|
||||
|
||||
impl RealizedFullAccum {
|
||||
pub(crate) fn add(&mut self, state: &RealizedState) {
|
||||
self.profit_value_created += CentsSats::new(state.profit_value_created_raw());
|
||||
self.profit_value_destroyed += CentsSats::new(state.profit_value_destroyed_raw());
|
||||
self.loss_value_created += CentsSats::new(state.loss_value_created_raw());
|
||||
self.loss_value_destroyed += CentsSats::new(state.loss_value_destroyed_raw());
|
||||
self.cap_raw += state.cap_raw();
|
||||
self.investor_cap_raw += state.investor_cap_raw();
|
||||
self.peak_regret += CentsSats::new(state.peak_regret_raw());
|
||||
}
|
||||
|
||||
pub(crate) fn profit_value_created(&self) -> Cents {
|
||||
self.profit_value_created.to_cents()
|
||||
}
|
||||
|
||||
pub(crate) fn profit_value_destroyed(&self) -> Cents {
|
||||
self.profit_value_destroyed.to_cents()
|
||||
}
|
||||
|
||||
pub(crate) fn loss_value_created(&self) -> Cents {
|
||||
self.loss_value_created.to_cents()
|
||||
}
|
||||
|
||||
pub(crate) fn loss_value_destroyed(&self) -> Cents {
|
||||
self.loss_value_destroyed.to_cents()
|
||||
}
|
||||
|
||||
pub(crate) fn peak_regret(&self) -> Cents {
|
||||
self.peak_regret.to_cents()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use vecdb::{
|
||||
use crate::{
|
||||
distribution::state::{CohortState, CostBasisOps, RealizedOps},
|
||||
internal::{
|
||||
PerBlockCumulativeWithSums, FiatPerBlockCumulativeWithSums,
|
||||
AmountPerBlockCumulativeWithSums, FiatPerBlockCumulativeWithSums,
|
||||
FiatPerBlockWithDeltas, Identity, LazyPerBlock, PriceWithRatioPerBlock,
|
||||
},
|
||||
prices,
|
||||
@@ -19,12 +19,6 @@ use crate::{
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedSoprMinimal<M: StorageMode = Rw> {
|
||||
pub value_created: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
pub value_destroyed: PerBlockCumulativeWithSums<Cents, Cents, M>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedMinimal<M: StorageMode = Rw> {
|
||||
pub cap: FiatPerBlockWithDeltas<Cents, CentsSigned, BasisPointsSigned32, M>,
|
||||
@@ -33,7 +27,7 @@ pub struct RealizedMinimal<M: StorageMode = Rw> {
|
||||
pub price: PriceWithRatioPerBlock<M>,
|
||||
pub mvrv: LazyPerBlock<StoredF32>,
|
||||
|
||||
pub sopr: RealizedSoprMinimal<M>,
|
||||
pub transfer_volume: AmountPerBlockCumulativeWithSums<M>,
|
||||
}
|
||||
|
||||
impl RealizedMinimal {
|
||||
@@ -56,16 +50,21 @@ impl RealizedMinimal {
|
||||
&price.ratio,
|
||||
);
|
||||
|
||||
let transfer_volume = AmountPerBlockCumulativeWithSums::forced_import(
|
||||
cfg.db,
|
||||
&cfg.name("transfer_volume"),
|
||||
cfg.version,
|
||||
cfg.indexes,
|
||||
cfg.cached_starts,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
cap,
|
||||
profit: cfg.import("realized_profit", v1)?,
|
||||
loss: cfg.import("realized_loss", v1)?,
|
||||
price,
|
||||
mvrv,
|
||||
sopr: RealizedSoprMinimal {
|
||||
value_created: cfg.import("value_created", v1)?,
|
||||
value_destroyed: cfg.import("value_destroyed", v1)?,
|
||||
},
|
||||
transfer_volume,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -76,8 +75,7 @@ impl RealizedMinimal {
|
||||
.len()
|
||||
.min(self.profit.base.cents.height.len())
|
||||
.min(self.loss.base.cents.height.len())
|
||||
.min(self.sopr.value_created.base.height.len())
|
||||
.min(self.sopr.value_destroyed.base.height.len())
|
||||
.min(self.transfer_volume.base.sats.height.len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -85,16 +83,7 @@ impl RealizedMinimal {
|
||||
self.cap.cents.height.push(state.realized.cap());
|
||||
self.profit.base.cents.height.push(state.realized.profit());
|
||||
self.loss.base.cents.height.push(state.realized.loss());
|
||||
self.sopr
|
||||
.value_created
|
||||
.base
|
||||
.height
|
||||
.push(state.realized.value_created());
|
||||
self.sopr
|
||||
.value_destroyed
|
||||
.base
|
||||
.height
|
||||
.push(state.realized.value_destroyed());
|
||||
self.transfer_volume.base.sats.height.push(state.sent);
|
||||
}
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
@@ -102,8 +91,7 @@ impl RealizedMinimal {
|
||||
&mut self.cap.cents.height as &mut dyn AnyStoredVec,
|
||||
&mut self.profit.base.cents.height,
|
||||
&mut self.loss.base.cents.height,
|
||||
&mut self.sopr.value_created.base.height,
|
||||
&mut self.sopr.value_destroyed.base.height,
|
||||
&mut self.transfer_volume.base.sats.height,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -116,24 +104,20 @@ impl RealizedMinimal {
|
||||
sum_others!(self, starting_indexes, others, exit; cap.cents.height);
|
||||
sum_others!(self, starting_indexes, others, exit; profit.base.cents.height);
|
||||
sum_others!(self, starting_indexes, others, exit; loss.base.cents.height);
|
||||
sum_others!(self, starting_indexes, others, exit; sopr.value_created.base.height);
|
||||
sum_others!(self, starting_indexes, others, exit; sopr.value_destroyed.base.height);
|
||||
sum_others!(self, starting_indexes, others, exit; transfer_volume.base.sats.height);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rest_part1(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.profit.compute_rest(starting_indexes.height, exit)?;
|
||||
self.loss.compute_rest(starting_indexes.height, exit)?;
|
||||
self.sopr
|
||||
.value_created
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
self.sopr
|
||||
.value_destroyed
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
self.transfer_volume
|
||||
.compute_rest(starting_indexes.height, prices, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@ use brk_error::Result;
|
||||
use brk_types::Indexes;
|
||||
use vecdb::Exit;
|
||||
|
||||
use crate::distribution::state::{WithCapital, CohortState, CostBasisData, RealizedState};
|
||||
use crate::{distribution::state::{WithCapital, CohortState, CostBasisData, RealizedState}, prices};
|
||||
|
||||
pub trait RealizedLike: Send + Sync {
|
||||
fn as_core(&self) -> &RealizedCore;
|
||||
fn as_core_mut(&mut self) -> &mut RealizedCore;
|
||||
fn min_stateful_len(&self) -> usize;
|
||||
fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>);
|
||||
fn compute_rest_part1(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
|
||||
fn compute_rest_part1(&mut self, prices: &prices::Vecs, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
|
||||
fn compute_from_stateful(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
@@ -36,8 +36,8 @@ impl RealizedLike for RealizedCore {
|
||||
fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>) {
|
||||
self.push_state(state)
|
||||
}
|
||||
fn compute_rest_part1(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
self.compute_rest_part1(starting_indexes, exit)
|
||||
fn compute_rest_part1(&mut self, prices: &prices::Vecs, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
self.compute_rest_part1(prices, starting_indexes, exit)
|
||||
}
|
||||
fn compute_from_stateful(&mut self, starting_indexes: &Indexes, others: &[&RealizedCore], exit: &Exit) -> Result<()> {
|
||||
self.compute_from_stateful(starting_indexes, others, exit)
|
||||
@@ -52,8 +52,8 @@ impl RealizedLike for RealizedFull {
|
||||
fn push_state(&mut self, state: &CohortState<RealizedState, CostBasisData<WithCapital>>) {
|
||||
self.push_state(state)
|
||||
}
|
||||
fn compute_rest_part1(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
self.compute_rest_part1(starting_indexes, exit)
|
||||
fn compute_rest_part1(&mut self, prices: &prices::Vecs, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
self.compute_rest_part1(prices, starting_indexes, exit)
|
||||
}
|
||||
fn compute_from_stateful(&mut self, starting_indexes: &Indexes, others: &[&RealizedCore], exit: &Exit) -> Result<()> {
|
||||
self.compute_from_stateful(starting_indexes, others, exit)
|
||||
|
||||
@@ -96,8 +96,8 @@ impl<R: RealizedOps, C: CostBasisOps> CohortState<R, C> {
|
||||
}
|
||||
|
||||
pub(crate) fn reset_single_iteration_values(&mut self) {
|
||||
self.sent = Sats::ZERO;
|
||||
if R::TRACK_ACTIVITY {
|
||||
self.sent = Sats::ZERO;
|
||||
self.satdays_destroyed = Sats::ZERO;
|
||||
}
|
||||
self.realized.reset_single_iteration_values();
|
||||
@@ -196,8 +196,8 @@ impl<R: RealizedOps, C: CostBasisOps> CohortState<R, C> {
|
||||
pre: &SendPrecomputed,
|
||||
) {
|
||||
self.supply -= supply;
|
||||
self.sent += pre.sats;
|
||||
if R::TRACK_ACTIVITY {
|
||||
self.sent += pre.sats;
|
||||
self.satdays_destroyed += pre.age.satdays_destroyed(pre.sats);
|
||||
}
|
||||
|
||||
@@ -241,8 +241,8 @@ impl<R: RealizedOps, C: CostBasisOps> CohortState<R, C> {
|
||||
self.supply -= supply;
|
||||
|
||||
if supply.value > Sats::ZERO {
|
||||
self.sent += supply.value;
|
||||
if R::TRACK_ACTIVITY {
|
||||
self.sent += supply.value;
|
||||
self.satdays_destroyed += age.satdays_destroyed(supply.value);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@ pub trait RealizedOps: Default + Clone + Send + Sync + 'static {
|
||||
fn cap(&self) -> Cents;
|
||||
fn profit(&self) -> Cents;
|
||||
fn loss(&self) -> Cents;
|
||||
fn value_created(&self) -> Cents {
|
||||
Cents::ZERO
|
||||
}
|
||||
fn value_destroyed(&self) -> Cents {
|
||||
Cents::ZERO
|
||||
}
|
||||
@@ -46,7 +43,6 @@ pub struct MinimalRealizedState {
|
||||
cap_raw: u128,
|
||||
profit_raw: u128,
|
||||
loss_raw: u128,
|
||||
value_created_raw: u128,
|
||||
value_destroyed_raw: u128,
|
||||
}
|
||||
|
||||
@@ -76,13 +72,6 @@ impl RealizedOps for MinimalRealizedState {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn value_created(&self) -> Cents {
|
||||
if self.value_created_raw == 0 {
|
||||
return Cents::ZERO;
|
||||
}
|
||||
Cents::new((self.value_created_raw / Sats::ONE_BTC_U128) as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn value_destroyed(&self) -> Cents {
|
||||
if self.value_destroyed_raw == 0 {
|
||||
@@ -103,7 +92,6 @@ impl RealizedOps for MinimalRealizedState {
|
||||
fn reset_single_iteration_values(&mut self) {
|
||||
self.profit_raw = 0;
|
||||
self.loss_raw = 0;
|
||||
self.value_created_raw = 0;
|
||||
self.value_destroyed_raw = 0;
|
||||
}
|
||||
|
||||
@@ -145,7 +133,6 @@ impl RealizedOps for MinimalRealizedState {
|
||||
Ordering::Equal => {}
|
||||
}
|
||||
self.cap_raw -= prev_ps.as_u128();
|
||||
self.value_created_raw += current_ps.as_u128();
|
||||
self.value_destroyed_raw += prev_ps.as_u128();
|
||||
}
|
||||
}
|
||||
@@ -177,11 +164,6 @@ impl RealizedOps for CoreRealizedState {
|
||||
self.minimal.loss()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn value_created(&self) -> Cents {
|
||||
self.minimal.value_created()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn value_destroyed(&self) -> Cents {
|
||||
self.minimal.value_destroyed()
|
||||
@@ -263,14 +245,6 @@ pub struct RealizedState {
|
||||
core: CoreRealizedState,
|
||||
/// Raw investor cap: Σ(price² × sats)
|
||||
investor_cap_raw: CentsSquaredSats,
|
||||
/// sell_price × sats for profit cases
|
||||
profit_value_created_raw: u128,
|
||||
/// cost_basis × sats for profit cases
|
||||
profit_value_destroyed_raw: u128,
|
||||
/// sell_price × sats for loss cases
|
||||
loss_value_created_raw: u128,
|
||||
/// cost_basis × sats for loss cases (= capitulation_flow)
|
||||
loss_value_destroyed_raw: u128,
|
||||
/// Raw realized peak regret: Σ((peak - sell_price) × sats)
|
||||
peak_regret_raw: u128,
|
||||
}
|
||||
@@ -293,22 +267,9 @@ impl RealizedOps for RealizedState {
|
||||
self.core.loss()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn value_created(&self) -> Cents {
|
||||
let raw = self.profit_value_created_raw + self.loss_value_created_raw;
|
||||
if raw == 0 {
|
||||
return Cents::ZERO;
|
||||
}
|
||||
Cents::new((raw / Sats::ONE_BTC_U128) as u64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn value_destroyed(&self) -> Cents {
|
||||
let raw = self.profit_value_destroyed_raw + self.loss_value_destroyed_raw;
|
||||
if raw == 0 {
|
||||
return Cents::ZERO;
|
||||
}
|
||||
Cents::new((raw / Sats::ONE_BTC_U128) as u64)
|
||||
self.core.value_destroyed()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -334,10 +295,6 @@ impl RealizedOps for RealizedState {
|
||||
#[inline]
|
||||
fn reset_single_iteration_values(&mut self) {
|
||||
self.core.reset_single_iteration_values();
|
||||
self.profit_value_created_raw = 0;
|
||||
self.profit_value_destroyed_raw = 0;
|
||||
self.loss_value_created_raw = 0;
|
||||
self.loss_value_destroyed_raw = 0;
|
||||
self.peak_regret_raw = 0;
|
||||
}
|
||||
|
||||
@@ -370,24 +327,9 @@ impl RealizedOps for RealizedState {
|
||||
ath_ps: CentsSats,
|
||||
prev_investor_cap: CentsSquaredSats,
|
||||
) {
|
||||
// Delegate cap/profit/loss + value_created/destroyed + sent tracking to core
|
||||
self.core
|
||||
.send(sats, current_ps, prev_ps, ath_ps, prev_investor_cap);
|
||||
|
||||
// Per-component value flow tracking
|
||||
let current = current_ps.as_u128();
|
||||
let prev = prev_ps.as_u128();
|
||||
match current_ps.cmp(&prev_ps) {
|
||||
Ordering::Greater | Ordering::Equal => {
|
||||
self.profit_value_created_raw += current;
|
||||
self.profit_value_destroyed_raw += prev;
|
||||
}
|
||||
Ordering::Less => {
|
||||
self.loss_value_created_raw += current;
|
||||
self.loss_value_destroyed_raw += prev;
|
||||
}
|
||||
}
|
||||
|
||||
self.peak_regret_raw += (ath_ps - current_ps).as_u128();
|
||||
self.investor_cap_raw -= prev_investor_cap;
|
||||
}
|
||||
@@ -417,42 +359,6 @@ impl RealizedState {
|
||||
self.investor_cap_raw
|
||||
}
|
||||
|
||||
/// Get profit value created as CentsUnsigned (sell_price × sats for profit cases).
|
||||
#[inline]
|
||||
pub(crate) fn profit_value_created(&self) -> Cents {
|
||||
if self.profit_value_created_raw == 0 {
|
||||
return Cents::ZERO;
|
||||
}
|
||||
Cents::new((self.profit_value_created_raw / Sats::ONE_BTC_U128) as u64)
|
||||
}
|
||||
|
||||
/// Get profit value destroyed as CentsUnsigned (cost_basis × sats for profit cases).
|
||||
#[inline]
|
||||
pub(crate) fn profit_value_destroyed(&self) -> Cents {
|
||||
if self.profit_value_destroyed_raw == 0 {
|
||||
return Cents::ZERO;
|
||||
}
|
||||
Cents::new((self.profit_value_destroyed_raw / Sats::ONE_BTC_U128) as u64)
|
||||
}
|
||||
|
||||
/// Get loss value created as CentsUnsigned (sell_price × sats for loss cases).
|
||||
#[inline]
|
||||
pub(crate) fn loss_value_created(&self) -> Cents {
|
||||
if self.loss_value_created_raw == 0 {
|
||||
return Cents::ZERO;
|
||||
}
|
||||
Cents::new((self.loss_value_created_raw / Sats::ONE_BTC_U128) as u64)
|
||||
}
|
||||
|
||||
/// Get loss value destroyed as CentsUnsigned (cost_basis × sats for loss cases).
|
||||
#[inline]
|
||||
pub(crate) fn loss_value_destroyed(&self) -> Cents {
|
||||
if self.loss_value_destroyed_raw == 0 {
|
||||
return Cents::ZERO;
|
||||
}
|
||||
Cents::new((self.loss_value_destroyed_raw / Sats::ONE_BTC_U128) as u64)
|
||||
}
|
||||
|
||||
/// Get realized peak regret as CentsUnsigned.
|
||||
#[inline]
|
||||
pub(crate) fn peak_regret(&self) -> Cents {
|
||||
@@ -462,30 +368,6 @@ impl RealizedState {
|
||||
Cents::new((self.peak_regret_raw / Sats::ONE_BTC_U128) as u64)
|
||||
}
|
||||
|
||||
/// Raw profit value created for lossless aggregation.
|
||||
#[inline]
|
||||
pub(crate) fn profit_value_created_raw(&self) -> u128 {
|
||||
self.profit_value_created_raw
|
||||
}
|
||||
|
||||
/// Raw profit value destroyed for lossless aggregation.
|
||||
#[inline]
|
||||
pub(crate) fn profit_value_destroyed_raw(&self) -> u128 {
|
||||
self.profit_value_destroyed_raw
|
||||
}
|
||||
|
||||
/// Raw loss value created for lossless aggregation.
|
||||
#[inline]
|
||||
pub(crate) fn loss_value_created_raw(&self) -> u128 {
|
||||
self.loss_value_created_raw
|
||||
}
|
||||
|
||||
/// Raw loss value destroyed for lossless aggregation.
|
||||
#[inline]
|
||||
pub(crate) fn loss_value_destroyed_raw(&self) -> u128 {
|
||||
self.loss_value_destroyed_raw
|
||||
}
|
||||
|
||||
/// Raw peak regret for lossless aggregation.
|
||||
#[inline]
|
||||
pub(crate) fn peak_regret_raw(&self) -> u128 {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
//! PerBlockCumulative - base PerBlock + cumulative PerBlock.
|
||||
//!
|
||||
//! Like PerBlockCumulativeWithSums but without RollingWindows.
|
||||
//! Used for distribution metrics where rolling is optional per cohort.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Version};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{PerBlock, NumericValue},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct PerBlockCumulative<T, M: StorageMode = Rw>
|
||||
where
|
||||
T: NumericValue + JsonSchema,
|
||||
{
|
||||
pub base: PerBlock<T, M>,
|
||||
pub cumulative: PerBlock<T, M>,
|
||||
}
|
||||
|
||||
impl<T> PerBlockCumulative<T>
|
||||
where
|
||||
T: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let base = PerBlock::forced_import(db, name, version, indexes)?;
|
||||
let cumulative =
|
||||
PerBlock::forced_import(db, &format!("{name}_cumulative"), version, indexes)?;
|
||||
|
||||
Ok(Self { base, cumulative })
|
||||
}
|
||||
|
||||
/// Compute cumulative from already-filled base vec.
|
||||
pub(crate) fn compute_rest(&mut self, max_from: Height, exit: &Exit) -> Result<()>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
self.cumulative
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.height, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
mod aggregated;
|
||||
mod base;
|
||||
mod cumulative;
|
||||
mod cumulative_sum;
|
||||
mod distribution;
|
||||
mod full;
|
||||
@@ -13,7 +12,6 @@ mod with_deltas;
|
||||
|
||||
pub use aggregated::*;
|
||||
pub use base::*;
|
||||
pub use cumulative::*;
|
||||
pub use cumulative_sum::*;
|
||||
pub use distribution::*;
|
||||
pub use full::*;
|
||||
|
||||
@@ -44,7 +44,7 @@ pub struct Bp16ToPercent;
|
||||
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints16) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
StoredF32::from(bp.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ pub struct Bp32ToPercent;
|
||||
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints32) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
StoredF32::from(bp.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ pub struct Bps16ToPercent;
|
||||
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
StoredF32::from(bp.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,6 @@ pub struct Bps32ToPercent;
|
||||
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
|
||||
StoredF32::from(bp.inner() as f32 / 100.0)
|
||||
StoredF32::from(bp.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::Indexes;
|
||||
use brk_types::{Indexes, Sats};
|
||||
use vecdb::Exit;
|
||||
|
||||
/// Initial block subsidy (50 BTC) in sats, as f64 for floating-point comparisons.
|
||||
const INITIAL_SUBSIDY: f64 = Sats::ONE_BTC_U64 as f64 * 50.0;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{blocks, distribution, mining, prices, scripts, transactions};
|
||||
|
||||
@@ -28,15 +31,24 @@ impl Vecs {
|
||||
)?;
|
||||
|
||||
// 2. Compute inflation rate: (supply[h] / supply[1y_ago]) - 1
|
||||
// Skip when lookback supply <= first block (50 BTC = 5B sats),
|
||||
// i.e. the lookback points to block 0 or 1 in the genesis era.
|
||||
let circulating_supply = &distribution.utxo_cohorts.all.metrics.supply.total.sats;
|
||||
self.inflation_rate
|
||||
.bps
|
||||
.height
|
||||
.compute_rolling_ratio_change(
|
||||
.compute_rolling_from_window_starts(
|
||||
starting_indexes.height,
|
||||
&blocks.lookback._1y,
|
||||
&circulating_supply.height,
|
||||
exit,
|
||||
|current, previous| {
|
||||
if previous.is_nan() || previous <= INITIAL_SUBSIDY {
|
||||
f64::NAN
|
||||
} else {
|
||||
current / previous - 1.0
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
// 3. Compute velocity at height level
|
||||
|
||||
@@ -37,8 +37,12 @@ impl Vecs {
|
||||
let burned = burned::Vecs::forced_import(&db, version, indexes, cached_starts)?;
|
||||
|
||||
// Inflation rate
|
||||
let inflation_rate =
|
||||
PercentPerBlock::forced_import(&db, "inflation_rate", version, indexes)?;
|
||||
let inflation_rate = PercentPerBlock::forced_import(
|
||||
&db,
|
||||
"inflation_rate",
|
||||
version + Version::ONE,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
// Velocity
|
||||
let velocity = super::velocity::Vecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
@@ -3,13 +3,14 @@ use std::ops::{Add, AddAssign, Div, Sub};
|
||||
use derive_more::Deref;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{CheckedSub, Formattable, Pco};
|
||||
use vecdb::{unlikely, CheckedSub, Formattable, Pco};
|
||||
|
||||
use super::StoredF32;
|
||||
|
||||
/// Unsigned basis points stored as u16.
|
||||
/// 1 bp = 0.0001. Range: 0–6.5535.
|
||||
/// Use for bounded 0–1 ratios (dominance, adoption, liveliness, etc.).
|
||||
/// `u16::MAX` is reserved as a NaN sentinel.
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
@@ -31,9 +32,12 @@ pub struct BasisPoints16(u16);
|
||||
impl BasisPoints16 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const ONE: Self = Self(10000);
|
||||
/// NaN sentinel — uses u16::MAX which is outside the practical range.
|
||||
pub const NAN: Self = Self(u16::MAX);
|
||||
|
||||
#[inline]
|
||||
pub const fn new(value: u16) -> Self {
|
||||
debug_assert!(value != u16::MAX, "u16::MAX is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
|
||||
@@ -42,10 +46,19 @@ impl BasisPoints16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Convert to f32: divide by 10000.
|
||||
#[inline]
|
||||
pub fn is_nan(self) -> bool {
|
||||
self.0 == u16::MAX
|
||||
}
|
||||
|
||||
/// Convert to f32: divide by 10000. Returns NaN for sentinel value.
|
||||
#[inline]
|
||||
pub fn to_f32(self) -> f32 {
|
||||
self.0 as f32 / 10000.0
|
||||
if unlikely(self.0 == u16::MAX) {
|
||||
f32::NAN
|
||||
} else {
|
||||
self.0 as f32 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +66,7 @@ impl From<usize> for BasisPoints16 {
|
||||
#[inline]
|
||||
fn from(value: usize) -> Self {
|
||||
debug_assert!(
|
||||
value <= u16::MAX as usize,
|
||||
value < u16::MAX as usize,
|
||||
"usize out of BasisPoints16 range: {value}"
|
||||
);
|
||||
Self(value as u16)
|
||||
@@ -63,6 +76,7 @@ impl From<usize> for BasisPoints16 {
|
||||
impl From<u16> for BasisPoints16 {
|
||||
#[inline]
|
||||
fn from(value: u16) -> Self {
|
||||
debug_assert!(value != u16::MAX, "u16::MAX is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
@@ -76,28 +90,28 @@ impl From<BasisPoints16> for u16 {
|
||||
|
||||
/// Convert from f32: multiply by 10000 and round.
|
||||
/// Input is in ratio form (e.g., 0.4523 for 45.23%).
|
||||
/// NaN/Inf → NaN sentinel.
|
||||
impl From<f32> for BasisPoints16 {
|
||||
#[inline]
|
||||
fn from(value: f32) -> Self {
|
||||
let scaled = (value * 10000.0).round();
|
||||
debug_assert!(
|
||||
scaled >= 0.0 && scaled <= u16::MAX as f32,
|
||||
"f32 out of BasisPoints16 range: {value}"
|
||||
);
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 10000.0).round().clamp(0.0, u16::MAX as f32 - 1.0);
|
||||
Self(scaled as u16)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from f64: multiply by 10000 and round.
|
||||
/// Input is in ratio form (e.g., 0.4523 for 45.23%).
|
||||
/// NaN/Inf → NaN sentinel.
|
||||
impl From<f64> for BasisPoints16 {
|
||||
#[inline]
|
||||
fn from(value: f64) -> Self {
|
||||
let scaled = (value * 10000.0).round();
|
||||
debug_assert!(
|
||||
scaled >= 0.0 && scaled <= u16::MAX as f64,
|
||||
"f64 out of BasisPoints16 range: {value}"
|
||||
);
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 10000.0).round().clamp(0.0, u16::MAX as f64 - 1.0);
|
||||
Self(scaled as u16)
|
||||
}
|
||||
}
|
||||
@@ -105,7 +119,11 @@ impl From<f64> for BasisPoints16 {
|
||||
impl From<BasisPoints16> for f64 {
|
||||
#[inline]
|
||||
fn from(value: BasisPoints16) -> Self {
|
||||
value.0 as f64 / 10000.0
|
||||
if unlikely(value.0 == u16::MAX) {
|
||||
f64::NAN
|
||||
} else {
|
||||
value.0 as f64 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +138,11 @@ impl Add for BasisPoints16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
if unlikely(self.0 == u16::MAX || rhs.0 == u16::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,14 +150,18 @@ impl Sub for BasisPoints16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
if unlikely(self.0 == u16::MAX || rhs.0 == u16::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for BasisPoints16 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 += rhs.0;
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,14 +169,22 @@ impl Div<usize> for BasisPoints16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
debug_assert!(rhs <= u16::MAX as usize, "divisor out of u16 range: {rhs}");
|
||||
Self(self.0 / rhs as u16)
|
||||
if unlikely(self.0 == u16::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
debug_assert!(rhs <= u16::MAX as usize, "divisor out of u16 range: {rhs}");
|
||||
Self(self.0 / rhs as u16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for BasisPoints16 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
if unlikely(self.0 == u16::MAX || rhs.0 == u16::MAX) {
|
||||
Some(Self::NAN)
|
||||
} else {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,4 +202,13 @@ impl Formattable for BasisPoints16 {
|
||||
let mut b = itoa::Buffer::new();
|
||||
buf.extend_from_slice(b.format(self.0).as_bytes());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fmt_json(&self, buf: &mut Vec<u8>) {
|
||||
if unlikely(self.0 == u16::MAX) {
|
||||
buf.extend_from_slice(b"null");
|
||||
} else {
|
||||
self.write_to(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ use std::ops::{Add, AddAssign, Div, Sub, SubAssign};
|
||||
use derive_more::Deref;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{CheckedSub, Formattable, Pco};
|
||||
use vecdb::{unlikely, CheckedSub, Formattable, Pco};
|
||||
|
||||
use super::StoredF32;
|
||||
|
||||
/// Signed basis points stored as i16.
|
||||
/// 1 bp = 0.0001. Range: -3.2767 to +3.2767.
|
||||
/// Use for signed bounded ratios (NUPL, net PnL ratios, etc.).
|
||||
/// `i16::MIN` is reserved as a NaN sentinel.
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
@@ -30,9 +31,12 @@ pub struct BasisPointsSigned16(i16);
|
||||
|
||||
impl BasisPointsSigned16 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
/// NaN sentinel — uses i16::MIN which is outside the documented range.
|
||||
pub const NAN: Self = Self(i16::MIN);
|
||||
|
||||
#[inline]
|
||||
pub const fn new(value: i16) -> Self {
|
||||
debug_assert!(value != i16::MIN, "i16::MIN is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
|
||||
@@ -42,14 +46,23 @@ impl BasisPointsSigned16 {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_negative(self) -> bool {
|
||||
self.0 < 0
|
||||
pub fn is_nan(self) -> bool {
|
||||
self.0 == i16::MIN
|
||||
}
|
||||
|
||||
/// Convert to f32: divide by 10000.
|
||||
#[inline]
|
||||
pub fn is_negative(self) -> bool {
|
||||
self.0 < 0 && self.0 != i16::MIN
|
||||
}
|
||||
|
||||
/// Convert to f32: divide by 10000. Returns NaN for sentinel value.
|
||||
#[inline]
|
||||
pub fn to_f32(self) -> f32 {
|
||||
self.0 as f32 / 10000.0
|
||||
if unlikely(self.0 == i16::MIN) {
|
||||
f32::NAN
|
||||
} else {
|
||||
self.0 as f32 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +80,7 @@ impl From<usize> for BasisPointsSigned16 {
|
||||
impl From<i16> for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn from(value: i16) -> Self {
|
||||
debug_assert!(value != i16::MIN, "i16::MIN is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
@@ -80,21 +94,28 @@ impl From<BasisPointsSigned16> for i16 {
|
||||
|
||||
/// Convert from float: multiply by 10000 and round.
|
||||
/// Input is in ratio form (e.g., -0.4523 for -45.23%).
|
||||
/// NaN/Inf → NaN sentinel.
|
||||
impl From<f64> for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn from(value: f64) -> Self {
|
||||
debug_assert!(
|
||||
value >= i16::MIN as f64 / 10000.0 && value <= i16::MAX as f64 / 10000.0,
|
||||
"f64 out of BasisPointsSigned16 range: {value}"
|
||||
);
|
||||
Self((value * 10000.0).round() as i16)
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 10000.0)
|
||||
.round()
|
||||
.clamp(i16::MIN as f64 + 1.0, i16::MAX as f64);
|
||||
Self(scaled as i16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPointsSigned16> for f64 {
|
||||
#[inline]
|
||||
fn from(value: BasisPointsSigned16) -> Self {
|
||||
value.0 as f64 / 10000.0
|
||||
if unlikely(value.0 == i16::MIN) {
|
||||
f64::NAN
|
||||
} else {
|
||||
value.0 as f64 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,14 +130,18 @@ impl Add for BasisPointsSigned16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
if unlikely(self.0 == i16::MIN || rhs.0 == i16::MIN) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 += rhs.0;
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,14 +149,18 @@ impl Sub for BasisPointsSigned16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
if unlikely(self.0 == i16::MIN || rhs.0 == i16::MIN) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
self.0 -= rhs.0;
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,14 +168,22 @@ impl Div<usize> for BasisPointsSigned16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
debug_assert!(rhs <= i16::MAX as usize, "divisor out of i16 range: {rhs}");
|
||||
Self(self.0 / rhs as i16)
|
||||
if unlikely(self.0 == i16::MIN) {
|
||||
Self::NAN
|
||||
} else {
|
||||
debug_assert!(rhs <= i16::MAX as usize, "divisor out of i16 range: {rhs}");
|
||||
Self(self.0 / rhs as i16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for BasisPointsSigned16 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
if unlikely(self.0 == i16::MIN || rhs.0 == i16::MIN) {
|
||||
Some(Self::NAN)
|
||||
} else {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,4 +201,13 @@ impl Formattable for BasisPointsSigned16 {
|
||||
let mut b = itoa::Buffer::new();
|
||||
buf.extend_from_slice(b.format(self.0).as_bytes());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fmt_json(&self, buf: &mut Vec<u8>) {
|
||||
if unlikely(self.0 == i16::MIN) {
|
||||
buf.extend_from_slice(b"null");
|
||||
} else {
|
||||
self.write_to(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
* Unsigned basis points stored as u16.
|
||||
* 1 bp = 0.0001. Range: 0–6.5535.
|
||||
* Use for bounded 0–1 ratios (dominance, adoption, liveliness, etc.).
|
||||
* `u16::MAX` is reserved as a NaN sentinel.
|
||||
*
|
||||
* @typedef {number} BasisPoints16
|
||||
*/
|
||||
@@ -85,6 +86,7 @@
|
||||
* Signed basis points stored as i16.
|
||||
* 1 bp = 0.0001. Range: -3.2767 to +3.2767.
|
||||
* Use for signed bounded ratios (NUPL, net PnL ratios, etc.).
|
||||
* `i16::MIN` is reserved as a NaN sentinel.
|
||||
*
|
||||
* @typedef {number} BasisPointsSigned16
|
||||
*/
|
||||
@@ -1786,12 +1788,12 @@ function create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(client, acc) {
|
||||
* @property {CentsDeltaToUsdPattern} cap
|
||||
* @property {BaseCumulativeSumPattern3} grossPnl
|
||||
* @property {PricePattern} investor
|
||||
* @property {BaseCapitulationCumulativeNegativeSumToValuePattern} loss
|
||||
* @property {BaseCumulativeNegativeSumToPattern} loss
|
||||
* @property {SeriesPattern1<StoredF32>} mvrv
|
||||
* @property {BaseChangeCumulativeDeltaSumToPattern} netPnl
|
||||
* @property {BaseCumulativeSumToPattern} peakRegret
|
||||
* @property {BpsCentsPercentilesRatioSatsSmaStdUsdPattern} price
|
||||
* @property {BaseCumulativeDistributionSumToValuePattern} profit
|
||||
* @property {BaseCumulativeSumToPattern} profit
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} profitToLossRatio
|
||||
* @property {_1m1w1y24hPattern6} sellSideRiskRatio
|
||||
* @property {AdjustedRatioValuePattern} sopr
|
||||
@@ -1983,18 +1985,6 @@ function createAverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BaseCapitulationCumulativeNegativeSumToValuePattern
|
||||
* @property {CentsUsdPattern2} base
|
||||
* @property {SeriesPattern1<Dollars>} capitulationFlow
|
||||
* @property {CentsUsdPattern2} cumulative
|
||||
* @property {BaseSumPattern} negative
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueCreated
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} BpsCentsPercentilesRatioSatsSmaStdUsdPattern
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
@@ -2098,17 +2088,6 @@ function create_1m1w1y24hBpsPercentRatioPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BaseCumulativeDistributionSumToValuePattern
|
||||
* @property {CentsUsdPattern2} base
|
||||
* @property {CentsUsdPattern2} cumulative
|
||||
* @property {SeriesPattern1<Dollars>} distributionFlow
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueCreated
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CapLossMvrvNetPriceProfitSoprPattern
|
||||
* @property {CentsDeltaUsdPattern} cap
|
||||
@@ -2467,6 +2446,15 @@ function createBaseCumulativeInSumPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BaseCumulativeNegativeSumToPattern
|
||||
* @property {CentsUsdPattern2} base
|
||||
* @property {CentsUsdPattern2} cumulative
|
||||
* @property {BaseSumPattern} negative
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} BpsCentsRatioSatsUsdPattern
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
@@ -5404,7 +5392,7 @@ function createUnspentPattern(client, acc) {
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_All_Realized
|
||||
* @property {CentsDeltaToUsdPattern} cap
|
||||
* @property {SeriesTree_Cohorts_Utxo_All_Realized_Profit} profit
|
||||
* @property {BaseCumulativeSumToPattern} profit
|
||||
* @property {SeriesTree_Cohorts_Utxo_All_Realized_Loss} loss
|
||||
* @property {SeriesTree_Cohorts_Utxo_All_Realized_Price} price
|
||||
* @property {SeriesPattern1<StoredF32>} mvrv
|
||||
@@ -5417,17 +5405,6 @@ function createUnspentPattern(client, acc) {
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} profitToLossRatio
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_All_Realized_Profit
|
||||
* @property {CentsUsdPattern2} base
|
||||
* @property {CentsUsdPattern2} cumulative
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueCreated
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
|
||||
* @property {SeriesPattern1<Dollars>} distributionFlow
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_All_Realized_Loss
|
||||
* @property {CentsUsdPattern2} base
|
||||
@@ -5435,9 +5412,6 @@ function createUnspentPattern(client, acc) {
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BaseSumPattern} negative
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueCreated
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
|
||||
* @property {SeriesPattern1<Dollars>} capitulationFlow
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -5623,7 +5597,7 @@ function createUnspentPattern(client, acc) {
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Sth_Realized
|
||||
* @property {CentsDeltaToUsdPattern} cap
|
||||
* @property {SeriesTree_Cohorts_Utxo_Sth_Realized_Profit} profit
|
||||
* @property {BaseCumulativeSumToPattern} profit
|
||||
* @property {SeriesTree_Cohorts_Utxo_Sth_Realized_Loss} loss
|
||||
* @property {SeriesTree_Cohorts_Utxo_Sth_Realized_Price} price
|
||||
* @property {SeriesPattern1<StoredF32>} mvrv
|
||||
@@ -5636,17 +5610,6 @@ function createUnspentPattern(client, acc) {
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} profitToLossRatio
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Sth_Realized_Profit
|
||||
* @property {CentsUsdPattern2} base
|
||||
* @property {CentsUsdPattern2} cumulative
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueCreated
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
|
||||
* @property {SeriesPattern1<Dollars>} distributionFlow
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Sth_Realized_Loss
|
||||
* @property {CentsUsdPattern2} base
|
||||
@@ -5654,9 +5617,6 @@ function createUnspentPattern(client, acc) {
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BaseSumPattern} negative
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueCreated
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
|
||||
* @property {SeriesPattern1<Dollars>} capitulationFlow
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -5818,7 +5778,7 @@ function createUnspentPattern(client, acc) {
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Lth_Realized
|
||||
* @property {CentsDeltaToUsdPattern} cap
|
||||
* @property {SeriesTree_Cohorts_Utxo_Lth_Realized_Profit} profit
|
||||
* @property {BaseCumulativeSumToPattern} profit
|
||||
* @property {SeriesTree_Cohorts_Utxo_Lth_Realized_Loss} loss
|
||||
* @property {SeriesTree_Cohorts_Utxo_Lth_Realized_Price} price
|
||||
* @property {SeriesPattern1<StoredF32>} mvrv
|
||||
@@ -5831,17 +5791,6 @@ function createUnspentPattern(client, acc) {
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} profitToLossRatio
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Lth_Realized_Profit
|
||||
* @property {CentsUsdPattern2} base
|
||||
* @property {CentsUsdPattern2} cumulative
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueCreated
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
|
||||
* @property {SeriesPattern1<Dollars>} distributionFlow
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Lth_Realized_Loss
|
||||
* @property {CentsUsdPattern2} base
|
||||
@@ -5849,9 +5798,6 @@ function createUnspentPattern(client, acc) {
|
||||
* @property {_1m1w1y24hPattern4} sum
|
||||
* @property {BaseSumPattern} negative
|
||||
* @property {BpsPercentRatioPattern4} toRcap
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueCreated
|
||||
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
|
||||
* @property {SeriesPattern1<Dollars>} capitulationFlow
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -8521,24 +8467,13 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
realized: {
|
||||
cap: createCentsDeltaToUsdPattern(this, 'realized_cap'),
|
||||
profit: {
|
||||
base: createCentsUsdPattern2(this, 'realized_profit'),
|
||||
cumulative: createCentsUsdPattern2(this, 'realized_profit_cumulative'),
|
||||
sum: create_1m1w1y24hPattern4(this, 'realized_profit_sum'),
|
||||
toRcap: createBpsPercentRatioPattern4(this, 'realized_profit_to_rcap'),
|
||||
valueCreated: createBaseCumulativeSumPattern(this, 'profit_value_created'),
|
||||
valueDestroyed: createBaseCumulativeSumPattern(this, 'profit_value_destroyed'),
|
||||
distributionFlow: createSeriesPattern1(this, 'distribution_flow'),
|
||||
},
|
||||
profit: createBaseCumulativeSumToPattern(this, 'realized_profit'),
|
||||
loss: {
|
||||
base: createCentsUsdPattern2(this, 'realized_loss'),
|
||||
cumulative: createCentsUsdPattern2(this, 'realized_loss_cumulative'),
|
||||
sum: create_1m1w1y24hPattern4(this, 'realized_loss_sum'),
|
||||
negative: createBaseSumPattern(this, 'neg_realized_loss'),
|
||||
toRcap: createBpsPercentRatioPattern4(this, 'realized_loss_to_rcap'),
|
||||
valueCreated: createBaseCumulativeSumPattern(this, 'loss_value_created'),
|
||||
valueDestroyed: createBaseCumulativeSumPattern(this, 'loss_value_destroyed'),
|
||||
capitulationFlow: createSeriesPattern1(this, 'capitulation_flow'),
|
||||
},
|
||||
price: {
|
||||
usd: createSeriesPattern1(this, 'realized_price'),
|
||||
@@ -8684,24 +8619,13 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
realized: {
|
||||
cap: createCentsDeltaToUsdPattern(this, 'sth_realized_cap'),
|
||||
profit: {
|
||||
base: createCentsUsdPattern2(this, 'sth_realized_profit'),
|
||||
cumulative: createCentsUsdPattern2(this, 'sth_realized_profit_cumulative'),
|
||||
sum: create_1m1w1y24hPattern4(this, 'sth_realized_profit_sum'),
|
||||
toRcap: createBpsPercentRatioPattern4(this, 'sth_realized_profit_to_rcap'),
|
||||
valueCreated: createBaseCumulativeSumPattern(this, 'sth_profit_value_created'),
|
||||
valueDestroyed: createBaseCumulativeSumPattern(this, 'sth_profit_value_destroyed'),
|
||||
distributionFlow: createSeriesPattern1(this, 'sth_distribution_flow'),
|
||||
},
|
||||
profit: createBaseCumulativeSumToPattern(this, 'sth_realized_profit'),
|
||||
loss: {
|
||||
base: createCentsUsdPattern2(this, 'sth_realized_loss'),
|
||||
cumulative: createCentsUsdPattern2(this, 'sth_realized_loss_cumulative'),
|
||||
sum: create_1m1w1y24hPattern4(this, 'sth_realized_loss_sum'),
|
||||
negative: createBaseSumPattern(this, 'sth_neg_realized_loss'),
|
||||
toRcap: createBpsPercentRatioPattern4(this, 'sth_realized_loss_to_rcap'),
|
||||
valueCreated: createBaseCumulativeSumPattern(this, 'sth_loss_value_created'),
|
||||
valueDestroyed: createBaseCumulativeSumPattern(this, 'sth_loss_value_destroyed'),
|
||||
capitulationFlow: createSeriesPattern1(this, 'sth_capitulation_flow'),
|
||||
},
|
||||
price: {
|
||||
usd: createSeriesPattern1(this, 'sth_realized_price'),
|
||||
@@ -8832,24 +8756,13 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
realized: {
|
||||
cap: createCentsDeltaToUsdPattern(this, 'lth_realized_cap'),
|
||||
profit: {
|
||||
base: createCentsUsdPattern2(this, 'lth_realized_profit'),
|
||||
cumulative: createCentsUsdPattern2(this, 'lth_realized_profit_cumulative'),
|
||||
sum: create_1m1w1y24hPattern4(this, 'lth_realized_profit_sum'),
|
||||
toRcap: createBpsPercentRatioPattern4(this, 'lth_realized_profit_to_rcap'),
|
||||
valueCreated: createBaseCumulativeSumPattern(this, 'lth_profit_value_created'),
|
||||
valueDestroyed: createBaseCumulativeSumPattern(this, 'lth_profit_value_destroyed'),
|
||||
distributionFlow: createSeriesPattern1(this, 'lth_distribution_flow'),
|
||||
},
|
||||
profit: createBaseCumulativeSumToPattern(this, 'lth_realized_profit'),
|
||||
loss: {
|
||||
base: createCentsUsdPattern2(this, 'lth_realized_loss'),
|
||||
cumulative: createCentsUsdPattern2(this, 'lth_realized_loss_cumulative'),
|
||||
sum: create_1m1w1y24hPattern4(this, 'lth_realized_loss_sum'),
|
||||
negative: createBaseSumPattern(this, 'lth_neg_realized_loss'),
|
||||
toRcap: createBpsPercentRatioPattern4(this, 'lth_realized_loss_to_rcap'),
|
||||
valueCreated: createBaseCumulativeSumPattern(this, 'lth_loss_value_created'),
|
||||
valueDestroyed: createBaseCumulativeSumPattern(this, 'lth_loss_value_destroyed'),
|
||||
capitulationFlow: createSeriesPattern1(this, 'lth_capitulation_flow'),
|
||||
},
|
||||
price: {
|
||||
usd: createSeriesPattern1(this, 'lth_realized_price'),
|
||||
|
||||
@@ -30,6 +30,7 @@ AnyAddrIndex = TypeIndex
|
||||
# Unsigned basis points stored as u16.
|
||||
# 1 bp = 0.0001. Range: 0–6.5535.
|
||||
# Use for bounded 0–1 ratios (dominance, adoption, liveliness, etc.).
|
||||
# `u16::MAX` is reserved as a NaN sentinel.
|
||||
BasisPoints16 = int
|
||||
# Unsigned basis points stored as u32.
|
||||
# 1 bp = 0.0001. Range: 0–429,496.7295.
|
||||
@@ -39,6 +40,7 @@ BasisPoints32 = int
|
||||
# Signed basis points stored as i16.
|
||||
# 1 bp = 0.0001. Range: -3.2767 to +3.2767.
|
||||
# Use for signed bounded ratios (NUPL, net PnL ratios, etc.).
|
||||
# `i16::MIN` is reserved as a NaN sentinel.
|
||||
BasisPointsSigned16 = int
|
||||
# Signed basis points stored as i32.
|
||||
# 1 bp = 0.0001. Range: -214,748.3647 to +214,748.3647.
|
||||
@@ -2304,10 +2306,6 @@ class AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2:
|
||||
self.pct75: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct75'))
|
||||
self.pct90: SeriesPattern18[Weight] = SeriesPattern18(client, _m(acc, 'pct90'))
|
||||
|
||||
class BaseCapitulationCumulativeNegativeSumToValuePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class BpsCentsPercentilesRatioSatsSmaStdUsdPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
@@ -2352,10 +2350,6 @@ class _1m1w1y24hBpsPercentRatioPattern:
|
||||
self.percent: SeriesPattern1[StoredF32] = SeriesPattern1(client, acc)
|
||||
self.ratio: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, 'ratio'))
|
||||
|
||||
class BaseCumulativeDistributionSumToValuePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class CapLossMvrvNetPriceProfitSoprPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2514,6 +2508,10 @@ class BaseCumulativeInSumPattern:
|
||||
self.in_profit: BaseCumulativeSumPattern4 = BaseCumulativeSumPattern4(client, _m(acc, 'in_profit'))
|
||||
self.sum: _1m1w1y24hPattern5 = _1m1w1y24hPattern5(client, _m(acc, 'sum'))
|
||||
|
||||
class BaseCumulativeNegativeSumToPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class BpsCentsRatioSatsUsdPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -4705,18 +4703,6 @@ class SeriesTree_Cohorts_Utxo_All_Activity:
|
||||
self.coinyears_destroyed: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'coinyears_destroyed')
|
||||
self.dormancy: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'dormancy')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_All_Realized_Profit:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.base: CentsUsdPattern2 = CentsUsdPattern2(client, 'realized_profit')
|
||||
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, 'realized_profit_cumulative')
|
||||
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'realized_profit_sum')
|
||||
self.to_rcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, 'realized_profit_to_rcap')
|
||||
self.value_created: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'profit_value_created')
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'profit_value_destroyed')
|
||||
self.distribution_flow: SeriesPattern1[Dollars] = SeriesPattern1(client, 'distribution_flow')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_All_Realized_Loss:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -4726,9 +4712,6 @@ class SeriesTree_Cohorts_Utxo_All_Realized_Loss:
|
||||
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'realized_loss_sum')
|
||||
self.negative: BaseSumPattern = BaseSumPattern(client, 'neg_realized_loss')
|
||||
self.to_rcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, 'realized_loss_to_rcap')
|
||||
self.value_created: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'loss_value_created')
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'loss_value_destroyed')
|
||||
self.capitulation_flow: SeriesPattern1[Dollars] = SeriesPattern1(client, 'capitulation_flow')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_All_Realized_Price_StdDev_All:
|
||||
"""Series tree node."""
|
||||
@@ -4854,7 +4837,7 @@ class SeriesTree_Cohorts_Utxo_All_Realized:
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.cap: CentsDeltaToUsdPattern = CentsDeltaToUsdPattern(client, 'realized_cap')
|
||||
self.profit: SeriesTree_Cohorts_Utxo_All_Realized_Profit = SeriesTree_Cohorts_Utxo_All_Realized_Profit(client)
|
||||
self.profit: BaseCumulativeSumToPattern = BaseCumulativeSumToPattern(client, 'realized_profit')
|
||||
self.loss: SeriesTree_Cohorts_Utxo_All_Realized_Loss = SeriesTree_Cohorts_Utxo_All_Realized_Loss(client)
|
||||
self.price: SeriesTree_Cohorts_Utxo_All_Realized_Price = SeriesTree_Cohorts_Utxo_All_Realized_Price(client)
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'mvrv')
|
||||
@@ -4943,18 +4926,6 @@ class SeriesTree_Cohorts_Utxo_Sth_Activity:
|
||||
self.coinyears_destroyed: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'sth_coinyears_destroyed')
|
||||
self.dormancy: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'sth_dormancy')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Sth_Realized_Profit:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.base: CentsUsdPattern2 = CentsUsdPattern2(client, 'sth_realized_profit')
|
||||
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, 'sth_realized_profit_cumulative')
|
||||
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'sth_realized_profit_sum')
|
||||
self.to_rcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, 'sth_realized_profit_to_rcap')
|
||||
self.value_created: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'sth_profit_value_created')
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'sth_profit_value_destroyed')
|
||||
self.distribution_flow: SeriesPattern1[Dollars] = SeriesPattern1(client, 'sth_distribution_flow')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Sth_Realized_Loss:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -4964,9 +4935,6 @@ class SeriesTree_Cohorts_Utxo_Sth_Realized_Loss:
|
||||
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'sth_realized_loss_sum')
|
||||
self.negative: BaseSumPattern = BaseSumPattern(client, 'sth_neg_realized_loss')
|
||||
self.to_rcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, 'sth_realized_loss_to_rcap')
|
||||
self.value_created: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'sth_loss_value_created')
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'sth_loss_value_destroyed')
|
||||
self.capitulation_flow: SeriesPattern1[Dollars] = SeriesPattern1(client, 'sth_capitulation_flow')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Sth_Realized_Price_StdDev_All:
|
||||
"""Series tree node."""
|
||||
@@ -5092,7 +5060,7 @@ class SeriesTree_Cohorts_Utxo_Sth_Realized:
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.cap: CentsDeltaToUsdPattern = CentsDeltaToUsdPattern(client, 'sth_realized_cap')
|
||||
self.profit: SeriesTree_Cohorts_Utxo_Sth_Realized_Profit = SeriesTree_Cohorts_Utxo_Sth_Realized_Profit(client)
|
||||
self.profit: BaseCumulativeSumToPattern = BaseCumulativeSumToPattern(client, 'sth_realized_profit')
|
||||
self.loss: SeriesTree_Cohorts_Utxo_Sth_Realized_Loss = SeriesTree_Cohorts_Utxo_Sth_Realized_Loss(client)
|
||||
self.price: SeriesTree_Cohorts_Utxo_Sth_Realized_Price = SeriesTree_Cohorts_Utxo_Sth_Realized_Price(client)
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'sth_mvrv')
|
||||
@@ -5154,18 +5122,6 @@ class SeriesTree_Cohorts_Utxo_Lth_Activity:
|
||||
self.coinyears_destroyed: SeriesPattern1[StoredF64] = SeriesPattern1(client, 'lth_coinyears_destroyed')
|
||||
self.dormancy: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'lth_dormancy')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Lth_Realized_Profit:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.base: CentsUsdPattern2 = CentsUsdPattern2(client, 'lth_realized_profit')
|
||||
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, 'lth_realized_profit_cumulative')
|
||||
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'lth_realized_profit_sum')
|
||||
self.to_rcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, 'lth_realized_profit_to_rcap')
|
||||
self.value_created: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'lth_profit_value_created')
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'lth_profit_value_destroyed')
|
||||
self.distribution_flow: SeriesPattern1[Dollars] = SeriesPattern1(client, 'lth_distribution_flow')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Lth_Realized_Loss:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -5175,9 +5131,6 @@ class SeriesTree_Cohorts_Utxo_Lth_Realized_Loss:
|
||||
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'lth_realized_loss_sum')
|
||||
self.negative: BaseSumPattern = BaseSumPattern(client, 'lth_neg_realized_loss')
|
||||
self.to_rcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, 'lth_realized_loss_to_rcap')
|
||||
self.value_created: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'lth_loss_value_created')
|
||||
self.value_destroyed: BaseCumulativeSumPattern[Cents] = BaseCumulativeSumPattern(client, 'lth_loss_value_destroyed')
|
||||
self.capitulation_flow: SeriesPattern1[Dollars] = SeriesPattern1(client, 'lth_capitulation_flow')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev_All:
|
||||
"""Series tree node."""
|
||||
@@ -5294,7 +5247,7 @@ class SeriesTree_Cohorts_Utxo_Lth_Realized:
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.cap: CentsDeltaToUsdPattern = CentsDeltaToUsdPattern(client, 'lth_realized_cap')
|
||||
self.profit: SeriesTree_Cohorts_Utxo_Lth_Realized_Profit = SeriesTree_Cohorts_Utxo_Lth_Realized_Profit(client)
|
||||
self.profit: BaseCumulativeSumToPattern = BaseCumulativeSumToPattern(client, 'lth_realized_profit')
|
||||
self.loss: SeriesTree_Cohorts_Utxo_Lth_Realized_Loss = SeriesTree_Cohorts_Utxo_Lth_Realized_Loss(client)
|
||||
self.price: SeriesTree_Cohorts_Utxo_Lth_Realized_Price = SeriesTree_Cohorts_Utxo_Lth_Realized_Price(client)
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'lth_mvrv')
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
*/
|
||||
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { line, baseline, dotsBaseline, percentRatio, percentRatioDots } from "../series.js";
|
||||
import { line, baseline, dotsBaseline, percentRatio, chartsFromCount, ROLLING_WINDOWS } from "../series.js";
|
||||
import {
|
||||
satsBtcUsdFullTree,
|
||||
mapCohortsWithAll,
|
||||
flatMapCohortsWithAll,
|
||||
} from "../shared.js";
|
||||
@@ -30,49 +31,21 @@ function volumeAndCoinsTree(activity, color, title) {
|
||||
return [
|
||||
{
|
||||
name: "Volume",
|
||||
tree: [
|
||||
{
|
||||
name: "Per Block",
|
||||
title: title("Sent Volume"),
|
||||
bottom: [
|
||||
line({ series: activity.transferVolume.base.sats, name: "Sum", color, unit: Unit.sats }),
|
||||
line({ series: activity.transferVolume.sum._24h.sats, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: activity.transferVolume.sum._1w.sats, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: activity.transferVolume.sum._1m.sats, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: activity.transferVolume.sum._1y.sats, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: title("Sent Volume (Total)"),
|
||||
bottom: [
|
||||
line({ series: activity.transferVolume.cumulative.sats, name: "All-time", color, unit: Unit.sats }),
|
||||
],
|
||||
},
|
||||
],
|
||||
tree: satsBtcUsdFullTree({
|
||||
pattern: activity.transferVolume,
|
||||
name: "Volume",
|
||||
title: title("Sent Volume"),
|
||||
color,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Coindays Destroyed",
|
||||
tree: [
|
||||
{
|
||||
name: "Per Block",
|
||||
title: title("Coindays Destroyed"),
|
||||
bottom: [
|
||||
line({ series: activity.coindaysDestroyed.base, name: "Base", color, unit: Unit.coindays }),
|
||||
line({ series: activity.coindaysDestroyed.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ series: activity.coindaysDestroyed.sum._1w, name: "1w", color: colors.time._1w, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ series: activity.coindaysDestroyed.sum._1m, name: "1m", color: colors.time._1m, unit: Unit.coindays, defaultActive: false }),
|
||||
line({ series: activity.coindaysDestroyed.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.coindays, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: title("Cumulative Coindays Destroyed"),
|
||||
bottom: [
|
||||
line({ series: activity.coindaysDestroyed.cumulative, name: "All-time", color, unit: Unit.coindays }),
|
||||
],
|
||||
},
|
||||
],
|
||||
tree: chartsFromCount({
|
||||
pattern: activity.coindaysDestroyed,
|
||||
title: title("Coindays Destroyed"),
|
||||
unit: Unit.coindays,
|
||||
color,
|
||||
}),
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -87,95 +60,27 @@ function sentProfitLossTree(sent, title) {
|
||||
return [
|
||||
{
|
||||
name: "Sent In Profit",
|
||||
tree: [
|
||||
{
|
||||
name: "USD",
|
||||
title: title("Sent Volume In Profit"),
|
||||
bottom: [
|
||||
line({ series: sent.inProfit.base.usd, name: "Base", color: colors.profit, unit: Unit.usd }),
|
||||
line({ series: sent.inProfit.sum._24h.usd, name: "24h", color: colors.time._24h, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1w.usd, name: "1w", color: colors.time._1w, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1m.usd, name: "1m", color: colors.time._1m, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1y.usd, name: "1y", color: colors.time._1y, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "BTC",
|
||||
title: title("Sent Volume In Profit (BTC)"),
|
||||
bottom: [
|
||||
line({ series: sent.inProfit.base.btc, name: "Base", color: colors.profit, unit: Unit.btc }),
|
||||
line({ series: sent.inProfit.sum._24h.btc, name: "24h", color: colors.time._24h, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1w.btc, name: "1w", color: colors.time._1w, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1m.btc, name: "1m", color: colors.time._1m, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1y.btc, name: "1y", color: colors.time._1y, unit: Unit.btc, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Sats",
|
||||
title: title("Sent Volume In Profit (Sats)"),
|
||||
bottom: [
|
||||
line({ series: sent.inProfit.base.sats, name: "Base", color: colors.profit, unit: Unit.sats }),
|
||||
line({ series: sent.inProfit.sum._24h.sats, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1w.sats, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1m.sats, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inProfit.sum._1y.sats, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{ name: "Cumulative", title: title("Cumulative Sent In Profit"), bottom: [
|
||||
line({ series: sent.inProfit.cumulative.usd, name: "USD", color: colors.profit, unit: Unit.usd }),
|
||||
line({ series: sent.inProfit.cumulative.btc, name: "BTC", color: colors.profit, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inProfit.cumulative.sats, name: "Sats", color: colors.profit, unit: Unit.sats, defaultActive: false }),
|
||||
]},
|
||||
],
|
||||
tree: satsBtcUsdFullTree({
|
||||
pattern: sent.inProfit,
|
||||
name: "In Profit",
|
||||
title: title("Sent Volume In Profit"),
|
||||
color: colors.profit,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Sent In Loss",
|
||||
tree: [
|
||||
{
|
||||
name: "USD",
|
||||
title: title("Sent Volume In Loss"),
|
||||
bottom: [
|
||||
line({ series: sent.inLoss.base.usd, name: "Base", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: sent.inLoss.sum._24h.usd, name: "24h", color: colors.time._24h, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1w.usd, name: "1w", color: colors.time._1w, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1m.usd, name: "1m", color: colors.time._1m, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1y.usd, name: "1y", color: colors.time._1y, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "BTC",
|
||||
title: title("Sent Volume In Loss (BTC)"),
|
||||
bottom: [
|
||||
line({ series: sent.inLoss.base.btc, name: "Base", color: colors.loss, unit: Unit.btc }),
|
||||
line({ series: sent.inLoss.sum._24h.btc, name: "24h", color: colors.time._24h, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1w.btc, name: "1w", color: colors.time._1w, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1m.btc, name: "1m", color: colors.time._1m, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1y.btc, name: "1y", color: colors.time._1y, unit: Unit.btc, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Sats",
|
||||
title: title("Sent Volume In Loss (Sats)"),
|
||||
bottom: [
|
||||
line({ series: sent.inLoss.base.sats, name: "Base", color: colors.loss, unit: Unit.sats }),
|
||||
line({ series: sent.inLoss.sum._24h.sats, name: "24h", color: colors.time._24h, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1w.sats, name: "1w", color: colors.time._1w, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1m.sats, name: "1m", color: colors.time._1m, unit: Unit.sats, defaultActive: false }),
|
||||
line({ series: sent.inLoss.sum._1y.sats, name: "1y", color: colors.time._1y, unit: Unit.sats, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{ name: "Cumulative", title: title("Cumulative Sent In Loss"), bottom: [
|
||||
line({ series: sent.inLoss.cumulative.usd, name: "USD", color: colors.loss, unit: Unit.usd }),
|
||||
line({ series: sent.inLoss.cumulative.btc, name: "BTC", color: colors.loss, unit: Unit.btc, defaultActive: false }),
|
||||
line({ series: sent.inLoss.cumulative.sats, name: "Sats", color: colors.loss, unit: Unit.sats, defaultActive: false }),
|
||||
]},
|
||||
],
|
||||
tree: satsBtcUsdFullTree({
|
||||
pattern: sent.inLoss,
|
||||
name: "In Loss",
|
||||
title: title("Sent Volume In Loss"),
|
||||
color: colors.loss,
|
||||
}),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Volume and coins tree with coinyears, dormancy, and sent in profit/loss (All/STH/LTH)
|
||||
* Volume and coins tree with dormancy, and sent in profit/loss (All/STH/LTH)
|
||||
* @param {FullActivityPattern} activity
|
||||
* @param {Color} color
|
||||
* @param {(name: string) => string} title
|
||||
@@ -185,11 +90,6 @@ function fullVolumeTree(activity, color, title) {
|
||||
return [
|
||||
...volumeAndCoinsTree(activity, color, title),
|
||||
...sentProfitLossTree(activity.transferVolume, title),
|
||||
{
|
||||
name: "Coinyears Destroyed",
|
||||
title: title("Coinyears Destroyed"),
|
||||
bottom: [line({ series: activity.coinyearsDestroyed, name: "CYD", color, unit: Unit.years })],
|
||||
},
|
||||
{
|
||||
name: "Dormancy",
|
||||
title: title("Dormancy"),
|
||||
@@ -212,34 +112,16 @@ function singleRollingSoprTree(ratio, title, prefix = "") {
|
||||
return [
|
||||
{
|
||||
name: "Compare",
|
||||
title: title(`Rolling ${prefix}SOPR`),
|
||||
bottom: [
|
||||
baseline({ series: ratio._24h, name: "24h", color: colors.time._24h, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: ratio._1w, name: "7d", color: colors.time._1w, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: ratio._1m, name: "30d", color: colors.time._1m, unit: Unit.ratio, base: 1 }),
|
||||
baseline({ series: ratio._1y, name: "1y", color: colors.time._1y, unit: Unit.ratio, base: 1 }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "24h",
|
||||
title: title(`${prefix}SOPR (24h)`),
|
||||
bottom: [dotsBaseline({ series: ratio._24h, name: "24h", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title(`${prefix}SOPR (7d)`),
|
||||
bottom: [baseline({ series: ratio._1w, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title(`${prefix}SOPR (30d)`),
|
||||
bottom: [baseline({ series: ratio._1m, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
{
|
||||
name: "1y",
|
||||
title: title(`${prefix}SOPR (1y)`),
|
||||
bottom: [baseline({ series: ratio._1y, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
title: title(`${prefix}SOPR`),
|
||||
bottom: ROLLING_WINDOWS.map((w) =>
|
||||
baseline({ series: ratio[w.key], name: w.name, color: w.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`${prefix}SOPR (${w.title})`),
|
||||
bottom: [baseline({ series: ratio[w.key], name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
})),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -256,173 +138,19 @@ function singleSellSideRiskTree(sellSideRisk, title) {
|
||||
return [
|
||||
{
|
||||
name: "Compare",
|
||||
title: title("Rolling Sell Side Risk"),
|
||||
bottom: [
|
||||
...percentRatioDots({ pattern: sellSideRisk._24h, name: "24h", color: colors.time._24h }),
|
||||
...percentRatio({ pattern: sellSideRisk._1w, name: "7d", color: colors.time._1w }),
|
||||
...percentRatio({ pattern: sellSideRisk._1m, name: "30d", color: colors.time._1m }),
|
||||
...percentRatio({ pattern: sellSideRisk._1y, name: "1y", color: colors.time._1y }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "24h",
|
||||
title: title("Sell Side Risk (24h)"),
|
||||
bottom: percentRatioDots({ pattern: sellSideRisk._24h, name: "Raw", color: colors.bitcoin }),
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title("Sell Side Risk (7d)"),
|
||||
bottom: percentRatio({ pattern: sellSideRisk._1w, name: "Risk" }),
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title("Sell Side Risk (30d)"),
|
||||
bottom: percentRatio({ pattern: sellSideRisk._1m, name: "Risk" }),
|
||||
},
|
||||
{
|
||||
name: "1y",
|
||||
title: title("Sell Side Risk (1y)"),
|
||||
bottom: percentRatio({ pattern: sellSideRisk._1y, name: "Risk" }),
|
||||
title: title("Sell Side Risk"),
|
||||
bottom: ROLLING_WINDOWS.flatMap((w) =>
|
||||
percentRatio({ pattern: sellSideRisk[w.key], name: w.name, color: w.color }),
|
||||
),
|
||||
},
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`Sell Side Risk (${w.title})`),
|
||||
bottom: percentRatio({ pattern: sellSideRisk[w.key], name: "Risk" }),
|
||||
})),
|
||||
];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Shared Value Helpers
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @param {CountPattern<number>} valueCreated
|
||||
* @param {CountPattern<number>} valueDestroyed
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function singleRollingValueTree(valueCreated, valueDestroyed, title, prefix = "") {
|
||||
return [
|
||||
{
|
||||
name: "Compare",
|
||||
tree: [
|
||||
{
|
||||
name: "Created",
|
||||
title: title(`Rolling ${prefix}Value Created`),
|
||||
bottom: [
|
||||
line({ series: valueCreated.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1w, name: "7d", color: colors.time._1w, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1m, name: "30d", color: colors.time._1m, unit: Unit.usd }),
|
||||
line({ series: valueCreated.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Destroyed",
|
||||
title: title(`Rolling ${prefix}Value Destroyed`),
|
||||
bottom: [
|
||||
line({ series: valueDestroyed.sum._24h, name: "24h", color: colors.time._24h, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1w, name: "7d", color: colors.time._1w, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1m, name: "30d", color: colors.time._1m, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1y, name: "1y", color: colors.time._1y, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "24h",
|
||||
title: title(`${prefix}Value Created & Destroyed (24h)`),
|
||||
bottom: [
|
||||
line({ series: valueCreated.sum._24h, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._24h, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title(`${prefix}Value Created & Destroyed (7d)`),
|
||||
bottom: [
|
||||
line({ series: valueCreated.sum._1w, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1w, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title(`${prefix}Value Created & Destroyed (30d)`),
|
||||
bottom: [
|
||||
line({ series: valueCreated.sum._1m, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1m, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "1y",
|
||||
title: title(`${prefix}Value Created & Destroyed (1y)`),
|
||||
bottom: [
|
||||
line({ series: valueCreated.sum._1y, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.sum._1y, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: title(`${prefix}Value Created & Destroyed (Total)`),
|
||||
bottom: [
|
||||
line({ series: valueCreated.cumulative, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.cumulative, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Value section: created & destroyed + rolling
|
||||
* @param {Object} args
|
||||
* @param {CountPattern<number>} args.valueCreated
|
||||
* @param {CountPattern<number>} args.valueDestroyed
|
||||
* @param {AnyFetchedSeriesBlueprint[]} [args.extraValueSeries]
|
||||
* @param {PartialOptionsTree} args.rollingTree
|
||||
* @param {(name: string) => string} args.title
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function fullValueSection({ valueCreated, valueDestroyed, extraValueSeries = [], rollingTree, title }) {
|
||||
return {
|
||||
name: "Value",
|
||||
tree: [
|
||||
{
|
||||
name: "Created & Destroyed",
|
||||
title: title("Value Created & Destroyed"),
|
||||
bottom: [
|
||||
line({ series: valueCreated.base, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
...extraValueSeries,
|
||||
],
|
||||
},
|
||||
{ name: "Rolling", tree: rollingTree },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple value section (created & destroyed + rolling)
|
||||
* @param {CountPattern<number>} valueCreated
|
||||
* @param {CountPattern<number>} valueDestroyed
|
||||
* @param {(name: string) => string} title
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function simpleValueSection(valueCreated, valueDestroyed, title) {
|
||||
return {
|
||||
name: "Value",
|
||||
tree: [
|
||||
{
|
||||
name: "Created & Destroyed",
|
||||
title: title("Value Created & Destroyed"),
|
||||
bottom: [
|
||||
line({ series: valueCreated.base, name: "Created", color: colors.usd, unit: Unit.usd }),
|
||||
line({ series: valueDestroyed.base, name: "Destroyed", color: colors.loss, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: singleRollingValueTree(valueCreated, valueDestroyed, title),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Single Cohort Activity Sections
|
||||
// ============================================================================
|
||||
@@ -444,10 +172,7 @@ export function createActivitySectionWithAdjusted({ cohort, title }) {
|
||||
{
|
||||
name: "SOPR",
|
||||
tree: [
|
||||
{
|
||||
name: "Normal",
|
||||
tree: singleRollingSoprTree(sopr.ratio, title),
|
||||
},
|
||||
...singleRollingSoprTree(sopr.ratio, title),
|
||||
{
|
||||
name: "Adjusted",
|
||||
tree: singleRollingSoprTree(sopr.adjusted.ratio, title, "Adjusted "),
|
||||
@@ -455,25 +180,6 @@ export function createActivitySectionWithAdjusted({ cohort, title }) {
|
||||
],
|
||||
},
|
||||
{ name: "Sell Side Risk", tree: singleSellSideRiskTree(r.sellSideRiskRatio, title) },
|
||||
fullValueSection({
|
||||
valueCreated: sopr.valueCreated,
|
||||
valueDestroyed: sopr.valueDestroyed,
|
||||
extraValueSeries: [
|
||||
line({ series: sopr.adjusted.valueCreated.base, name: "Adjusted Created", color: colors.adjustedCreated, unit: Unit.usd, defaultActive: false }),
|
||||
line({ series: sopr.adjusted.valueDestroyed.base, name: "Adjusted Destroyed", color: colors.adjustedDestroyed, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
rollingTree: [
|
||||
{
|
||||
name: "Normal",
|
||||
tree: singleRollingValueTree(sopr.valueCreated, sopr.valueDestroyed, title),
|
||||
},
|
||||
{
|
||||
name: "Adjusted",
|
||||
tree: singleRollingValueTree(sopr.adjusted.valueCreated, sopr.adjusted.valueDestroyed, title, "Adjusted "),
|
||||
},
|
||||
],
|
||||
title,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -497,12 +203,6 @@ export function createActivitySection({ cohort, title }) {
|
||||
tree: singleRollingSoprTree(sopr.ratio, title),
|
||||
},
|
||||
{ name: "Sell Side Risk", tree: singleSellSideRiskTree(r.sellSideRiskRatio, title) },
|
||||
fullValueSection({
|
||||
valueCreated: sopr.valueCreated,
|
||||
valueDestroyed: sopr.valueDestroyed,
|
||||
rollingTree: singleRollingValueTree(sopr.valueCreated, sopr.valueDestroyed, title),
|
||||
title,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -526,24 +226,42 @@ export function createActivitySectionWithActivity({ cohort, title }) {
|
||||
title: title("SOPR (24h)"),
|
||||
bottom: [dotsBaseline({ series: sopr.ratio._24h, name: "SOPR", unit: Unit.ratio, base: 1 })],
|
||||
},
|
||||
simpleValueSection(sopr.valueCreated, sopr.valueDestroyed, title),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Minimal activity section for cohorts without activity field (value only)
|
||||
* Minimal activity section: volume only
|
||||
* @param {{ cohort: CohortBasicWithMarketCap | CohortBasicWithoutMarketCap | CohortWithoutRelative | CohortAddr | AddrCohortObject, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createActivitySectionMinimal({ cohort, title }) {
|
||||
const sopr = cohort.tree.realized.sopr;
|
||||
|
||||
return {
|
||||
name: "Activity",
|
||||
tree: [
|
||||
simpleValueSection(sopr.valueCreated, sopr.valueDestroyed, title),
|
||||
],
|
||||
tree: chartsFromCount({
|
||||
pattern: cohort.tree.realized.sopr.valueCreated,
|
||||
title: title("Volume"),
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Grouped minimal activity: volume
|
||||
* @param {{ list: readonly (UtxoCohortObject | CohortWithoutRelative | CohortAddr | AddrCohortObject)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedActivitySectionMinimal({ list, all, title }) {
|
||||
return {
|
||||
name: "Activity",
|
||||
tree: ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`Volume (${w.title})`),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
line({ series: tree.realized.sopr.valueCreated.sum[w.key], name, color, unit: Unit.usd }),
|
||||
),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -556,83 +274,19 @@ export function createActivitySectionMinimal({ cohort, title }) {
|
||||
* @template {{ color: Color, name: string }} A
|
||||
* @param {readonly T[]} list
|
||||
* @param {A} all
|
||||
* @param {(item: T | A) => AnySeriesPattern} getRaw
|
||||
* @param {(item: T | A) => AnySeriesPattern} get7d
|
||||
* @param {(item: T | A) => AnySeriesPattern} get30d
|
||||
* @param {(item: T | A) => { _24h: AnySeriesPattern, _1w: AnySeriesPattern, _1m: AnySeriesPattern, _1y: AnySeriesPattern }} getRatio
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function groupedSoprCharts(list, all, getRaw, get7d, get30d, title, prefix = "") {
|
||||
return [
|
||||
{
|
||||
name: "Raw",
|
||||
title: title(`${prefix}SOPR`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
baseline({ series: getRaw(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title(`${prefix}SOPR (7d)`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
baseline({ series: get7d(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title(`${prefix}SOPR (30d)`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
baseline({ series: get30d(item), name: item.name, color: item.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @template {{ color: Color, name: string }} T
|
||||
* @template {{ color: Color, name: string }} A
|
||||
* @param {readonly T[]} list
|
||||
* @param {A} all
|
||||
* @param {(item: T | A) => AnySeriesPattern} get24h
|
||||
* @param {(item: T | A) => AnySeriesPattern} get7d
|
||||
* @param {(item: T | A) => AnySeriesPattern} get30d
|
||||
* @param {(item: T | A) => AnySeriesPattern} get1y
|
||||
* @param {(name: string) => string} title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function groupedRollingSoprCharts(list, all, get24h, get7d, get30d, get1y, title, prefix = "") {
|
||||
return [
|
||||
{
|
||||
name: "24h",
|
||||
title: title(`${prefix}SOPR (24h)`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ series: get24h(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "7d",
|
||||
title: title(`${prefix}SOPR (7d)`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ series: get7d(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "30d",
|
||||
title: title(`${prefix}SOPR (30d)`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ series: get30d(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "1y",
|
||||
title: title(`${prefix}SOPR (1y)`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ series: get1y(c), name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
];
|
||||
function groupedSoprCharts(list, all, getRatio, title, prefix = "") {
|
||||
return ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`${prefix}SOPR (${w.title})`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
baseline({ series: getRatio(c)[w.key], name: c.name, color: c.color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -649,43 +303,7 @@ function groupedRollingSoprCharts(list, all, get24h, get7d, get30d, get1y, title
|
||||
* @param {string} [prefix]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function groupedRollingValueCharts(list, all, windows, title, prefix = "") {
|
||||
return [
|
||||
{
|
||||
name: "Created",
|
||||
tree: windows.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`${prefix}Value Created (${w.title})`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
line({ series: w.getCreated(item), name: item.name, color: item.color, unit: Unit.usd }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
{
|
||||
name: "Destroyed",
|
||||
tree: windows.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`${prefix}Value Destroyed (${w.title})`),
|
||||
bottom: mapCohortsWithAll(list, all, (item) =>
|
||||
line({ series: w.getDestroyed(item), name: item.name, color: item.color, unit: Unit.usd }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {readonly (CohortFull | CohortLongTerm | CohortAll)[]} list
|
||||
* @param {CohortAll} all
|
||||
*/
|
||||
function valueWindows(list, all) {
|
||||
return [
|
||||
{ name: "24h", title: "Daily", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._24h, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._24h },
|
||||
{ name: "7d", title: "Weekly", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1w, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1w },
|
||||
{ name: "30d", title: "Monthly", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1m, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1m },
|
||||
{ name: "1y", title: "Yearly", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1y, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1y },
|
||||
];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Grouped Activity Sections
|
||||
@@ -709,94 +327,22 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
|
||||
{
|
||||
name: "SOPR",
|
||||
tree: [
|
||||
{
|
||||
name: "Normal",
|
||||
tree: [
|
||||
...groupedSoprCharts(
|
||||
list, all,
|
||||
(c) => c.tree.realized.sopr.ratio._24h,
|
||||
(c) => c.tree.realized.sopr.ratio._1w,
|
||||
(c) => c.tree.realized.sopr.ratio._1m,
|
||||
title,
|
||||
),
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: groupedRollingSoprCharts(
|
||||
list, all,
|
||||
(c) => c.tree.realized.sopr.ratio._24h,
|
||||
(c) => c.tree.realized.sopr.ratio._1w,
|
||||
(c) => c.tree.realized.sopr.ratio._1m,
|
||||
(c) => c.tree.realized.sopr.ratio._1y,
|
||||
title,
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
...groupedSoprCharts(list, all, (c) => c.tree.realized.sopr.ratio, title),
|
||||
{
|
||||
name: "Adjusted",
|
||||
tree: [
|
||||
...groupedSoprCharts(
|
||||
list, all,
|
||||
(c) => c.tree.realized.sopr.adjusted.ratio._24h,
|
||||
(c) => c.tree.realized.sopr.adjusted.ratio._1w,
|
||||
(c) => c.tree.realized.sopr.adjusted.ratio._1m,
|
||||
title,
|
||||
"Adjusted ",
|
||||
),
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: groupedRollingSoprCharts(
|
||||
list, all,
|
||||
(c) => c.tree.realized.sopr.adjusted.ratio._24h,
|
||||
(c) => c.tree.realized.sopr.adjusted.ratio._1w,
|
||||
(c) => c.tree.realized.sopr.adjusted.ratio._1m,
|
||||
(c) => c.tree.realized.sopr.adjusted.ratio._1y,
|
||||
title,
|
||||
"Adjusted ",
|
||||
),
|
||||
},
|
||||
],
|
||||
tree: groupedSoprCharts(list, all, (c) => c.tree.realized.sopr.adjusted.ratio, title, "Adjusted "),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Sell Side Risk",
|
||||
tree: [
|
||||
{ name: "24h", title: title("Sell Side Risk (24h)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._24h.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "7d", title: title("Sell Side Risk (7d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1w.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "30d", title: title("Sell Side Risk (30d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1m.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "1y", title: title("Sell Side Risk (1y)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1y.ratio, name, color, unit: Unit.ratio })) },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Value",
|
||||
tree: [
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: [
|
||||
{
|
||||
name: "Normal",
|
||||
tree: groupedRollingValueCharts(list, all, valueWindows(list, all), title),
|
||||
},
|
||||
{
|
||||
name: "Adjusted",
|
||||
tree: groupedRollingValueCharts(
|
||||
list, all,
|
||||
[
|
||||
{ name: "24h", title: "Daily", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._24h, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._24h },
|
||||
{ name: "7d", title: "Weekly", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1w, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1w },
|
||||
{ name: "30d", title: "Monthly", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1m, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1m },
|
||||
{ name: "1y", title: "Yearly", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1y, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1y },
|
||||
],
|
||||
title,
|
||||
"Adjusted ",
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
tree: ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`Sell Side Risk (${w.title})`),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
line({ series: tree.realized.sellSideRiskRatio[w.key].ratio, name, color, unit: Unit.ratio }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
{
|
||||
name: "Coindays Destroyed",
|
||||
@@ -828,45 +374,18 @@ export function createGroupedActivitySection({ list, all, title }) {
|
||||
{
|
||||
name: "SOPR",
|
||||
tree: [
|
||||
...groupedSoprCharts(
|
||||
list, all,
|
||||
(c) => c.tree.realized.sopr.ratio._24h,
|
||||
(c) => c.tree.realized.sopr.ratio._1w,
|
||||
(c) => c.tree.realized.sopr.ratio._1m,
|
||||
title,
|
||||
),
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: groupedRollingSoprCharts(
|
||||
list, all,
|
||||
(c) => c.tree.realized.sopr.ratio._24h,
|
||||
(c) => c.tree.realized.sopr.ratio._1w,
|
||||
(c) => c.tree.realized.sopr.ratio._1m,
|
||||
(c) => c.tree.realized.sopr.ratio._1y,
|
||||
title,
|
||||
),
|
||||
},
|
||||
...groupedSoprCharts(list, all, (c) => c.tree.realized.sopr.ratio, title),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Sell Side Risk",
|
||||
tree: [
|
||||
{ name: "24h", title: title("Sell Side Risk (24h)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._24h.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "7d", title: title("Sell Side Risk (7d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1w.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "30d", title: title("Sell Side Risk (30d)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1m.ratio, name, color, unit: Unit.ratio })) },
|
||||
{ name: "1y", title: title("Sell Side Risk (1y)"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sellSideRiskRatio._1y.ratio, name, color, unit: Unit.ratio })) },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Value",
|
||||
tree: [
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
{
|
||||
name: "Rolling",
|
||||
tree: groupedRollingValueCharts(list, all, valueWindows(list, all), title),
|
||||
},
|
||||
],
|
||||
tree: ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`Sell Side Risk (${w.title})`),
|
||||
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
|
||||
line({ series: tree.realized.sellSideRiskRatio[w.key].ratio, name, color, unit: Unit.ratio }),
|
||||
),
|
||||
})),
|
||||
},
|
||||
{
|
||||
name: "Coindays Destroyed",
|
||||
@@ -902,13 +421,6 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) {
|
||||
baseline({ series: tree.realized.sopr.ratio._24h, name, color, unit: Unit.ratio, base: 1 }),
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Value",
|
||||
tree: [
|
||||
{ name: "Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Coindays Destroyed",
|
||||
title: title("Coindays Destroyed"),
|
||||
@@ -920,17 +432,3 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Grouped minimal activity (value only, no activity field)
|
||||
* @param {{ list: readonly (UtxoCohortObject | CohortWithoutRelative | CohortAddr | AddrCohortObject)[], all: CohortAll, title: (name: string) => string }} args
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createGroupedActivitySectionMinimal({ list, all, title }) {
|
||||
return {
|
||||
name: "Activity",
|
||||
tree: [
|
||||
{ name: "Value Created", title: title("Value Created"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueCreated.base, name, color, unit: Unit.usd })) },
|
||||
{ name: "Value Destroyed", title: title("Value Destroyed"), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.sopr.valueDestroyed.base, name, color, unit: Unit.usd })) },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -66,10 +66,10 @@ import {
|
||||
createActivitySection,
|
||||
createActivitySectionWithAdjusted,
|
||||
createActivitySectionWithActivity,
|
||||
createActivitySectionMinimal,
|
||||
createGroupedActivitySection,
|
||||
createGroupedActivitySectionWithAdjusted,
|
||||
createGroupedActivitySectionWithActivity,
|
||||
createActivitySectionMinimal,
|
||||
createGroupedActivitySectionMinimal,
|
||||
} from "./activity.js";
|
||||
|
||||
|
||||
@@ -369,7 +369,7 @@ function realizedNetFolder({ netPnl, title, toRcap, extraChange = [] }) {
|
||||
* @param {{ sum: Record<string, { usd: AnySeriesPattern }>, negative: { sum: Record<string, AnySeriesPattern> } }} args.loss
|
||||
* @param {{ sum: Record<string, { usd: AnySeriesPattern }> }} args.netPnl
|
||||
* @param {{ sum: Record<string, { usd: AnySeriesPattern }> }} [args.grossPnl]
|
||||
* @param {{ sum: Record<string, AnySeriesPattern> }} [args.peakRegret]
|
||||
* @param {{ sum: Record<string, { usd: AnySeriesPattern }> }} [args.peakRegret]
|
||||
* @param {(name: string) => string} args.title
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
|
||||
@@ -60,14 +60,10 @@
|
||||
* @typedef {Brk.BpsCentsPercentilesRatioSatsUsdPattern} PriceRatioPercentilesPattern
|
||||
* AnyRatioPattern: full ratio pattern with percentiles, SMAs, and std dev bands
|
||||
* @typedef {Brk.BpsCentsPercentilesRatioSatsSmaStdUsdPattern} AnyRatioPattern
|
||||
* ValuePattern: patterns with base + cumulative (no rolling)
|
||||
* @typedef {Brk.BaseCumulativeSumPattern<number> | Brk.BaseCumulativeToPattern} ValuePattern
|
||||
* FullValuePattern: base + cumulative + rolling windows (flattened)
|
||||
* @typedef {Brk.BaseCumulativeSumPattern4} FullValuePattern
|
||||
* RollingWindowSlot: a single rolling window with stats (average, pct10, pct25, median, pct75, pct90, max, min) per unit
|
||||
* @typedef {Brk.AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern<number>} RollingWindowSlot
|
||||
* AnyValuePatternType: union of all value pattern types
|
||||
* @typedef {Brk.BaseCumulativeSumPattern4 | Brk.BaseCumulativeSumPattern<number> | Brk.BaseCumulativeToPattern} AnyValuePatternType
|
||||
* @typedef {Brk.AnySeriesPattern} AnySeriesPattern
|
||||
* @typedef {Brk.CentsSatsUsdPattern} ActivePricePattern
|
||||
* @typedef {Brk.AnySeriesEndpoint} AnySeriesEndpoint
|
||||
@@ -101,11 +97,6 @@
|
||||
* Full activity pattern (coindays, coinyears, dormancy, transfer volume)
|
||||
* @typedef {Brk.CoindaysCoinyearsDormancyTransferPattern} FullActivityPattern
|
||||
*
|
||||
* Profit distribution detail (base + cumulative + distribution flow + rel + sum + value)
|
||||
* @typedef {Brk.BaseCumulativeDistributionSumToValuePattern} ProfitDetailPattern
|
||||
*
|
||||
* Loss detail with capitulation (base + capitulation + cumulative + negative + rel + sum + value)
|
||||
* @typedef {Brk.BaseCapitulationCumulativeNegativeSumToValuePattern} LossDetailPattern
|
||||
*
|
||||
* BPS + ratio pattern (for NUPL and similar)
|
||||
* @typedef {Brk.BpsRatioPattern} NuplPattern
|
||||
|
||||
Reference in New Issue
Block a user