diff --git a/Cargo.lock b/Cargo.lock index dc554bb1a..23e73f8ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2433,8 +2433,6 @@ dependencies = [ [[package]] name = "rawdb" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ebb540a243e937d5ec268361bbf7b83e05e6c4ad8de21ac9ee64c4f72e9001" dependencies = [ "libc", "log", @@ -3253,8 +3251,6 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23" [[package]] name = "vecdb" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64486e34d56d63797295aa928288542226b6f28f96a3b58f661b1efd9f54cde" dependencies = [ "ctrlc", "log", @@ -3274,8 +3270,6 @@ dependencies = [ [[package]] name = "vecdb_derive" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c1f863f6687e9ff90962a51a0f6c9646a14dc0ccfd9ea2ea79e288d88187bef" dependencies = [ "quote", "syn", diff --git a/Cargo.toml b/Cargo.toml index 1e9780179..83afdf843 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,8 +82,8 @@ tokio = { version = "1.49.0", features = ["rt-multi-thread"] } tracing = { version = "0.1", default-features = false, features = ["std"] } tower-http = { version = "0.6.8", features = ["catch-panic", "compression-br", "compression-gzip", "compression-zstd", "cors", "normalize-path", "timeout", "trace"] } tower-layer = "0.3" -vecdb = { version = "0.6.1", features = ["derive", "serde_json", "pco", "schemars"] } -# vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] } +# vecdb = { version = "0.6.1", features = ["derive", "serde_json", "pco", "schemars"] } +vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] } [workspace.metadata.release] shared-version = true diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index 322f01206..c9e62937d 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -1532,42 +1532,6 @@ impl PeriodLumpSumStackPattern { } } -/// Pattern struct for repeated tree structure. -pub struct PeriodAveragePricePattern { - pub _10y: MetricPattern4, - pub _1m: MetricPattern4, - pub _1w: MetricPattern4, - pub _1y: MetricPattern4, - pub _2y: MetricPattern4, - pub _3m: MetricPattern4, - pub _3y: MetricPattern4, - pub _4y: MetricPattern4, - pub _5y: MetricPattern4, - pub _6m: MetricPattern4, - pub _6y: MetricPattern4, - pub _8y: MetricPattern4, -} - -impl PeriodAveragePricePattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - _10y: MetricPattern4::new(client.clone(), _p("10y", &acc)), - _1m: MetricPattern4::new(client.clone(), _p("1m", &acc)), - _1w: MetricPattern4::new(client.clone(), _p("1w", &acc)), - _1y: MetricPattern4::new(client.clone(), _p("1y", &acc)), - _2y: MetricPattern4::new(client.clone(), _p("2y", &acc)), - _3m: MetricPattern4::new(client.clone(), _p("3m", &acc)), - _3y: MetricPattern4::new(client.clone(), _p("3y", &acc)), - _4y: MetricPattern4::new(client.clone(), _p("4y", &acc)), - _5y: MetricPattern4::new(client.clone(), _p("5y", &acc)), - _6m: MetricPattern4::new(client.clone(), _p("6m", &acc)), - _6y: MetricPattern4::new(client.clone(), _p("6y", &acc)), - _8y: MetricPattern4::new(client.clone(), _p("8y", &acc)), - } - } -} - /// Pattern struct for repeated tree structure. pub struct ClassAveragePricePattern { pub _2015: MetricPattern4, @@ -1604,6 +1568,42 @@ impl ClassAveragePricePattern { } } +/// Pattern struct for repeated tree structure. +pub struct PeriodAveragePricePattern { + pub _10y: MetricPattern4, + pub _1m: MetricPattern4, + pub _1w: MetricPattern4, + pub _1y: MetricPattern4, + pub _2y: MetricPattern4, + pub _3m: MetricPattern4, + pub _3y: MetricPattern4, + pub _4y: MetricPattern4, + pub _5y: MetricPattern4, + pub _6m: MetricPattern4, + pub _6y: MetricPattern4, + pub _8y: MetricPattern4, +} + +impl PeriodAveragePricePattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + _10y: MetricPattern4::new(client.clone(), _p("10y", &acc)), + _1m: MetricPattern4::new(client.clone(), _p("1m", &acc)), + _1w: MetricPattern4::new(client.clone(), _p("1w", &acc)), + _1y: MetricPattern4::new(client.clone(), _p("1y", &acc)), + _2y: MetricPattern4::new(client.clone(), _p("2y", &acc)), + _3m: MetricPattern4::new(client.clone(), _p("3m", &acc)), + _3y: MetricPattern4::new(client.clone(), _p("3y", &acc)), + _4y: MetricPattern4::new(client.clone(), _p("4y", &acc)), + _5y: MetricPattern4::new(client.clone(), _p("5y", &acc)), + _6m: MetricPattern4::new(client.clone(), _p("6m", &acc)), + _6y: MetricPattern4::new(client.clone(), _p("6y", &acc)), + _8y: MetricPattern4::new(client.clone(), _p("8y", &acc)), + } + } +} + /// Pattern struct for repeated tree structure. pub struct BitcoinPattern { pub average: MetricPattern2, @@ -1798,36 +1798,6 @@ impl AddrCountPattern { } } -/// Pattern struct for repeated tree structure. -pub struct FullnessPattern { - pub average: MetricPattern2, - pub base: MetricPattern11, - pub max: MetricPattern2, - pub median: MetricPattern6, - pub min: MetricPattern2, - pub pct10: MetricPattern6, - pub pct25: MetricPattern6, - pub pct75: MetricPattern6, - pub pct90: MetricPattern6, -} - -impl FullnessPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - average: MetricPattern2::new(client.clone(), _m(&acc, "average")), - base: MetricPattern11::new(client.clone(), acc.clone()), - max: MetricPattern2::new(client.clone(), _m(&acc, "max")), - median: MetricPattern6::new(client.clone(), _m(&acc, "median")), - min: MetricPattern2::new(client.clone(), _m(&acc, "min")), - pct10: MetricPattern6::new(client.clone(), _m(&acc, "pct10")), - pct25: MetricPattern6::new(client.clone(), _m(&acc, "pct25")), - pct75: MetricPattern6::new(client.clone(), _m(&acc, "pct75")), - pct90: MetricPattern6::new(client.clone(), _m(&acc, "pct90")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct FeeRatePattern { pub average: MetricPattern1, @@ -1858,6 +1828,36 @@ impl FeeRatePattern { } } +/// Pattern struct for repeated tree structure. +pub struct FullnessPattern { + pub average: MetricPattern2, + pub base: MetricPattern11, + pub max: MetricPattern2, + pub median: MetricPattern6, + pub min: MetricPattern2, + pub pct10: MetricPattern6, + pub pct25: MetricPattern6, + pub pct75: MetricPattern6, + pub pct90: MetricPattern6, +} + +impl FullnessPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + average: MetricPattern2::new(client.clone(), _m(&acc, "average")), + base: MetricPattern11::new(client.clone(), acc.clone()), + max: MetricPattern2::new(client.clone(), _m(&acc, "max")), + median: MetricPattern6::new(client.clone(), _m(&acc, "median")), + min: MetricPattern2::new(client.clone(), _m(&acc, "min")), + pct10: MetricPattern6::new(client.clone(), _m(&acc, "pct10")), + pct25: MetricPattern6::new(client.clone(), _m(&acc, "pct25")), + pct75: MetricPattern6::new(client.clone(), _m(&acc, "pct75")), + pct90: MetricPattern6::new(client.clone(), _m(&acc, "pct90")), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _0satsPattern { pub activity: ActivityPattern2, @@ -1914,6 +1914,32 @@ impl PhaseDailyCentsPattern { } } +/// Pattern struct for repeated tree structure. +pub struct _0satsPattern2 { + pub activity: ActivityPattern2, + pub cost_basis: CostBasisPattern, + pub outputs: OutputsPattern, + pub realized: RealizedPattern, + pub relative: RelativePattern4, + pub supply: SupplyPattern2, + pub unrealized: UnrealizedPattern, +} + +impl _0satsPattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + activity: ActivityPattern2::new(client.clone(), acc.clone()), + cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), + outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), + realized: RealizedPattern::new(client.clone(), acc.clone()), + relative: RelativePattern4::new(client.clone(), _m(&acc, "supply_in")), + supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), + unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _100btcPattern { pub activity: ActivityPattern2, @@ -1966,32 +1992,6 @@ impl PeriodCagrPattern { } } -/// Pattern struct for repeated tree structure. -pub struct _0satsPattern2 { - pub activity: ActivityPattern2, - pub cost_basis: CostBasisPattern, - pub outputs: OutputsPattern, - pub realized: RealizedPattern, - pub relative: RelativePattern4, - pub supply: SupplyPattern2, - pub unrealized: UnrealizedPattern, -} - -impl _0satsPattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - activity: ActivityPattern2::new(client.clone(), acc.clone()), - cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), - outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: RealizedPattern::new(client.clone(), acc.clone()), - relative: RelativePattern4::new(client.clone(), _m(&acc, "supply_in")), - supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), - unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct _10yTo12yPattern { pub activity: ActivityPattern2, @@ -2018,6 +2018,32 @@ impl _10yTo12yPattern { } } +/// Pattern struct for repeated tree structure. +pub struct _10yPattern { + pub activity: ActivityPattern2, + pub cost_basis: CostBasisPattern, + pub outputs: OutputsPattern, + pub realized: RealizedPattern4, + pub relative: RelativePattern, + pub supply: SupplyPattern2, + pub unrealized: UnrealizedPattern, +} + +impl _10yPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + activity: ActivityPattern2::new(client.clone(), acc.clone()), + cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), + outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), + realized: RealizedPattern4::new(client.clone(), acc.clone()), + relative: RelativePattern::new(client.clone(), acc.clone()), + supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), + unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct UnrealizedPattern { pub neg_unrealized_loss: MetricPattern1, @@ -2044,32 +2070,6 @@ impl UnrealizedPattern { } } -/// Pattern struct for repeated tree structure. -pub struct _10yPattern { - pub activity: ActivityPattern2, - pub cost_basis: CostBasisPattern, - pub outputs: OutputsPattern, - pub realized: RealizedPattern4, - pub relative: RelativePattern, - pub supply: SupplyPattern2, - pub unrealized: UnrealizedPattern, -} - -impl _10yPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - activity: ActivityPattern2::new(client.clone(), acc.clone()), - cost_basis: CostBasisPattern::new(client.clone(), acc.clone()), - outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")), - realized: RealizedPattern4::new(client.clone(), acc.clone()), - relative: RelativePattern::new(client.clone(), acc.clone()), - supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")), - unrealized: UnrealizedPattern::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct ActivityPattern2 { pub coinblocks_destroyed: BlockCountPattern, @@ -2130,42 +2130,6 @@ impl CostBasisPattern2 { } } -/// Pattern struct for repeated tree structure. -pub struct CoinbasePattern { - pub bitcoin: BitcoinPattern, - pub dollars: DollarsPattern, - pub sats: DollarsPattern, -} - -impl CoinbasePattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - bitcoin: BitcoinPattern::new(client.clone(), _m(&acc, "btc")), - dollars: DollarsPattern::new(client.clone(), _m(&acc, "usd")), - sats: DollarsPattern::new(client.clone(), acc.clone()), - } - } -} - -/// Pattern struct for repeated tree structure. -pub struct CoinbasePattern2 { - pub bitcoin: BlockCountPattern, - pub dollars: BlockCountPattern, - pub sats: BlockCountPattern, -} - -impl CoinbasePattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")), - dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), - sats: BlockCountPattern::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct ActiveSupplyPattern { pub bitcoin: MetricPattern1, @@ -2202,6 +2166,24 @@ impl SegwitAdoptionPattern { } } +/// Pattern struct for repeated tree structure. +pub struct CoinbasePattern2 { + pub bitcoin: BlockCountPattern, + pub dollars: BlockCountPattern, + pub sats: BlockCountPattern, +} + +impl CoinbasePattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")), + dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")), + sats: BlockCountPattern::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct UnclaimedRewardsPattern { pub bitcoin: BitcoinPattern2, @@ -2220,6 +2202,24 @@ impl UnclaimedRewardsPattern { } } +/// Pattern struct for repeated tree structure. +pub struct CoinbasePattern { + pub bitcoin: BitcoinPattern, + pub dollars: DollarsPattern, + pub sats: DollarsPattern, +} + +impl CoinbasePattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + bitcoin: BitcoinPattern::new(client.clone(), _m(&acc, "btc")), + dollars: DollarsPattern::new(client.clone(), _m(&acc, "usd")), + sats: DollarsPattern::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct _2015Pattern { pub bitcoin: MetricPattern4, @@ -2238,22 +2238,6 @@ impl _2015Pattern { } } -/// Pattern struct for repeated tree structure. -pub struct SupplyPattern2 { - pub halved: ActiveSupplyPattern, - pub total: ActiveSupplyPattern, -} - -impl SupplyPattern2 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - halved: ActiveSupplyPattern::new(client.clone(), _m(&acc, "halved")), - total: ActiveSupplyPattern::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct RelativePattern4 { pub supply_in_loss_rel_to_own_supply: MetricPattern1, @@ -2270,6 +2254,22 @@ impl RelativePattern4 { } } +/// Pattern struct for repeated tree structure. +pub struct SupplyPattern2 { + pub halved: ActiveSupplyPattern, + pub total: ActiveSupplyPattern, +} + +impl SupplyPattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + halved: ActiveSupplyPattern::new(client.clone(), _m(&acc, "halved")), + total: ActiveSupplyPattern::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct CostBasisPattern { pub max: MetricPattern1, @@ -4205,11 +4205,24 @@ impl MetricsTree_Market_Ath { /// Metrics tree node. pub struct MetricsTree_Market_Dca { pub class_average_price: ClassAveragePricePattern, + pub class_days_in_loss: MetricsTree_Market_Dca_ClassDaysInLoss, + pub class_days_in_profit: MetricsTree_Market_Dca_ClassDaysInProfit, + pub class_max_drawdown: MetricsTree_Market_Dca_ClassMaxDrawdown, + pub class_max_return: MetricsTree_Market_Dca_ClassMaxReturn, pub class_returns: MetricsTree_Market_Dca_ClassReturns, pub class_stack: MetricsTree_Market_Dca_ClassStack, pub period_average_price: PeriodAveragePricePattern, pub period_cagr: PeriodCagrPattern, + pub period_days_in_loss: PeriodAveragePricePattern, + pub period_days_in_profit: PeriodAveragePricePattern, + pub period_lump_sum_days_in_loss: PeriodAveragePricePattern, + pub period_lump_sum_days_in_profit: PeriodAveragePricePattern, + pub period_lump_sum_max_drawdown: PeriodAveragePricePattern, + pub period_lump_sum_max_return: PeriodAveragePricePattern, + pub period_lump_sum_returns: PeriodAveragePricePattern, pub period_lump_sum_stack: PeriodLumpSumStackPattern, + pub period_max_drawdown: PeriodAveragePricePattern, + pub period_max_return: PeriodAveragePricePattern, pub period_returns: PeriodAveragePricePattern, pub period_stack: PeriodLumpSumStackPattern, } @@ -4218,17 +4231,170 @@ impl MetricsTree_Market_Dca { pub fn new(client: Arc, base_path: String) -> Self { Self { class_average_price: ClassAveragePricePattern::new(client.clone(), "dca_class".to_string()), + class_days_in_loss: MetricsTree_Market_Dca_ClassDaysInLoss::new(client.clone(), format!("{base_path}_class_days_in_loss")), + class_days_in_profit: MetricsTree_Market_Dca_ClassDaysInProfit::new(client.clone(), format!("{base_path}_class_days_in_profit")), + class_max_drawdown: MetricsTree_Market_Dca_ClassMaxDrawdown::new(client.clone(), format!("{base_path}_class_max_drawdown")), + class_max_return: MetricsTree_Market_Dca_ClassMaxReturn::new(client.clone(), format!("{base_path}_class_max_return")), class_returns: MetricsTree_Market_Dca_ClassReturns::new(client.clone(), format!("{base_path}_class_returns")), class_stack: MetricsTree_Market_Dca_ClassStack::new(client.clone(), format!("{base_path}_class_stack")), period_average_price: PeriodAveragePricePattern::new(client.clone(), "dca_average_price".to_string()), period_cagr: PeriodCagrPattern::new(client.clone(), "dca_cagr".to_string()), + period_days_in_loss: PeriodAveragePricePattern::new(client.clone(), "dca_days_in_loss".to_string()), + period_days_in_profit: PeriodAveragePricePattern::new(client.clone(), "dca_days_in_profit".to_string()), + period_lump_sum_days_in_loss: PeriodAveragePricePattern::new(client.clone(), "lump_sum_days_in_loss".to_string()), + period_lump_sum_days_in_profit: PeriodAveragePricePattern::new(client.clone(), "lump_sum_days_in_profit".to_string()), + period_lump_sum_max_drawdown: PeriodAveragePricePattern::new(client.clone(), "lump_sum_max_drawdown".to_string()), + period_lump_sum_max_return: PeriodAveragePricePattern::new(client.clone(), "lump_sum_max_return".to_string()), + period_lump_sum_returns: PeriodAveragePricePattern::new(client.clone(), "lump_sum_returns".to_string()), period_lump_sum_stack: PeriodLumpSumStackPattern::new(client.clone(), "lump_sum_stack".to_string()), + period_max_drawdown: PeriodAveragePricePattern::new(client.clone(), "dca_max_drawdown".to_string()), + period_max_return: PeriodAveragePricePattern::new(client.clone(), "dca_max_return".to_string()), period_returns: PeriodAveragePricePattern::new(client.clone(), "dca_returns".to_string()), period_stack: PeriodLumpSumStackPattern::new(client.clone(), "dca_stack".to_string()), } } } +/// Metrics tree node. +pub struct MetricsTree_Market_Dca_ClassDaysInLoss { + pub _2015: MetricPattern4, + pub _2016: MetricPattern4, + pub _2017: MetricPattern4, + pub _2018: MetricPattern4, + pub _2019: MetricPattern4, + pub _2020: MetricPattern4, + pub _2021: MetricPattern4, + pub _2022: MetricPattern4, + pub _2023: MetricPattern4, + pub _2024: MetricPattern4, + pub _2025: MetricPattern4, + pub _2026: MetricPattern4, +} + +impl MetricsTree_Market_Dca_ClassDaysInLoss { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + _2015: MetricPattern4::new(client.clone(), "dca_class_2015_days_in_loss".to_string()), + _2016: MetricPattern4::new(client.clone(), "dca_class_2016_days_in_loss".to_string()), + _2017: MetricPattern4::new(client.clone(), "dca_class_2017_days_in_loss".to_string()), + _2018: MetricPattern4::new(client.clone(), "dca_class_2018_days_in_loss".to_string()), + _2019: MetricPattern4::new(client.clone(), "dca_class_2019_days_in_loss".to_string()), + _2020: MetricPattern4::new(client.clone(), "dca_class_2020_days_in_loss".to_string()), + _2021: MetricPattern4::new(client.clone(), "dca_class_2021_days_in_loss".to_string()), + _2022: MetricPattern4::new(client.clone(), "dca_class_2022_days_in_loss".to_string()), + _2023: MetricPattern4::new(client.clone(), "dca_class_2023_days_in_loss".to_string()), + _2024: MetricPattern4::new(client.clone(), "dca_class_2024_days_in_loss".to_string()), + _2025: MetricPattern4::new(client.clone(), "dca_class_2025_days_in_loss".to_string()), + _2026: MetricPattern4::new(client.clone(), "dca_class_2026_days_in_loss".to_string()), + } + } +} + +/// Metrics tree node. +pub struct MetricsTree_Market_Dca_ClassDaysInProfit { + pub _2015: MetricPattern4, + pub _2016: MetricPattern4, + pub _2017: MetricPattern4, + pub _2018: MetricPattern4, + pub _2019: MetricPattern4, + pub _2020: MetricPattern4, + pub _2021: MetricPattern4, + pub _2022: MetricPattern4, + pub _2023: MetricPattern4, + pub _2024: MetricPattern4, + pub _2025: MetricPattern4, + pub _2026: MetricPattern4, +} + +impl MetricsTree_Market_Dca_ClassDaysInProfit { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + _2015: MetricPattern4::new(client.clone(), "dca_class_2015_days_in_profit".to_string()), + _2016: MetricPattern4::new(client.clone(), "dca_class_2016_days_in_profit".to_string()), + _2017: MetricPattern4::new(client.clone(), "dca_class_2017_days_in_profit".to_string()), + _2018: MetricPattern4::new(client.clone(), "dca_class_2018_days_in_profit".to_string()), + _2019: MetricPattern4::new(client.clone(), "dca_class_2019_days_in_profit".to_string()), + _2020: MetricPattern4::new(client.clone(), "dca_class_2020_days_in_profit".to_string()), + _2021: MetricPattern4::new(client.clone(), "dca_class_2021_days_in_profit".to_string()), + _2022: MetricPattern4::new(client.clone(), "dca_class_2022_days_in_profit".to_string()), + _2023: MetricPattern4::new(client.clone(), "dca_class_2023_days_in_profit".to_string()), + _2024: MetricPattern4::new(client.clone(), "dca_class_2024_days_in_profit".to_string()), + _2025: MetricPattern4::new(client.clone(), "dca_class_2025_days_in_profit".to_string()), + _2026: MetricPattern4::new(client.clone(), "dca_class_2026_days_in_profit".to_string()), + } + } +} + +/// Metrics tree node. +pub struct MetricsTree_Market_Dca_ClassMaxDrawdown { + pub _2015: MetricPattern4, + pub _2016: MetricPattern4, + pub _2017: MetricPattern4, + pub _2018: MetricPattern4, + pub _2019: MetricPattern4, + pub _2020: MetricPattern4, + pub _2021: MetricPattern4, + pub _2022: MetricPattern4, + pub _2023: MetricPattern4, + pub _2024: MetricPattern4, + pub _2025: MetricPattern4, + pub _2026: MetricPattern4, +} + +impl MetricsTree_Market_Dca_ClassMaxDrawdown { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + _2015: MetricPattern4::new(client.clone(), "dca_class_2015_max_drawdown".to_string()), + _2016: MetricPattern4::new(client.clone(), "dca_class_2016_max_drawdown".to_string()), + _2017: MetricPattern4::new(client.clone(), "dca_class_2017_max_drawdown".to_string()), + _2018: MetricPattern4::new(client.clone(), "dca_class_2018_max_drawdown".to_string()), + _2019: MetricPattern4::new(client.clone(), "dca_class_2019_max_drawdown".to_string()), + _2020: MetricPattern4::new(client.clone(), "dca_class_2020_max_drawdown".to_string()), + _2021: MetricPattern4::new(client.clone(), "dca_class_2021_max_drawdown".to_string()), + _2022: MetricPattern4::new(client.clone(), "dca_class_2022_max_drawdown".to_string()), + _2023: MetricPattern4::new(client.clone(), "dca_class_2023_max_drawdown".to_string()), + _2024: MetricPattern4::new(client.clone(), "dca_class_2024_max_drawdown".to_string()), + _2025: MetricPattern4::new(client.clone(), "dca_class_2025_max_drawdown".to_string()), + _2026: MetricPattern4::new(client.clone(), "dca_class_2026_max_drawdown".to_string()), + } + } +} + +/// Metrics tree node. +pub struct MetricsTree_Market_Dca_ClassMaxReturn { + pub _2015: MetricPattern4, + pub _2016: MetricPattern4, + pub _2017: MetricPattern4, + pub _2018: MetricPattern4, + pub _2019: MetricPattern4, + pub _2020: MetricPattern4, + pub _2021: MetricPattern4, + pub _2022: MetricPattern4, + pub _2023: MetricPattern4, + pub _2024: MetricPattern4, + pub _2025: MetricPattern4, + pub _2026: MetricPattern4, +} + +impl MetricsTree_Market_Dca_ClassMaxReturn { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + _2015: MetricPattern4::new(client.clone(), "dca_class_2015_max_return".to_string()), + _2016: MetricPattern4::new(client.clone(), "dca_class_2016_max_return".to_string()), + _2017: MetricPattern4::new(client.clone(), "dca_class_2017_max_return".to_string()), + _2018: MetricPattern4::new(client.clone(), "dca_class_2018_max_return".to_string()), + _2019: MetricPattern4::new(client.clone(), "dca_class_2019_max_return".to_string()), + _2020: MetricPattern4::new(client.clone(), "dca_class_2020_max_return".to_string()), + _2021: MetricPattern4::new(client.clone(), "dca_class_2021_max_return".to_string()), + _2022: MetricPattern4::new(client.clone(), "dca_class_2022_max_return".to_string()), + _2023: MetricPattern4::new(client.clone(), "dca_class_2023_max_return".to_string()), + _2024: MetricPattern4::new(client.clone(), "dca_class_2024_max_return".to_string()), + _2025: MetricPattern4::new(client.clone(), "dca_class_2025_max_return".to_string()), + _2026: MetricPattern4::new(client.clone(), "dca_class_2026_max_return".to_string()), + } + } +} + /// Metrics tree node. pub struct MetricsTree_Market_Dca_ClassReturns { pub _2015: MetricPattern4, diff --git a/crates/brk_computer/src/market/dca/compute.rs b/crates/brk_computer/src/market/dca/compute.rs index 75d039b50..cf51fe26f 100644 --- a/crates/brk_computer/src/market/dca/compute.rs +++ b/crates/brk_computer/src/market/dca/compute.rs @@ -1,9 +1,11 @@ use brk_error::Result; +use brk_types::{Close, Dollars, StoredF32, StoredU32}; use vecdb::Exit; -use super::Vecs; +use super::{ByDcaClass, ByDcaPeriod, Vecs}; use crate::{ ComputeIndexes, + internal::{ComputedFromDateLast, LazyBinaryFromDateLast}, market::lookback, price, traits::{ComputeDCAAveragePriceViaLen, ComputeDCAStackViaLen, ComputeLumpSumStackViaLen}, @@ -61,6 +63,17 @@ impl Vecs { })?; } + // DCA by period - profitability + compute_period_profitability( + &mut self.period_days_in_profit, + &mut self.period_days_in_loss, + &mut self.period_max_drawdown, + &mut self.period_max_return, + &self.period_returns, + starting_indexes, + exit, + )?; + // Lump sum by period - stack (for comparison with DCA) let lookback_dca = lookback.price_ago.as_dca_period(); for (stack, lookback_price, days) in @@ -78,6 +91,17 @@ impl Vecs { })?; } + // Lump sum by period - profitability + compute_period_profitability( + &mut self.period_lump_sum_days_in_profit, + &mut self.period_lump_sum_days_in_loss, + &mut self.period_lump_sum_max_drawdown, + &mut self.period_lump_sum_max_return, + &self.period_lump_sum_returns, + starting_indexes, + exit, + )?; + // DCA by year class - stack and average_price let dateindexes = super::ByDcaClass::<()>::dateindexes(); for ((stack, average_price), dateindex) in self @@ -102,6 +126,134 @@ impl Vecs { })?; } + // DCA by year class - profitability + compute_class_profitability( + &mut self.class_days_in_profit, + &mut self.class_days_in_loss, + &mut self.class_max_drawdown, + &mut self.class_max_return, + &self.class_returns, + starting_indexes, + exit, + )?; + Ok(()) } } + +fn compute_period_profitability( + days_in_profit: &mut ByDcaPeriod>, + days_in_loss: &mut ByDcaPeriod>, + max_drawdown: &mut ByDcaPeriod>, + max_return: &mut ByDcaPeriod>, + returns: &ByDcaPeriod, Dollars>>, + starting_indexes: &ComputeIndexes, + exit: &Exit, +) -> Result<()> { + for ((((dip, dil), md), mr), (ret, days)) in days_in_profit + .iter_mut() + .zip(days_in_loss.iter_mut()) + .zip(max_drawdown.iter_mut()) + .zip(max_return.iter_mut()) + .zip(returns.iter_with_days()) + { + dip.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_rolling_count( + starting_indexes.dateindex, + &ret.dateindex, + days as usize, + |r| f32::from(*r) > 0.0, + exit, + )?) + })?; + + dil.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_rolling_count( + starting_indexes.dateindex, + &ret.dateindex, + days as usize, + |r| f32::from(*r) < 0.0, + exit, + )?) + })?; + + md.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_min( + starting_indexes.dateindex, + &ret.dateindex, + days as usize, + exit, + )?) + })?; + + mr.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_max( + starting_indexes.dateindex, + &ret.dateindex, + days as usize, + exit, + )?) + })?; + } + Ok(()) +} + +fn compute_class_profitability( + days_in_profit: &mut ByDcaClass>, + days_in_loss: &mut ByDcaClass>, + max_drawdown: &mut ByDcaClass>, + max_return: &mut ByDcaClass>, + returns: &ByDcaClass, Dollars>>, + starting_indexes: &ComputeIndexes, + exit: &Exit, +) -> Result<()> { + let dateindexes = ByDcaClass::<()>::dateindexes(); + + for (((((dip, dil), md), mr), ret), from) in days_in_profit + .iter_mut() + .zip(days_in_loss.iter_mut()) + .zip(max_drawdown.iter_mut()) + .zip(max_return.iter_mut()) + .zip(returns.iter()) + .zip(dateindexes) + { + dip.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_cumulative_count_from( + starting_indexes.dateindex, + &ret.dateindex, + from, + |r| f32::from(*r) > 0.0, + exit, + )?) + })?; + + dil.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_cumulative_count_from( + starting_indexes.dateindex, + &ret.dateindex, + from, + |r| f32::from(*r) < 0.0, + exit, + )?) + })?; + + md.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_all_time_low_from( + starting_indexes.dateindex, + &ret.dateindex, + from, + exit, + )?) + })?; + + mr.compute_all(starting_indexes, exit, |v| { + Ok(v.compute_all_time_high_from( + starting_indexes.dateindex, + &ret.dateindex, + from, + exit, + )?) + })?; + } + Ok(()) +} diff --git a/crates/brk_computer/src/market/dca/import.rs b/crates/brk_computer/src/market/dca/import.rs index 236fb178a..856de19f5 100644 --- a/crates/brk_computer/src/market/dca/import.rs +++ b/crates/brk_computer/src/market/dca/import.rs @@ -1,11 +1,15 @@ use brk_error::Result; use brk_types::Version; -use vecdb::Database; +use vecdb::{Database, IterableCloneableVec}; use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod, DCA_CLASS_NAMES, DCA_PERIOD_NAMES, Vecs}; use crate::{ indexes, - internal::{ComputedFromDateLast, LazyBinaryFromDateLast, PercentageDiffCloseDollars, ValueFromDateLast}, + internal::{ + ComputedFromDateLast, LazyBinaryFromDateLast, PercentageDiffCloseDollars, + ValueFromDateLast, + }, + market::lookback, price, }; @@ -15,6 +19,7 @@ impl Vecs { version: Version, indexes: &indexes::Vecs, price: &price::Vecs, + lookback: &lookback::Vecs, ) -> Result { // DCA by period - stack (KISS) let period_stack = ByDcaPeriod::try_new(|name, _days| { @@ -48,6 +53,43 @@ impl Vecs { ComputedFromDateLast::forced_import(db, &format!("{name}_dca_cagr"), version, indexes) })?; + // DCA by period - profitability + let period_days_in_profit = ByDcaPeriod::try_new(|name, _days| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_dca_days_in_profit"), + version + Version::ONE, + indexes, + ) + })?; + + let period_days_in_loss = ByDcaPeriod::try_new(|name, _days| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_dca_days_in_loss"), + version + Version::ONE, + indexes, + ) + })?; + + let period_max_drawdown = ByDcaPeriod::try_new(|name, _days| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_dca_max_drawdown"), + version, + indexes, + ) + })?; + + let period_max_return = ByDcaPeriod::try_new(|name, _days| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_dca_max_return"), + version, + indexes, + ) + })?; + // Lump sum by period - stack (KISS) let period_lump_sum_stack = ByDcaPeriod::try_new(|name, _days| { ValueFromDateLast::forced_import( @@ -59,6 +101,58 @@ impl Vecs { ) })?; + // Lump sum by period - returns + let period_lump_sum_returns = DCA_PERIOD_NAMES + .zip_ref(&lookback.price_ago.as_dca_period()) + .map(|(name, lookback_price)| { + LazyBinaryFromDateLast::from_derived_last_and_computed_last::< + PercentageDiffCloseDollars, + >( + &format!("{name}_lump_sum_returns"), + version, + price.usd.split.close.dateindex.boxed_clone(), + &price.usd.split.close.rest, + lookback_price, + ) + }); + + // Lump sum by period - profitability + let period_lump_sum_days_in_profit = ByDcaPeriod::try_new(|name, _days| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_lump_sum_days_in_profit"), + version + Version::ONE, + indexes, + ) + })?; + + let period_lump_sum_days_in_loss = ByDcaPeriod::try_new(|name, _days| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_lump_sum_days_in_loss"), + version + Version::ONE, + indexes, + ) + })?; + + let period_lump_sum_max_drawdown = ByDcaPeriod::try_new(|name, _days| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_lump_sum_max_drawdown"), + version, + indexes, + ) + })?; + + let period_lump_sum_max_return = ByDcaPeriod::try_new(|name, _days| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_lump_sum_max_return"), + version, + indexes, + ) + })?; + // DCA by year class - stack (KISS) let class_stack = ByDcaClass::try_new(|name, _year, _dateindex| { ValueFromDateLast::forced_import(db, &format!("{name}_stack"), version, true, indexes) @@ -81,15 +175,65 @@ impl Vecs { ) }); + // DCA by year class - profitability + let class_days_in_profit = ByDcaClass::try_new(|name, _year, _dateindex| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_days_in_profit"), + version, + indexes, + ) + })?; + + let class_days_in_loss = ByDcaClass::try_new(|name, _year, _dateindex| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_days_in_loss"), + version, + indexes, + ) + })?; + + let class_max_drawdown = ByDcaClass::try_new(|name, _year, _dateindex| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_max_drawdown"), + version, + indexes, + ) + })?; + + let class_max_return = ByDcaClass::try_new(|name, _year, _dateindex| { + ComputedFromDateLast::forced_import( + db, + &format!("{name}_max_return"), + version, + indexes, + ) + })?; + Ok(Self { period_stack, period_average_price, period_returns, period_cagr, + period_days_in_profit, + period_days_in_loss, + period_max_drawdown, + period_max_return, period_lump_sum_stack, + period_lump_sum_returns, + period_lump_sum_days_in_profit, + period_lump_sum_days_in_loss, + period_lump_sum_max_drawdown, + period_lump_sum_max_return, class_stack, class_average_price, class_returns, + class_days_in_profit, + class_days_in_loss, + class_max_drawdown, + class_max_return, }) } } diff --git a/crates/brk_computer/src/market/dca/vecs.rs b/crates/brk_computer/src/market/dca/vecs.rs index 36043caf1..b1badcb48 100644 --- a/crates/brk_computer/src/market/dca/vecs.rs +++ b/crates/brk_computer/src/market/dca/vecs.rs @@ -1,5 +1,5 @@ use brk_traversable::Traversable; -use brk_types::{Close, Dollars, StoredF32}; +use brk_types::{Close, Dollars, StoredF32, StoredU32}; use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod}; use crate::internal::{ComputedFromDateLast, LazyBinaryFromDateLast, ValueFromDateLast}; @@ -13,11 +13,30 @@ pub struct Vecs { pub period_returns: ByDcaPeriod, Dollars>>, pub period_cagr: ByDcaCagr>, + // DCA by period - profitability + pub period_days_in_profit: ByDcaPeriod>, + pub period_days_in_loss: ByDcaPeriod>, + pub period_max_drawdown: ByDcaPeriod>, + pub period_max_return: ByDcaPeriod>, + // Lump sum by period (for comparison with DCA) - KISS types pub period_lump_sum_stack: ByDcaPeriod, + pub period_lump_sum_returns: ByDcaPeriod, Dollars>>, + + // Lump sum by period - profitability + pub period_lump_sum_days_in_profit: ByDcaPeriod>, + pub period_lump_sum_days_in_loss: ByDcaPeriod>, + pub period_lump_sum_max_drawdown: ByDcaPeriod>, + pub period_lump_sum_max_return: ByDcaPeriod>, // DCA by year class - KISS types pub class_stack: ByDcaClass, pub class_average_price: ByDcaClass>, pub class_returns: ByDcaClass, Dollars>>, + + // DCA by year class - profitability + pub class_days_in_profit: ByDcaClass>, + pub class_days_in_loss: ByDcaClass>, + pub class_max_drawdown: ByDcaClass>, + pub class_max_return: ByDcaClass>, } diff --git a/crates/brk_computer/src/market/import.rs b/crates/brk_computer/src/market/import.rs index 683c96a9c..b90191a8c 100644 --- a/crates/brk_computer/src/market/import.rs +++ b/crates/brk_computer/src/market/import.rs @@ -34,7 +34,7 @@ impl Vecs { let volatility = VolatilityVecs::forced_import(version, &returns); let range = RangeVecs::forced_import(&db, version, indexes)?; let moving_average = MovingAverageVecs::forced_import(&db, version, indexes, Some(price))?; - let dca = DcaVecs::forced_import(&db, version, indexes, price)?; + let dca = DcaVecs::forced_import(&db, version, indexes, price, &lookback)?; let indicators = IndicatorsVecs::forced_import( &db, version, diff --git a/crates/brk_types/src/stored_u32.rs b/crates/brk_types/src/stored_u32.rs index 0ef196256..a315867cc 100644 --- a/crates/brk_types/src/stored_u32.rs +++ b/crates/brk_types/src/stored_u32.rs @@ -49,6 +49,13 @@ impl From for StoredU32 { } } +impl From for u32 { + #[inline] + fn from(value: StoredU32) -> Self { + value.0 + } +} + impl From for f32 { #[inline] fn from(value: StoredU32) -> Self { diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index a51392745..2b762f679 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -1931,47 +1931,6 @@ function createPeriodLumpSumStackPattern(client, acc) { }; } -/** - * @template T - * @typedef {Object} PeriodAveragePricePattern - * @property {MetricPattern4} _10y - * @property {MetricPattern4} _1m - * @property {MetricPattern4} _1w - * @property {MetricPattern4} _1y - * @property {MetricPattern4} _2y - * @property {MetricPattern4} _3m - * @property {MetricPattern4} _3y - * @property {MetricPattern4} _4y - * @property {MetricPattern4} _5y - * @property {MetricPattern4} _6m - * @property {MetricPattern4} _6y - * @property {MetricPattern4} _8y - */ - -/** - * Create a PeriodAveragePricePattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {PeriodAveragePricePattern} - */ -function createPeriodAveragePricePattern(client, acc) { - return { - _10y: createMetricPattern4(client, _p('10y', acc)), - _1m: createMetricPattern4(client, _p('1m', acc)), - _1w: createMetricPattern4(client, _p('1w', acc)), - _1y: createMetricPattern4(client, _p('1y', acc)), - _2y: createMetricPattern4(client, _p('2y', acc)), - _3m: createMetricPattern4(client, _p('3m', acc)), - _3y: createMetricPattern4(client, _p('3y', acc)), - _4y: createMetricPattern4(client, _p('4y', acc)), - _5y: createMetricPattern4(client, _p('5y', acc)), - _6m: createMetricPattern4(client, _p('6m', acc)), - _6y: createMetricPattern4(client, _p('6y', acc)), - _8y: createMetricPattern4(client, _p('8y', acc)), - }; -} - /** * @template T * @typedef {Object} ClassAveragePricePattern @@ -2013,6 +1972,47 @@ function createClassAveragePricePattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} PeriodAveragePricePattern + * @property {MetricPattern4} _10y + * @property {MetricPattern4} _1m + * @property {MetricPattern4} _1w + * @property {MetricPattern4} _1y + * @property {MetricPattern4} _2y + * @property {MetricPattern4} _3m + * @property {MetricPattern4} _3y + * @property {MetricPattern4} _4y + * @property {MetricPattern4} _5y + * @property {MetricPattern4} _6m + * @property {MetricPattern4} _6y + * @property {MetricPattern4} _8y + */ + +/** + * Create a PeriodAveragePricePattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {PeriodAveragePricePattern} + */ +function createPeriodAveragePricePattern(client, acc) { + return { + _10y: createMetricPattern4(client, _p('10y', acc)), + _1m: createMetricPattern4(client, _p('1m', acc)), + _1w: createMetricPattern4(client, _p('1w', acc)), + _1y: createMetricPattern4(client, _p('1y', acc)), + _2y: createMetricPattern4(client, _p('2y', acc)), + _3m: createMetricPattern4(client, _p('3m', acc)), + _3y: createMetricPattern4(client, _p('3y', acc)), + _4y: createMetricPattern4(client, _p('4y', acc)), + _5y: createMetricPattern4(client, _p('5y', acc)), + _6m: createMetricPattern4(client, _p('6m', acc)), + _6y: createMetricPattern4(client, _p('6y', acc)), + _8y: createMetricPattern4(client, _p('8y', acc)), + }; +} + /** * @typedef {Object} BitcoinPattern * @property {MetricPattern2} average @@ -2229,41 +2229,6 @@ function createAddrCountPattern(client, acc) { }; } -/** - * @template T - * @typedef {Object} FullnessPattern - * @property {MetricPattern2} average - * @property {MetricPattern11} base - * @property {MetricPattern2} max - * @property {MetricPattern6} median - * @property {MetricPattern2} min - * @property {MetricPattern6} pct10 - * @property {MetricPattern6} pct25 - * @property {MetricPattern6} pct75 - * @property {MetricPattern6} pct90 - */ - -/** - * Create a FullnessPattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {FullnessPattern} - */ -function createFullnessPattern(client, acc) { - return { - average: createMetricPattern2(client, _m(acc, 'average')), - base: createMetricPattern11(client, acc), - max: createMetricPattern2(client, _m(acc, 'max')), - median: createMetricPattern6(client, _m(acc, 'median')), - min: createMetricPattern2(client, _m(acc, 'min')), - pct10: createMetricPattern6(client, _m(acc, 'pct10')), - pct25: createMetricPattern6(client, _m(acc, 'pct25')), - pct75: createMetricPattern6(client, _m(acc, 'pct75')), - pct90: createMetricPattern6(client, _m(acc, 'pct90')), - }; -} - /** * @template T * @typedef {Object} FeeRatePattern @@ -2299,6 +2264,41 @@ function createFeeRatePattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} FullnessPattern + * @property {MetricPattern2} average + * @property {MetricPattern11} base + * @property {MetricPattern2} max + * @property {MetricPattern6} median + * @property {MetricPattern2} min + * @property {MetricPattern6} pct10 + * @property {MetricPattern6} pct25 + * @property {MetricPattern6} pct75 + * @property {MetricPattern6} pct90 + */ + +/** + * Create a FullnessPattern pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {FullnessPattern} + */ +function createFullnessPattern(client, acc) { + return { + average: createMetricPattern2(client, _m(acc, 'average')), + base: createMetricPattern11(client, acc), + max: createMetricPattern2(client, _m(acc, 'max')), + median: createMetricPattern6(client, _m(acc, 'median')), + min: createMetricPattern2(client, _m(acc, 'min')), + pct10: createMetricPattern6(client, _m(acc, 'pct10')), + pct25: createMetricPattern6(client, _m(acc, 'pct25')), + pct75: createMetricPattern6(client, _m(acc, 'pct75')), + pct90: createMetricPattern6(client, _m(acc, 'pct90')), + }; +} + /** * @typedef {Object} _0satsPattern * @property {ActivityPattern2} activity @@ -2363,6 +2363,35 @@ function createPhaseDailyCentsPattern(client, acc) { }; } +/** + * @typedef {Object} _0satsPattern2 + * @property {ActivityPattern2} activity + * @property {CostBasisPattern} costBasis + * @property {OutputsPattern} outputs + * @property {RealizedPattern} realized + * @property {RelativePattern4} relative + * @property {SupplyPattern2} supply + * @property {UnrealizedPattern} unrealized + */ + +/** + * Create a _0satsPattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_0satsPattern2} + */ +function create_0satsPattern2(client, acc) { + return { + activity: createActivityPattern2(client, acc), + costBasis: createCostBasisPattern(client, acc), + outputs: createOutputsPattern(client, _m(acc, 'utxo_count')), + realized: createRealizedPattern(client, acc), + relative: createRelativePattern4(client, _m(acc, 'supply_in')), + supply: createSupplyPattern2(client, _m(acc, 'supply')), + unrealized: createUnrealizedPattern(client, acc), + }; +} + /** * @typedef {Object} _100btcPattern * @property {ActivityPattern2} activity @@ -2421,35 +2450,6 @@ function createPeriodCagrPattern(client, acc) { }; } -/** - * @typedef {Object} _0satsPattern2 - * @property {ActivityPattern2} activity - * @property {CostBasisPattern} costBasis - * @property {OutputsPattern} outputs - * @property {RealizedPattern} realized - * @property {RelativePattern4} relative - * @property {SupplyPattern2} supply - * @property {UnrealizedPattern} unrealized - */ - -/** - * Create a _0satsPattern2 pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {_0satsPattern2} - */ -function create_0satsPattern2(client, acc) { - return { - activity: createActivityPattern2(client, acc), - costBasis: createCostBasisPattern(client, acc), - outputs: createOutputsPattern(client, _m(acc, 'utxo_count')), - realized: createRealizedPattern(client, acc), - relative: createRelativePattern4(client, _m(acc, 'supply_in')), - supply: createSupplyPattern2(client, _m(acc, 'supply')), - unrealized: createUnrealizedPattern(client, acc), - }; -} - /** * @typedef {Object} _10yTo12yPattern * @property {ActivityPattern2} activity @@ -2479,6 +2479,35 @@ function create_10yTo12yPattern(client, acc) { }; } +/** + * @typedef {Object} _10yPattern + * @property {ActivityPattern2} activity + * @property {CostBasisPattern} costBasis + * @property {OutputsPattern} outputs + * @property {RealizedPattern4} realized + * @property {RelativePattern} relative + * @property {SupplyPattern2} supply + * @property {UnrealizedPattern} unrealized + */ + +/** + * Create a _10yPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_10yPattern} + */ +function create_10yPattern(client, acc) { + return { + activity: createActivityPattern2(client, acc), + costBasis: createCostBasisPattern(client, acc), + outputs: createOutputsPattern(client, _m(acc, 'utxo_count')), + realized: createRealizedPattern4(client, acc), + relative: createRelativePattern(client, acc), + supply: createSupplyPattern2(client, _m(acc, 'supply')), + unrealized: createUnrealizedPattern(client, acc), + }; +} + /** * @typedef {Object} UnrealizedPattern * @property {MetricPattern1} negUnrealizedLoss @@ -2508,35 +2537,6 @@ function createUnrealizedPattern(client, acc) { }; } -/** - * @typedef {Object} _10yPattern - * @property {ActivityPattern2} activity - * @property {CostBasisPattern} costBasis - * @property {OutputsPattern} outputs - * @property {RealizedPattern4} realized - * @property {RelativePattern} relative - * @property {SupplyPattern2} supply - * @property {UnrealizedPattern} unrealized - */ - -/** - * Create a _10yPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {_10yPattern} - */ -function create_10yPattern(client, acc) { - return { - activity: createActivityPattern2(client, acc), - costBasis: createCostBasisPattern(client, acc), - outputs: createOutputsPattern(client, _m(acc, 'utxo_count')), - realized: createRealizedPattern4(client, acc), - relative: createRelativePattern(client, acc), - supply: createSupplyPattern2(client, _m(acc, 'supply')), - unrealized: createUnrealizedPattern(client, acc), - }; -} - /** * @typedef {Object} ActivityPattern2 * @property {BlockCountPattern} coinblocksDestroyed @@ -2608,48 +2608,6 @@ function createCostBasisPattern2(client, acc) { }; } -/** - * @typedef {Object} CoinbasePattern - * @property {BitcoinPattern} bitcoin - * @property {DollarsPattern} dollars - * @property {DollarsPattern} sats - */ - -/** - * Create a CoinbasePattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {CoinbasePattern} - */ -function createCoinbasePattern(client, acc) { - return { - bitcoin: createBitcoinPattern(client, _m(acc, 'btc')), - dollars: createDollarsPattern(client, _m(acc, 'usd')), - sats: createDollarsPattern(client, acc), - }; -} - -/** - * @typedef {Object} CoinbasePattern2 - * @property {BlockCountPattern} bitcoin - * @property {BlockCountPattern} dollars - * @property {BlockCountPattern} sats - */ - -/** - * Create a CoinbasePattern2 pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {CoinbasePattern2} - */ -function createCoinbasePattern2(client, acc) { - return { - bitcoin: createBlockCountPattern(client, _m(acc, 'btc')), - dollars: createBlockCountPattern(client, _m(acc, 'usd')), - sats: createBlockCountPattern(client, acc), - }; -} - /** * @typedef {Object} ActiveSupplyPattern * @property {MetricPattern1} bitcoin @@ -2692,6 +2650,27 @@ function createSegwitAdoptionPattern(client, acc) { }; } +/** + * @typedef {Object} CoinbasePattern2 + * @property {BlockCountPattern} bitcoin + * @property {BlockCountPattern} dollars + * @property {BlockCountPattern} sats + */ + +/** + * Create a CoinbasePattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {CoinbasePattern2} + */ +function createCoinbasePattern2(client, acc) { + return { + bitcoin: createBlockCountPattern(client, _m(acc, 'btc')), + dollars: createBlockCountPattern(client, _m(acc, 'usd')), + sats: createBlockCountPattern(client, acc), + }; +} + /** * @typedef {Object} UnclaimedRewardsPattern * @property {BitcoinPattern2} bitcoin @@ -2713,6 +2692,27 @@ function createUnclaimedRewardsPattern(client, acc) { }; } +/** + * @typedef {Object} CoinbasePattern + * @property {BitcoinPattern} bitcoin + * @property {DollarsPattern} dollars + * @property {DollarsPattern} sats + */ + +/** + * Create a CoinbasePattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {CoinbasePattern} + */ +function createCoinbasePattern(client, acc) { + return { + bitcoin: createBitcoinPattern(client, _m(acc, 'btc')), + dollars: createDollarsPattern(client, _m(acc, 'usd')), + sats: createDollarsPattern(client, acc), + }; +} + /** * @typedef {Object} _2015Pattern * @property {MetricPattern4} bitcoin @@ -2734,25 +2734,6 @@ function create_2015Pattern(client, acc) { }; } -/** - * @typedef {Object} SupplyPattern2 - * @property {ActiveSupplyPattern} halved - * @property {ActiveSupplyPattern} total - */ - -/** - * Create a SupplyPattern2 pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {SupplyPattern2} - */ -function createSupplyPattern2(client, acc) { - return { - halved: createActiveSupplyPattern(client, _m(acc, 'halved')), - total: createActiveSupplyPattern(client, acc), - }; -} - /** * @typedef {Object} RelativePattern4 * @property {MetricPattern1} supplyInLossRelToOwnSupply @@ -2772,6 +2753,25 @@ function createRelativePattern4(client, acc) { }; } +/** + * @typedef {Object} SupplyPattern2 + * @property {ActiveSupplyPattern} halved + * @property {ActiveSupplyPattern} total + */ + +/** + * Create a SupplyPattern2 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {SupplyPattern2} + */ +function createSupplyPattern2(client, acc) { + return { + halved: createActiveSupplyPattern(client, _m(acc, 'halved')), + total: createActiveSupplyPattern(client, acc), + }; +} + /** * @typedef {Object} CostBasisPattern * @property {MetricPattern1} max @@ -3712,15 +3712,92 @@ function createOutputsPattern(client, acc) { /** * @typedef {Object} MetricsTree_Market_Dca * @property {ClassAveragePricePattern} classAveragePrice + * @property {MetricsTree_Market_Dca_ClassDaysInLoss} classDaysInLoss + * @property {MetricsTree_Market_Dca_ClassDaysInProfit} classDaysInProfit + * @property {MetricsTree_Market_Dca_ClassMaxDrawdown} classMaxDrawdown + * @property {MetricsTree_Market_Dca_ClassMaxReturn} classMaxReturn * @property {MetricsTree_Market_Dca_ClassReturns} classReturns * @property {MetricsTree_Market_Dca_ClassStack} classStack * @property {PeriodAveragePricePattern} periodAveragePrice * @property {PeriodCagrPattern} periodCagr + * @property {PeriodAveragePricePattern} periodDaysInLoss + * @property {PeriodAveragePricePattern} periodDaysInProfit + * @property {PeriodAveragePricePattern} periodLumpSumDaysInLoss + * @property {PeriodAveragePricePattern} periodLumpSumDaysInProfit + * @property {PeriodAveragePricePattern} periodLumpSumMaxDrawdown + * @property {PeriodAveragePricePattern} periodLumpSumMaxReturn + * @property {PeriodAveragePricePattern} periodLumpSumReturns * @property {PeriodLumpSumStackPattern} periodLumpSumStack + * @property {PeriodAveragePricePattern} periodMaxDrawdown + * @property {PeriodAveragePricePattern} periodMaxReturn * @property {PeriodAveragePricePattern} periodReturns * @property {PeriodLumpSumStackPattern} periodStack */ +/** + * @typedef {Object} MetricsTree_Market_Dca_ClassDaysInLoss + * @property {MetricPattern4} _2015 + * @property {MetricPattern4} _2016 + * @property {MetricPattern4} _2017 + * @property {MetricPattern4} _2018 + * @property {MetricPattern4} _2019 + * @property {MetricPattern4} _2020 + * @property {MetricPattern4} _2021 + * @property {MetricPattern4} _2022 + * @property {MetricPattern4} _2023 + * @property {MetricPattern4} _2024 + * @property {MetricPattern4} _2025 + * @property {MetricPattern4} _2026 + */ + +/** + * @typedef {Object} MetricsTree_Market_Dca_ClassDaysInProfit + * @property {MetricPattern4} _2015 + * @property {MetricPattern4} _2016 + * @property {MetricPattern4} _2017 + * @property {MetricPattern4} _2018 + * @property {MetricPattern4} _2019 + * @property {MetricPattern4} _2020 + * @property {MetricPattern4} _2021 + * @property {MetricPattern4} _2022 + * @property {MetricPattern4} _2023 + * @property {MetricPattern4} _2024 + * @property {MetricPattern4} _2025 + * @property {MetricPattern4} _2026 + */ + +/** + * @typedef {Object} MetricsTree_Market_Dca_ClassMaxDrawdown + * @property {MetricPattern4} _2015 + * @property {MetricPattern4} _2016 + * @property {MetricPattern4} _2017 + * @property {MetricPattern4} _2018 + * @property {MetricPattern4} _2019 + * @property {MetricPattern4} _2020 + * @property {MetricPattern4} _2021 + * @property {MetricPattern4} _2022 + * @property {MetricPattern4} _2023 + * @property {MetricPattern4} _2024 + * @property {MetricPattern4} _2025 + * @property {MetricPattern4} _2026 + */ + +/** + * @typedef {Object} MetricsTree_Market_Dca_ClassMaxReturn + * @property {MetricPattern4} _2015 + * @property {MetricPattern4} _2016 + * @property {MetricPattern4} _2017 + * @property {MetricPattern4} _2018 + * @property {MetricPattern4} _2019 + * @property {MetricPattern4} _2020 + * @property {MetricPattern4} _2021 + * @property {MetricPattern4} _2022 + * @property {MetricPattern4} _2023 + * @property {MetricPattern4} _2024 + * @property {MetricPattern4} _2025 + * @property {MetricPattern4} _2026 + */ + /** * @typedef {Object} MetricsTree_Market_Dca_ClassReturns * @property {MetricPattern4} _2015 @@ -5740,6 +5817,62 @@ class BrkClient extends BrkClientBase { }, dca: { classAveragePrice: createClassAveragePricePattern(this, 'dca_class'), + classDaysInLoss: { + _2015: createMetricPattern4(this, 'dca_class_2015_days_in_loss'), + _2016: createMetricPattern4(this, 'dca_class_2016_days_in_loss'), + _2017: createMetricPattern4(this, 'dca_class_2017_days_in_loss'), + _2018: createMetricPattern4(this, 'dca_class_2018_days_in_loss'), + _2019: createMetricPattern4(this, 'dca_class_2019_days_in_loss'), + _2020: createMetricPattern4(this, 'dca_class_2020_days_in_loss'), + _2021: createMetricPattern4(this, 'dca_class_2021_days_in_loss'), + _2022: createMetricPattern4(this, 'dca_class_2022_days_in_loss'), + _2023: createMetricPattern4(this, 'dca_class_2023_days_in_loss'), + _2024: createMetricPattern4(this, 'dca_class_2024_days_in_loss'), + _2025: createMetricPattern4(this, 'dca_class_2025_days_in_loss'), + _2026: createMetricPattern4(this, 'dca_class_2026_days_in_loss'), + }, + classDaysInProfit: { + _2015: createMetricPattern4(this, 'dca_class_2015_days_in_profit'), + _2016: createMetricPattern4(this, 'dca_class_2016_days_in_profit'), + _2017: createMetricPattern4(this, 'dca_class_2017_days_in_profit'), + _2018: createMetricPattern4(this, 'dca_class_2018_days_in_profit'), + _2019: createMetricPattern4(this, 'dca_class_2019_days_in_profit'), + _2020: createMetricPattern4(this, 'dca_class_2020_days_in_profit'), + _2021: createMetricPattern4(this, 'dca_class_2021_days_in_profit'), + _2022: createMetricPattern4(this, 'dca_class_2022_days_in_profit'), + _2023: createMetricPattern4(this, 'dca_class_2023_days_in_profit'), + _2024: createMetricPattern4(this, 'dca_class_2024_days_in_profit'), + _2025: createMetricPattern4(this, 'dca_class_2025_days_in_profit'), + _2026: createMetricPattern4(this, 'dca_class_2026_days_in_profit'), + }, + classMaxDrawdown: { + _2015: createMetricPattern4(this, 'dca_class_2015_max_drawdown'), + _2016: createMetricPattern4(this, 'dca_class_2016_max_drawdown'), + _2017: createMetricPattern4(this, 'dca_class_2017_max_drawdown'), + _2018: createMetricPattern4(this, 'dca_class_2018_max_drawdown'), + _2019: createMetricPattern4(this, 'dca_class_2019_max_drawdown'), + _2020: createMetricPattern4(this, 'dca_class_2020_max_drawdown'), + _2021: createMetricPattern4(this, 'dca_class_2021_max_drawdown'), + _2022: createMetricPattern4(this, 'dca_class_2022_max_drawdown'), + _2023: createMetricPattern4(this, 'dca_class_2023_max_drawdown'), + _2024: createMetricPattern4(this, 'dca_class_2024_max_drawdown'), + _2025: createMetricPattern4(this, 'dca_class_2025_max_drawdown'), + _2026: createMetricPattern4(this, 'dca_class_2026_max_drawdown'), + }, + classMaxReturn: { + _2015: createMetricPattern4(this, 'dca_class_2015_max_return'), + _2016: createMetricPattern4(this, 'dca_class_2016_max_return'), + _2017: createMetricPattern4(this, 'dca_class_2017_max_return'), + _2018: createMetricPattern4(this, 'dca_class_2018_max_return'), + _2019: createMetricPattern4(this, 'dca_class_2019_max_return'), + _2020: createMetricPattern4(this, 'dca_class_2020_max_return'), + _2021: createMetricPattern4(this, 'dca_class_2021_max_return'), + _2022: createMetricPattern4(this, 'dca_class_2022_max_return'), + _2023: createMetricPattern4(this, 'dca_class_2023_max_return'), + _2024: createMetricPattern4(this, 'dca_class_2024_max_return'), + _2025: createMetricPattern4(this, 'dca_class_2025_max_return'), + _2026: createMetricPattern4(this, 'dca_class_2026_max_return'), + }, classReturns: { _2015: createMetricPattern4(this, 'dca_class_2015_returns'), _2016: createMetricPattern4(this, 'dca_class_2016_returns'), @@ -5770,7 +5903,16 @@ class BrkClient extends BrkClientBase { }, periodAveragePrice: createPeriodAveragePricePattern(this, 'dca_average_price'), periodCagr: createPeriodCagrPattern(this, 'dca_cagr'), + periodDaysInLoss: createPeriodAveragePricePattern(this, 'dca_days_in_loss'), + periodDaysInProfit: createPeriodAveragePricePattern(this, 'dca_days_in_profit'), + periodLumpSumDaysInLoss: createPeriodAveragePricePattern(this, 'lump_sum_days_in_loss'), + periodLumpSumDaysInProfit: createPeriodAveragePricePattern(this, 'lump_sum_days_in_profit'), + periodLumpSumMaxDrawdown: createPeriodAveragePricePattern(this, 'lump_sum_max_drawdown'), + periodLumpSumMaxReturn: createPeriodAveragePricePattern(this, 'lump_sum_max_return'), + periodLumpSumReturns: createPeriodAveragePricePattern(this, 'lump_sum_returns'), periodLumpSumStack: createPeriodLumpSumStackPattern(this, 'lump_sum_stack'), + periodMaxDrawdown: createPeriodAveragePricePattern(this, 'dca_max_drawdown'), + periodMaxReturn: createPeriodAveragePricePattern(this, 'dca_max_return'), periodReturns: createPeriodAveragePricePattern(this, 'dca_returns'), periodStack: createPeriodLumpSumStackPattern(this, 'dca_stack'), }, diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 434aac43d..5f9002139 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -2054,24 +2054,6 @@ class PeriodLumpSumStackPattern: self._6y: _2015Pattern = _2015Pattern(client, _p('6y', acc)) self._8y: _2015Pattern = _2015Pattern(client, _p('8y', acc)) -class PeriodAveragePricePattern(Generic[T]): - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self._10y: MetricPattern4[T] = MetricPattern4(client, _p('10y', acc)) - self._1m: MetricPattern4[T] = MetricPattern4(client, _p('1m', acc)) - self._1w: MetricPattern4[T] = MetricPattern4(client, _p('1w', acc)) - self._1y: MetricPattern4[T] = MetricPattern4(client, _p('1y', acc)) - self._2y: MetricPattern4[T] = MetricPattern4(client, _p('2y', acc)) - self._3m: MetricPattern4[T] = MetricPattern4(client, _p('3m', acc)) - self._3y: MetricPattern4[T] = MetricPattern4(client, _p('3y', acc)) - self._4y: MetricPattern4[T] = MetricPattern4(client, _p('4y', acc)) - self._5y: MetricPattern4[T] = MetricPattern4(client, _p('5y', acc)) - self._6m: MetricPattern4[T] = MetricPattern4(client, _p('6m', acc)) - self._6y: MetricPattern4[T] = MetricPattern4(client, _p('6y', acc)) - self._8y: MetricPattern4[T] = MetricPattern4(client, _p('8y', acc)) - class ClassAveragePricePattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2090,6 +2072,24 @@ class ClassAveragePricePattern(Generic[T]): self._2025: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2025_average_price')) self._2026: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2026_average_price')) +class PeriodAveragePricePattern(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self._10y: MetricPattern4[T] = MetricPattern4(client, _p('10y', acc)) + self._1m: MetricPattern4[T] = MetricPattern4(client, _p('1m', acc)) + self._1w: MetricPattern4[T] = MetricPattern4(client, _p('1w', acc)) + self._1y: MetricPattern4[T] = MetricPattern4(client, _p('1y', acc)) + self._2y: MetricPattern4[T] = MetricPattern4(client, _p('2y', acc)) + self._3m: MetricPattern4[T] = MetricPattern4(client, _p('3m', acc)) + self._3y: MetricPattern4[T] = MetricPattern4(client, _p('3y', acc)) + self._4y: MetricPattern4[T] = MetricPattern4(client, _p('4y', acc)) + self._5y: MetricPattern4[T] = MetricPattern4(client, _p('5y', acc)) + self._6m: MetricPattern4[T] = MetricPattern4(client, _p('6m', acc)) + self._6y: MetricPattern4[T] = MetricPattern4(client, _p('6y', acc)) + self._8y: MetricPattern4[T] = MetricPattern4(client, _p('8y', acc)) + class BitcoinPattern: """Pattern struct for repeated tree structure.""" @@ -2187,21 +2187,6 @@ class AddrCountPattern: self.p2wpkh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wpkh', acc)) self.p2wsh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wsh', acc)) -class FullnessPattern(Generic[T]): - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.average: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'average')) - self.base: MetricPattern11[T] = MetricPattern11(client, acc) - self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max')) - self.median: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'median')) - self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min')) - self.pct10: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct10')) - self.pct25: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct25')) - self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75')) - self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90')) - class FeeRatePattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2217,6 +2202,21 @@ class FeeRatePattern(Generic[T]): self.pct90: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct90')) self.txindex: MetricPattern27[T] = MetricPattern27(client, acc) +class FullnessPattern(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.average: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'average')) + self.base: MetricPattern11[T] = MetricPattern11(client, acc) + self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max')) + self.median: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'median')) + self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min')) + self.pct10: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct10')) + self.pct25: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct25')) + self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75')) + self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90')) + class _0satsPattern: """Pattern struct for repeated tree structure.""" @@ -2245,6 +2245,19 @@ class PhaseDailyCentsPattern(Generic[T]): self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75')) self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90')) +class _0satsPattern2: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.activity: ActivityPattern2 = ActivityPattern2(client, acc) + self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc) + self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) + self.realized: RealizedPattern = RealizedPattern(client, acc) + self.relative: RelativePattern4 = RelativePattern4(client, _m(acc, 'supply_in')) + self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) + self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) + class _100btcPattern: """Pattern struct for repeated tree structure.""" @@ -2271,19 +2284,6 @@ class PeriodCagrPattern: self._6y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('6y', acc)) self._8y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('8y', acc)) -class _0satsPattern2: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.activity: ActivityPattern2 = ActivityPattern2(client, acc) - self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc) - self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) - self.realized: RealizedPattern = RealizedPattern(client, acc) - self.relative: RelativePattern4 = RelativePattern4(client, _m(acc, 'supply_in')) - self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) - self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) - class _10yTo12yPattern: """Pattern struct for repeated tree structure.""" @@ -2297,6 +2297,19 @@ class _10yTo12yPattern: self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) +class _10yPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.activity: ActivityPattern2 = ActivityPattern2(client, acc) + self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc) + self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) + self.realized: RealizedPattern4 = RealizedPattern4(client, acc) + self.relative: RelativePattern = RelativePattern(client, acc) + self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) + self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) + class UnrealizedPattern: """Pattern struct for repeated tree structure.""" @@ -2310,19 +2323,6 @@ class UnrealizedPattern: self.unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_loss')) self.unrealized_profit: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_profit')) -class _10yPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.activity: ActivityPattern2 = ActivityPattern2(client, acc) - self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc) - self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count')) - self.realized: RealizedPattern4 = RealizedPattern4(client, acc) - self.relative: RelativePattern = RelativePattern(client, acc) - self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) - self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc) - class ActivityPattern2: """Pattern struct for repeated tree structure.""" @@ -2353,24 +2353,6 @@ class CostBasisPattern2: self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis')) self.percentiles: PercentilesPattern = PercentilesPattern(client, _m(acc, 'cost_basis')) -class CoinbasePattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.bitcoin: BitcoinPattern = BitcoinPattern(client, _m(acc, 'btc')) - self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd')) - self.sats: DollarsPattern[Sats] = DollarsPattern(client, acc) - -class CoinbasePattern2: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.bitcoin: BlockCountPattern[Bitcoin] = BlockCountPattern(client, _m(acc, 'btc')) - self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd')) - self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc) - class ActiveSupplyPattern: """Pattern struct for repeated tree structure.""" @@ -2389,6 +2371,15 @@ class SegwitAdoptionPattern: self.cumulative: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'cumulative')) self.sum: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'sum')) +class CoinbasePattern2: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.bitcoin: BlockCountPattern[Bitcoin] = BlockCountPattern(client, _m(acc, 'btc')) + self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd')) + self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc) + class UnclaimedRewardsPattern: """Pattern struct for repeated tree structure.""" @@ -2398,6 +2389,15 @@ class UnclaimedRewardsPattern: self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd')) self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc) +class CoinbasePattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.bitcoin: BitcoinPattern = BitcoinPattern(client, _m(acc, 'btc')) + self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd')) + self.sats: DollarsPattern[Sats] = DollarsPattern(client, acc) + class _2015Pattern: """Pattern struct for repeated tree structure.""" @@ -2407,14 +2407,6 @@ class _2015Pattern: self.dollars: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'usd')) self.sats: MetricPattern4[Sats] = MetricPattern4(client, acc) -class SupplyPattern2: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.halved: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'halved')) - self.total: ActiveSupplyPattern = ActiveSupplyPattern(client, acc) - class RelativePattern4: """Pattern struct for repeated tree structure.""" @@ -2423,6 +2415,14 @@ class RelativePattern4: self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'loss_rel_to_own_supply')) self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'profit_rel_to_own_supply')) +class SupplyPattern2: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.halved: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'halved')) + self.total: ActiveSupplyPattern = ActiveSupplyPattern(client, acc) + class CostBasisPattern: """Pattern struct for repeated tree structure.""" @@ -3320,6 +3320,74 @@ class MetricsTree_Market_Ath: self.price_drawdown: MetricPattern3[StoredF32] = MetricPattern3(client, 'price_drawdown') self.years_since_price_ath: MetricPattern4[StoredF32] = MetricPattern4(client, 'years_since_price_ath') +class MetricsTree_Market_Dca_ClassDaysInLoss: + """Metrics tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self._2015: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2015_days_in_loss') + self._2016: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2016_days_in_loss') + self._2017: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2017_days_in_loss') + self._2018: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2018_days_in_loss') + self._2019: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2019_days_in_loss') + self._2020: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2020_days_in_loss') + self._2021: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2021_days_in_loss') + self._2022: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2022_days_in_loss') + self._2023: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2023_days_in_loss') + self._2024: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2024_days_in_loss') + self._2025: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2025_days_in_loss') + self._2026: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2026_days_in_loss') + +class MetricsTree_Market_Dca_ClassDaysInProfit: + """Metrics tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self._2015: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2015_days_in_profit') + self._2016: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2016_days_in_profit') + self._2017: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2017_days_in_profit') + self._2018: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2018_days_in_profit') + self._2019: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2019_days_in_profit') + self._2020: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2020_days_in_profit') + self._2021: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2021_days_in_profit') + self._2022: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2022_days_in_profit') + self._2023: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2023_days_in_profit') + self._2024: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2024_days_in_profit') + self._2025: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2025_days_in_profit') + self._2026: MetricPattern4[StoredU32] = MetricPattern4(client, 'dca_class_2026_days_in_profit') + +class MetricsTree_Market_Dca_ClassMaxDrawdown: + """Metrics tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self._2015: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2015_max_drawdown') + self._2016: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2016_max_drawdown') + self._2017: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2017_max_drawdown') + self._2018: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2018_max_drawdown') + self._2019: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2019_max_drawdown') + self._2020: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2020_max_drawdown') + self._2021: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2021_max_drawdown') + self._2022: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2022_max_drawdown') + self._2023: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2023_max_drawdown') + self._2024: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2024_max_drawdown') + self._2025: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2025_max_drawdown') + self._2026: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2026_max_drawdown') + +class MetricsTree_Market_Dca_ClassMaxReturn: + """Metrics tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self._2015: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2015_max_return') + self._2016: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2016_max_return') + self._2017: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2017_max_return') + self._2018: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2018_max_return') + self._2019: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2019_max_return') + self._2020: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2020_max_return') + self._2021: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2021_max_return') + self._2022: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2022_max_return') + self._2023: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2023_max_return') + self._2024: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2024_max_return') + self._2025: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2025_max_return') + self._2026: MetricPattern4[StoredF32] = MetricPattern4(client, 'dca_class_2026_max_return') + class MetricsTree_Market_Dca_ClassReturns: """Metrics tree node.""" @@ -3359,11 +3427,24 @@ class MetricsTree_Market_Dca: def __init__(self, client: BrkClientBase, base_path: str = ''): self.class_average_price: ClassAveragePricePattern[Dollars] = ClassAveragePricePattern(client, 'dca_class') + self.class_days_in_loss: MetricsTree_Market_Dca_ClassDaysInLoss = MetricsTree_Market_Dca_ClassDaysInLoss(client) + self.class_days_in_profit: MetricsTree_Market_Dca_ClassDaysInProfit = MetricsTree_Market_Dca_ClassDaysInProfit(client) + self.class_max_drawdown: MetricsTree_Market_Dca_ClassMaxDrawdown = MetricsTree_Market_Dca_ClassMaxDrawdown(client) + self.class_max_return: MetricsTree_Market_Dca_ClassMaxReturn = MetricsTree_Market_Dca_ClassMaxReturn(client) self.class_returns: MetricsTree_Market_Dca_ClassReturns = MetricsTree_Market_Dca_ClassReturns(client) self.class_stack: MetricsTree_Market_Dca_ClassStack = MetricsTree_Market_Dca_ClassStack(client) self.period_average_price: PeriodAveragePricePattern[Dollars] = PeriodAveragePricePattern(client, 'dca_average_price') self.period_cagr: PeriodCagrPattern = PeriodCagrPattern(client, 'dca_cagr') + self.period_days_in_loss: PeriodAveragePricePattern[StoredU32] = PeriodAveragePricePattern(client, 'dca_days_in_loss') + self.period_days_in_profit: PeriodAveragePricePattern[StoredU32] = PeriodAveragePricePattern(client, 'dca_days_in_profit') + self.period_lump_sum_days_in_loss: PeriodAveragePricePattern[StoredU32] = PeriodAveragePricePattern(client, 'lump_sum_days_in_loss') + self.period_lump_sum_days_in_profit: PeriodAveragePricePattern[StoredU32] = PeriodAveragePricePattern(client, 'lump_sum_days_in_profit') + self.period_lump_sum_max_drawdown: PeriodAveragePricePattern[StoredF32] = PeriodAveragePricePattern(client, 'lump_sum_max_drawdown') + self.period_lump_sum_max_return: PeriodAveragePricePattern[StoredF32] = PeriodAveragePricePattern(client, 'lump_sum_max_return') + self.period_lump_sum_returns: PeriodAveragePricePattern[StoredF32] = PeriodAveragePricePattern(client, 'lump_sum_returns') self.period_lump_sum_stack: PeriodLumpSumStackPattern = PeriodLumpSumStackPattern(client, 'lump_sum_stack') + self.period_max_drawdown: PeriodAveragePricePattern[StoredF32] = PeriodAveragePricePattern(client, 'dca_max_drawdown') + self.period_max_return: PeriodAveragePricePattern[StoredF32] = PeriodAveragePricePattern(client, 'dca_max_return') self.period_returns: PeriodAveragePricePattern[StoredF32] = PeriodAveragePricePattern(client, 'dca_returns') self.period_stack: PeriodLumpSumStackPattern = PeriodLumpSumStackPattern(client, 'dca_stack') diff --git a/website/scripts/chart/index.js b/website/scripts/chart/index.js index 531736a7f..25d6299ac 100644 --- a/website/scripts/chart/index.js +++ b/website/scripts/chart/index.js @@ -161,6 +161,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) { /** @satisfies {DeepPartial} */ ({ autoSize: true, layout: { + // fontSize: 14, fontFamily: style.fontFamily, background: { color: "transparent" }, attributionLogo: false, diff --git a/website/scripts/options/chain.js b/website/scripts/options/chain.js index 3ad87ea4d..3d586a2bf 100644 --- a/website/scripts/options/chain.js +++ b/website/scripts/options/chain.js @@ -30,7 +30,6 @@ export function createChainSection(ctx) { pools, inputs, outputs, - market, scripts, supply, distribution, @@ -381,17 +380,22 @@ export function createChainSection(ctx) { ], }, - // Input + // UTXO Set (merged Input, Output, UTXO) { - name: "Input", + name: "UTXO Set", tree: [ { - name: "Count", + name: "Input Count", title: "Input Count", bottom: [...fromSizePattern(inputs.count, Unit.count)], }, { - name: "Speed", + name: "Output Count", + title: "Output Count", + bottom: [...fromSizePattern(outputs.count.totalCount, Unit.count)], + }, + { + name: "Inputs/sec", title: "Inputs Per Second", bottom: [ dots({ @@ -401,20 +405,8 @@ export function createChainSection(ctx) { }), ], }, - ], - }, - - // Output - { - name: "Output", - tree: [ { - name: "Count", - title: "Output Count", - bottom: [...fromSizePattern(outputs.count.totalCount, Unit.count)], - }, - { - name: "Speed", + name: "Outputs/sec", title: "Outputs Per Second", bottom: [ dots({ @@ -424,14 +416,8 @@ export function createChainSection(ctx) { }), ], }, - ], - }, - - { - name: "UTXO", - tree: [ { - name: "Count", + name: "UTXO Count", title: "UTXO Count", bottom: [ line({ @@ -451,19 +437,49 @@ export function createChainSection(ctx) { { name: "Count", tree: [ - { name: "P2PKH", title: "P2PKH Output Count", bottom: fromDollarsPattern(scripts.count.p2pkh, Unit.count) }, - { name: "P2SH", title: "P2SH Output Count", bottom: fromDollarsPattern(scripts.count.p2sh, Unit.count) }, - { name: "P2WPKH", title: "P2WPKH Output Count", bottom: fromDollarsPattern(scripts.count.p2wpkh, Unit.count) }, - { name: "P2WSH", title: "P2WSH Output Count", bottom: fromDollarsPattern(scripts.count.p2wsh, Unit.count) }, - { name: "P2TR", title: "P2TR Output Count", bottom: fromDollarsPattern(scripts.count.p2tr, Unit.count) }, - { name: "P2PK33", title: "P2PK33 Output Count", bottom: fromDollarsPattern(scripts.count.p2pk33, Unit.count) }, - { name: "P2PK65", title: "P2PK65 Output Count", bottom: fromDollarsPattern(scripts.count.p2pk65, Unit.count) }, - { name: "P2MS", title: "P2MS Output Count", bottom: fromDollarsPattern(scripts.count.p2ms, Unit.count) }, - { name: "P2A", title: "P2A Output Count", bottom: fromDollarsPattern(scripts.count.p2a, Unit.count) }, - { name: "OP_RETURN", title: "OP_RETURN Output Count", bottom: fromDollarsPattern(scripts.count.opreturn, Unit.count) }, - { name: "SegWit", title: "SegWit Output Count", bottom: fromDollarsPattern(scripts.count.segwit, Unit.count) }, - { name: "Empty", title: "Empty Output Count", bottom: fromDollarsPattern(scripts.count.emptyoutput, Unit.count) }, - { name: "Unknown", title: "Unknown Output Count", bottom: fromDollarsPattern(scripts.count.unknownoutput, Unit.count) }, + // Legacy scripts + { + name: "Legacy", + tree: [ + { name: "P2PKH", title: "P2PKH Output Count", bottom: fromDollarsPattern(scripts.count.p2pkh, Unit.count) }, + { name: "P2PK33", title: "P2PK33 Output Count", bottom: fromDollarsPattern(scripts.count.p2pk33, Unit.count) }, + { name: "P2PK65", title: "P2PK65 Output Count", bottom: fromDollarsPattern(scripts.count.p2pk65, Unit.count) }, + ], + }, + // Script Hash + { + name: "Script Hash", + tree: [ + { name: "P2SH", title: "P2SH Output Count", bottom: fromDollarsPattern(scripts.count.p2sh, Unit.count) }, + { name: "P2MS", title: "P2MS Output Count", bottom: fromDollarsPattern(scripts.count.p2ms, Unit.count) }, + ], + }, + // SegWit scripts + { + name: "SegWit", + tree: [ + { name: "All SegWit", title: "SegWit Output Count", bottom: fromDollarsPattern(scripts.count.segwit, Unit.count) }, + { name: "P2WPKH", title: "P2WPKH Output Count", bottom: fromDollarsPattern(scripts.count.p2wpkh, Unit.count) }, + { name: "P2WSH", title: "P2WSH Output Count", bottom: fromDollarsPattern(scripts.count.p2wsh, Unit.count) }, + ], + }, + // Taproot scripts + { + name: "Taproot", + tree: [ + { name: "P2TR", title: "P2TR Output Count", bottom: fromDollarsPattern(scripts.count.p2tr, Unit.count) }, + { name: "P2A", title: "P2A Output Count", bottom: fromDollarsPattern(scripts.count.p2a, Unit.count) }, + ], + }, + // Other scripts + { + name: "Other", + tree: [ + { name: "OP_RETURN", title: "OP_RETURN Output Count", bottom: fromDollarsPattern(scripts.count.opreturn, Unit.count) }, + { name: "Empty", title: "Empty Output Count", bottom: fromDollarsPattern(scripts.count.emptyoutput, Unit.count) }, + { name: "Unknown", title: "Unknown Output Count", bottom: fromDollarsPattern(scripts.count.unknownoutput, Unit.count) }, + ], + }, ], }, { @@ -489,12 +505,7 @@ export function createChainSection(ctx) { }, ], }, - { - name: "Value", - tree: [ - { name: "OP_RETURN", title: "OP_RETURN Value", bottom: fromCoinbasePattern(scripts.value.opreturn) }, - ], - }, + { name: "OP_RETURN Value", title: "OP_RETURN Value", bottom: fromCoinbasePattern(scripts.value.opreturn) }, ], }, @@ -925,18 +936,6 @@ export function createChainSection(ctx) { }), ], }, - { - name: "Puell Multiple", - title: "Puell Multiple", - bottom: [ - baseline({ - metric: market.indicators.puellMultiple, - name: "Puell Multiple", - unit: Unit.ratio, - base: 1, - }), - ], - }, ], }, diff --git a/website/scripts/options/cointime.js b/website/scripts/options/cointime.js index 59df148f8..622c7b220 100644 --- a/website/scripts/options/cointime.js +++ b/website/scripts/options/cointime.js @@ -24,7 +24,7 @@ function createCointimePriceWithRatioOptions( ) { return [ { - name: "price", + name: "Price", title, top: [line({ metric: price, name: legend, color, unit: Unit.usd })], }, @@ -78,7 +78,7 @@ export function createCointimeSection(ctx) { { price: pricing.cointimePrice, ratio: pricing.cointimePriceRatio, - name: "cointime", + name: "Cointime", title: "Cointime Price", color: colors.yellow, }, @@ -88,31 +88,31 @@ export function createCointimeSection(ctx) { const cointimeCapitalizations = [ { metric: cap.vaultedCap, - name: "vaulted", + name: "Vaulted", title: "Vaulted Cap", color: colors.lime, }, { metric: cap.activeCap, - name: "active", + name: "Active", title: "Active Cap", color: colors.rose, }, { metric: cap.cointimeCap, - name: "cointime", + name: "Cointime", title: "Cointime Cap", color: colors.yellow, }, { metric: cap.investorCap, - name: "investor", + name: "Investor", title: "Investor Cap", color: colors.fuchsia, }, { metric: cap.thermoCap, - name: "thermo", + name: "Thermo", title: "Thermo Cap", color: colors.emerald, }, @@ -283,7 +283,7 @@ export function createCointimeSection(ctx) { name: "Reserve Risk", tree: [ { - name: "reserve risk", + name: "Ratio", title: "Reserve Risk", bottom: [ line({ @@ -295,7 +295,7 @@ export function createCointimeSection(ctx) { ], }, { - name: "hodl bank", + name: "HODL Bank", title: "HODL Bank", bottom: [ line({ @@ -307,7 +307,7 @@ export function createCointimeSection(ctx) { ], }, { - name: "vocdd 365d sma", + name: "VOCDD 365d SMA", title: "VOCDD 365d SMA", bottom: [ line({ @@ -326,7 +326,7 @@ export function createCointimeSection(ctx) { name: "Value", tree: [ { - name: "created", + name: "Created", title: "Cointime Value Created", bottom: [ line({ @@ -345,7 +345,7 @@ export function createCointimeSection(ctx) { ], }, { - name: "destroyed", + name: "Destroyed", title: "Cointime Value Destroyed", bottom: [ line({ @@ -364,7 +364,7 @@ export function createCointimeSection(ctx) { ], }, { - name: "stored", + name: "Stored", title: "Cointime Value Stored", bottom: [ line({ @@ -383,7 +383,7 @@ export function createCointimeSection(ctx) { ], }, { - name: "vocdd", + name: "VOCDD", title: "VOCDD (Value of Coin Days Destroyed)", bottom: [ line({ diff --git a/website/scripts/options/distribution/address.js b/website/scripts/options/distribution/address.js index b738a6a8e..29296a1c0 100644 --- a/website/scripts/options/distribution/address.js +++ b/website/scripts/options/distribution/address.js @@ -18,8 +18,6 @@ import { createSingleCoinsDestroyedSeries, createGroupedCoinblocksDestroyedSeries, createGroupedCoindaysDestroyedSeries, - createGroupedSatblocksDestroyedSeries, - createGroupedSatdaysDestroyedSeries, createSingleSentSeries, createGroupedSentSatsSeries, createGroupedSentBitcoinSeries, @@ -48,7 +46,7 @@ export function createAddressCohortFolder(ctx, args) { // Supply section isSingle ? { - name: "supply", + name: "Supply", title: title("Supply"), bottom: createSingleSupplySeries( ctx, @@ -60,14 +58,14 @@ export function createAddressCohortFolder(ctx, args) { // UTXO count { - name: "utxo count", + name: "UTXO Count", title: title("UTXO Count"), bottom: createUtxoCountSeries(list, useGroupName), }, // Address count (ADDRESS COHORTS ONLY - fully type safe!) { - name: "address count", + name: "Address Count", title: title("Address Count"), bottom: createAddressCountSeries(ctx, list, useGroupName), }, @@ -94,12 +92,12 @@ export function createAddressCohortFolder(ctx, args) { title, )), { - name: "capitalization", + name: "Capitalization", title: title("Realized Cap"), bottom: createRealizedCapWithExtras(ctx, list, args, useGroupName), }, { - name: "value", + name: "Value", title: title("Realized Value"), bottom: list.map(({ color, name, tree }) => line({ @@ -143,7 +141,7 @@ function createRealizedPriceOptions(args, title) { return [ { - name: "price", + name: "Price", title: title("Realized Price"), top: [ line({ @@ -179,7 +177,7 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName) { ? [ baseline({ metric: tree.realized.realizedCap30dDelta, - name: "30d Change", + name: "1m Change", unit: Unit.usd, defaultActive: false, }), @@ -203,7 +201,7 @@ function createRealizedPnlSection(ctx, args, title) { return [ { - name: "pnl", + name: "P&L", title: title("Realized P&L"), bottom: [ line({ @@ -297,7 +295,7 @@ function createRealizedPnlSection(ctx, args, title) { }), baseline({ metric: realized.netRealizedPnlCumulative30dDelta, - name: "Cumulative 30d change", + name: "Cumulative 1m Change", unit: Unit.usd, defaultActive: false, }), @@ -314,13 +312,13 @@ function createRealizedPnlSection(ctx, args, title) { }), baseline({ metric: realized.netRealizedPnlCumulative30dDeltaRelToRealizedCap, - name: "Cumulative 30d change", + name: "Cumulative 1m Change", unit: Unit.pctRcap, defaultActive: false, }), baseline({ metric: realized.netRealizedPnlCumulative30dDeltaRelToMarketCap, - name: "Cumulative 30d change", + name: "Cumulative 1m Change", unit: Unit.pctMcap, }), priceLine({ @@ -339,7 +337,7 @@ function createRealizedPnlSection(ctx, args, title) { ], }, { - name: "sopr", + name: "SOPR", title: title("SOPR"), bottom: [ baseline({ @@ -398,7 +396,7 @@ function createRealizedPnlSection(ctx, args, title) { ], }, { - name: "value", + name: "Value", title: title("Value Created & Destroyed"), bottom: [ line({ @@ -434,7 +432,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { name: "Unrealized", tree: [ { - name: "profit", + name: "Profit", title: title("Unrealized Profit"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -446,7 +444,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { ]), }, { - name: "loss", + name: "Loss", title: title("Unrealized Loss"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -458,7 +456,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { ]), }, { - name: "total pnl", + name: "Total P&L", title: title("Total Unrealized P&L"), bottom: list.flatMap(({ color, name, tree }) => [ baseline({ @@ -470,7 +468,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { ]), }, { - name: "negative loss", + name: "Negative Loss", title: title("Negative Unrealized Loss"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -485,7 +483,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { name: "Relative", tree: [ { - name: "nupl", + name: "NUPL", title: title("NUPL (Rel to Market Cap)"), bottom: list.flatMap(({ color, name, tree }) => [ baseline({ @@ -498,7 +496,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { ]), }, { - name: "profit", + name: "Profit", title: title("Unrealized Profit (% of Market Cap)"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -510,7 +508,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { ]), }, { - name: "loss", + name: "Loss", title: title("Unrealized Loss (% of Market Cap)"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -522,7 +520,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { ]), }, { - name: "net pnl", + name: "Net P&L", title: title("Net Unrealized P&L (% of Market Cap)"), bottom: list.flatMap(({ color, name, tree }) => [ baseline({ @@ -534,7 +532,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { ]), }, { - name: "negative loss", + name: "Negative Loss", title: title("Negative Unrealized Loss (% of Market Cap)"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -548,7 +546,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) { ], }, { - name: "nupl", + name: "NUPL", title: title("Net Unrealized P&L"), bottom: list.flatMap(({ color, name, tree }) => [ baseline({ @@ -581,7 +579,7 @@ function createCostBasisSection(list, useGroupName, title) { name: "Cost Basis", tree: [ { - name: "min", + name: "Min", title: title("Min Cost Basis"), top: list.map(({ color, name, tree }) => line({ @@ -656,16 +654,6 @@ function createActivitySection(args, title) { title: title("Coindays Destroyed"), bottom: createGroupedCoindaysDestroyedSeries(list), }, - { - name: "satblocks destroyed", - title: title("Satblocks Destroyed"), - bottom: createGroupedSatblocksDestroyedSeries(list), - }, - { - name: "satdays destroyed", - title: title("Satdays Destroyed"), - bottom: createGroupedSatdaysDestroyedSeries(list), - }, { name: "Sent", tree: [ diff --git a/website/scripts/options/distribution/shared.js b/website/scripts/options/distribution/shared.js index ffeb9aa1c..3bfda83eb 100644 --- a/website/scripts/options/distribution/shared.js +++ b/website/scripts/options/distribution/shared.js @@ -109,20 +109,20 @@ export function createGroupedSupplyInLossSeries(list, { relativeMetrics } = {}) */ export function createGroupedSupplySection(list, title, { supplyRelativeMetrics, profitRelativeMetrics, lossRelativeMetrics } = {}) { return { - name: "supply", + name: "Supply", tree: [ { - name: "total", + name: "Total", title: title("Supply"), bottom: createGroupedSupplyTotalSeries(list, { relativeMetrics: supplyRelativeMetrics }), }, { - name: "in profit", + name: "In Profit", title: title("Supply In Profit"), bottom: createGroupedSupplyInProfitSeries(list, { relativeMetrics: profitRelativeMetrics }), }, { - name: "in loss", + name: "In Loss", title: title("Supply In Loss"), bottom: createGroupedSupplyInLossSeries(list, { relativeMetrics: lossRelativeMetrics }), }, @@ -404,18 +404,6 @@ export function createSingleCoinsDestroyedSeries(cohort) { unit: Unit.coindays, defaultActive: false, }), - line({ - metric: tree.activity.satblocksDestroyed, - name: "Satblocks", - color, - unit: Unit.satblocks, - }), - line({ - metric: tree.activity.satdaysDestroyed, - name: "Satdays", - color, - unit: Unit.satdays, - }), ]; } @@ -451,38 +439,6 @@ export function createGroupedCoindaysDestroyedSeries(list) { ]); } -/** - * Create satblocks destroyed series for grouped cohorts (comparison) - * @param {readonly CohortObject[]} list - * @returns {AnyFetchedSeriesBlueprint[]} - */ -export function createGroupedSatblocksDestroyedSeries(list) { - return list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.satblocksDestroyed, - name, - color, - unit: Unit.satblocks, - }), - ]); -} - -/** - * Create satdays destroyed series for grouped cohorts (comparison) - * @param {readonly CohortObject[]} list - * @returns {AnyFetchedSeriesBlueprint[]} - */ -export function createGroupedSatdaysDestroyedSeries(list) { - return list.flatMap(({ color, name, tree }) => [ - line({ - metric: tree.activity.satdaysDestroyed, - name, - color, - unit: Unit.satdays, - }), - ]); -} - /** * Create sent series (sats, btc, usd) for single cohort - all on one chart * @param {CohortObject} cohort diff --git a/website/scripts/options/distribution/utxo.js b/website/scripts/options/distribution/utxo.js index 17b2b9913..00ed4abea 100644 --- a/website/scripts/options/distribution/utxo.js +++ b/website/scripts/options/distribution/utxo.js @@ -136,7 +136,7 @@ export function createCohortFolderWithAdjusted(ctx, args) { createSingleUtxoCountChart(args, title), createSingleRealizedSectionWithAdjusted(ctx, args, title), createSingleUnrealizedSectionWithMarketCap(ctx, args, title), - createCostBasisSection({ cohort: args, title }), + createCostBasisSection(ctx, { cohort: args, title }), createSingleActivitySectionWithAdjusted(ctx, args, title), ], }; @@ -249,7 +249,7 @@ export function createCohortFolderBasicWithMarketCap(ctx, args) { createSingleUtxoCountChart(args, title), createSingleRealizedSectionBasic(ctx, args, title), createSingleUnrealizedSectionWithMarketCapOnly(ctx, args, title), - createCostBasisSection({ cohort: args, title }), + createCostBasisSection(ctx, { cohort: args, title }), createActivitySection({ ctx, cohort: args, title }), ], }; @@ -285,7 +285,7 @@ export function createCohortFolderBasicWithoutMarketCap(ctx, args) { createSingleUtxoCountChart(args, title), createSingleRealizedSectionBasic(ctx, args, title), createSingleUnrealizedSectionBase(ctx, args, title), - createCostBasisSection({ cohort: args, title }), + createCostBasisSection(ctx, { cohort: args, title }), createActivitySection({ ctx, cohort: args, title }), ], }; @@ -324,7 +324,7 @@ export function createCohortFolderAddress(ctx, args) { createSingleAddrCountChart(ctx, args, title), createSingleRealizedSectionBasic(ctx, args, title), createSingleUnrealizedSectionBase(ctx, args, title), - createCostBasisSection({ cohort: args, title }), + createCostBasisSection(ctx, { cohort: args, title }), createActivitySection({ ctx, cohort: args, title }), ], }; @@ -342,7 +342,7 @@ export function createCohortFolderAddress(ctx, args) { */ function createSingleSupplyChart(ctx, cohort, title, options = {}) { return { - name: "supply", + name: "Supply", title: title("Supply"), bottom: createSingleSupplySeries(ctx, cohort, options), }; @@ -356,7 +356,7 @@ function createSingleSupplyChart(ctx, cohort, title, options = {}) { */ function createSingleUtxoCountChart(cohort, title) { return { - name: "utxo count", + name: "UTXO Count", title: title("UTXO Count"), bottom: createUtxoCountSeries([cohort], false), }; @@ -370,7 +370,7 @@ function createSingleUtxoCountChart(cohort, title) { */ function createGroupedUtxoCountChart(list, title) { return { - name: "utxo count", + name: "UTXO Count", title: title("UTXO Count"), bottom: createUtxoCountSeries(list, true), }; @@ -385,7 +385,7 @@ function createGroupedUtxoCountChart(list, title) { */ function createSingleAddrCountChart(ctx, cohort, title) { return { - name: "address count", + name: "Address Count", title: title("Address Count"), bottom: [ line({ @@ -406,7 +406,7 @@ function createSingleAddrCountChart(ctx, cohort, title) { */ function createGroupedAddrCountChart(list, title) { return { - name: "address count", + name: "Address Count", title: title("Address Count"), bottom: list.map(({ color, name, addrCount }) => line({ metric: addrCount, name, color, unit: Unit.count }), @@ -427,7 +427,7 @@ function createSingleRealizedSectionFull(ctx, cohort, title) { tree: [ ...createSingleRealizedPriceChartsWithRatio(ctx, cohort, title), { - name: "capitalization", + name: "Capitalization", title: title("Realized Cap"), bottom: createSingleRealizedCapSeries(ctx, cohort, { extra: createRealizedCapRatioSeries(ctx, cohort.tree), @@ -454,7 +454,7 @@ function createSingleRealizedSectionWithAdjusted(ctx, cohort, title) { tree: [ ...createSingleRealizedPriceChartsBasic(ctx, cohort, title), { - name: "capitalization", + name: "Capitalization", title: title("Realized Cap"), bottom: createSingleRealizedCapSeries(ctx, cohort), }, @@ -489,7 +489,7 @@ function createGroupedRealizedSectionWithAdjusted(ctx, list, title, { ratioMetri bottom: createRealizedPriceRatioSeries(list), }, { - name: "capitalization", + name: "Capitalization", title: title("Realized Cap"), bottom: createGroupedRealizedCapSeries(list), }, @@ -512,7 +512,7 @@ function createSingleRealizedSectionWithPercentiles(ctx, cohort, title) { tree: [ ...createSingleRealizedPriceChartsWithRatio(ctx, cohort, title), { - name: "capitalization", + name: "Capitalization", title: title("Realized Cap"), bottom: createSingleRealizedCapSeries(ctx, cohort, { extra: createRealizedCapRatioSeries(ctx, cohort.tree), @@ -539,7 +539,7 @@ function createSingleRealizedSectionBasic(ctx, cohort, title) { tree: [ ...createSingleRealizedPriceChartsBasic(ctx, cohort, title), { - name: "capitalization", + name: "Capitalization", title: title("Realized Cap"), bottom: createSingleRealizedCapSeries(ctx, cohort), }, @@ -574,7 +574,7 @@ function createGroupedRealizedSectionBasic(ctx, list, title, { ratioMetrics } = bottom: createRealizedPriceRatioSeries(list), }, { - name: "capitalization", + name: "Capitalization", title: title("Realized Cap"), bottom: createGroupedRealizedCapSeries(list), }, @@ -593,7 +593,7 @@ function createGroupedRealizedSectionBasic(ctx, list, title, { ratioMetrics } = function createSingleRealizedPriceChart(cohort, title) { const { tree, color } = cohort; return { - name: "price", + name: "Price", title: title("Realized Price"), top: [ line({ @@ -651,7 +651,7 @@ function createSingleRealizedPriceChartsBasic(ctx, cohort, title) { return [ createSingleRealizedPriceChart(cohort, title), { - name: "ratio", + name: "Ratio", title: title("Realized Price Ratio"), bottom: [ baseline({ @@ -693,7 +693,7 @@ function createSingleRealizedCapSeries(ctx, cohort, { extra = [] } = {}) { }), baseline({ metric: tree.realized.realizedCap30dDelta, - name: "30d change", + name: "1m Change", unit: Unit.usd, defaultActive: false, }), @@ -789,7 +789,7 @@ function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) return [ { - name: "pnl", + name: "P&L", title: title("Realized P&L"), bottom: [ ...fromBlockCountWithUnit( @@ -849,7 +849,7 @@ function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) ], }, { - name: "Net pnl", + name: "Net P&L", title: title("Net Realized P&L"), bottom: [ ...fromBlockCountWithUnit( @@ -859,7 +859,7 @@ function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) ), baseline({ metric: tree.realized.netRealizedPnlCumulative30dDelta, - name: "Cumulative 30d change", + name: "Cumulative 1m Change", unit: Unit.usd, defaultActive: false, }), @@ -877,13 +877,13 @@ function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) baseline({ metric: tree.realized.netRealizedPnlCumulative30dDeltaRelToRealizedCap, - name: "Cumulative 30d change", + name: "Cumulative 1m Change", unit: Unit.pctRcap, defaultActive: false, }), baseline({ metric: tree.realized.netRealizedPnlCumulative30dDeltaRelToMarketCap, - name: "Cumulative 30d change", + name: "Cumulative 1m Change", unit: Unit.pctMcap, }), priceLine({ ctx, unit: Unit.pctMcap }), @@ -907,7 +907,7 @@ function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = {}) { return [ { - name: "profit", + name: "Profit", title: title("Realized Profit"), bottom: [ ...list.flatMap(({ color, name, tree }) => [ @@ -928,7 +928,7 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { ], }, { - name: "loss", + name: "Loss", title: title("Realized Loss"), bottom: [ ...list.flatMap(({ color, name, tree }) => [ @@ -949,7 +949,7 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { ], }, { - name: "Total pnl", + name: "Total P&L", title: title("Total Realized P&L"), bottom: [ ...list.flatMap((cohort) => [ @@ -964,7 +964,7 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { ], }, { - name: "Net pnl", + name: "Net P&L", title: title("Net Realized P&L"), bottom: [ ...list.flatMap(({ color, name, tree }) => [ @@ -986,10 +986,10 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { ], }, { - name: "cumulative", + name: "Cumulative", tree: [ { - name: "profit", + name: "Profit", title: title("Cumulative Realized Profit"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -1001,7 +1001,7 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { ]), }, { - name: "loss", + name: "Loss", title: title("Cumulative Realized Loss"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -1013,7 +1013,7 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { ]), }, { - name: "Net pnl", + name: "Net P&L", title: title("Cumulative Net Realized P&L"), bottom: [ ...list.flatMap(({ color, name, tree }) => [ @@ -1028,8 +1028,8 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { ], }, { - name: "Net pnl 30d change", - title: title("Net Realized P&L 30d Change"), + name: "Net P&L 1m Change", + title: title("Net Realized P&L 1m Change"), bottom: [ ...list.flatMap(({ color, name, tree }) => [ baseline({ @@ -1244,7 +1244,7 @@ function createGroupedAdjustedSoprChart(list, title) { */ function createSingleSoprSectionWithAdjusted(ctx, cohort, title) { return { - name: "sopr", + name: "SOPR", tree: [ createSingleBaseSoprChart(ctx, cohort, title), createSingleAdjustedSoprChart(ctx, cohort, title), @@ -1260,7 +1260,7 @@ function createSingleSoprSectionWithAdjusted(ctx, cohort, title) { */ function createGroupedSoprSectionWithAdjusted(list, title) { return { - name: "sopr", + name: "SOPR", tree: [ createGroupedBaseSoprChart(list, title), createGroupedAdjustedSoprChart(list, title), @@ -1277,7 +1277,7 @@ function createGroupedSoprSectionWithAdjusted(list, title) { */ function createSingleSoprSectionBasic(ctx, cohort, title) { return { - name: "sopr", + name: "SOPR", tree: [createSingleBaseSoprChart(ctx, cohort, title)], }; } @@ -1290,7 +1290,7 @@ function createSingleSoprSectionBasic(ctx, cohort, title) { */ function createGroupedSoprSectionBasic(list, title) { return { - name: "sopr", + name: "SOPR", tree: [createGroupedBaseSoprChart(list, title)], }; } @@ -1494,7 +1494,7 @@ function createNetUnrealizedPnlBaseMetric(tree) { */ function createNuplChart(ctx, rel, title) { return { - name: "nupl", + name: "NUPL", title: title("NUPL"), bottom: [ baseline({ @@ -1516,7 +1516,7 @@ function createNuplChart(ctx, rel, title) { */ function createGroupedNuplChart(ctx, list, title) { return { - name: "nupl", + name: "NUPL", title: title("NUPL"), bottom: [ ...list.map(({ color, name, tree }) => @@ -1552,7 +1552,7 @@ function createUnrealizedSection({ ctx, tree, title, pnl = [], netPnl = [], char name: "Unrealized", tree: [ { - name: "pnl", + name: "P&L", title: title("Unrealized P&L"), bottom: [ ...createUnrealizedPnlBaseMetrics(ctx, tree), @@ -1561,7 +1561,7 @@ function createUnrealizedSection({ ctx, tree, title, pnl = [], netPnl = [], char ], }, { - name: "Net pnl", + name: "Net P&L", title: title("Net Unrealized P&L"), bottom: [ createNetUnrealizedPnlBaseMetric(tree), @@ -1590,7 +1590,7 @@ function createGroupedUnrealizedSection({ list, title, netPnlMetrics, charts = [ tree: [ ...createGroupedUnrealizedBaseCharts(list, title), { - name: "Net pnl", + name: "Net P&L", title: title("Net Unrealized P&L"), bottom: [ ...list.flatMap((cohort) => [ @@ -1725,7 +1725,7 @@ function createSingleUnrealizedSectionBase(ctx, cohort, title) { function createGroupedUnrealizedBaseCharts(list, title) { return [ { - name: "profit", + name: "Profit", title: title("Unrealized Profit"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -1737,7 +1737,7 @@ function createGroupedUnrealizedBaseCharts(list, title) { ]), }, { - name: "loss", + name: "Loss", title: title("Unrealized Loss"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -1749,7 +1749,7 @@ function createGroupedUnrealizedBaseCharts(list, title) { ]), }, { - name: "total pnl", + name: "Total P&L", title: title("Unrealized Total P&L"), bottom: list.flatMap(({ color, name, tree }) => [ line({ @@ -1918,19 +1918,21 @@ function createGroupedUnrealizedSectionAgeRange(list, title) { /** * Generic single cost basis section builder - callers pass optional percentiles + * @param {PartialContext} ctx * @param {Object} args * @param {UtxoCohortObject} args.cohort * @param {(metric: string) => string} args.title * @param {PartialChartOption[]} [args.charts] - Extra charts (e.g., percentiles) * @returns {PartialOptionsGroup} */ -function createCostBasisSection({ cohort, title, charts = [] }) { +function createCostBasisSection(ctx, { cohort, title, charts = [] }) { + const { colors } = ctx; const { color, tree } = cohort; return { name: "Cost Basis", tree: [ { - name: charts.length > 0 ? "Average" : "cost basis", + name: "Average", title: title("Cost Basis"), top: [ line({ @@ -1940,16 +1942,41 @@ function createCostBasisSection({ cohort, title, charts = [] }) { unit: Unit.usd, }), line({ - metric: tree.costBasis.min, - name: "Min", - color, + metric: tree.costBasis.max, + name: "Max", + color: colors.green, unit: Unit.usd, defaultActive: false, }), + line({ + metric: tree.costBasis.min, + name: "Min", + color: colors.red, + unit: Unit.usd, + defaultActive: false, + }), + ], + }, + { + name: "Max", + title: title("Max Cost Basis"), + top: [ line({ metric: tree.costBasis.max, name: "Max", - color, + color: colors.green, + unit: Unit.usd, + }), + ], + }, + { + name: "Min", + title: title("Min Cost Basis"), + top: [ + line({ + metric: tree.costBasis.min, + name: "Min", + color: colors.red, unit: Unit.usd, }), ], @@ -1984,13 +2011,6 @@ function createGroupedCostBasisSection({ list, title, charts = [] }) { }), ), }, - { - name: "Min", - title: title("Min Cost Basis"), - top: list.map(({ color, name, tree }) => - line({ metric: tree.costBasis.min, name, color, unit: Unit.usd }), - ), - }, { name: "Max", title: title("Max Cost Basis"), @@ -1998,6 +2018,13 @@ function createGroupedCostBasisSection({ list, title, charts = [] }) { line({ metric: tree.costBasis.max, name, color, unit: Unit.usd }), ), }, + { + name: "Min", + title: title("Min Cost Basis"), + top: list.map(({ color, name, tree }) => + line({ metric: tree.costBasis.min, name, color, unit: Unit.usd }), + ), + }, ...charts, ], }; @@ -2016,12 +2043,12 @@ function createGroupedCostBasisSection({ list, title, charts = [] }) { */ function createSingleCostBasisSectionWithPercentiles(ctx, cohort, title) { const { colors } = ctx; - return createCostBasisSection({ + return createCostBasisSection(ctx, { cohort, title, charts: [ { - name: "percentiles", + name: "Percentiles", title: title("Cost Basis Percentiles"), top: createCostBasisPercentilesSeries(colors, [cohort], false), }, @@ -2043,7 +2070,7 @@ function createGroupedCostBasisSectionWithPercentiles(ctx, list, title) { title, charts: [ { - name: "percentiles", + name: "Percentiles", title: title("Cost Basis Percentiles"), top: createCostBasisPercentilesSeries(colors, list, true), }, @@ -2091,7 +2118,7 @@ function createActivitySection({ ctx, cohort, title, valueMetrics = [] }) { ], }, { - name: "value", + name: "Value", title: title("Value Created & Destroyed"), bottom: [ line({ metric: tree.realized.valueCreated, name: "Created", color: colors.emerald, unit: Unit.usd }), @@ -2107,8 +2134,6 @@ function createActivitySection({ ctx, cohort, title, valueMetrics = [] }) { line({ metric: tree.activity.coinblocksDestroyed.cumulative, name: "Cumulative", color, unit: Unit.coinblocks, defaultActive: false }), line({ metric: tree.activity.coindaysDestroyed.sum, name: "Coindays", color, unit: Unit.coindays }), line({ metric: tree.activity.coindaysDestroyed.cumulative, name: "Cumulative", color, unit: Unit.coindays, defaultActive: false }), - line({ metric: tree.activity.satblocksDestroyed, name: "Satblocks", color, unit: Unit.satblocks }), - line({ metric: tree.activity.satdaysDestroyed, name: "Satdays", color, unit: Unit.satdays }), ], }, ], @@ -2136,17 +2161,17 @@ function createGroupedActivitySection({ list, title, valueTree }) { ]), }, { - name: "value", + name: "Value", tree: valueTree ?? [ { - name: "created", + name: "Created", title: title("Value Created"), bottom: list.flatMap(({ color, name, tree }) => [ line({ metric: tree.realized.valueCreated, name, color, unit: Unit.usd }), ]), }, { - name: "destroyed", + name: "Destroyed", title: title("Value Destroyed"), bottom: list.flatMap(({ color, name, tree }) => [ line({ metric: tree.realized.valueDestroyed, name, color, unit: Unit.usd }), @@ -2216,7 +2241,7 @@ function createGroupedActivitySectionWithAdjusted(list, title) { title, valueTree: [ { - name: "created", + name: "Created", tree: [ { name: "Normal", @@ -2235,7 +2260,7 @@ function createGroupedActivitySectionWithAdjusted(list, title) { ], }, { - name: "destroyed", + name: "Destroyed", tree: [ { name: "Normal", diff --git a/website/scripts/options/full.js b/website/scripts/options/full.js index bb8e28c23..c8d0c0055 100644 --- a/website/scripts/options/full.js +++ b/website/scripts/options/full.js @@ -115,7 +115,8 @@ export function initOptions(brk) { } // Remove from set if manual price line already exists - if (blueprint.type === "Line") { + // Note: line() doesn't set type, so undefined means Line + if (blueprint.type === "Line" || blueprint.type === undefined) { const path = Object.values(blueprint.metric.by)[0]?.path ?? ""; if (path.includes("constant_")) { priceLines.get(unit)?.delete(parseFloat(blueprint.title)); diff --git a/website/scripts/options/market/averages.js b/website/scripts/options/market/averages.js index 12cc73a13..9ae5e7029 100644 --- a/website/scripts/options/market/averages.js +++ b/website/scripts/options/market/averages.js @@ -85,7 +85,7 @@ export function createPriceWithRatioOptions( return [ { - name: "price", + name: "Price", title, top: [line({ metric: priceMetric, name: legend, color, unit: Unit.usd })], }, @@ -100,6 +100,9 @@ export function createPriceWithRatioOptions( ]; } +/** Common period IDs to show at top level */ +const COMMON_PERIODS = ["1w", "1m", "200d", "1y", "200w", "4y"]; + /** * @param {PartialContext} ctx * @param {MarketMovingAverage} movingAverage @@ -113,35 +116,54 @@ export function createAveragesSection(ctx, movingAverage) { * @param {string} label * @param {ReturnType | ReturnType} averages */ - const createSubSection = (label, averages) => ({ - name: label, - tree: [ - { - name: "Compare", - title: `Price ${label}s`, - top: averages.map(({ id, color, ratio }) => - line({ - metric: ratio.price, - name: id, + const createSubSection = (label, averages) => { + const commonAverages = averages.filter(({ id }) => COMMON_PERIODS.includes(id)); + const moreAverages = averages.filter(({ id }) => !COMMON_PERIODS.includes(id)); + + return { + name: label, + tree: [ + { + name: "Compare", + title: `Price ${label}s`, + top: averages.map(({ id, color, ratio }) => + line({ + metric: ratio.price, + name: id, + color, + unit: Unit.usd, + }), + ), + }, + // Common periods at top level + ...commonAverages.map(({ name, color, ratio }) => ({ + name, + tree: createPriceWithRatioOptions(ctx, { + ratio, + title: `${name} ${label}`, + legend: "average", color, - unit: Unit.usd, }), - ), - }, - ...averages.map(({ name, color, ratio }) => ({ - name, - tree: createPriceWithRatioOptions(ctx, { - ratio, - title: `${name} ${label}`, - legend: "average", - color, - }), - })), - ], - }); + })), + // Less common periods in "More..." folder + { + name: "More...", + tree: moreAverages.map(({ name, color, ratio }) => ({ + name, + tree: createPriceWithRatioOptions(ctx, { + ratio, + title: `${name} ${label}`, + legend: "average", + color, + }), + })), + }, + ], + }; + }; return { - name: "Averages", + name: "Moving Averages", tree: [ createSubSection("SMA", smaAverages), createSubSection("EMA", emaAverages), diff --git a/website/scripts/options/market/indicators/bands.js b/website/scripts/options/market/bands.js similarity index 96% rename from website/scripts/options/market/indicators/bands.js rename to website/scripts/options/market/bands.js index 86966740f..a9422de24 100644 --- a/website/scripts/options/market/indicators/bands.js +++ b/website/scripts/options/market/bands.js @@ -1,7 +1,7 @@ /** Bands indicators (MinMax, Mayer Multiple) */ -import { Unit } from "../../../utils/units.js"; -import { line } from "../../series.js"; +import { Unit } from "../../utils/units.js"; +import { line } from "../series.js"; /** * Create Bands section diff --git a/website/scripts/options/market/index.js b/website/scripts/options/market/index.js index e48d7e8a4..d746a7550 100644 --- a/website/scripts/options/market/index.js +++ b/website/scripts/options/market/index.js @@ -4,9 +4,12 @@ import { localhost } from "../../utils/env.js"; import { Unit } from "../../utils/units.js"; import { candlestick, line } from "../series.js"; import { createAveragesSection } from "./averages.js"; -import { createPerformanceSection } from "./performance.js"; -import { createIndicatorsSection } from "./indicators/index.js"; -import { createInvestingSection } from "./investing.js"; +import { createReturnsSection } from "./performance.js"; +import { createMomentumSection } from "./momentum.js"; +import { createVolatilitySection } from "./volatility.js"; +import { createBandsSection } from "./bands.js"; +import { createValuationSection } from "./onchain.js"; +import { createDcaVsLumpSumSection, createDcaByYearSection } from "./investing.js"; /** * Create Market section @@ -161,22 +164,29 @@ export function createMarketSection(ctx) { ], }, - // Averages + // Moving Averages createAveragesSection(ctx, movingAverage), - // Performance - createPerformanceSection(ctx, returns), + // Returns + createReturnsSection(ctx, returns), - // Indicators - createIndicatorsSection(ctx, { - volatility, - range, - movingAverage, - indicators, - }), + // Volatility + createVolatilitySection(ctx, { volatility, range }), - // Investing - createInvestingSection(ctx, { dca, lookback, returns }), + // Momentum + createMomentumSection(ctx, indicators), + + // Bands + createBandsSection(ctx, { range, movingAverage }), + + // Valuation + createValuationSection(ctx, { indicators, movingAverage }), + + // DCA vs Lump Sum + createDcaVsLumpSumSection(ctx, { dca, lookback, returns }), + + // DCA by Year + createDcaByYearSection(ctx, { dca }), ], }; } diff --git a/website/scripts/options/market/indicators/index.js b/website/scripts/options/market/indicators/index.js deleted file mode 100644 index ddf7a06bf..000000000 --- a/website/scripts/options/market/indicators/index.js +++ /dev/null @@ -1,27 +0,0 @@ -/** Indicators section - Main entry point */ - -import { createMomentumSection } from "./momentum.js"; -import { createVolatilitySection } from "./volatility.js"; -import { createBandsSection } from "./bands.js"; -import { createOnchainSection } from "./onchain.js"; - -/** - * Create Indicators section - * @param {PartialContext} ctx - * @param {Object} args - * @param {Market["volatility"]} args.volatility - * @param {Market["range"]} args.range - * @param {Market["movingAverage"]} args.movingAverage - * @param {Market["indicators"]} args.indicators - */ -export function createIndicatorsSection(ctx, { volatility, range, movingAverage, indicators }) { - return { - name: "Indicators", - tree: [ - createMomentumSection(ctx, indicators), - createVolatilitySection(ctx, { volatility, range }), - createBandsSection(ctx, { range, movingAverage }), - createOnchainSection(ctx, { indicators, movingAverage }), - ], - }; -} diff --git a/website/scripts/options/market/investing.js b/website/scripts/options/market/investing.js index f44df92e6..580579f1a 100644 --- a/website/scripts/options/market/investing.js +++ b/website/scripts/options/market/investing.js @@ -32,20 +32,115 @@ export function buildDcaClasses(colors, dca) { costBasis: dca.classAveragePrice[`_${year}`], returns: dca.classReturns[`_${year}`], stack: dca.classStack[`_${year}`], + daysInProfit: dca.classDaysInProfit[`_${year}`], + daysInLoss: dca.classDaysInLoss[`_${year}`], + maxDrawdown: dca.classMaxDrawdown[`_${year}`], + maxReturn: dca.classMaxReturn[`_${year}`], })); } /** - * Create Investing section + * Create DCA vs Lump Sum section * @param {PartialContext} ctx * @param {Object} args * @param {Market["dca"]} args.dca * @param {Market["lookback"]} args.lookback * @param {Market["returns"]} args.returns */ -export function createInvestingSection(ctx, { dca, lookback, returns }) { +export function createDcaVsLumpSumSection(ctx, { dca, lookback, returns }) { const { colors } = ctx; - const dcaClasses = buildDcaClasses(colors, dca); + + /** + * @param {string} name + * @param {ShortPeriodKey | LongPeriodKey} key + */ + const costBasisChart = (name, key) => ({ + name: "Cost Basis", + title: `${name} Cost Basis`, + top: [ + line({ + metric: dca.periodAveragePrice[key], + name: "DCA", + color: colors.green, + unit: Unit.usd, + }), + line({ + metric: lookback[key], + name: "Lump sum", + color: colors.orange, + unit: Unit.usd, + }), + ], + }); + + /** @param {string} name @param {ShortPeriodKey | LongPeriodKey} key */ + const daysInProfitChart = (name, key) => ({ + name: "Days in Profit", + title: `${name} Days in Profit`, + top: [ + line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }), + line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }), + ], + bottom: [ + line({ metric: dca.periodDaysInProfit[key], name: "DCA", color: colors.green, unit: Unit.days }), + line({ metric: dca.periodLumpSumDaysInProfit[key], name: "Lump sum", color: colors.orange, unit: Unit.days }), + ], + }); + + /** @param {string} name @param {ShortPeriodKey | LongPeriodKey} key */ + const daysInLossChart = (name, key) => ({ + name: "Days in Loss", + title: `${name} Days in Loss`, + top: [ + line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }), + line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }), + ], + bottom: [ + line({ metric: dca.periodDaysInLoss[key], name: "DCA", color: colors.red, unit: Unit.days }), + line({ metric: dca.periodLumpSumDaysInLoss[key], name: "Lump sum", color: colors.orange, unit: Unit.days }), + ], + }); + + /** @param {string} name @param {ShortPeriodKey | LongPeriodKey} key */ + const maxDrawdownChart = (name, key) => ({ + name: "Max Drawdown", + title: `${name} Max Drawdown`, + top: [ + line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }), + line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }), + ], + bottom: [ + line({ metric: dca.periodMaxDrawdown[key], name: "DCA", color: colors.green, unit: Unit.percentage }), + line({ metric: dca.periodLumpSumMaxDrawdown[key], name: "Lump sum", color: colors.orange, unit: Unit.percentage }), + ], + }); + + /** @param {string} name @param {ShortPeriodKey | LongPeriodKey} key */ + const maxReturnChart = (name, key) => ({ + name: "Max Return", + title: `${name} Max Return`, + top: [ + line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }), + line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }), + ], + bottom: [ + line({ metric: dca.periodMaxReturn[key], name: "DCA", color: colors.green, unit: Unit.percentage }), + line({ metric: dca.periodLumpSumMaxReturn[key], name: "Lump sum", color: colors.orange, unit: Unit.percentage }), + ], + }); + + /** + * @param {string} name + * @param {ShortPeriodKey | LongPeriodKey} key + */ + const stackChart = (name, key) => ({ + name: "Stack", + title: `${name} Stack`, + bottom: [ + ...satsBtcUsd(dca.periodStack[key], "DCA", colors.green), + ...satsBtcUsd(dca.periodLumpSumStack[key], "Lump sum", colors.orange), + ], + }); /** * @param {string} id @@ -56,31 +151,34 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { return { name, tree: [ - { - name: "Cost basis", - title: `${name} Cost Basis`, - top: [ - line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }), - line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }), - ], - }, + costBasisChart(name, key), { name: "Returns", title: `${name} Returns`, bottom: [ - baseline({ metric: dca.periodReturns[key], name: "DCA", unit: Unit.percentage }), - baseline({ metric: returns.priceReturns[key], name: "Lump sum", color: [colors.cyan, colors.orange], unit: Unit.percentage }), - priceLine({ ctx, unit: Unit.percentage }), + baseline({ + metric: dca.periodReturns[key], + name: "DCA", + unit: Unit.percentage, + }), + baseline({ + metric: dca.periodLumpSumReturns[key], + name: "Lump sum", + color: [colors.cyan, colors.orange], + unit: Unit.percentage, + }), ], }, { - name: "Stack", - title: `${name} Stack`, - bottom: [ - ...satsBtcUsd(dca.periodStack[key], "DCA", colors.green), - ...satsBtcUsd(dca.periodLumpSumStack[key], "Lump sum", colors.orange), + name: "Profitability", + tree: [ + daysInProfitChart(name, key), + daysInLossChart(name, key), + maxDrawdownChart(name, key), + maxReturnChart(name, key), ], }, + stackChart(name, key), ], }; }; @@ -94,142 +192,226 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) { return { name, tree: [ - { - name: "Cost basis", - title: `${name} Cost Basis`, - top: [ - line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }), - line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }), - ], - }, + costBasisChart(name, key), { name: "Returns", title: `${name} Returns`, bottom: [ - baseline({ metric: dca.periodReturns[key], name: "DCA", unit: Unit.percentage }), - baseline({ metric: returns.priceReturns[key], name: "Lump sum", color: [colors.cyan, colors.orange], unit: Unit.percentage }), - line({ metric: dca.periodCagr[key], name: "DCA CAGR", color: colors.purple, unit: Unit.percentage, defaultActive: false }), - line({ metric: returns.cagr[key], name: "Lump sum CAGR", color: colors.indigo, unit: Unit.percentage, defaultActive: false }), + baseline({ + metric: dca.periodReturns[key], + name: "DCA", + unit: Unit.percentage, + }), + baseline({ + metric: dca.periodLumpSumReturns[key], + name: "Lump sum", + color: [colors.cyan, colors.orange], + unit: Unit.percentage, + }), + line({ + metric: dca.periodCagr[key], + name: "DCA CAGR", + color: colors.purple, + unit: Unit.percentage, + defaultActive: false, + }), + line({ + metric: returns.cagr[key], + name: "Lump sum CAGR", + color: colors.indigo, + unit: Unit.percentage, + defaultActive: false, + }), priceLine({ ctx, unit: Unit.percentage }), ], }, { - name: "Stack", - title: `${name} Stack`, - bottom: [ - ...satsBtcUsd(dca.periodStack[key], "DCA", colors.green), - ...satsBtcUsd(dca.periodLumpSumStack[key], "Lump sum", colors.orange), + name: "Profitability", + tree: [ + daysInProfitChart(name, key), + daysInLossChart(name, key), + maxDrawdownChart(name, key), + maxReturnChart(name, key), ], }, + stackChart(name, key), ], }; }; return { - name: "Investing", + name: "DCA vs Lump Sum", tree: [ - // DCA vs Lump sum - { - name: "DCA vs Lump sum", - tree: [ - createPeriodTree("1w", "_1w"), - createPeriodTree("1m", "_1m"), - createPeriodTree("3m", "_3m"), - createPeriodTree("6m", "_6m"), - createPeriodTree("1y", "_1y"), - createPeriodTreeWithCagr("2y", "_2y"), - createPeriodTreeWithCagr("3y", "_3y"), - createPeriodTreeWithCagr("4y", "_4y"), - createPeriodTreeWithCagr("5y", "_5y"), - createPeriodTreeWithCagr("6y", "_6y"), - createPeriodTreeWithCagr("8y", "_8y"), - createPeriodTreeWithCagr("10y", "_10y"), - ], - }, - - // DCA classes - { - name: "DCA classes", - tree: [ - // Comparison charts (all years overlaid) - { - name: "Compare", - tree: [ - { - name: "Cost basis", - title: "DCA Cost Basis", - top: dcaClasses.map( - ({ year, color, defaultActive, costBasis }) => - line({ - metric: costBasis, - name: `${year}`, - color, - defaultActive, - unit: Unit.usd, - }), - ), - }, - { - name: "Returns", - title: "DCA Returns", - bottom: dcaClasses.map( - ({ year, color, defaultActive, returns }) => - baseline({ - metric: returns, - name: `${year}`, - color, - defaultActive, - unit: Unit.percentage, - }), - ), - }, - { - name: "Stack", - title: "DCA Stack", - bottom: dcaClasses.flatMap( - ({ year, color, defaultActive, stack }) => - satsBtcUsd(stack, `${year}`, color, { defaultActive }), - ), - }, - ], - }, - // Individual year charts - ...dcaClasses.map(({ year, color, costBasis, returns, stack }) => ({ - name: `${year}`, - tree: [ - { - name: "Cost basis", - title: `${year} Cost Basis`, - top: [ - line({ - metric: costBasis, - name: "Cost basis", - color, - unit: Unit.usd, - }), - ], - }, - { - name: "Returns", - title: `${year} Returns`, - bottom: [ - baseline({ - metric: returns, - name: "Returns", - color, - unit: Unit.percentage, - }), - ], - }, - { - name: "Stack", - title: `${year} Stack`, - bottom: satsBtcUsd(stack, "Stack", color), - }, - ], - })), - ], - }, + createPeriodTree("1w", "_1w"), + createPeriodTree("1m", "_1m"), + createPeriodTree("3m", "_3m"), + createPeriodTree("6m", "_6m"), + createPeriodTree("1y", "_1y"), + createPeriodTreeWithCagr("2y", "_2y"), + createPeriodTreeWithCagr("3y", "_3y"), + createPeriodTreeWithCagr("4y", "_4y"), + createPeriodTreeWithCagr("5y", "_5y"), + createPeriodTreeWithCagr("6y", "_6y"), + createPeriodTreeWithCagr("8y", "_8y"), + createPeriodTreeWithCagr("10y", "_10y"), + ], + }; +} + +/** + * Create DCA by Year section + * @param {PartialContext} ctx + * @param {Object} args + * @param {Market["dca"]} args.dca + */ +export function createDcaByYearSection(ctx, { dca }) { + const { colors } = ctx; + const dcaClasses = buildDcaClasses(colors, dca); + + return { + name: "DCA by Year", + tree: [ + // Comparison charts (all years overlaid) + { + name: "Compare", + tree: [ + { + name: "Cost basis", + title: "DCA Cost Basis", + top: dcaClasses.map(({ year, color, defaultActive, costBasis }) => + line({ + metric: costBasis, + name: `${year}`, + color, + defaultActive, + unit: Unit.usd, + }), + ), + }, + { + name: "Returns", + title: "DCA Returns", + bottom: dcaClasses.map(({ year, defaultActive, returns }) => + baseline({ + metric: returns, + name: `${year}`, + defaultActive, + unit: Unit.percentage, + }), + ), + }, + { + name: "Profitability", + title: "DCA Profitability", + bottom: [ + ...dcaClasses.map(({ year, color, defaultActive, daysInProfit }) => + line({ + metric: daysInProfit, + name: `${year} Days in Profit`, + color, + defaultActive, + unit: Unit.days, + }), + ), + ...dcaClasses.map(({ year, color, daysInLoss }) => + line({ + metric: daysInLoss, + name: `${year} Days in Loss`, + color, + defaultActive: false, + unit: Unit.days, + }), + ), + ], + }, + { + name: "Stack", + title: "DCA Stack", + bottom: dcaClasses.flatMap( + ({ year, color, defaultActive, stack }) => + satsBtcUsd(stack, `${year}`, color, { defaultActive }), + ), + }, + ], + }, + // Individual year charts + ...dcaClasses.map( + ({ + year, + color, + costBasis, + returns, + stack, + daysInProfit, + daysInLoss, + maxDrawdown, + maxReturn, + }) => ({ + name: `${year}`, + tree: [ + { + name: "Cost Basis", + title: `${year} Cost Basis`, + top: [ + line({ + metric: costBasis, + name: "Cost Basis", + color, + unit: Unit.usd, + }), + ], + }, + { + name: "Returns", + title: `${year} Returns`, + bottom: [ + baseline({ + metric: returns, + name: "Returns", + unit: Unit.percentage, + }), + ], + }, + { + name: "Profitability", + title: `${year} Profitability`, + bottom: [ + line({ + metric: daysInProfit, + name: "Days in Profit", + color: colors.green, + unit: Unit.days, + }), + line({ + metric: daysInLoss, + name: "Days in Loss", + color: colors.red, + unit: Unit.days, + }), + line({ + metric: maxDrawdown, + name: "Max Drawdown", + color: colors.purple, + unit: Unit.percentage, + defaultActive: false, + }), + line({ + metric: maxReturn, + name: "Max Return", + color: colors.cyan, + unit: Unit.percentage, + defaultActive: false, + }), + ], + }, + { + name: "Stack", + title: `${year} Stack`, + bottom: satsBtcUsd(stack, "Stack", color), + }, + ], + }), + ), ], }; } diff --git a/website/scripts/options/market/indicators/momentum.js b/website/scripts/options/market/momentum.js similarity index 94% rename from website/scripts/options/market/indicators/momentum.js rename to website/scripts/options/market/momentum.js index 231be6792..f35179e44 100644 --- a/website/scripts/options/market/indicators/momentum.js +++ b/website/scripts/options/market/momentum.js @@ -1,8 +1,8 @@ /** Momentum indicators (RSI, StochRSI, Stochastic, MACD) */ -import { Unit } from "../../../utils/units.js"; -import { priceLine, priceLines } from "../../constants.js"; -import { line, histogram } from "../../series.js"; +import { Unit } from "../../utils/units.js"; +import { priceLine, priceLines } from "../constants.js"; +import { line, histogram } from "../series.js"; /** * Create Momentum section diff --git a/website/scripts/options/market/indicators/onchain.js b/website/scripts/options/market/onchain.js similarity index 88% rename from website/scripts/options/market/indicators/onchain.js rename to website/scripts/options/market/onchain.js index 4c68c5f51..def96d2b5 100644 --- a/website/scripts/options/market/indicators/onchain.js +++ b/website/scripts/options/market/onchain.js @@ -1,20 +1,20 @@ /** On-chain indicators (Pi Cycle, Puell, NVT, Gini) */ -import { Unit } from "../../../utils/units.js"; -import { baseline, line } from "../../series.js"; +import { Unit } from "../../utils/units.js"; +import { baseline, line } from "../series.js"; /** - * Create On-chain section + * Create Valuation section * @param {PartialContext} ctx * @param {Object} args * @param {Market["indicators"]} args.indicators * @param {Market["movingAverage"]} args.movingAverage */ -export function createOnchainSection(ctx, { indicators, movingAverage }) { +export function createValuationSection(ctx, { indicators, movingAverage }) { const { colors } = ctx; return { - name: "On-chain", + name: "Valuation", tree: [ { name: "Pi Cycle", diff --git a/website/scripts/options/market/performance.js b/website/scripts/options/market/performance.js index d411432b4..6370a4449 100644 --- a/website/scripts/options/market/performance.js +++ b/website/scripts/options/market/performance.js @@ -6,55 +6,100 @@ import { baseline } from "../series.js"; import { periodIdToName } from "./utils.js"; /** - * Create Performance section + * Create Returns section * @param {PartialContext} ctx * @param {Market["returns"]} returns */ -export function createPerformanceSection(ctx, returns) { +export function createReturnsSection(ctx, returns) { const { colors } = ctx; + const shortTermPeriods = /** @type {const} */ ([ + ["1d", "_1d", undefined], + ["1w", "_1w", undefined], + ["1m", "_1m", undefined], + ]); + + const mediumTermPeriods = /** @type {const} */ ([ + ["3m", "_3m", undefined], + ["6m", "_6m", undefined], + ["1y", "_1y", undefined], + ]); + + const longTermPeriods = /** @type {const} */ ([ + ["2y", "_2y", "_2y"], + ["3y", "_3y", "_3y"], + ["4y", "_4y", "_4y"], + ["5y", "_5y", "_5y"], + ["6y", "_6y", "_6y"], + ["8y", "_8y", "_8y"], + ["10y", "_10y", "_10y"], + ]); + + /** + * @template {keyof typeof returns.priceReturns} K + * @param {readonly [string, K, K | undefined]} period + */ + const createPeriodChart = ([id, returnKey, cagrKey]) => { + const priceReturns = returns.priceReturns[/** @type {K} */ (returnKey)]; + const cagr = cagrKey ? returns.cagr[/** @type {keyof typeof returns.cagr} */ (cagrKey)] : undefined; + const name = periodIdToName(id, true); + return { + name, + title: `${name} Returns`, + bottom: [ + baseline({ + metric: priceReturns, + name: "Total", + unit: Unit.percentage, + }), + ...(cagr + ? [ + baseline({ + metric: cagr, + name: "CAGR", + color: [colors.cyan, colors.orange], + unit: Unit.percentage, + }), + ] + : []), + priceLine({ ctx, unit: Unit.percentage }), + ], + }; + }; + return { - name: "Performance", - tree: /** @type {const} */ ([ - ["1d", "_1d", undefined], - ["1w", "_1w", undefined], - ["1m", "_1m", undefined], - ["3m", "_3m", undefined], - ["6m", "_6m", undefined], - ["1y", "_1y", undefined], - ["2y", "_2y", "_2y"], - ["3y", "_3y", "_3y"], - ["4y", "_4y", "_4y"], - ["5y", "_5y", "_5y"], - ["6y", "_6y", "_6y"], - ["8y", "_8y", "_8y"], - ["10y", "_10y", "_10y"], - ]).map(([id, returnKey, cagrKey]) => { - const priceReturns = returns.priceReturns[returnKey]; - const cagr = cagrKey ? returns.cagr[cagrKey] : undefined; - const name = periodIdToName(id, true); - return { - name, - title: `${name} Returns`, + name: "Returns", + tree: [ + // Compare all periods + { + name: "Compare", + title: "Returns Comparison", bottom: [ - baseline({ - metric: priceReturns, - name: "Total", - unit: Unit.percentage, - }), - ...(cagr - ? [ - baseline({ - metric: cagr, - name: "CAGR", - color: [colors.cyan, colors.orange], - unit: Unit.percentage, - }), - ] - : []), + baseline({ metric: returns.priceReturns._1d, name: "1d", color: colors.red, unit: Unit.percentage }), + baseline({ metric: returns.priceReturns._1w, name: "1w", color: colors.orange, unit: Unit.percentage }), + baseline({ metric: returns.priceReturns._1m, name: "1m", color: colors.yellow, unit: Unit.percentage }), + baseline({ metric: returns.priceReturns._3m, name: "3m", color: colors.lime, unit: Unit.percentage, defaultActive: false }), + baseline({ metric: returns.priceReturns._6m, name: "6m", color: colors.green, unit: Unit.percentage, defaultActive: false }), + baseline({ metric: returns.priceReturns._1y, name: "1y", color: colors.teal, unit: Unit.percentage }), + baseline({ metric: returns.priceReturns._4y, name: "4y", color: colors.blue, unit: Unit.percentage }), priceLine({ ctx, unit: Unit.percentage }), ], - }; - }), + }, + // Short-term (1d, 1w, 1m) + { + name: "Short-term", + tree: shortTermPeriods.map(createPeriodChart), + }, + // Medium-term (3m, 6m, 1y) + { + name: "Medium-term", + tree: mediumTermPeriods.map(createPeriodChart), + }, + // Long-term (2y+) + { + name: "Long-term", + tree: longTermPeriods.map(createPeriodChart), + }, + ], }; } diff --git a/website/scripts/options/market/indicators/volatility.js b/website/scripts/options/market/volatility.js similarity index 95% rename from website/scripts/options/market/indicators/volatility.js rename to website/scripts/options/market/volatility.js index 29ea21018..a8e7fd434 100644 --- a/website/scripts/options/market/indicators/volatility.js +++ b/website/scripts/options/market/volatility.js @@ -1,8 +1,8 @@ /** Volatility indicators (Index, True Range, Choppiness, Sharpe, Sortino) */ -import { Unit } from "../../../utils/units.js"; -import { priceLine, priceLines } from "../../constants.js"; -import { line } from "../../series.js"; +import { Unit } from "../../utils/units.js"; +import { priceLine, priceLines } from "../constants.js"; +import { line } from "../series.js"; /** * Create Volatility section diff --git a/website/scripts/options/partial.js b/website/scripts/options/partial.js index d5ab329b1..32ee3579e 100644 --- a/website/scripts/options/partial.js +++ b/website/scripts/options/partial.js @@ -95,62 +95,45 @@ export function createPartialOptions({ brk }) { { name: "Distribution", tree: [ - // All UTXOs - CohortAll (adjustedSopr + percentiles but no RelToMarketCap) - createCohortFolderAll(ctx, cohortAll), + // Overview - All UTXOs (adjustedSopr + percentiles but no RelToMarketCap) + createCohortFolderAll(ctx, { ...cohortAll, name: "Overview" }), - // Terms (STH/LTH) - Short is Full, Long has nupl - { - name: "Terms", - tree: [ - // Compare folder - both have nupl + percentiles - createCohortFolderWithNupl(ctx, { - name: "Compare", - title: "Term", - list: [termShort, termLong], - }), - // Individual cohorts with their specific capabilities - createCohortFolderFull(ctx, termShort), - createCohortFolderWithNupl(ctx, termLong), - ], - }, + // STH - Short term holder cohort (Full capability) + createCohortFolderFull(ctx, termShort), - // Types - addressable types have addrCount, others don't - { - name: "Types", - tree: [ - createCohortFolderAddress(ctx, { - name: "Compare", - title: "Type", - list: typeAddressable, - }), - ...typeAddressable.map(mapAddress), - ...typeOther.map(mapBasicWithoutMarketCap), - ], - }, + // LTH - Long term holder cohort (nupl) + createCohortFolderWithNupl(ctx, termLong), - // Age cohorts + // STH vs LTH - Direct comparison + createCohortFolderWithNupl(ctx, { + name: "STH vs LTH", + title: "Term", + list: [termShort, termLong], + }), + + // Ages cohorts { - name: "Age", + name: "Ages", tree: [ - // Up To (< X old) + // Younger Than (< X old) { - name: "Up To", + name: "Younger Than", tree: [ createCohortFolderWithAdjusted(ctx, { name: "Compare", - title: "Age Up To", + title: "Age Younger Than", list: upToDate, }), ...upToDate.map(mapWithAdjusted), ], }, - // At Least (≥ X old) + // Older Than (≥ X old) { - name: "At Least", + name: "Older Than", tree: [ createCohortFolderBasicWithMarketCap(ctx, { name: "Compare", - title: "Age At Least", + title: "Age Older Than", list: fromDate, }), ...fromDate.map(mapBasicWithMarketCap), @@ -171,29 +154,29 @@ export function createPartialOptions({ brk }) { ], }, - // Amount cohorts (UTXO size) + // Sizes cohorts (UTXO size) { - name: "Amount", + name: "Sizes", tree: [ - // Under (< X sats) + // Less Than (< X sats) { - name: "Under", + name: "Less Than", tree: [ createCohortFolderBasicWithMarketCap(ctx, { name: "Compare", - title: "Amount Under", + title: "Size Less Than", list: utxosUnderAmount, }), ...utxosUnderAmount.map(mapBasicWithMarketCap), ], }, - // Above (≥ X sats) + // More Than (≥ X sats) { - name: "Above", + name: "More Than", tree: [ createCohortFolderBasicWithMarketCap(ctx, { name: "Compare", - title: "Amount Above", + title: "Size More Than", list: utxosAboveAmount, }), ...utxosAboveAmount.map(mapBasicWithMarketCap), @@ -205,7 +188,7 @@ export function createPartialOptions({ brk }) { tree: [ createCohortFolderBasicWithoutMarketCap(ctx, { name: "Compare", - title: "Amount Range", + title: "Size Range", list: utxosAmountRanges, }), ...utxosAmountRanges.map(mapBasicWithoutMarketCap), @@ -214,29 +197,29 @@ export function createPartialOptions({ brk }) { ], }, - // Balance cohorts (Address balance) + // Balances cohorts (Address balance) { - name: "Balance", + name: "Balances", tree: [ - // Under (< X sats) + // Less Than (< X sats) { - name: "Under", + name: "Less Than", tree: [ createAddressCohortFolder(ctx, { name: "Compare", - title: "Balance Under", + title: "Balance Less Than", list: addressesUnderAmount, }), ...addressesUnderAmount.map(mapAddressCohorts), ], }, - // Above (≥ X sats) + // More Than (≥ X sats) { - name: "Above", + name: "More Than", tree: [ createAddressCohortFolder(ctx, { name: "Compare", - title: "Balance Above", + title: "Balance More Than", list: addressesAboveAmount, }), ...addressesAboveAmount.map(mapAddressCohorts), @@ -257,6 +240,20 @@ export function createPartialOptions({ brk }) { ], }, + // Script Types - addressable types have addrCount, others don't + { + name: "Script Types", + tree: [ + createCohortFolderAddress(ctx, { + name: "Compare", + title: "Script Type", + list: typeAddressable, + }), + ...typeAddressable.map(mapAddress), + ...typeOther.map(mapBasicWithoutMarketCap), + ], + }, + // Epochs - CohortBasicWithoutMarketCap (no RelToMarketCap) { name: "Epochs", @@ -285,8 +282,13 @@ export function createPartialOptions({ brk }) { ], }, - // Cointime section - createCointimeSection(ctx), + // Research section + { + name: "Research", + tree: [ + createCointimeSection(ctx), + ], + }, ], }, diff --git a/website/scripts/options/shared.js b/website/scripts/options/shared.js index 7dab5a89f..b664c52e6 100644 --- a/website/scripts/options/shared.js +++ b/website/scripts/options/shared.js @@ -166,7 +166,7 @@ export function createRatioChart(ctx, { title, price, ratio, color, name }) { name: name ?? "ratio", title: title(name ?? "Ratio"), top: [ - line({ metric: price, name: "price", color, unit: Unit.usd }), + line({ metric: price, name: "Price", color, unit: Unit.usd }), ...percentileUsdMap(colors, ratio).map(({ name, prop, color }) => line({ metric: prop, @@ -221,7 +221,7 @@ export function createZScoresFolder( const sdPats = sdPatterns(ratio); return { - name: "ZScores", + name: "Z-Scores", tree: [ { name: "Compare", diff --git a/website/scripts/options/unused.js b/website/scripts/options/unused.js index a0d581ee4..b04365daf 100644 --- a/website/scripts/options/unused.js +++ b/website/scripts/options/unused.js @@ -41,6 +41,8 @@ function walk(node, map, path) { kn === "outputtype" || kn === "heighttopool" || kn === "txid" || + kn.startsWith("satblocks") || + kn.startsWith("satdays") || kn.endsWith("state") || kn.endsWith("index") || kn.endsWith("indexes") || diff --git a/website/styles/elements.css b/website/styles/elements.css index 64f5049b4..d18c40f5c 100644 --- a/website/styles/elements.css +++ b/website/styles/elements.css @@ -40,10 +40,11 @@ a { &[target="_blank"]::after { color: var(--off-color); content: "↗"; - align-self: baseline; - font-weight: 300; + font-weight: 400; + font-size: 1rem; - margin-left: 0.25rem; + margin-top: 0.1rem; + margin-left: 0.375rem; line-height: 1; &:hover {