From 2991562234208ec86690908ea9a5344478690a57 Mon Sep 17 00:00:00 2001 From: nym21 Date: Sat, 21 Mar 2026 17:15:53 +0100 Subject: [PATCH] global: snapshot part 16 --- crates/brk_client/src/lib.rs | 119 ++++++------- .../src/distribution/compute/block_loop.rs | 4 +- .../src/distribution/metrics/realized/core.rs | 8 +- crates/brk_computer/src/indicators/compute.rs | 2 +- .../internal/per_block/amount/cumulative.rs | 15 +- .../internal/per_block/computed/aggregated.rs | 20 +-- crates/brk_computer/src/market/compute.rs | 3 +- .../src/market/technical/compute.rs | 29 +-- .../src/market/technical/import.rs | 5 - .../brk_computer/src/market/technical/vecs.rs | 10 +- .../src/mining/rewards/compute.rs | 7 - .../brk_computer/src/mining/rewards/import.rs | 3 +- .../brk_computer/src/mining/rewards/vecs.rs | 7 +- crates/brk_computer/src/scripts/import.rs | 2 +- .../brk_computer/src/scripts/value/compute.rs | 2 +- .../brk_computer/src/scripts/value/import.rs | 6 +- crates/brk_computer/src/scripts/value/vecs.rs | 4 +- .../brk_computer/src/supply/burned/compute.rs | 53 ++---- .../brk_computer/src/supply/burned/import.rs | 6 +- crates/brk_computer/src/supply/burned/vecs.rs | 4 +- crates/brk_computer/src/supply/import.rs | 2 +- modules/brk-client/index.js | 124 ++++++------- packages/brk_client/brk_client/__init__.py | 59 +++---- .../scripts/options/distribution/activity.js | 18 +- .../options/distribution/cost-basis.js | 2 +- .../scripts/options/distribution/holdings.js | 29 +-- website/scripts/options/distribution/index.js | 25 +-- .../options/distribution/profitability.js | 167 +++++++++++------- .../scripts/options/distribution/valuation.js | 4 +- website/scripts/options/mining.js | 4 +- website/scripts/options/unused.js | 35 ++-- 31 files changed, 355 insertions(+), 423 deletions(-) diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index d7533f6ad..045acb18c 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -1134,38 +1134,6 @@ pub struct AverageBaseCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern { pub sum: _1m1w1y24hPattern, } -/// Pattern struct for repeated tree structure. -pub struct AverageGainsLossesRsiStochPattern { - pub average_gain: SeriesPattern1, - pub average_loss: SeriesPattern1, - pub gains: SeriesPattern1, - pub losses: SeriesPattern1, - pub rsi: BpsPercentRatioPattern3, - pub rsi_max: BpsPercentRatioPattern3, - pub rsi_min: BpsPercentRatioPattern3, - pub stoch_rsi: BpsPercentRatioPattern3, - pub stoch_rsi_d: BpsPercentRatioPattern3, - pub stoch_rsi_k: BpsPercentRatioPattern3, -} - -impl AverageGainsLossesRsiStochPattern { - /// Create a new pattern node with accumulated series name. - pub fn new(client: Arc, acc: String, disc: String) -> Self { - Self { - average_gain: SeriesPattern1::new(client.clone(), _m(&acc, &format!("average_gain_{disc}", disc=disc))), - average_loss: SeriesPattern1::new(client.clone(), _m(&acc, &format!("average_loss_{disc}", disc=disc))), - gains: SeriesPattern1::new(client.clone(), _m(&acc, &format!("gains_{disc}", disc=disc))), - losses: SeriesPattern1::new(client.clone(), _m(&acc, &format!("losses_{disc}", disc=disc))), - rsi: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &disc)), - rsi_max: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &format!("max_{disc}", disc=disc))), - rsi_min: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &format!("min_{disc}", disc=disc))), - stoch_rsi: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &format!("stoch_{disc}", disc=disc))), - stoch_rsi_d: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &format!("stoch_d_{disc}", disc=disc))), - stoch_rsi_k: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &format!("stoch_k_{disc}", disc=disc))), - } - } -} - /// Pattern struct for repeated tree structure. pub struct AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 { pub all: SeriesPattern1, @@ -2528,7 +2496,7 @@ impl CentsSatsUsdPattern { pub struct CumulativeRollingSumPattern { pub cumulative: SeriesPattern1, pub rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern, - pub sum: SeriesPattern1, + pub sum: SeriesPattern18, } impl CumulativeRollingSumPattern { @@ -2537,7 +2505,7 @@ impl CumulativeRollingSumPattern { Self { cumulative: SeriesPattern1::new(client.clone(), _m(&acc, "cumulative")), rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), acc.clone()), - sum: SeriesPattern1::new(client.clone(), _m(&acc, "sum")), + sum: SeriesPattern18::new(client.clone(), _m(&acc, "sum")), } } } @@ -2592,6 +2560,24 @@ pub struct RatioTransferValuePattern { pub value_destroyed: AverageBlockCumulativeSumPattern, } +/// Pattern struct for repeated tree structure. +pub struct RsiStochPattern { + pub rsi: BpsPercentRatioPattern3, + pub stoch_rsi_d: BpsPercentRatioPattern3, + pub stoch_rsi_k: BpsPercentRatioPattern3, +} + +impl RsiStochPattern { + /// Create a new pattern node with accumulated series name. + pub fn new(client: Arc, acc: String, disc: String) -> Self { + Self { + rsi: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &disc)), + stoch_rsi_d: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &format!("stoch_d_{disc}", disc=disc))), + stoch_rsi_k: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, &format!("stoch_k_{disc}", disc=disc))), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _6bBlockTxPattern { pub _6b: MaxMedianMinPct10Pct25Pct75Pct90Pattern, @@ -2676,7 +2662,7 @@ impl AllSthPattern { /// Pattern struct for repeated tree structure. pub struct BaseSumPattern { - pub base: SeriesPattern1, + pub base: SeriesPattern18, pub sum: _1m1w1y24hPattern, } @@ -2684,7 +2670,7 @@ impl BaseSumPattern { /// Create a new pattern node with accumulated series name. pub fn new(client: Arc, acc: String) -> Self { Self { - base: SeriesPattern1::new(client.clone(), acc.clone()), + base: SeriesPattern18::new(client.clone(), acc.clone()), sum: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "sum")), } } @@ -2706,6 +2692,22 @@ impl BaseDeltaPattern { } } +/// Pattern struct for repeated tree structure. +pub struct BlockCumulativePattern { + pub block: BtcCentsSatsUsdPattern2, + pub cumulative: BtcCentsSatsUsdPattern3, +} + +impl BlockCumulativePattern { + /// Create a new pattern node with accumulated series name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + block: BtcCentsSatsUsdPattern2::new(client.clone(), acc.clone()), + cumulative: BtcCentsSatsUsdPattern3::new(client.clone(), _m(&acc, "cumulative")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct BlocksDominancePattern { pub blocks_mined: AverageBlockCumulativeSumPattern2, @@ -4076,13 +4078,13 @@ impl SeriesTree_Scripts_Count { /// Series tree node. pub struct SeriesTree_Scripts_Value { - pub op_return: AverageBlockCumulativeSumPattern3, + pub op_return: BlockCumulativePattern, } impl SeriesTree_Scripts_Value { pub fn new(client: Arc, base_path: String) -> Self { Self { - op_return: AverageBlockCumulativeSumPattern3::new(client.clone(), "op_return_value".to_string()), + op_return: BlockCumulativePattern::new(client.clone(), "op_return_value".to_string()), } } } @@ -4107,7 +4109,7 @@ pub struct SeriesTree_Mining_Rewards { pub coinbase: AverageBlockCumulativeSumPattern3, pub subsidy: SeriesTree_Mining_Rewards_Subsidy, pub fees: SeriesTree_Mining_Rewards_Fees, - pub unclaimed: SeriesTree_Mining_Rewards_Unclaimed, + pub unclaimed: BlockCumulativePattern, } impl SeriesTree_Mining_Rewards { @@ -4116,7 +4118,7 @@ impl SeriesTree_Mining_Rewards { coinbase: AverageBlockCumulativeSumPattern3::new(client.clone(), "coinbase".to_string()), subsidy: SeriesTree_Mining_Rewards_Subsidy::new(client.clone(), format!("{base_path}_subsidy")), fees: SeriesTree_Mining_Rewards_Fees::new(client.clone(), format!("{base_path}_fees")), - unclaimed: SeriesTree_Mining_Rewards_Unclaimed::new(client.clone(), format!("{base_path}_unclaimed")), + unclaimed: BlockCumulativePattern::new(client.clone(), "unclaimed_rewards".to_string()), } } } @@ -4128,7 +4130,6 @@ pub struct SeriesTree_Mining_Rewards_Subsidy { pub sum: _1m1w1y24hPattern4, pub average: _1m1w1y24hPattern3, pub dominance: _1m1w1y24hBpsPercentRatioPattern, - pub sma_1y: CentsUsdPattern3, } impl SeriesTree_Mining_Rewards_Subsidy { @@ -4139,7 +4140,6 @@ impl SeriesTree_Mining_Rewards_Subsidy { sum: _1m1w1y24hPattern4::new(client.clone(), "subsidy_sum".to_string()), average: _1m1w1y24hPattern3::new(client.clone(), "subsidy_average".to_string()), dominance: _1m1w1y24hBpsPercentRatioPattern::new(client.clone(), "subsidy_dominance".to_string()), - sma_1y: CentsUsdPattern3::new(client.clone(), "subsidy_sma_1y".to_string()), } } } @@ -4200,21 +4200,6 @@ impl SeriesTree_Mining_Rewards_Fees_ToSubsidyRatio { } } -/// Series tree node. -pub struct SeriesTree_Mining_Rewards_Unclaimed { - pub block: BtcCentsSatsUsdPattern2, - pub cumulative: BtcCentsSatsUsdPattern3, -} - -impl SeriesTree_Mining_Rewards_Unclaimed { - pub fn new(client: Arc, base_path: String) -> Self { - Self { - block: BtcCentsSatsUsdPattern2::new(client.clone(), "unclaimed_rewards".to_string()), - cumulative: BtcCentsSatsUsdPattern3::new(client.clone(), "unclaimed_rewards_cumulative".to_string()), - } - } -} - /// Series tree node. pub struct SeriesTree_Mining_Hashrate { pub rate: SeriesTree_Mining_Hashrate_Rate, @@ -5715,8 +5700,6 @@ impl SeriesTree_Market_Dca_Class_Return { /// Series tree node. pub struct SeriesTree_Market_Technical { pub rsi: SeriesTree_Market_Technical_Rsi, - pub stoch_k: BpsPercentRatioPattern3, - pub stoch_d: BpsPercentRatioPattern3, pub pi_cycle: BpsRatioPattern2, pub macd: SeriesTree_Market_Technical_Macd, } @@ -5725,8 +5708,6 @@ impl SeriesTree_Market_Technical { pub fn new(client: Arc, base_path: String) -> Self { Self { rsi: SeriesTree_Market_Technical_Rsi::new(client.clone(), format!("{base_path}_rsi")), - stoch_k: BpsPercentRatioPattern3::new(client.clone(), "stoch_k".to_string()), - stoch_d: BpsPercentRatioPattern3::new(client.clone(), "stoch_d".to_string()), pi_cycle: BpsRatioPattern2::new(client.clone(), "pi_cycle".to_string()), macd: SeriesTree_Market_Technical_Macd::new(client.clone(), format!("{base_path}_macd")), } @@ -5735,17 +5716,17 @@ impl SeriesTree_Market_Technical { /// Series tree node. pub struct SeriesTree_Market_Technical_Rsi { - pub _24h: AverageGainsLossesRsiStochPattern, - pub _1w: AverageGainsLossesRsiStochPattern, - pub _1m: AverageGainsLossesRsiStochPattern, + pub _24h: RsiStochPattern, + pub _1w: RsiStochPattern, + pub _1m: RsiStochPattern, } impl SeriesTree_Market_Technical_Rsi { pub fn new(client: Arc, base_path: String) -> Self { Self { - _24h: AverageGainsLossesRsiStochPattern::new(client.clone(), "rsi".to_string(), "24h".to_string()), - _1w: AverageGainsLossesRsiStochPattern::new(client.clone(), "rsi".to_string(), "1w".to_string()), - _1m: AverageGainsLossesRsiStochPattern::new(client.clone(), "rsi".to_string(), "1m".to_string()), + _24h: RsiStochPattern::new(client.clone(), "rsi".to_string(), "24h".to_string()), + _1w: RsiStochPattern::new(client.clone(), "rsi".to_string(), "1w".to_string()), + _1m: RsiStochPattern::new(client.clone(), "rsi".to_string(), "1m".to_string()), } } } @@ -6267,7 +6248,7 @@ impl SeriesTree_Prices_Spot { pub struct SeriesTree_Supply { pub state: SeriesPattern18, pub circulating: BtcCentsSatsUsdPattern3, - pub burned: AverageBlockCumulativeSumPattern3, + pub burned: BlockCumulativePattern, pub inflation_rate: BpsPercentRatioPattern, pub velocity: SeriesTree_Supply_Velocity, pub market_cap: CentsDeltaUsdPattern, @@ -6280,7 +6261,7 @@ impl SeriesTree_Supply { Self { state: SeriesPattern18::new(client.clone(), "supply_state".to_string()), circulating: BtcCentsSatsUsdPattern3::new(client.clone(), "circulating_supply".to_string()), - burned: AverageBlockCumulativeSumPattern3::new(client.clone(), "unspendable_supply".to_string()), + burned: BlockCumulativePattern::new(client.clone(), "unspendable_supply".to_string()), inflation_rate: BpsPercentRatioPattern::new(client.clone(), "inflation_rate".to_string()), velocity: SeriesTree_Supply_Velocity::new(client.clone(), format!("{base_path}_velocity")), market_cap: CentsDeltaUsdPattern::new(client.clone(), "market_cap".to_string()), diff --git a/crates/brk_computer/src/distribution/compute/block_loop.rs b/crates/brk_computer/src/distribution/compute/block_loop.rs index dd808e91c..02fe88101 100644 --- a/crates/brk_computer/src/distribution/compute/block_loop.rs +++ b/crates/brk_computer/src/distribution/compute/block_loop.rs @@ -67,8 +67,8 @@ pub(crate) fn process_blocks( let height_to_first_txout_index = &indexer.vecs.outputs.first_txout_index; let height_to_first_txin_index = &indexer.vecs.inputs.first_txin_index; let height_to_tx_count = &transactions.count.total.block; - let height_to_output_count = &outputs.count.total.sum.height; - let height_to_input_count = &inputs.count.sum.height; + let height_to_output_count = &outputs.count.total.sum; + let height_to_input_count = &inputs.count.sum; let tx_index_to_output_count = &indexes.tx_index.output_count; let tx_index_to_input_count = &indexes.tx_index.input_count; diff --git a/crates/brk_computer/src/distribution/metrics/realized/core.rs b/crates/brk_computer/src/distribution/metrics/realized/core.rs index 7f8de1601..0bbefc0db 100644 --- a/crates/brk_computer/src/distribution/metrics/realized/core.rs +++ b/crates/brk_computer/src/distribution/metrics/realized/core.rs @@ -3,7 +3,8 @@ 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, WritableVec, + AnyStoredVec, Exit, LazyVecFrom1, ReadableCloneableVec, ReadableVec, Rw, StorageMode, + WritableVec, }; use crate::{ @@ -22,7 +23,7 @@ use super::RealizedMinimal; #[derive(Clone, Traversable)] pub struct NegRealizedLoss { #[traversable(flatten)] - pub base: LazyPerBlock, + pub base: LazyVecFrom1, pub sum: Windows>, } @@ -51,11 +52,10 @@ impl RealizedCore { let minimal = RealizedMinimal::forced_import(cfg)?; - let neg_loss_base = LazyPerBlock::from_height_source::( + let neg_loss_base = LazyVecFrom1::transformed::( &cfg.name("realized_loss_neg"), cfg.version + Version::ONE, minimal.loss.block.cents.read_only_boxed_clone(), - cfg.indexes, ); let neg_loss_sum = minimal.loss.sum.0.map_with_suffix(|suffix, slot| { diff --git a/crates/brk_computer/src/indicators/compute.rs b/crates/brk_computer/src/indicators/compute.rs index b7c7f1384..e540db7e0 100644 --- a/crates/brk_computer/src/indicators/compute.rs +++ b/crates/brk_computer/src/indicators/compute.rs @@ -22,7 +22,7 @@ impl Vecs { .compute_binary::( starting_indexes.height, &mining.rewards.subsidy.block.usd, - &mining.rewards.subsidy_sma_1y.usd.height, + &mining.rewards.subsidy.average._1y.usd.height, exit, )?; diff --git a/crates/brk_computer/src/internal/per_block/amount/cumulative.rs b/crates/brk_computer/src/internal/per_block/amount/cumulative.rs index 7ec2d0b28..eac036da5 100644 --- a/crates/brk_computer/src/internal/per_block/amount/cumulative.rs +++ b/crates/brk_computer/src/internal/per_block/amount/cumulative.rs @@ -1,7 +1,7 @@ use brk_error::Result; use brk_traversable::Traversable; -use brk_types::{Height, Version}; -use vecdb::{Database, Exit, Rw, StorageMode}; +use brk_types::{Height, Sats, Version}; +use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode}; use crate::{ indexes, @@ -57,4 +57,15 @@ impl AmountPerBlockCumulative { Ok(()) } + + pub(crate) fn compute_with( + &mut self, + max_from: Height, + prices: &prices::Vecs, + exit: &Exit, + compute_sats: impl FnOnce(&mut EagerVec>) -> Result<()>, + ) -> Result<()> { + compute_sats(&mut self.block.sats)?; + self.compute(prices, max_from, exit) + } } diff --git a/crates/brk_computer/src/internal/per_block/computed/aggregated.rs b/crates/brk_computer/src/internal/per_block/computed/aggregated.rs index 42bb81948..4b9f7b3f1 100644 --- a/crates/brk_computer/src/internal/per_block/computed/aggregated.rs +++ b/crates/brk_computer/src/internal/per_block/computed/aggregated.rs @@ -3,8 +3,8 @@ use brk_traversable::Traversable; use brk_types::Height; use schemars::JsonSchema; use vecdb::{ - AnyStoredVec, AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, VecIndex, VecValue, - Version, WritableVec, + AnyStoredVec, AnyVec, Database, EagerVec, Exit, ImportableVec, PcoVec, ReadableVec, Rw, + StorageMode, VecIndex, VecValue, Version, WritableVec, }; use crate::{ @@ -17,7 +17,7 @@ pub struct PerBlockAggregated where T: NumericValue + JsonSchema, { - pub sum: PerBlock, + pub sum: M::Stored>>, pub cumulative: PerBlock, pub rolling: RollingComplete, } @@ -33,7 +33,7 @@ where indexes: &indexes::Vecs, cached_starts: &CachedWindowStarts, ) -> Result { - let sum = PerBlock::forced_import(db, &format!("{name}_sum"), version, indexes)?; + let sum = EagerVec::forced_import(db, &format!("{name}_sum"), version)?; let cumulative = PerBlock::forced_import(db, &format!("{name}_cumulative"), version, indexes)?; let rolling = RollingComplete::forced_import( @@ -73,9 +73,8 @@ where let mut index = max_from; index = { self.sum - .height .validate_computed_version_or_reset(combined_version)?; - index.min(Height::from(self.sum.height.len())) + index.min(Height::from(self.sum.len())) }; index = { self.cumulative @@ -86,7 +85,7 @@ where let start = index.to_usize(); - self.sum.height.truncate_if_needed_at(start)?; + self.sum.truncate_if_needed_at(start)?; self.cumulative.height.truncate_if_needed_at(start)?; let mut cumulative_val = index.decremented().map_or(T::from(0_usize), |idx| { @@ -117,7 +116,7 @@ where |acc, val| acc + val, ); - self.sum.height.push(sum_val); + self.sum.push(sum_val); cumulative_val += sum_val; self.cumulative.height.push(cumulative_val); @@ -125,12 +124,11 @@ where })?; let _lock = exit.lock(); - self.sum.height.write()?; + self.sum.write()?; self.cumulative.height.write()?; drop(_lock); - self.rolling - .compute(max_from, windows, &self.sum.height, exit)?; + self.rolling.compute(max_from, windows, &self.sum, exit)?; Ok(()) } } diff --git a/crates/brk_computer/src/market/compute.rs b/crates/brk_computer/src/market/compute.rs index 3e4258779..bfb333e0b 100644 --- a/crates/brk_computer/src/market/compute.rs +++ b/crates/brk_computer/src/market/compute.rs @@ -58,10 +58,9 @@ impl Vecs { r3?; r4?; - // Phase 3: Depends on returns, range, moving_average + // Phase 3: Depends on returns, moving_average self.technical.compute( &self.returns, - &self.range, prices, blocks, &self.moving_average, diff --git a/crates/brk_computer/src/market/technical/compute.rs b/crates/brk_computer/src/market/technical/compute.rs index f70d0e98d..65ca6a97f 100644 --- a/crates/brk_computer/src/market/technical/compute.rs +++ b/crates/brk_computer/src/market/technical/compute.rs @@ -1,9 +1,9 @@ use brk_error::Result; -use brk_types::{BasisPoints16, Dollars, Indexes}; +use brk_types::{Dollars, Indexes}; use vecdb::Exit; use super::{ - super::{moving_average, range, returns}, + super::{moving_average, returns}, Vecs, macd, rsi, }; use crate::{blocks, internal::{RatioDollarsBp32, WindowsTo1m}, prices}; @@ -13,37 +13,12 @@ impl Vecs { pub(crate) fn compute( &mut self, returns: &returns::Vecs, - range: &range::Vecs, prices: &prices::Vecs, blocks: &blocks::Vecs, moving_average: &moving_average::Vecs, starting_indexes: &Indexes, exit: &Exit, ) -> Result<()> { - self.stoch_k.bps.height.compute_transform3( - starting_indexes.height, - &prices.spot.usd.height, - &range.min._2w.usd.height, - &range.max._2w.usd.height, - |(h, close, low, high, ..)| { - let range = *high - *low; - let stoch = if range == 0.0 { - BasisPoints16::ZERO - } else { - BasisPoints16::from((*close - *low) / range) - }; - (h, stoch) - }, - exit, - )?; - - self.stoch_d.bps.height.compute_rolling_average( - starting_indexes.height, - &blocks.lookback._3d, - &self.stoch_k.bps.height, - exit, - )?; - let daily_returns = &returns.periods._24h.ratio.height; for (rsi_chain, &m) in self.rsi.as_mut_array().into_iter().zip(&WindowsTo1m::<()>::DAYS) { rsi::compute( diff --git a/crates/brk_computer/src/market/technical/import.rs b/crates/brk_computer/src/market/technical/import.rs index 6b37f7909..c5d9aab05 100644 --- a/crates/brk_computer/src/market/technical/import.rs +++ b/crates/brk_computer/src/market/technical/import.rs @@ -110,15 +110,10 @@ impl Vecs { WindowsTo1m::try_from_fn(|tf| RsiChain::forced_import(db, tf, v + Version::TWO, indexes))?; let macd = WindowsTo1m::try_from_fn(|tf| MacdChain::forced_import(db, tf, v, indexes))?; - let stoch_k = PercentPerBlock::forced_import(db, "stoch_k", v, indexes)?; - let stoch_d = PercentPerBlock::forced_import(db, "stoch_d", v, indexes)?; - let pi_cycle = RatioPerBlock::forced_import_raw(db, "pi_cycle", v, indexes)?; Ok(Self { rsi, - stoch_k, - stoch_d, pi_cycle, macd, }) diff --git a/crates/brk_computer/src/market/technical/vecs.rs b/crates/brk_computer/src/market/technical/vecs.rs index 1fef8cb3e..cc622e974 100644 --- a/crates/brk_computer/src/market/technical/vecs.rs +++ b/crates/brk_computer/src/market/technical/vecs.rs @@ -6,13 +6,20 @@ use crate::internal::{PerBlock, PercentPerBlock, RatioPerBlock, WindowsTo1m}; #[derive(Traversable)] pub struct RsiChain { + #[traversable(hidden)] pub gains: PerBlock, + #[traversable(hidden)] pub losses: PerBlock, + #[traversable(hidden)] pub average_gain: PerBlock, + #[traversable(hidden)] pub average_loss: PerBlock, pub rsi: PercentPerBlock, + #[traversable(hidden)] pub rsi_min: PercentPerBlock, + #[traversable(hidden)] pub rsi_max: PercentPerBlock, + #[traversable(hidden)] pub stoch_rsi: PercentPerBlock, pub stoch_rsi_k: PercentPerBlock, pub stoch_rsi_d: PercentPerBlock, @@ -31,9 +38,6 @@ pub struct MacdChain { pub struct Vecs { pub rsi: WindowsTo1m>, - pub stoch_k: PercentPerBlock, - pub stoch_d: PercentPerBlock, - pub pi_cycle: RatioPerBlock, pub macd: WindowsTo1m>, diff --git a/crates/brk_computer/src/mining/rewards/compute.rs b/crates/brk_computer/src/mining/rewards/compute.rs index c3afdedad..2037c7604 100644 --- a/crates/brk_computer/src/mining/rewards/compute.rs +++ b/crates/brk_computer/src/mining/rewards/compute.rs @@ -133,13 +133,6 @@ impl Vecs { exit, )?; - self.subsidy_sma_1y.cents.height.compute_rolling_average( - starting_indexes.height, - &lookback._1y, - &self.subsidy.block.cents, - exit, - )?; - self.fee_to_subsidy_ratio .compute_binary::( starting_indexes.height, diff --git a/crates/brk_computer/src/mining/rewards/import.rs b/crates/brk_computer/src/mining/rewards/import.rs index dd45e6a63..26dad2a23 100644 --- a/crates/brk_computer/src/mining/rewards/import.rs +++ b/crates/brk_computer/src/mining/rewards/import.rs @@ -7,7 +7,7 @@ use crate::{ indexes, internal::{ AmountPerBlockCumulative, AmountPerBlockCumulativeRolling, AmountPerBlockFull, - CachedWindowStarts, FiatPerBlock, LazyPercentRollingWindows, OneMinusBp16, + CachedWindowStarts, LazyPercentRollingWindows, OneMinusBp16, PercentPerBlock, PercentRollingWindows, RatioRollingWindows, }, }; @@ -55,7 +55,6 @@ impl Vecs { indexes, )?, subsidy_dominance_rolling, - subsidy_sma_1y: FiatPerBlock::forced_import(db, "subsidy_sma_1y", version, indexes)?, fee_to_subsidy_ratio: RatioRollingWindows::forced_import( db, "fee_to_subsidy_ratio", diff --git a/crates/brk_computer/src/mining/rewards/vecs.rs b/crates/brk_computer/src/mining/rewards/vecs.rs index 50ef039b5..a6e1e5d9b 100644 --- a/crates/brk_computer/src/mining/rewards/vecs.rs +++ b/crates/brk_computer/src/mining/rewards/vecs.rs @@ -1,11 +1,10 @@ use brk_traversable::Traversable; -use brk_types::{BasisPoints16, BasisPoints32, Cents}; +use brk_types::{BasisPoints16, BasisPoints32}; use vecdb::{Rw, StorageMode}; use crate::internal::{ AmountPerBlockCumulative, AmountPerBlockCumulativeRolling, AmountPerBlockFull, - FiatPerBlock, LazyPercentRollingWindows, PercentPerBlock, PercentRollingWindows, - RatioRollingWindows, + LazyPercentRollingWindows, PercentPerBlock, PercentRollingWindows, RatioRollingWindows, }; #[derive(Traversable)] @@ -22,8 +21,6 @@ pub struct Vecs { pub subsidy_dominance: PercentPerBlock, #[traversable(wrap = "subsidy", rename = "dominance")] pub subsidy_dominance_rolling: LazyPercentRollingWindows, - #[traversable(wrap = "subsidy", rename = "sma_1y")] - pub subsidy_sma_1y: FiatPerBlock, #[traversable(wrap = "fees", rename = "to_subsidy_ratio")] pub fee_to_subsidy_ratio: RatioRollingWindows, } diff --git a/crates/brk_computer/src/scripts/import.rs b/crates/brk_computer/src/scripts/import.rs index e93203365..a17660a24 100644 --- a/crates/brk_computer/src/scripts/import.rs +++ b/crates/brk_computer/src/scripts/import.rs @@ -22,7 +22,7 @@ impl Vecs { let version = parent_version; let count = CountVecs::forced_import(&db, version, indexes, cached_starts)?; - let value = ValueVecs::forced_import(&db, version, indexes, cached_starts)?; + let value = ValueVecs::forced_import(&db, version, indexes)?; let this = Self { db, count, value }; finalize_db(&this.db, &this)?; diff --git a/crates/brk_computer/src/scripts/value/compute.rs b/crates/brk_computer/src/scripts/value/compute.rs index 0f57f59b5..449953f36 100644 --- a/crates/brk_computer/src/scripts/value/compute.rs +++ b/crates/brk_computer/src/scripts/value/compute.rs @@ -14,7 +14,7 @@ impl Vecs { starting_indexes: &Indexes, exit: &Exit, ) -> Result<()> { - self.op_return.compute( + self.op_return.compute_with( starting_indexes.height, prices, exit, diff --git a/crates/brk_computer/src/scripts/value/import.rs b/crates/brk_computer/src/scripts/value/import.rs index 1bafba9cb..6d45eacb0 100644 --- a/crates/brk_computer/src/scripts/value/import.rs +++ b/crates/brk_computer/src/scripts/value/import.rs @@ -3,22 +3,20 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{indexes, internal::{AmountPerBlockCumulativeRolling, CachedWindowStarts}}; +use crate::{indexes, internal::AmountPerBlockCumulative}; impl Vecs { pub(crate) fn forced_import( db: &Database, version: Version, indexes: &indexes::Vecs, - cached_starts: &CachedWindowStarts, ) -> Result { Ok(Self { - op_return: AmountPerBlockCumulativeRolling::forced_import( + op_return: AmountPerBlockCumulative::forced_import( db, "op_return_value", version, indexes, - cached_starts, )?, }) } diff --git a/crates/brk_computer/src/scripts/value/vecs.rs b/crates/brk_computer/src/scripts/value/vecs.rs index c25267534..511f88aac 100644 --- a/crates/brk_computer/src/scripts/value/vecs.rs +++ b/crates/brk_computer/src/scripts/value/vecs.rs @@ -1,9 +1,9 @@ use brk_traversable::Traversable; use vecdb::{Rw, StorageMode}; -use crate::internal::AmountPerBlockCumulativeRolling; +use crate::internal::AmountPerBlockCumulative; #[derive(Traversable)] pub struct Vecs { - pub op_return: AmountPerBlockCumulativeRolling, + pub op_return: AmountPerBlockCumulative, } diff --git a/crates/brk_computer/src/supply/burned/compute.rs b/crates/brk_computer/src/supply/burned/compute.rs index 91568d2c5..4997c718c 100644 --- a/crates/brk_computer/src/supply/burned/compute.rs +++ b/crates/brk_computer/src/supply/burned/compute.rs @@ -1,6 +1,6 @@ use brk_error::Result; -use brk_types::{Height, Indexes, Sats}; -use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec}; +use brk_types::{Indexes, Sats}; +use vecdb::{Exit, VecIndex}; use super::Vecs; use crate::{mining, prices, scripts}; @@ -14,46 +14,21 @@ impl Vecs { starting_indexes: &Indexes, exit: &Exit, ) -> Result<()> { - let op_return_height = &scripts.value.op_return.block.sats; - let unclaimed_height = &mining.rewards.unclaimed.block.sats; - - self.total.compute( + self.total.compute_with( starting_indexes.height, prices, exit, - |height_vec| { - let unspendable_dep_version = - op_return_height.version() + unclaimed_height.version(); - height_vec.validate_computed_version_or_reset(unspendable_dep_version)?; - - let op_return_target = op_return_height.len(); - if op_return_target > 0 { - let target_height = Height::from(op_return_target - 1); - let current_len = height_vec.len(); - let starting_height = - Height::from(current_len.min(starting_indexes.height.to_usize())); - - if starting_height <= target_height { - let start = starting_height.to_usize(); - let end = target_height.to_usize() + 1; - let unclaimed_data = unclaimed_height.collect_range_at(start, end); - height_vec.truncate_if_needed(starting_height)?; - op_return_height.fold_range_at(start, end, start, |idx, op_return| { - let unclaimed = unclaimed_data[idx - start]; - let genesis = if idx == 0 { - Sats::FIFTY_BTC - } else { - Sats::ZERO - }; - let unspendable = genesis + op_return + unclaimed; - height_vec.push(unspendable); - idx + 1 - }); - } - } - - height_vec.write()?; - Ok(()) + |sats| { + Ok(sats.compute_transform2( + starting_indexes.height, + &scripts.value.op_return.block.sats, + &mining.rewards.unclaimed.block.sats, + |(h, op_return, unclaimed, ..)| { + let genesis = if h.to_usize() == 0 { Sats::FIFTY_BTC } else { Sats::ZERO }; + (h, genesis + op_return + unclaimed) + }, + exit, + )?) }, )?; diff --git a/crates/brk_computer/src/supply/burned/import.rs b/crates/brk_computer/src/supply/burned/import.rs index 161e76c55..9d80530fe 100644 --- a/crates/brk_computer/src/supply/burned/import.rs +++ b/crates/brk_computer/src/supply/burned/import.rs @@ -3,22 +3,20 @@ use brk_types::Version; use vecdb::Database; use super::Vecs; -use crate::{indexes, internal::{AmountPerBlockCumulativeRolling, CachedWindowStarts}}; +use crate::{indexes, internal::AmountPerBlockCumulative}; impl Vecs { pub(crate) fn forced_import( db: &Database, version: Version, indexes: &indexes::Vecs, - cached_starts: &CachedWindowStarts, ) -> Result { Ok(Self { - total: AmountPerBlockCumulativeRolling::forced_import( + total: AmountPerBlockCumulative::forced_import( db, "unspendable_supply", version, indexes, - cached_starts, )?, }) } diff --git a/crates/brk_computer/src/supply/burned/vecs.rs b/crates/brk_computer/src/supply/burned/vecs.rs index e24aafd0b..3db0928cc 100644 --- a/crates/brk_computer/src/supply/burned/vecs.rs +++ b/crates/brk_computer/src/supply/burned/vecs.rs @@ -1,10 +1,10 @@ use brk_traversable::Traversable; use vecdb::{Rw, StorageMode}; -use crate::internal::AmountPerBlockCumulativeRolling; +use crate::internal::AmountPerBlockCumulative; #[derive(Traversable)] #[traversable(transparent)] pub struct Vecs { - pub total: AmountPerBlockCumulativeRolling, + pub total: AmountPerBlockCumulative, } diff --git a/crates/brk_computer/src/supply/import.rs b/crates/brk_computer/src/supply/import.rs index de25201a1..7bca20832 100644 --- a/crates/brk_computer/src/supply/import.rs +++ b/crates/brk_computer/src/supply/import.rs @@ -34,7 +34,7 @@ impl Vecs { let circulating = LazyAmountPerBlock::identity("circulating_supply", &supply_metrics.total, version); - let burned = burned::Vecs::forced_import(&db, version, indexes, cached_starts)?; + let burned = burned::Vecs::forced_import(&db, version, indexes)?; // Inflation rate let inflation_rate = PercentPerBlock::forced_import( diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index e5f990497..08656e89c 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -1852,42 +1852,6 @@ function createAverageBlockCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern( * @property {_1m1w1y24hPattern} sum */ -/** - * @typedef {Object} AverageGainsLossesRsiStochPattern - * @property {SeriesPattern1} averageGain - * @property {SeriesPattern1} averageLoss - * @property {SeriesPattern1} gains - * @property {SeriesPattern1} losses - * @property {BpsPercentRatioPattern3} rsi - * @property {BpsPercentRatioPattern3} rsiMax - * @property {BpsPercentRatioPattern3} rsiMin - * @property {BpsPercentRatioPattern3} stochRsi - * @property {BpsPercentRatioPattern3} stochRsiD - * @property {BpsPercentRatioPattern3} stochRsiK - */ - -/** - * Create a AverageGainsLossesRsiStochPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated series name - * @param {string} disc - Discriminator suffix - * @returns {AverageGainsLossesRsiStochPattern} - */ -function createAverageGainsLossesRsiStochPattern(client, acc, disc) { - return { - averageGain: createSeriesPattern1(client, _m(_m(acc, 'average_gain'), disc)), - averageLoss: createSeriesPattern1(client, _m(_m(acc, 'average_loss'), disc)), - gains: createSeriesPattern1(client, _m(_m(acc, 'gains'), disc)), - losses: createSeriesPattern1(client, _m(_m(acc, 'losses'), disc)), - rsi: createBpsPercentRatioPattern3(client, _m(acc, disc)), - rsiMax: createBpsPercentRatioPattern3(client, _m(_m(acc, 'max'), disc)), - rsiMin: createBpsPercentRatioPattern3(client, _m(_m(acc, 'min'), disc)), - stochRsi: createBpsPercentRatioPattern3(client, _m(_m(acc, 'stoch'), disc)), - stochRsiD: createBpsPercentRatioPattern3(client, _m(_m(acc, 'stoch_d'), disc)), - stochRsiK: createBpsPercentRatioPattern3(client, _m(_m(acc, 'stoch_k'), disc)), - }; -} - /** * @typedef {Object} AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3 * @property {SeriesPattern1} all @@ -3437,7 +3401,7 @@ function createCentsSatsUsdPattern(client, acc) { * @typedef {Object} CumulativeRollingSumPattern * @property {SeriesPattern1} cumulative * @property {AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern} rolling - * @property {SeriesPattern1} sum + * @property {SeriesPattern18} sum */ /** @@ -3450,7 +3414,7 @@ function createCumulativeRollingSumPattern(client, acc) { return { cumulative: createSeriesPattern1(client, _m(acc, 'cumulative')), rolling: createAverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern(client, acc), - sum: createSeriesPattern1(client, _m(acc, 'sum')), + sum: createSeriesPattern18(client, _m(acc, 'sum')), }; } @@ -3510,6 +3474,28 @@ function createNuplRealizedSupplyPattern(client, acc) { * @property {AverageBlockCumulativeSumPattern} valueDestroyed */ +/** + * @typedef {Object} RsiStochPattern + * @property {BpsPercentRatioPattern3} rsi + * @property {BpsPercentRatioPattern3} stochRsiD + * @property {BpsPercentRatioPattern3} stochRsiK + */ + +/** + * Create a RsiStochPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated series name + * @param {string} disc - Discriminator suffix + * @returns {RsiStochPattern} + */ +function createRsiStochPattern(client, acc, disc) { + return { + rsi: createBpsPercentRatioPattern3(client, _m(acc, disc)), + stochRsiD: createBpsPercentRatioPattern3(client, _m(_m(acc, 'stoch_d'), disc)), + stochRsiK: createBpsPercentRatioPattern3(client, _m(_m(acc, 'stoch_k'), disc)), + }; +} + /** * @template T * @typedef {Object} _6bBlockTxPattern @@ -3611,7 +3597,7 @@ function createAllSthPattern(client, acc) { /** * @typedef {Object} BaseSumPattern - * @property {SeriesPattern1} base + * @property {SeriesPattern18} base * @property {_1m1w1y24hPattern} sum */ @@ -3623,7 +3609,7 @@ function createAllSthPattern(client, acc) { */ function createBaseSumPattern(client, acc) { return { - base: createSeriesPattern1(client, acc), + base: createSeriesPattern18(client, acc), sum: create_1m1w1y24hPattern(client, _m(acc, 'sum')), }; } @@ -3647,6 +3633,25 @@ function createBaseDeltaPattern(client, acc) { }; } +/** + * @typedef {Object} BlockCumulativePattern + * @property {BtcCentsSatsUsdPattern2} block + * @property {BtcCentsSatsUsdPattern3} cumulative + */ + +/** + * Create a BlockCumulativePattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated series name + * @returns {BlockCumulativePattern} + */ +function createBlockCumulativePattern(client, acc) { + return { + block: createBtcCentsSatsUsdPattern2(client, acc), + cumulative: createBtcCentsSatsUsdPattern3(client, _m(acc, 'cumulative')), + }; +} + /** * @typedef {Object} BlocksDominancePattern * @property {AverageBlockCumulativeSumPattern2} blocksMined @@ -4470,7 +4475,7 @@ function createUnspentPattern(client, acc) { /** * @typedef {Object} SeriesTree_Scripts_Value - * @property {AverageBlockCumulativeSumPattern3} opReturn + * @property {BlockCumulativePattern} opReturn */ /** @@ -4484,7 +4489,7 @@ function createUnspentPattern(client, acc) { * @property {AverageBlockCumulativeSumPattern3} coinbase * @property {SeriesTree_Mining_Rewards_Subsidy} subsidy * @property {SeriesTree_Mining_Rewards_Fees} fees - * @property {SeriesTree_Mining_Rewards_Unclaimed} unclaimed + * @property {BlockCumulativePattern} unclaimed */ /** @@ -4494,7 +4499,6 @@ function createUnspentPattern(client, acc) { * @property {_1m1w1y24hPattern4} sum * @property {_1m1w1y24hPattern3} average * @property {_1m1w1y24hBpsPercentRatioPattern} dominance - * @property {CentsUsdPattern3} sma1y */ /** @@ -4522,12 +4526,6 @@ function createUnspentPattern(client, acc) { * @property {BpsRatioPattern2} _1y */ -/** - * @typedef {Object} SeriesTree_Mining_Rewards_Unclaimed - * @property {BtcCentsSatsUsdPattern2} block - * @property {BtcCentsSatsUsdPattern3} cumulative - */ - /** * @typedef {Object} SeriesTree_Mining_Hashrate * @property {SeriesTree_Mining_Hashrate_Rate} rate @@ -5173,17 +5171,15 @@ function createUnspentPattern(client, acc) { /** * @typedef {Object} SeriesTree_Market_Technical * @property {SeriesTree_Market_Technical_Rsi} rsi - * @property {BpsPercentRatioPattern3} stochK - * @property {BpsPercentRatioPattern3} stochD * @property {BpsRatioPattern2} piCycle * @property {SeriesTree_Market_Technical_Macd} macd */ /** * @typedef {Object} SeriesTree_Market_Technical_Rsi - * @property {AverageGainsLossesRsiStochPattern} _24h - * @property {AverageGainsLossesRsiStochPattern} _1w - * @property {AverageGainsLossesRsiStochPattern} _1m + * @property {RsiStochPattern} _24h + * @property {RsiStochPattern} _1w + * @property {RsiStochPattern} _1m */ /** @@ -5430,7 +5426,7 @@ function createUnspentPattern(client, acc) { * @typedef {Object} SeriesTree_Supply * @property {SeriesPattern18} state * @property {BtcCentsSatsUsdPattern3} circulating - * @property {AverageBlockCumulativeSumPattern3} burned + * @property {BlockCumulativePattern} burned * @property {BpsPercentRatioPattern} inflationRate * @property {SeriesTree_Supply_Velocity} velocity * @property {CentsDeltaUsdPattern} marketCap @@ -7836,7 +7832,7 @@ class BrkClient extends BrkClientBase { unknownOutput: createAverageBlockCumulativeSumPattern(this, 'unknown_output_count'), }, value: { - opReturn: createAverageBlockCumulativeSumPattern3(this, 'op_return_value'), + opReturn: createBlockCumulativePattern(this, 'op_return_value'), }, }, mining: { @@ -7848,7 +7844,6 @@ class BrkClient extends BrkClientBase { sum: create_1m1w1y24hPattern4(this, 'subsidy_sum'), average: create_1m1w1y24hPattern3(this, 'subsidy_average'), dominance: create_1m1w1y24hBpsPercentRatioPattern(this, 'subsidy_dominance'), - sma1y: createCentsUsdPattern3(this, 'subsidy_sma_1y'), }, fees: { block: createBtcCentsSatsUsdPattern2(this, 'fees'), @@ -7870,10 +7865,7 @@ class BrkClient extends BrkClientBase { _1y: createBpsRatioPattern2(this, 'fee_to_subsidy_ratio_1y'), }, }, - unclaimed: { - block: createBtcCentsSatsUsdPattern2(this, 'unclaimed_rewards'), - cumulative: createBtcCentsSatsUsdPattern3(this, 'unclaimed_rewards_cumulative'), - }, + unclaimed: createBlockCumulativePattern(this, 'unclaimed_rewards'), }, hashrate: { rate: { @@ -8312,12 +8304,10 @@ class BrkClient extends BrkClientBase { }, technical: { rsi: { - _24h: createAverageGainsLossesRsiStochPattern(this, 'rsi', '24h'), - _1w: createAverageGainsLossesRsiStochPattern(this, 'rsi', '1w'), - _1m: createAverageGainsLossesRsiStochPattern(this, 'rsi', '1m'), + _24h: createRsiStochPattern(this, 'rsi', '24h'), + _1w: createRsiStochPattern(this, 'rsi', '1w'), + _1m: createRsiStochPattern(this, 'rsi', '1m'), }, - stochK: createBpsPercentRatioPattern3(this, 'stoch_k'), - stochD: createBpsPercentRatioPattern3(this, 'stoch_d'), piCycle: createBpsRatioPattern2(this, 'pi_cycle'), macd: { _24h: { @@ -8534,7 +8524,7 @@ class BrkClient extends BrkClientBase { supply: { state: createSeriesPattern18(this, 'supply_state'), circulating: createBtcCentsSatsUsdPattern3(this, 'circulating_supply'), - burned: createAverageBlockCumulativeSumPattern3(this, 'unspendable_supply'), + burned: createBlockCumulativePattern(this, 'unspendable_supply'), inflationRate: createBpsPercentRatioPattern(this, 'inflation_rate'), velocity: { native: createSeriesPattern1(this, 'velocity'), diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 38f12281a..ac237965b 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -2246,22 +2246,6 @@ class AverageBaseCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern(Generic[T] """Pattern struct for repeated tree structure.""" pass -class AverageGainsLossesRsiStochPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str, disc: str): - """Create pattern node with accumulated series name.""" - self.average_gain: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, f'average_gain_{disc}')) - self.average_loss: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, f'average_loss_{disc}')) - self.gains: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, f'gains_{disc}')) - self.losses: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, f'losses_{disc}')) - self.rsi: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, disc)) - self.rsi_max: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, f'max_{disc}')) - self.rsi_min: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, f'min_{disc}')) - self.stoch_rsi: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, f'stoch_{disc}')) - self.stoch_rsi_d: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, f'stoch_d_{disc}')) - self.stoch_rsi_k: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, f'stoch_k_{disc}')) - class AllP2aP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshPattern3: """Pattern struct for repeated tree structure.""" @@ -2942,7 +2926,7 @@ class CumulativeRollingSumPattern: """Create pattern node with accumulated series name.""" self.cumulative: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'cumulative')) self.rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern = AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern(client, acc) - self.sum: SeriesPattern1[StoredU64] = SeriesPattern1(client, _m(acc, 'sum')) + self.sum: SeriesPattern18[StoredU64] = SeriesPattern18(client, _m(acc, 'sum')) class GreedNetPainPattern: """Pattern struct for repeated tree structure.""" @@ -2970,6 +2954,15 @@ class RatioTransferValuePattern: """Pattern struct for repeated tree structure.""" pass +class RsiStochPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str, disc: str): + """Create pattern node with accumulated series name.""" + self.rsi: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, disc)) + self.stoch_rsi_d: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, f'stoch_d_{disc}')) + self.stoch_rsi_k: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, f'stoch_k_{disc}')) + class _6bBlockTxPattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -3016,7 +3009,7 @@ class BaseSumPattern: def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated series name.""" - self.base: SeriesPattern1[Dollars] = SeriesPattern1(client, acc) + self.base: SeriesPattern18[Dollars] = SeriesPattern18(client, acc) self.sum: _1m1w1y24hPattern[Dollars] = _1m1w1y24hPattern(client, _m(acc, 'sum')) class BaseDeltaPattern: @@ -3027,6 +3020,14 @@ class BaseDeltaPattern: self.base: SeriesPattern1[StoredU64] = SeriesPattern1(client, acc) self.delta: AbsoluteRatePattern = AbsoluteRatePattern(client, _m(acc, 'delta')) +class BlockCumulativePattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated series name.""" + self.block: BtcCentsSatsUsdPattern2 = BtcCentsSatsUsdPattern2(client, acc) + self.cumulative: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, _m(acc, 'cumulative')) + class BlocksDominancePattern: """Pattern struct for repeated tree structure.""" @@ -3663,7 +3664,7 @@ class SeriesTree_Scripts_Value: """Series tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.op_return: AverageBlockCumulativeSumPattern3 = AverageBlockCumulativeSumPattern3(client, 'op_return_value') + self.op_return: BlockCumulativePattern = BlockCumulativePattern(client, 'op_return_value') class SeriesTree_Scripts: """Series tree node.""" @@ -3682,7 +3683,6 @@ class SeriesTree_Mining_Rewards_Subsidy: self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'subsidy_sum') self.average: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, 'subsidy_average') self.dominance: _1m1w1y24hBpsPercentRatioPattern = _1m1w1y24hBpsPercentRatioPattern(client, 'subsidy_dominance') - self.sma_1y: CentsUsdPattern3 = CentsUsdPattern3(client, 'subsidy_sma_1y') class SeriesTree_Mining_Rewards_Fees_ToSubsidyRatio: """Series tree node.""" @@ -3711,13 +3711,6 @@ class SeriesTree_Mining_Rewards_Fees: self.dominance: _1m1w1y24hBpsPercentRatioPattern = _1m1w1y24hBpsPercentRatioPattern(client, 'fee_dominance') self.to_subsidy_ratio: SeriesTree_Mining_Rewards_Fees_ToSubsidyRatio = SeriesTree_Mining_Rewards_Fees_ToSubsidyRatio(client) -class SeriesTree_Mining_Rewards_Unclaimed: - """Series tree node.""" - - def __init__(self, client: BrkClientBase, base_path: str = ''): - self.block: BtcCentsSatsUsdPattern2 = BtcCentsSatsUsdPattern2(client, 'unclaimed_rewards') - self.cumulative: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'unclaimed_rewards_cumulative') - class SeriesTree_Mining_Rewards: """Series tree node.""" @@ -3725,7 +3718,7 @@ class SeriesTree_Mining_Rewards: self.coinbase: AverageBlockCumulativeSumPattern3 = AverageBlockCumulativeSumPattern3(client, 'coinbase') self.subsidy: SeriesTree_Mining_Rewards_Subsidy = SeriesTree_Mining_Rewards_Subsidy(client) self.fees: SeriesTree_Mining_Rewards_Fees = SeriesTree_Mining_Rewards_Fees(client) - self.unclaimed: SeriesTree_Mining_Rewards_Unclaimed = SeriesTree_Mining_Rewards_Unclaimed(client) + self.unclaimed: BlockCumulativePattern = BlockCumulativePattern(client, 'unclaimed_rewards') class SeriesTree_Mining_Hashrate_Rate_Sma: """Series tree node.""" @@ -4438,9 +4431,9 @@ class SeriesTree_Market_Technical_Rsi: """Series tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self._24h: AverageGainsLossesRsiStochPattern = AverageGainsLossesRsiStochPattern(client, 'rsi', '24h') - self._1w: AverageGainsLossesRsiStochPattern = AverageGainsLossesRsiStochPattern(client, 'rsi', '1w') - self._1m: AverageGainsLossesRsiStochPattern = AverageGainsLossesRsiStochPattern(client, 'rsi', '1m') + self._24h: RsiStochPattern = RsiStochPattern(client, 'rsi', '24h') + self._1w: RsiStochPattern = RsiStochPattern(client, 'rsi', '1w') + self._1m: RsiStochPattern = RsiStochPattern(client, 'rsi', '1m') class SeriesTree_Market_Technical_Macd_24h: """Series tree node.""" @@ -4485,8 +4478,6 @@ class SeriesTree_Market_Technical: def __init__(self, client: BrkClientBase, base_path: str = ''): self.rsi: SeriesTree_Market_Technical_Rsi = SeriesTree_Market_Technical_Rsi(client) - self.stoch_k: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'stoch_k') - self.stoch_d: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'stoch_d') self.pi_cycle: BpsRatioPattern2 = BpsRatioPattern2(client, 'pi_cycle') self.macd: SeriesTree_Market_Technical_Macd = SeriesTree_Market_Technical_Macd(client) @@ -4729,7 +4720,7 @@ class SeriesTree_Supply: def __init__(self, client: BrkClientBase, base_path: str = ''): self.state: SeriesPattern18[SupplyState] = SeriesPattern18(client, 'supply_state') self.circulating: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'circulating_supply') - self.burned: AverageBlockCumulativeSumPattern3 = AverageBlockCumulativeSumPattern3(client, 'unspendable_supply') + self.burned: BlockCumulativePattern = BlockCumulativePattern(client, 'unspendable_supply') self.inflation_rate: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'inflation_rate') self.velocity: SeriesTree_Supply_Velocity = SeriesTree_Supply_Velocity(client) self.market_cap: CentsDeltaUsdPattern = CentsDeltaUsdPattern(client, 'market_cap') diff --git a/website/scripts/options/distribution/activity.js b/website/scripts/options/distribution/activity.js index bb742d4c4..d1df5ea48 100644 --- a/website/scripts/options/distribution/activity.js +++ b/website/scripts/options/distribution/activity.js @@ -41,7 +41,7 @@ function volumeTree(tv, color, title) { return [ ...satsBtcUsdFullTree({ pattern: tv, - title: title("Sent Volume"), + title: title("Transfer Volume"), color, }), { @@ -49,7 +49,7 @@ function volumeTree(tv, color, title) { tree: [ ...ROLLING_WINDOWS.map((w) => ({ name: w.name, - title: title(`Sent Volume Profitability (${w.title})`), + title: title(`Transfer Volume Profitability (${w.title})`), bottom: [ ...satsBtcUsd({ pattern: tv.inProfit.sum[w.key], @@ -65,7 +65,7 @@ function volumeTree(tv, color, title) { })), { name: "Cumulative", - title: title("Cumulative Sent Volume Profitability"), + title: title("Cumulative Transfer Volume"), bottom: [ ...satsBtcUsd({ pattern: tv.inProfit.cumulative, @@ -83,7 +83,7 @@ function volumeTree(tv, color, title) { name: "In Profit", tree: satsBtcUsdFullTree({ pattern: tv.inProfit, - title: title("Sent In Profit"), + title: title("Transfer Volume In Profit"), color: colors.profit, }), }, @@ -91,7 +91,7 @@ function volumeTree(tv, color, title) { name: "In Loss", tree: satsBtcUsdFullTree({ pattern: tv.inLoss, - title: title("Sent In Loss"), + title: title("Transfer Volume In Loss"), color: colors.loss, }), }, @@ -360,7 +360,7 @@ export function createActivitySectionMinimal({ cohort, title }) { name: "Activity", tree: satsBtcUsdFullTree({ pattern: cohort.tree.activity.transferVolume, - title: title("Volume"), + title: title("Transfer Volume"), }), }; } @@ -399,7 +399,7 @@ function groupedProfitabilityArray(list, all, title, getInProfit, getInLoss) { list, all, title, - metricTitle: "Sent In Profit", + metricTitle: "Transfer Volume In Profit", getMetric: (c) => getInProfit(c), }), }, @@ -409,7 +409,7 @@ function groupedProfitabilityArray(list, all, title, getInProfit, getInLoss) { list, all, title, - metricTitle: "Sent In Loss", + metricTitle: "Transfer Volume In Loss", getMetric: (c) => getInLoss(c), }), }, @@ -431,7 +431,7 @@ function groupedVolumeTree(list, all, title, getTransferVolume) { list, all, title, - metricTitle: "Sent Volume", + metricTitle: "Transfer Volume", getMetric: (c) => getTransferVolume(c), }), ...groupedProfitabilityArray( diff --git a/website/scripts/options/distribution/cost-basis.js b/website/scripts/options/distribution/cost-basis.js index cb02e9593..4e62eb3a6 100644 --- a/website/scripts/options/distribution/cost-basis.js +++ b/website/scripts/options/distribution/cost-basis.js @@ -136,7 +136,7 @@ function groupedWeightFolder({ list, all, getAvgPrice, getInProfit, getInLoss, g return [ { name: "Average", - title: title(`${avgTitle} Comparison`), + title: title(`Cost Basis ${avgTitle} (${weightLabel})`), top: mapCohortsWithAll(list, all, (c) => price({ series: getAvgPrice(c), name: c.name, color: c.color }), ), diff --git a/website/scripts/options/distribution/holdings.js b/website/scripts/options/distribution/holdings.js index d8791e028..859a82b01 100644 --- a/website/scripts/options/distribution/holdings.js +++ b/website/scripts/options/distribution/holdings.js @@ -82,7 +82,7 @@ function singleDeltaItems(delta, unit, title, name) { { ...rollingPercentRatioTree({ windows: delta.rate, - title: title(`${name} Rate`), + title: title(`${name} Growth Rate`), }), name: "Growth Rate", }, @@ -121,7 +121,7 @@ function groupedDeltaItems(list, all, getDelta, unit, title, name) { name: "Growth Rate", tree: ROLLING_WINDOWS.map((w) => ({ name: w.name, - title: title(`${name} Rate (${w.title})`), + title: title(`${name} Growth Rate (${w.title})`), bottom: flatMapCohortsWithAll(list, all, (c) => percentRatioBaseline({ pattern: getDelta(c).rate[w.key], @@ -212,17 +212,18 @@ function ownSupplyChart(supply, title) { * Count folder (UTXO or Address) with value + change * @param {{ base: AnySeriesPattern, delta: DeltaPattern }} pattern * @param {string} name + * @param {string} chartTitle * @param {Color} color * @param {(name: string) => string} title * @returns {PartialOptionsGroup} */ -function countFolder(pattern, name, color, title) { +function countFolder(pattern, name, chartTitle, color, title) { return { name, tree: [ { name: "Count", - title: title(name), + title: title(chartTitle), bottom: [ line({ series: pattern.base, @@ -259,7 +260,7 @@ export function createHoldingsSection({ cohort, title }) { ...singleDeltaItems(supply.delta, Unit.sats, title, "Change"), ], }, - countFolder(cohort.tree.outputs.unspentCount, "UTXOs", cohort.color, title), + countFolder(cohort.tree.outputs.unspentCount, "UTXOs", "UTXO Count", cohort.color, title), ]; } @@ -283,8 +284,8 @@ export function createHoldingsSectionAll({ cohort, title }) { ...singleDeltaItems(supply.delta, Unit.sats, title, "Change"), ], }, - countFolder(cohort.tree.outputs.unspentCount, "UTXOs", cohort.color, title), - countFolder(cohort.addressCount, "Addresses", cohort.color, title), + countFolder(cohort.tree.outputs.unspentCount, "UTXOs", "UTXO Count", cohort.color, title), + countFolder(cohort.addressCount, "Addresses", "Address Count", cohort.color, title), ]; } @@ -309,7 +310,7 @@ export function createHoldingsSectionWithRelative({ cohort, title }) { ...singleDeltaItems(supply.delta, Unit.sats, title, "Change"), ], }, - countFolder(cohort.tree.outputs.unspentCount, "UTXOs", cohort.color, title), + countFolder(cohort.tree.outputs.unspentCount, "UTXOs", "UTXO Count", cohort.color, title), ]; } @@ -333,7 +334,7 @@ export function createHoldingsSectionWithOwnSupply({ cohort, title }) { ...singleDeltaItems(supply.delta, Unit.sats, title, "Change"), ], }, - countFolder(cohort.tree.outputs.unspentCount, "UTXOs", cohort.color, title), + countFolder(cohort.tree.outputs.unspentCount, "UTXOs", "UTXO Count", cohort.color, title), ]; } @@ -356,7 +357,7 @@ export function createHoldingsSectionWithProfitLoss({ cohort, title }) { ...singleDeltaItems(supply.delta, Unit.sats, title, "Change"), ], }, - countFolder(cohort.tree.outputs.unspentCount, "UTXOs", cohort.color, title), + countFolder(cohort.tree.outputs.unspentCount, "UTXOs", "UTXO Count", cohort.color, title), ]; } @@ -379,8 +380,8 @@ export function createHoldingsSectionAddress({ cohort, title }) { ...singleDeltaItems(supply.delta, Unit.sats, title, "Change"), ], }, - countFolder(cohort.tree.outputs.unspentCount, "UTXOs", cohort.color, title), - countFolder(cohort.addressCount, "Addresses", cohort.color, title), + countFolder(cohort.tree.outputs.unspentCount, "UTXOs", "UTXO Count", cohort.color, title), + countFolder(cohort.addressCount, "Addresses", "Address Count", cohort.color, title), ]; } @@ -402,8 +403,8 @@ export function createHoldingsSectionAddressAmount({ cohort, title }) { ...singleDeltaItems(supply.delta, Unit.sats, title, "Change"), ], }, - countFolder(cohort.tree.outputs.unspentCount, "UTXOs", cohort.color, title), - countFolder(cohort.addressCount, "Addresses", cohort.color, title), + countFolder(cohort.tree.outputs.unspentCount, "UTXOs", "UTXO Count", cohort.color, title), + countFolder(cohort.addressCount, "Addresses", "Address Count", cohort.color, title), ]; } diff --git a/website/scripts/options/distribution/index.js b/website/scripts/options/distribution/index.js index d1bf8a568..61c10c8f5 100644 --- a/website/scripts/options/distribution/index.js +++ b/website/scripts/options/distribution/index.js @@ -65,6 +65,7 @@ import { createProfitabilitySectionWithInvestedCapitalPct, createProfitabilitySectionLongTerm, createGroupedProfitabilitySection, + createGroupedProfitabilitySectionWithProfitLoss, createGroupedProfitabilitySectionWithNupl, createGroupedProfitabilitySectionWithInvestedCapitalPct, } from "./profitability.js"; @@ -91,7 +92,7 @@ export { buildCohortData } from "./data.js"; * @returns {PartialOptionsGroup} */ export function createCohortFolderAll(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -111,7 +112,7 @@ export function createCohortFolderAll(cohort) { * @returns {PartialOptionsGroup} */ export function createCohortFolderFull(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -131,7 +132,7 @@ export function createCohortFolderFull(cohort) { * @returns {PartialOptionsGroup} */ export function createCohortFolderWithAdjusted(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -150,7 +151,7 @@ export function createCohortFolderWithAdjusted(cohort) { * @returns {PartialOptionsGroup} */ export function createCohortFolderWithNupl(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -170,7 +171,7 @@ export function createCohortFolderWithNupl(cohort) { * @returns {PartialOptionsGroup} */ export function createCohortFolderLongTerm(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -190,7 +191,7 @@ export function createCohortFolderLongTerm(cohort) { * @returns {PartialOptionsGroup} */ export function createCohortFolderAgeRange(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -210,7 +211,7 @@ export function createCohortFolderAgeRange(cohort) { */ export function createCohortFolderAgeRangeWithMatured(cohort) { const folder = createCohortFolderAgeRange(cohort); - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); folder.tree.push({ name: "Matured", tree: satsBtcUsdFullTree({ @@ -227,7 +228,7 @@ export function createCohortFolderAgeRangeWithMatured(cohort) { * @returns {PartialOptionsGroup} */ export function createCohortFolderBasicWithMarketCap(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -247,7 +248,7 @@ export function createCohortFolderBasicWithMarketCap(cohort) { * @returns {PartialOptionsGroup} */ export function createCohortFolderAddress(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -266,7 +267,7 @@ export function createCohortFolderAddress(cohort) { * @returns {PartialOptionsGroup} */ export function createCohortFolderWithoutRelative(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -285,7 +286,7 @@ export function createCohortFolderWithoutRelative(cohort) { * @returns {PartialOptionsGroup} */ export function createAddressCohortFolder(cohort) { - const title = formatCohortTitle(cohort.name); + const title = formatCohortTitle(cohort.title); return { name: cohort.name || "all", tree: [ @@ -455,7 +456,7 @@ export function createGroupedCohortFolderAddress({ ...createGroupedHoldingsSectionAddress({ list, all, title }), createGroupedValuationSection({ list, all, title }), createGroupedPricesSection({ list, all, title }), - createGroupedProfitabilitySection({ + createGroupedProfitabilitySectionWithProfitLoss({ list, all, title, diff --git a/website/scripts/options/distribution/profitability.js b/website/scripts/options/distribution/profitability.js index 88d3ad818..ba4afde7d 100644 --- a/website/scripts/options/distribution/profitability.js +++ b/website/scripts/options/distribution/profitability.js @@ -100,6 +100,19 @@ function relPnlChart(profit, loss, name, title) { }; } +/** @param {{ percent: AnySeriesPattern, ratio: AnySeriesPattern }} net @param {{ percent: AnySeriesPattern, ratio: AnySeriesPattern }} profit @param {{ percent: AnySeriesPattern, ratio: AnySeriesPattern }} loss @param {string} name @param {(name: string) => string} title */ +function relPnlChartWithNet(net, profit, loss, name, title) { + return { + name, + title: title(`Unrealized P&L (${name})`), + bottom: [ + ...percentRatioBaseline({ pattern: net, name: "Net" }), + ...percentRatio({ pattern: profit, name: "Profit", color: colors.profit }), + ...percentRatio({ pattern: loss, name: "Loss", color: colors.loss }), + ], + }; +} + /** * Core unrealized items: Overview + Net + NUPL + Profit + Loss * @param {{ profit: { usd: AnySeriesPattern }, loss: { usd: AnySeriesPattern, negative: AnySeriesPattern }, netPnl: { usd: AnySeriesPattern }, nupl: NuplPattern }} u @@ -142,6 +155,30 @@ function unrealizedCore(u, title) { ]; } +/** + * Core unrealized items + Gross + * @param {{ profit: { usd: AnySeriesPattern }, loss: { usd: AnySeriesPattern, negative: AnySeriesPattern }, netPnl: { usd: AnySeriesPattern }, grossPnl: { usd: AnySeriesPattern }, nupl: NuplPattern }} u + * @param {(name: string) => string} title + * @returns {PartialOptionsTree} + */ +function unrealizedCoreWithGross(u, title) { + return [ + ...unrealizedCore(u, title), + { + name: "Gross", + title: title("Gross Unrealized P&L"), + bottom: [ + line({ + series: u.grossPnl.usd, + name: "Gross", + color: colors.gross, + unit: Unit.usd, + }), + ], + }, + ]; +} + /** * % of Own P&L chart * @param {AllRelativePattern | FullRelativePattern} u @@ -173,7 +210,7 @@ function ownPnlChart(u, title) { /** @param {AllRelativePattern} u @param {(name: string) => string} title */ function unrealizedTreeAll(u, title) { return [ - ...unrealizedCore(u, title), + ...unrealizedCoreWithGross(u, title), ownPnlChart(u, title), relPnlChart(u.profit.toMcap, u.loss.toMcap, "% of Market Cap", title), ]; @@ -182,22 +219,17 @@ function unrealizedTreeAll(u, title) { /** @param {FullRelativePattern} u @param {(name: string) => string} title */ function unrealizedTreeFull(u, title) { return [ - ...unrealizedCore(u, title), + ...unrealizedCoreWithGross(u, title), ownPnlChart(u, title), relPnlChart(u.profit.toMcap, u.loss.toMcap, "% of Market Cap", title), - relPnlChart( - u.profit.toOwnMcap, - u.loss.toOwnMcap, - "% of Own Market Cap", - title, - ), + relPnlChartWithNet(u.netPnl.toOwnMcap, u.profit.toOwnMcap, u.loss.toOwnMcap, "% of Own Market Cap", title), ]; } /** @param {FullRelativePattern} u @param {(name: string) => string} title */ function unrealizedTreeLongTerm(u, title) { return [ - ...unrealizedCore(u, title), + ...unrealizedCoreWithGross(u, title), ownPnlChart(u, title), { name: "% of Market Cap", @@ -208,12 +240,7 @@ function unrealizedTreeLongTerm(u, title) { color: colors.loss, }), }, - relPnlChart( - u.profit.toOwnMcap, - u.loss.toOwnMcap, - "% of Own Market Cap", - title, - ), + relPnlChartWithNet(u.netPnl.toOwnMcap, u.profit.toOwnMcap, u.loss.toOwnMcap, "% of Own Market Cap", title), ]; } @@ -300,7 +327,7 @@ function realizedMetricFolder({ pattern, metricTitle, color, title }) { })), { name: "Cumulative", - title: title(`Realized ${metricTitle} (Total)`), + title: title(`Cumulative Realized ${metricTitle}`), bottom: [ line({ series: pattern.cumulative.usd, @@ -350,7 +377,7 @@ function realizedNetFolder({ netPnl, title, extraChange = [] }) { })), { name: "Cumulative", - title: title("Net Realized P&L (Total)"), + title: title("Cumulative Net Realized P&L"), bottom: [ baseline({ series: netPnl.cumulative.usd, @@ -372,7 +399,7 @@ function realizedNetFolder({ netPnl, title, extraChange = [] }) { tree: [ ...rollingPercentRatioTree({ windows: netPnl.delta.rate, - title: title("Net Realized P&L Rate"), + title: title("Net Realized P&L Growth Rate"), }).tree, ...extraChange, ], @@ -587,7 +614,7 @@ function realizedSubfolderFull(r, title) { })), { name: "Cumulative", - title: title("Peak Regret (Total)"), + title: title("Cumulative Peak Regret"), bottom: [ line({ series: r.peakRegret.cumulative.usd, @@ -706,6 +733,16 @@ export function createProfitabilitySectionWithProfitLoss({ cohort, title }) { { name: "Unrealized", tree: [ + { + name: "Overview", + title: title("Unrealized P&L"), + bottom: [ + line({ series: u.profit.usd, name: "Profit", color: colors.profit, unit: Unit.usd }), + line({ series: u.loss.negative, name: "Neg. Loss", color: colors.loss, unit: Unit.usd }), + line({ series: u.loss.usd, name: "Loss", color: colors.loss, unit: Unit.usd, defaultActive: false }), + priceLine({ unit: Unit.usd }), + ], + }, { name: "NUPL", title: title("NUPL"), bottom: nuplSeries(u.nupl) }, { name: "Profit", @@ -840,32 +877,49 @@ export function createProfitabilitySectionWithInvestedCapitalPct({ * @param {(name: string) => string} title * @returns {PartialOptionsGroup} */ +/** + * Grouped realized profit + loss items + * @param {readonly UtxoCohortObject[]} list + * @param {CohortAll} all + * @param {(name: string) => string} title + * @returns {PartialOptionsTree} + */ +function groupedRealizedProfitLossItems(list, all, title) { + return [ + { name: "Profit", tree: groupedWindowsCumulativeUsd({ list, all, title, metricTitle: "Realized Profit", getMetric: (c) => c.tree.realized.profit }) }, + { name: "Loss", tree: groupedWindowsCumulativeUsd({ list, all, title, metricTitle: "Realized Loss", getMetric: (c) => c.tree.realized.loss }) }, + ]; +} + +/** + * Grouped realized net item + * @param {readonly (CohortAgeRange | CohortWithAdjusted | CohortAll | CohortFull | CohortLongTerm)[]} list + * @param {CohortAll} all + * @param {(name: string) => string} title + * @returns {PartialOptionsGroup} + */ +function groupedRealizedNetItem(list, all, title) { + return { name: "Net", tree: groupedWindowsCumulativeUsd({ list, all, title, metricTitle: "Net Realized P&L", getMetric: (c) => c.tree.realized.netPnl, seriesFn: baseline }) }; +} + +/** + * @param {readonly UtxoCohortObject[]} list + * @param {CohortAll} all + * @param {(name: string) => string} title + * @returns {PartialOptionsGroup} + */ function groupedRealizedSubfolder(list, all, title) { - return { - name: "Realized", - tree: [ - { - name: "Profit", - tree: groupedWindowsCumulativeUsd({ - list, - all, - title, - metricTitle: "Realized Profit", - getMetric: (c) => c.tree.realized.profit, - }), - }, - { - name: "Loss", - tree: groupedWindowsCumulativeUsd({ - list, - all, - title, - metricTitle: "Realized Loss", - getMetric: (c) => c.tree.realized.loss, - }), - }, - ], - }; + return { name: "Realized", tree: groupedRealizedProfitLossItems(list, all, title) }; +} + +/** + * @param {readonly (CohortAgeRange | CohortWithAdjusted)[]} list + * @param {CohortAll} all + * @param {(name: string) => string} title + * @returns {PartialOptionsGroup} + */ +function groupedRealizedSubfolderMid(list, all, title) { + return { name: "Realized", tree: [groupedRealizedNetItem(list, all, title), ...groupedRealizedProfitLossItems(list, all, title)] }; } /** @@ -896,7 +950,7 @@ function groupedRealizedNetPnlDeltaItems(list, all, title) { name: "Growth Rate", tree: ROLLING_WINDOWS.map((w) => ({ name: w.name, - title: title(`Net Realized P&L Rate (${w.title})`), + title: title(`Net Realized P&L Growth Rate (${w.title})`), bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => percentRatioBaseline({ pattern: tree.realized.netPnl.delta.rate[w.key], @@ -934,26 +988,7 @@ function groupedRealizedSubfolderFull(list, all, title) { ...groupedRealizedNetPnlDeltaItems(list, all, title), ], }, - { - name: "Profit", - tree: groupedWindowsCumulativeUsd({ - list, - all, - title, - metricTitle: "Realized Profit", - getMetric: (c) => c.tree.realized.profit, - }), - }, - { - name: "Loss", - tree: groupedWindowsCumulativeUsd({ - list, - all, - title, - metricTitle: "Realized Loss", - getMetric: (c) => c.tree.realized.loss, - }), - }, + ...groupedRealizedProfitLossItems(list, all, title), { name: "Gross", tree: groupedWindowsCumulativeUsd({ @@ -1234,7 +1269,7 @@ export function createGroupedProfitabilitySectionWithInvestedCapitalPct({ name: "Profitability", tree: [ { name: "Unrealized", tree: groupedUnrealizedMid(list, all, title) }, - groupedRealizedSubfolder(list, all, title), + groupedRealizedSubfolderMid(list, all, title), ], }; } diff --git a/website/scripts/options/distribution/valuation.js b/website/scripts/options/distribution/valuation.js index 26430cf17..df5085a51 100644 --- a/website/scripts/options/distribution/valuation.js +++ b/website/scripts/options/distribution/valuation.js @@ -20,7 +20,7 @@ import { ratioBottomSeries, mapCohortsWithAll, flatMapCohortsWithAll } from "../ function singleDeltaItems(tree, title) { return [ { ...sumsTreeBaseline({ windows: mapWindows(tree.realized.cap.delta.absolute, (c) => c.usd), title: title("Realized Cap Change"), unit: Unit.usd }), name: "Change" }, - { ...rollingPercentRatioTree({ windows: tree.realized.cap.delta.rate, title: title("Realized Cap Rate") }), name: "Growth Rate" }, + { ...rollingPercentRatioTree({ windows: tree.realized.cap.delta.rate, title: title("Realized Cap Growth Rate") }), name: "Growth Rate" }, ]; } @@ -54,7 +54,7 @@ function groupedDeltaAndMvrv(list, all, title) { name: "Growth Rate", tree: ROLLING_WINDOWS.map((w) => ({ name: w.name, - title: title(`Realized Cap Rate (${w.title})`), + title: title(`Realized Cap Growth Rate (${w.title})`), bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => percentRatioBaseline({ pattern: tree.realized.cap.delta.rate[w.key], name, color }), ), diff --git a/website/scripts/options/mining.js b/website/scripts/options/mining.js index 67c654ed4..5de4c54ce 100644 --- a/website/scripts/options/mining.js +++ b/website/scripts/options/mining.js @@ -5,13 +5,13 @@ import { entries, includes } from "../utils/array.js"; import { colors } from "../utils/colors.js"; import { line, - baseline, dots, dotted, distributionBtcSatsUsd, statsAtWindow, ROLLING_WINDOWS, percentRatio, + percentRatioBaseline, chartsFromCount, } from "./series.js"; import { @@ -438,7 +438,7 @@ export function createMiningSection() { { name: "Adjustment", title: "Difficulty Adjustment", - bottom: [baseline({ series: blocks.difficulty.adjustment.percent, name: "Change", unit: Unit.percentage })], + bottom: percentRatioBaseline({ pattern: blocks.difficulty.adjustment, name: "Change" }), }, { name: "Countdown", diff --git a/website/scripts/options/unused.js b/website/scripts/options/unused.js index 7d429005a..8bfc9996f 100644 --- a/website/scripts/options/unused.js +++ b/website/scripts/options/unused.js @@ -15,40 +15,31 @@ function walkSeries(node, map, path) { for (const [key, value] of Object.entries(node)) { const kn = key.toLowerCase(); if ( - key === "lookback" || - key === "cumulativeMarketCap" || key === "sd24h" || - key === "spot" || - key === "ohlc" || - key === "state" || key === "emaSlow" || key === "emaFast" || - key.endsWith("Raw") || - key.endsWith("Cents") || - key.endsWith("State") || - key.endsWith("Start") || kn === "cents" || kn === "bps" || - kn === "mvrv" || kn === "constants" || - kn === "blockhash" || - kn === "date" || + kn === "ohlc" || kn === "split" || - kn === "outpoint" || - kn === "positions" || - kn === "heighttopool" || - kn === "txid" || + kn === "spot" || kn.startsWith("timestamp") || - kn.startsWith("satdays") || - kn.startsWith("satblocks") || + kn.startsWith("coinyears") || kn.endsWith("index") || kn.endsWith("indexes") ) continue; - walkSeries(/** @type {TreeNode | null | undefined} */ (value), map, [ - ...path, - key, - ]); + const newPath = [...path, key]; + const joined = newPath.join("."); + if ( + joined.endsWith(".count.total.average") || + joined.endsWith(".versions.v1.average") || + joined.endsWith(".versions.v2.average") || + joined.endsWith(".versions.v3.average") + ) + continue; + walkSeries(/** @type {TreeNode | null | undefined} */ (value), map, newPath); } } }