diff --git a/crates/brk_client/src/lib.rs b/crates/brk_client/src/lib.rs index c9e62937d..c1a81db83 100644 --- a/crates/brk_client/src/lib.rs +++ b/crates/brk_client/src/lib.rs @@ -891,7 +891,7 @@ pub struct RealizedPattern3 { pub realized_cap_rel_to_own_market_cap: MetricPattern1, pub realized_loss: BlockCountPattern, pub realized_loss_rel_to_realized_cap: BlockCountPattern, - pub realized_price: MetricPattern1, + pub realized_price: ActivePricePattern, pub realized_price_extra: ActivePriceRatioPattern, pub realized_profit: BlockCountPattern, pub realized_profit_rel_to_realized_cap: BlockCountPattern, @@ -929,7 +929,7 @@ impl RealizedPattern3 { realized_cap_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_rel_to_own_market_cap")), realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss")), realized_loss_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), - realized_price: MetricPattern1::new(client.clone(), _m(&acc, "realized_price")), + realized_price: ActivePricePattern::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: ActivePriceRatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit")), realized_profit_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), @@ -966,7 +966,7 @@ pub struct RealizedPattern4 { pub realized_cap_30d_delta: MetricPattern4, pub realized_loss: BlockCountPattern, pub realized_loss_rel_to_realized_cap: BlockCountPattern, - pub realized_price: MetricPattern1, + pub realized_price: ActivePricePattern, pub realized_price_extra: RealizedPriceExtraPattern, pub realized_profit: BlockCountPattern, pub realized_profit_rel_to_realized_cap: BlockCountPattern, @@ -1002,7 +1002,7 @@ impl RealizedPattern4 { realized_cap_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss")), realized_loss_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), - realized_price: MetricPattern1::new(client.clone(), _m(&acc, "realized_price")), + realized_price: ActivePricePattern::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: RealizedPriceExtraPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit")), realized_profit_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), @@ -1022,31 +1022,31 @@ impl RealizedPattern4 { /// Pattern struct for repeated tree structure. pub struct Ratio1ySdPattern { - pub _0sd_usd: MetricPattern4, + pub _0sd_usd: _0sdUsdPattern, pub m0_5sd: MetricPattern4, - pub m0_5sd_usd: MetricPattern4, + pub m0_5sd_usd: _0sdUsdPattern, pub m1_5sd: MetricPattern4, - pub m1_5sd_usd: MetricPattern4, + pub m1_5sd_usd: _0sdUsdPattern, pub m1sd: MetricPattern4, - pub m1sd_usd: MetricPattern4, + pub m1sd_usd: _0sdUsdPattern, pub m2_5sd: MetricPattern4, - pub m2_5sd_usd: MetricPattern4, + pub m2_5sd_usd: _0sdUsdPattern, pub m2sd: MetricPattern4, - pub m2sd_usd: MetricPattern4, + pub m2sd_usd: _0sdUsdPattern, pub m3sd: MetricPattern4, - pub m3sd_usd: MetricPattern4, + pub m3sd_usd: _0sdUsdPattern, pub p0_5sd: MetricPattern4, - pub p0_5sd_usd: MetricPattern4, + pub p0_5sd_usd: _0sdUsdPattern, pub p1_5sd: MetricPattern4, - pub p1_5sd_usd: MetricPattern4, + pub p1_5sd_usd: _0sdUsdPattern, pub p1sd: MetricPattern4, - pub p1sd_usd: MetricPattern4, + pub p1sd_usd: _0sdUsdPattern, pub p2_5sd: MetricPattern4, - pub p2_5sd_usd: MetricPattern4, + pub p2_5sd_usd: _0sdUsdPattern, pub p2sd: MetricPattern4, - pub p2sd_usd: MetricPattern4, + pub p2sd_usd: _0sdUsdPattern, pub p3sd: MetricPattern4, - pub p3sd_usd: MetricPattern4, + pub p3sd_usd: _0sdUsdPattern, pub sd: MetricPattern4, pub sma: MetricPattern4, pub zscore: MetricPattern4, @@ -1056,31 +1056,31 @@ impl Ratio1ySdPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _0sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "0sd_usd")), + _0sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "0sd_usd")), m0_5sd: MetricPattern4::new(client.clone(), _m(&acc, "m0_5sd")), - m0_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m0_5sd_usd")), + m0_5sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "m0_5sd_usd")), m1_5sd: MetricPattern4::new(client.clone(), _m(&acc, "m1_5sd")), - m1_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m1_5sd_usd")), + m1_5sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "m1_5sd_usd")), m1sd: MetricPattern4::new(client.clone(), _m(&acc, "m1sd")), - m1sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m1sd_usd")), + m1sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "m1sd_usd")), m2_5sd: MetricPattern4::new(client.clone(), _m(&acc, "m2_5sd")), - m2_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m2_5sd_usd")), + m2_5sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "m2_5sd_usd")), m2sd: MetricPattern4::new(client.clone(), _m(&acc, "m2sd")), - m2sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m2sd_usd")), + m2sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "m2sd_usd")), m3sd: MetricPattern4::new(client.clone(), _m(&acc, "m3sd")), - m3sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "m3sd_usd")), + m3sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "m3sd_usd")), p0_5sd: MetricPattern4::new(client.clone(), _m(&acc, "p0_5sd")), - p0_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p0_5sd_usd")), + p0_5sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "p0_5sd_usd")), p1_5sd: MetricPattern4::new(client.clone(), _m(&acc, "p1_5sd")), - p1_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p1_5sd_usd")), + p1_5sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "p1_5sd_usd")), p1sd: MetricPattern4::new(client.clone(), _m(&acc, "p1sd")), - p1sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p1sd_usd")), + p1sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "p1sd_usd")), p2_5sd: MetricPattern4::new(client.clone(), _m(&acc, "p2_5sd")), - p2_5sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p2_5sd_usd")), + p2_5sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "p2_5sd_usd")), p2sd: MetricPattern4::new(client.clone(), _m(&acc, "p2sd")), - p2sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p2sd_usd")), + p2sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "p2sd_usd")), p3sd: MetricPattern4::new(client.clone(), _m(&acc, "p3sd")), - p3sd_usd: MetricPattern4::new(client.clone(), _m(&acc, "p3sd_usd")), + p3sd_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "p3sd_usd")), sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")), sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")), zscore: MetricPattern4::new(client.clone(), _m(&acc, "zscore")), @@ -1102,7 +1102,7 @@ pub struct RealizedPattern2 { pub realized_cap_rel_to_own_market_cap: MetricPattern1, pub realized_loss: BlockCountPattern, pub realized_loss_rel_to_realized_cap: BlockCountPattern, - pub realized_price: MetricPattern1, + pub realized_price: ActivePricePattern, pub realized_price_extra: ActivePriceRatioPattern, pub realized_profit: BlockCountPattern, pub realized_profit_rel_to_realized_cap: BlockCountPattern, @@ -1135,7 +1135,7 @@ impl RealizedPattern2 { realized_cap_rel_to_own_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "realized_cap_rel_to_own_market_cap")), realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss")), realized_loss_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), - realized_price: MetricPattern1::new(client.clone(), _m(&acc, "realized_price")), + realized_price: ActivePricePattern::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: ActivePriceRatioPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit")), realized_profit_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), @@ -1167,7 +1167,7 @@ pub struct RealizedPattern { pub realized_cap_30d_delta: MetricPattern4, pub realized_loss: BlockCountPattern, pub realized_loss_rel_to_realized_cap: BlockCountPattern, - pub realized_price: MetricPattern1, + pub realized_price: ActivePricePattern, pub realized_price_extra: RealizedPriceExtraPattern, pub realized_profit: BlockCountPattern, pub realized_profit_rel_to_realized_cap: BlockCountPattern, @@ -1198,7 +1198,7 @@ impl RealizedPattern { realized_cap_30d_delta: MetricPattern4::new(client.clone(), _m(&acc, "realized_cap_30d_delta")), realized_loss: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss")), realized_loss_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_loss_rel_to_realized_cap")), - realized_price: MetricPattern1::new(client.clone(), _m(&acc, "realized_price")), + realized_price: ActivePricePattern::new(client.clone(), _m(&acc, "realized_price")), realized_price_extra: RealizedPriceExtraPattern::new(client.clone(), _m(&acc, "realized_price_ratio")), realized_profit: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit")), realized_profit_rel_to_realized_cap: BlockCountPattern::new(client.clone(), _m(&acc, "realized_profit_rel_to_realized_cap")), @@ -1218,7 +1218,7 @@ impl RealizedPattern { /// Pattern struct for repeated tree structure. pub struct Price111dSmaPattern { - pub price: MetricPattern4, + pub price: _0sdUsdPattern, pub ratio: MetricPattern4, pub ratio_1m_sma: MetricPattern4, pub ratio_1w_sma: MetricPattern4, @@ -1226,17 +1226,17 @@ pub struct Price111dSmaPattern { pub ratio_2y_sd: Ratio1ySdPattern, pub ratio_4y_sd: Ratio1ySdPattern, pub ratio_pct1: MetricPattern4, - pub ratio_pct1_usd: MetricPattern4, + pub ratio_pct1_usd: _0sdUsdPattern, pub ratio_pct2: MetricPattern4, - pub ratio_pct2_usd: MetricPattern4, + pub ratio_pct2_usd: _0sdUsdPattern, pub ratio_pct5: MetricPattern4, - pub ratio_pct5_usd: MetricPattern4, + pub ratio_pct5_usd: _0sdUsdPattern, pub ratio_pct95: MetricPattern4, - pub ratio_pct95_usd: MetricPattern4, + pub ratio_pct95_usd: _0sdUsdPattern, pub ratio_pct98: MetricPattern4, - pub ratio_pct98_usd: MetricPattern4, + pub ratio_pct98_usd: _0sdUsdPattern, pub ratio_pct99: MetricPattern4, - pub ratio_pct99_usd: MetricPattern4, + pub ratio_pct99_usd: _0sdUsdPattern, pub ratio_sd: Ratio1ySdPattern, } @@ -1244,7 +1244,7 @@ impl Price111dSmaPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - price: MetricPattern4::new(client.clone(), acc.clone()), + price: _0sdUsdPattern::new(client.clone(), acc.clone()), ratio: MetricPattern4::new(client.clone(), _m(&acc, "ratio")), ratio_1m_sma: MetricPattern4::new(client.clone(), _m(&acc, "ratio_1m_sma")), ratio_1w_sma: MetricPattern4::new(client.clone(), _m(&acc, "ratio_1w_sma")), @@ -1252,17 +1252,17 @@ impl Price111dSmaPattern { ratio_2y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "ratio_2y")), ratio_4y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "ratio_4y")), ratio_pct1: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct1")), - ratio_pct1_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct1_usd")), + ratio_pct1_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "ratio_pct1_usd")), ratio_pct2: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct2")), - ratio_pct2_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct2_usd")), + ratio_pct2_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "ratio_pct2_usd")), ratio_pct5: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct5")), - ratio_pct5_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct5_usd")), + ratio_pct5_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "ratio_pct5_usd")), ratio_pct95: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct95")), - ratio_pct95_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct95_usd")), + ratio_pct95_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "ratio_pct95_usd")), ratio_pct98: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct98")), - ratio_pct98_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct98_usd")), + ratio_pct98_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "ratio_pct98_usd")), ratio_pct99: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct99")), - ratio_pct99_usd: MetricPattern4::new(client.clone(), _m(&acc, "ratio_pct99_usd")), + ratio_pct99_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "ratio_pct99_usd")), ratio_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "ratio")), } } @@ -1277,17 +1277,17 @@ pub struct ActivePriceRatioPattern { pub ratio_2y_sd: Ratio1ySdPattern, pub ratio_4y_sd: Ratio1ySdPattern, pub ratio_pct1: MetricPattern4, - pub ratio_pct1_usd: MetricPattern4, + pub ratio_pct1_usd: _0sdUsdPattern, pub ratio_pct2: MetricPattern4, - pub ratio_pct2_usd: MetricPattern4, + pub ratio_pct2_usd: _0sdUsdPattern, pub ratio_pct5: MetricPattern4, - pub ratio_pct5_usd: MetricPattern4, + pub ratio_pct5_usd: _0sdUsdPattern, pub ratio_pct95: MetricPattern4, - pub ratio_pct95_usd: MetricPattern4, + pub ratio_pct95_usd: _0sdUsdPattern, pub ratio_pct98: MetricPattern4, - pub ratio_pct98_usd: MetricPattern4, + pub ratio_pct98_usd: _0sdUsdPattern, pub ratio_pct99: MetricPattern4, - pub ratio_pct99_usd: MetricPattern4, + pub ratio_pct99_usd: _0sdUsdPattern, pub ratio_sd: Ratio1ySdPattern, } @@ -1302,17 +1302,17 @@ impl ActivePriceRatioPattern { ratio_2y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "2y")), ratio_4y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "4y")), ratio_pct1: MetricPattern4::new(client.clone(), _m(&acc, "pct1")), - ratio_pct1_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct1_usd")), + ratio_pct1_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct1_usd")), ratio_pct2: MetricPattern4::new(client.clone(), _m(&acc, "pct2")), - ratio_pct2_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct2_usd")), + ratio_pct2_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct2_usd")), ratio_pct5: MetricPattern4::new(client.clone(), _m(&acc, "pct5")), - ratio_pct5_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct5_usd")), + ratio_pct5_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct5_usd")), ratio_pct95: MetricPattern4::new(client.clone(), _m(&acc, "pct95")), - ratio_pct95_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct95_usd")), + ratio_pct95_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct95_usd")), ratio_pct98: MetricPattern4::new(client.clone(), _m(&acc, "pct98")), - ratio_pct98_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct98_usd")), + ratio_pct98_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct98_usd")), ratio_pct99: MetricPattern4::new(client.clone(), _m(&acc, "pct99")), - ratio_pct99_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct99_usd")), + ratio_pct99_usd: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct99_usd")), ratio_sd: Ratio1ySdPattern::new(client.clone(), acc.clone()), } } @@ -1320,50 +1320,50 @@ impl ActivePriceRatioPattern { /// Pattern struct for repeated tree structure. pub struct PercentilesPattern { - pub pct05: MetricPattern4, - pub pct10: MetricPattern4, - pub pct15: MetricPattern4, - pub pct20: MetricPattern4, - pub pct25: MetricPattern4, - pub pct30: MetricPattern4, - pub pct35: MetricPattern4, - pub pct40: MetricPattern4, - pub pct45: MetricPattern4, - pub pct50: MetricPattern4, - pub pct55: MetricPattern4, - pub pct60: MetricPattern4, - pub pct65: MetricPattern4, - pub pct70: MetricPattern4, - pub pct75: MetricPattern4, - pub pct80: MetricPattern4, - pub pct85: MetricPattern4, - pub pct90: MetricPattern4, - pub pct95: MetricPattern4, + pub pct05: _0sdUsdPattern, + pub pct10: _0sdUsdPattern, + pub pct15: _0sdUsdPattern, + pub pct20: _0sdUsdPattern, + pub pct25: _0sdUsdPattern, + pub pct30: _0sdUsdPattern, + pub pct35: _0sdUsdPattern, + pub pct40: _0sdUsdPattern, + pub pct45: _0sdUsdPattern, + pub pct50: _0sdUsdPattern, + pub pct55: _0sdUsdPattern, + pub pct60: _0sdUsdPattern, + pub pct65: _0sdUsdPattern, + pub pct70: _0sdUsdPattern, + pub pct75: _0sdUsdPattern, + pub pct80: _0sdUsdPattern, + pub pct85: _0sdUsdPattern, + pub pct90: _0sdUsdPattern, + pub pct95: _0sdUsdPattern, } impl PercentilesPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - pct05: MetricPattern4::new(client.clone(), _m(&acc, "pct05")), - pct10: MetricPattern4::new(client.clone(), _m(&acc, "pct10")), - pct15: MetricPattern4::new(client.clone(), _m(&acc, "pct15")), - pct20: MetricPattern4::new(client.clone(), _m(&acc, "pct20")), - pct25: MetricPattern4::new(client.clone(), _m(&acc, "pct25")), - pct30: MetricPattern4::new(client.clone(), _m(&acc, "pct30")), - pct35: MetricPattern4::new(client.clone(), _m(&acc, "pct35")), - pct40: MetricPattern4::new(client.clone(), _m(&acc, "pct40")), - pct45: MetricPattern4::new(client.clone(), _m(&acc, "pct45")), - pct50: MetricPattern4::new(client.clone(), _m(&acc, "pct50")), - pct55: MetricPattern4::new(client.clone(), _m(&acc, "pct55")), - pct60: MetricPattern4::new(client.clone(), _m(&acc, "pct60")), - pct65: MetricPattern4::new(client.clone(), _m(&acc, "pct65")), - pct70: MetricPattern4::new(client.clone(), _m(&acc, "pct70")), - pct75: MetricPattern4::new(client.clone(), _m(&acc, "pct75")), - pct80: MetricPattern4::new(client.clone(), _m(&acc, "pct80")), - pct85: MetricPattern4::new(client.clone(), _m(&acc, "pct85")), - pct90: MetricPattern4::new(client.clone(), _m(&acc, "pct90")), - pct95: MetricPattern4::new(client.clone(), _m(&acc, "pct95")), + pct05: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct05")), + pct10: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct10")), + pct15: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct15")), + pct20: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct20")), + pct25: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct25")), + pct30: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct30")), + pct35: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct35")), + pct40: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct40")), + pct45: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct45")), + pct50: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct50")), + pct55: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct55")), + pct60: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct60")), + pct65: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct65")), + pct70: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct70")), + pct75: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct75")), + pct80: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct80")), + pct85: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct85")), + pct90: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct90")), + pct95: _0sdUsdPattern::new(client.clone(), _m(&acc, "pct95")), } } } @@ -1458,44 +1458,6 @@ impl AaopoolPattern { } } -/// Pattern struct for repeated tree structure. -pub struct LookbackPattern { - pub _10y: MetricPattern4, - pub _1d: 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 LookbackPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - _10y: MetricPattern4::new(client.clone(), _m(&acc, "10y_ago")), - _1d: MetricPattern4::new(client.clone(), _m(&acc, "1d_ago")), - _1m: MetricPattern4::new(client.clone(), _m(&acc, "1m_ago")), - _1w: MetricPattern4::new(client.clone(), _m(&acc, "1w_ago")), - _1y: MetricPattern4::new(client.clone(), _m(&acc, "1y_ago")), - _2y: MetricPattern4::new(client.clone(), _m(&acc, "2y_ago")), - _3m: MetricPattern4::new(client.clone(), _m(&acc, "3m_ago")), - _3y: MetricPattern4::new(client.clone(), _m(&acc, "3y_ago")), - _4y: MetricPattern4::new(client.clone(), _m(&acc, "4y_ago")), - _5y: MetricPattern4::new(client.clone(), _m(&acc, "5y_ago")), - _6m: MetricPattern4::new(client.clone(), _m(&acc, "6m_ago")), - _6y: MetricPattern4::new(client.clone(), _m(&acc, "6y_ago")), - _8y: MetricPattern4::new(client.clone(), _m(&acc, "8y_ago")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct PeriodLumpSumStackPattern { pub _10y: _2015Pattern, @@ -1533,7 +1495,7 @@ impl PeriodLumpSumStackPattern { } /// Pattern struct for repeated tree structure. -pub struct ClassAveragePricePattern { +pub struct ClassDaysInLossPattern { pub _2015: MetricPattern4, pub _2016: MetricPattern4, pub _2017: MetricPattern4, @@ -1548,28 +1510,28 @@ pub struct ClassAveragePricePattern { pub _2026: MetricPattern4, } -impl ClassAveragePricePattern { +impl ClassDaysInLossPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - _2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_average_price")), - _2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_average_price")), - _2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_average_price")), - _2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_average_price")), - _2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_average_price")), - _2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_average_price")), - _2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_average_price")), - _2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_average_price")), - _2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_average_price")), - _2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_average_price")), - _2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_average_price")), - _2026: MetricPattern4::new(client.clone(), _m(&acc, "2026_average_price")), + _2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_max_return")), + _2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_max_return")), + _2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_max_return")), + _2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_max_return")), + _2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_max_return")), + _2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_max_return")), + _2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_max_return")), + _2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_max_return")), + _2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_max_return")), + _2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_max_return")), + _2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_max_return")), + _2026: MetricPattern4::new(client.clone(), _m(&acc, "2026_max_return")), } } } /// Pattern struct for repeated tree structure. -pub struct PeriodAveragePricePattern { +pub struct PeriodDaysInLossPattern { pub _10y: MetricPattern4, pub _1m: MetricPattern4, pub _1w: MetricPattern4, @@ -1584,7 +1546,7 @@ pub struct PeriodAveragePricePattern { pub _8y: MetricPattern4, } -impl PeriodAveragePricePattern { +impl PeriodDaysInLossPattern { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { @@ -1915,25 +1877,51 @@ impl PhaseDailyCentsPattern { } /// Pattern struct for repeated tree structure. -pub struct _0satsPattern2 { +pub struct UnrealizedPattern { + pub neg_unrealized_loss: MetricPattern1, + pub net_unrealized_pnl: MetricPattern1, + pub supply_in_loss: ActiveSupplyPattern, + pub supply_in_profit: ActiveSupplyPattern, + pub total_unrealized_pnl: MetricPattern1, + pub unrealized_loss: MetricPattern1, + pub unrealized_profit: MetricPattern1, +} + +impl UnrealizedPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + neg_unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")), + net_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl")), + supply_in_loss: ActiveSupplyPattern::new(client.clone(), _m(&acc, "supply_in_loss")), + supply_in_profit: ActiveSupplyPattern::new(client.clone(), _m(&acc, "supply_in_profit")), + total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_unrealized_pnl")), + unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss")), + unrealized_profit: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct _10yPattern { pub activity: ActivityPattern2, pub cost_basis: CostBasisPattern, pub outputs: OutputsPattern, - pub realized: RealizedPattern, - pub relative: RelativePattern4, + pub realized: RealizedPattern4, + pub relative: RelativePattern, pub supply: SupplyPattern2, pub unrealized: UnrealizedPattern, } -impl _0satsPattern2 { +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: RealizedPattern::new(client.clone(), acc.clone()), - relative: RelativePattern4::new(client.clone(), _m(&acc, "supply_in")), + 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()), } @@ -1966,6 +1954,32 @@ impl _100btcPattern { } } +/// 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 PeriodCagrPattern { pub _10y: MetricPattern4, @@ -2018,58 +2032,6 @@ 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, - pub net_unrealized_pnl: MetricPattern1, - pub supply_in_loss: ActiveSupplyPattern, - pub supply_in_profit: ActiveSupplyPattern, - pub total_unrealized_pnl: MetricPattern1, - pub unrealized_loss: MetricPattern1, - pub unrealized_profit: MetricPattern1, -} - -impl UnrealizedPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - neg_unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")), - net_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl")), - supply_in_loss: ActiveSupplyPattern::new(client.clone(), _m(&acc, "supply_in_loss")), - supply_in_profit: ActiveSupplyPattern::new(client.clone(), _m(&acc, "supply_in_profit")), - total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_unrealized_pnl")), - unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss")), - unrealized_profit: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct ActivityPattern2 { pub coinblocks_destroyed: BlockCountPattern, @@ -2114,8 +2076,8 @@ impl SplitPattern2 { /// Pattern struct for repeated tree structure. pub struct CostBasisPattern2 { - pub max: MetricPattern1, - pub min: MetricPattern1, + pub max: ActivePricePattern, + pub min: ActivePricePattern, pub percentiles: PercentilesPattern, } @@ -2123,8 +2085,8 @@ impl CostBasisPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), - min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), + max: ActivePricePattern::new(client.clone(), _m(&acc, "max_cost_basis")), + min: ActivePricePattern::new(client.clone(), _m(&acc, "min_cost_basis")), percentiles: PercentilesPattern::new(client.clone(), _m(&acc, "cost_basis")), } } @@ -2148,6 +2110,24 @@ impl ActiveSupplyPattern { } } +/// 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 SegwitAdoptionPattern { pub base: MetricPattern11, @@ -2202,24 +2182,6 @@ 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,54 +2200,6 @@ impl _2015Pattern { } } -/// Pattern struct for repeated tree structure. -pub struct RelativePattern4 { - pub supply_in_loss_rel_to_own_supply: MetricPattern1, - pub supply_in_profit_rel_to_own_supply: MetricPattern1, -} - -impl RelativePattern4 { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "loss_rel_to_own_supply")), - supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "profit_rel_to_own_supply")), - } - } -} - -/// 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, - pub min: MetricPattern1, -} - -impl CostBasisPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")), - min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")), - } - } -} - /// Pattern struct for repeated tree structure. pub struct _1dReturns1mSdPattern { pub sd: MetricPattern4, @@ -2303,17 +2217,81 @@ impl _1dReturns1mSdPattern { } /// Pattern struct for repeated tree structure. -pub struct BitcoinPattern2 { - pub cumulative: MetricPattern2, - pub sum: MetricPattern1, +pub struct SupplyPattern2 { + pub halved: ActiveSupplyPattern, + pub total: ActiveSupplyPattern, } -impl BitcoinPattern2 { +impl SupplyPattern2 { /// Create a new pattern node with accumulated metric name. pub fn new(client: Arc, acc: String) -> Self { Self { - cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), - sum: MetricPattern1::new(client.clone(), acc.clone()), + 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, + pub supply_in_profit_rel_to_own_supply: MetricPattern1, +} + +impl RelativePattern4 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "loss_rel_to_own_supply")), + supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "profit_rel_to_own_supply")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct CostBasisPattern { + pub max: ActivePricePattern, + pub min: ActivePricePattern, +} + +impl CostBasisPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + max: ActivePricePattern::new(client.clone(), _m(&acc, "max_cost_basis")), + min: ActivePricePattern::new(client.clone(), _m(&acc, "min_cost_basis")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct _0sdUsdPattern { + pub dollars: MetricPattern4, + pub sats: MetricPattern4, +} + +impl _0sdUsdPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + dollars: MetricPattern4::new(client.clone(), acc.clone()), + sats: MetricPattern4::new(client.clone(), _m(&acc, "sats")), + } + } +} + +/// Pattern struct for repeated tree structure. +pub struct ActivePricePattern { + pub dollars: MetricPattern1, + pub sats: MetricPattern1, +} + +impl ActivePricePattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + dollars: MetricPattern1::new(client.clone(), acc.clone()), + sats: MetricPattern1::new(client.clone(), _m(&acc, "sats")), } } } @@ -2334,6 +2312,22 @@ impl BlockCountPattern { } } +/// Pattern struct for repeated tree structure. +pub struct BitcoinPattern2 { + pub cumulative: MetricPattern2, + pub sum: MetricPattern1, +} + +impl BitcoinPattern2 { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")), + sum: MetricPattern1::new(client.clone(), acc.clone()), + } + } +} + /// Pattern struct for repeated tree structure. pub struct SatsPattern { pub ohlc: MetricPattern1, @@ -2350,20 +2344,6 @@ impl SatsPattern { } } -/// Pattern struct for repeated tree structure. -pub struct RealizedPriceExtraPattern { - pub ratio: MetricPattern4, -} - -impl RealizedPriceExtraPattern { - /// Create a new pattern node with accumulated metric name. - pub fn new(client: Arc, acc: String) -> Self { - Self { - ratio: MetricPattern4::new(client.clone(), acc.clone()), - } - } -} - /// Pattern struct for repeated tree structure. pub struct OutputsPattern { pub utxo_count: MetricPattern1, @@ -2378,6 +2358,20 @@ impl OutputsPattern { } } +/// Pattern struct for repeated tree structure. +pub struct RealizedPriceExtraPattern { + pub ratio: MetricPattern4, +} + +impl RealizedPriceExtraPattern { + /// Create a new pattern node with accumulated metric name. + pub fn new(client: Arc, acc: String) -> Self { + Self { + ratio: MetricPattern4::new(client.clone(), acc.clone()), + } + } +} + // Metrics tree /// Metrics tree node. @@ -2789,26 +2783,26 @@ impl MetricsTree_Cointime_Cap { /// Metrics tree node. pub struct MetricsTree_Cointime_Pricing { - pub active_price: MetricPattern1, + pub active_price: ActivePricePattern, pub active_price_ratio: ActivePriceRatioPattern, - pub cointime_price: MetricPattern1, + pub cointime_price: ActivePricePattern, pub cointime_price_ratio: ActivePriceRatioPattern, - pub true_market_mean: MetricPattern1, + pub true_market_mean: ActivePricePattern, pub true_market_mean_ratio: ActivePriceRatioPattern, - pub vaulted_price: MetricPattern1, + pub vaulted_price: ActivePricePattern, pub vaulted_price_ratio: ActivePriceRatioPattern, } impl MetricsTree_Cointime_Pricing { pub fn new(client: Arc, base_path: String) -> Self { Self { - active_price: MetricPattern1::new(client.clone(), "active_price".to_string()), + active_price: ActivePricePattern::new(client.clone(), "active_price".to_string()), active_price_ratio: ActivePriceRatioPattern::new(client.clone(), "active_price_ratio".to_string()), - cointime_price: MetricPattern1::new(client.clone(), "cointime_price".to_string()), + cointime_price: ActivePricePattern::new(client.clone(), "cointime_price".to_string()), cointime_price_ratio: ActivePriceRatioPattern::new(client.clone(), "cointime_price_ratio".to_string()), - true_market_mean: MetricPattern1::new(client.clone(), "true_market_mean".to_string()), + true_market_mean: ActivePricePattern::new(client.clone(), "true_market_mean".to_string()), true_market_mean_ratio: ActivePriceRatioPattern::new(client.clone(), "true_market_mean_ratio".to_string()), - vaulted_price: MetricPattern1::new(client.clone(), "vaulted_price".to_string()), + vaulted_price: ActivePricePattern::new(client.clone(), "vaulted_price".to_string()), vaulted_price_ratio: ActivePriceRatioPattern::new(client.clone(), "vaulted_price_ratio".to_string()), } } @@ -3228,16 +3222,16 @@ impl MetricsTree_Distribution_UtxoCohorts_All { /// Metrics tree node. pub struct MetricsTree_Distribution_UtxoCohorts_All_CostBasis { - pub max: MetricPattern1, - pub min: MetricPattern1, + pub max: ActivePricePattern, + pub min: ActivePricePattern, pub percentiles: PercentilesPattern, } impl MetricsTree_Distribution_UtxoCohorts_All_CostBasis { pub fn new(client: Arc, base_path: String) -> Self { Self { - max: MetricPattern1::new(client.clone(), "max_cost_basis".to_string()), - min: MetricPattern1::new(client.clone(), "min_cost_basis".to_string()), + max: ActivePricePattern::new(client.clone(), "max_cost_basis".to_string()), + min: ActivePricePattern::new(client.clone(), "min_cost_basis".to_string()), percentiles: PercentilesPattern::new(client.clone(), "cost_basis".to_string()), } } @@ -4157,7 +4151,7 @@ pub struct MetricsTree_Market { pub ath: MetricsTree_Market_Ath, pub dca: MetricsTree_Market_Dca, pub indicators: MetricsTree_Market_Indicators, - pub lookback: LookbackPattern, + pub lookback: MetricsTree_Market_Lookback, pub moving_average: MetricsTree_Market_MovingAverage, pub range: MetricsTree_Market_Range, pub returns: MetricsTree_Market_Returns, @@ -4170,7 +4164,7 @@ impl MetricsTree_Market { ath: MetricsTree_Market_Ath::new(client.clone(), format!("{base_path}_ath")), dca: MetricsTree_Market_Dca::new(client.clone(), format!("{base_path}_dca")), indicators: MetricsTree_Market_Indicators::new(client.clone(), format!("{base_path}_indicators")), - lookback: LookbackPattern::new(client.clone(), "price".to_string()), + lookback: MetricsTree_Market_Lookback::new(client.clone(), format!("{base_path}_lookback")), moving_average: MetricsTree_Market_MovingAverage::new(client.clone(), format!("{base_path}_moving_average")), range: MetricsTree_Market_Range::new(client.clone(), format!("{base_path}_range")), returns: MetricsTree_Market_Returns::new(client.clone(), format!("{base_path}_returns")), @@ -4184,7 +4178,7 @@ pub struct MetricsTree_Market_Ath { pub days_since_price_ath: MetricPattern4, pub max_days_between_price_aths: MetricPattern4, pub max_years_between_price_aths: MetricPattern4, - pub price_ath: MetricPattern1, + pub price_ath: ActivePricePattern, pub price_drawdown: MetricPattern3, pub years_since_price_ath: MetricPattern4, } @@ -4195,7 +4189,7 @@ impl MetricsTree_Market_Ath { days_since_price_ath: MetricPattern4::new(client.clone(), "days_since_price_ath".to_string()), max_days_between_price_aths: MetricPattern4::new(client.clone(), "max_days_between_price_aths".to_string()), max_years_between_price_aths: MetricPattern4::new(client.clone(), "max_years_between_price_aths".to_string()), - price_ath: MetricPattern1::new(client.clone(), "price_ath".to_string()), + price_ath: ActivePricePattern::new(client.clone(), "price_ath".to_string()), price_drawdown: MetricPattern3::new(client.clone(), "price_drawdown".to_string()), years_since_price_ath: MetricPattern4::new(client.clone(), "years_since_price_ath".to_string()), } @@ -4204,57 +4198,92 @@ impl MetricsTree_Market_Ath { /// Metrics tree node. pub struct MetricsTree_Market_Dca { - pub class_average_price: ClassAveragePricePattern, + pub class_average_price: MetricsTree_Market_Dca_ClassAveragePrice, 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_max_return: ClassDaysInLossPattern, pub class_returns: MetricsTree_Market_Dca_ClassReturns, pub class_stack: MetricsTree_Market_Dca_ClassStack, - pub period_average_price: PeriodAveragePricePattern, + pub period_average_price: MetricsTree_Market_Dca_PeriodAveragePrice, 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_days_in_loss: PeriodDaysInLossPattern, + pub period_days_in_profit: PeriodDaysInLossPattern, + pub period_lump_sum_days_in_loss: PeriodDaysInLossPattern, + pub period_lump_sum_days_in_profit: PeriodDaysInLossPattern, + pub period_lump_sum_max_drawdown: PeriodDaysInLossPattern, + pub period_lump_sum_max_return: PeriodDaysInLossPattern, + pub period_lump_sum_returns: PeriodDaysInLossPattern, pub period_lump_sum_stack: PeriodLumpSumStackPattern, - pub period_max_drawdown: PeriodAveragePricePattern, - pub period_max_return: PeriodAveragePricePattern, - pub period_returns: PeriodAveragePricePattern, + pub period_max_drawdown: PeriodDaysInLossPattern, + pub period_max_return: PeriodDaysInLossPattern, + pub period_returns: PeriodDaysInLossPattern, pub period_stack: PeriodLumpSumStackPattern, } 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_average_price: MetricsTree_Market_Dca_ClassAveragePrice::new(client.clone(), format!("{base_path}_class_average_price")), 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_max_return: ClassDaysInLossPattern::new(client.clone(), "dca_class".to_string()), 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_average_price: MetricsTree_Market_Dca_PeriodAveragePrice::new(client.clone(), format!("{base_path}_period_average_price")), 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_days_in_loss: PeriodDaysInLossPattern::new(client.clone(), "dca_days_in_loss".to_string()), + period_days_in_profit: PeriodDaysInLossPattern::new(client.clone(), "dca_days_in_profit".to_string()), + period_lump_sum_days_in_loss: PeriodDaysInLossPattern::new(client.clone(), "lump_sum_days_in_loss".to_string()), + period_lump_sum_days_in_profit: PeriodDaysInLossPattern::new(client.clone(), "lump_sum_days_in_profit".to_string()), + period_lump_sum_max_drawdown: PeriodDaysInLossPattern::new(client.clone(), "lump_sum_max_drawdown".to_string()), + period_lump_sum_max_return: PeriodDaysInLossPattern::new(client.clone(), "lump_sum_max_return".to_string()), + period_lump_sum_returns: PeriodDaysInLossPattern::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_max_drawdown: PeriodDaysInLossPattern::new(client.clone(), "dca_max_drawdown".to_string()), + period_max_return: PeriodDaysInLossPattern::new(client.clone(), "dca_max_return".to_string()), + period_returns: PeriodDaysInLossPattern::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_ClassAveragePrice { + pub _2015: _0sdUsdPattern, + pub _2016: _0sdUsdPattern, + pub _2017: _0sdUsdPattern, + pub _2018: _0sdUsdPattern, + pub _2019: _0sdUsdPattern, + pub _2020: _0sdUsdPattern, + pub _2021: _0sdUsdPattern, + pub _2022: _0sdUsdPattern, + pub _2023: _0sdUsdPattern, + pub _2024: _0sdUsdPattern, + pub _2025: _0sdUsdPattern, + pub _2026: _0sdUsdPattern, +} + +impl MetricsTree_Market_Dca_ClassAveragePrice { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + _2015: _0sdUsdPattern::new(client.clone(), "dca_class_2015_average_price".to_string()), + _2016: _0sdUsdPattern::new(client.clone(), "dca_class_2016_average_price".to_string()), + _2017: _0sdUsdPattern::new(client.clone(), "dca_class_2017_average_price".to_string()), + _2018: _0sdUsdPattern::new(client.clone(), "dca_class_2018_average_price".to_string()), + _2019: _0sdUsdPattern::new(client.clone(), "dca_class_2019_average_price".to_string()), + _2020: _0sdUsdPattern::new(client.clone(), "dca_class_2020_average_price".to_string()), + _2021: _0sdUsdPattern::new(client.clone(), "dca_class_2021_average_price".to_string()), + _2022: _0sdUsdPattern::new(client.clone(), "dca_class_2022_average_price".to_string()), + _2023: _0sdUsdPattern::new(client.clone(), "dca_class_2023_average_price".to_string()), + _2024: _0sdUsdPattern::new(client.clone(), "dca_class_2024_average_price".to_string()), + _2025: _0sdUsdPattern::new(client.clone(), "dca_class_2025_average_price".to_string()), + _2026: _0sdUsdPattern::new(client.clone(), "dca_class_2026_average_price".to_string()), + } + } +} + /// Metrics tree node. pub struct MetricsTree_Market_Dca_ClassDaysInLoss { pub _2015: MetricPattern4, @@ -4360,41 +4389,6 @@ impl MetricsTree_Market_Dca_ClassMaxDrawdown { } } -/// 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, @@ -4465,6 +4459,41 @@ impl MetricsTree_Market_Dca_ClassStack { } } +/// Metrics tree node. +pub struct MetricsTree_Market_Dca_PeriodAveragePrice { + pub _10y: _0sdUsdPattern, + pub _1m: _0sdUsdPattern, + pub _1w: _0sdUsdPattern, + pub _1y: _0sdUsdPattern, + pub _2y: _0sdUsdPattern, + pub _3m: _0sdUsdPattern, + pub _3y: _0sdUsdPattern, + pub _4y: _0sdUsdPattern, + pub _5y: _0sdUsdPattern, + pub _6m: _0sdUsdPattern, + pub _6y: _0sdUsdPattern, + pub _8y: _0sdUsdPattern, +} + +impl MetricsTree_Market_Dca_PeriodAveragePrice { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + _10y: _0sdUsdPattern::new(client.clone(), "10y_dca_average_price".to_string()), + _1m: _0sdUsdPattern::new(client.clone(), "1m_dca_average_price".to_string()), + _1w: _0sdUsdPattern::new(client.clone(), "1w_dca_average_price".to_string()), + _1y: _0sdUsdPattern::new(client.clone(), "1y_dca_average_price".to_string()), + _2y: _0sdUsdPattern::new(client.clone(), "2y_dca_average_price".to_string()), + _3m: _0sdUsdPattern::new(client.clone(), "3m_dca_average_price".to_string()), + _3y: _0sdUsdPattern::new(client.clone(), "3y_dca_average_price".to_string()), + _4y: _0sdUsdPattern::new(client.clone(), "4y_dca_average_price".to_string()), + _5y: _0sdUsdPattern::new(client.clone(), "5y_dca_average_price".to_string()), + _6m: _0sdUsdPattern::new(client.clone(), "6m_dca_average_price".to_string()), + _6y: _0sdUsdPattern::new(client.clone(), "6y_dca_average_price".to_string()), + _8y: _0sdUsdPattern::new(client.clone(), "8y_dca_average_price".to_string()), + } + } +} + /// Metrics tree node. pub struct MetricsTree_Market_Indicators { pub gini: MetricPattern6, @@ -4514,6 +4543,43 @@ impl MetricsTree_Market_Indicators { } } +/// Metrics tree node. +pub struct MetricsTree_Market_Lookback { + pub _10y: _0sdUsdPattern, + pub _1d: _0sdUsdPattern, + pub _1m: _0sdUsdPattern, + pub _1w: _0sdUsdPattern, + pub _1y: _0sdUsdPattern, + pub _2y: _0sdUsdPattern, + pub _3m: _0sdUsdPattern, + pub _3y: _0sdUsdPattern, + pub _4y: _0sdUsdPattern, + pub _5y: _0sdUsdPattern, + pub _6m: _0sdUsdPattern, + pub _6y: _0sdUsdPattern, + pub _8y: _0sdUsdPattern, +} + +impl MetricsTree_Market_Lookback { + pub fn new(client: Arc, base_path: String) -> Self { + Self { + _10y: _0sdUsdPattern::new(client.clone(), "price_10y_ago".to_string()), + _1d: _0sdUsdPattern::new(client.clone(), "price_1d_ago".to_string()), + _1m: _0sdUsdPattern::new(client.clone(), "price_1m_ago".to_string()), + _1w: _0sdUsdPattern::new(client.clone(), "price_1w_ago".to_string()), + _1y: _0sdUsdPattern::new(client.clone(), "price_1y_ago".to_string()), + _2y: _0sdUsdPattern::new(client.clone(), "price_2y_ago".to_string()), + _3m: _0sdUsdPattern::new(client.clone(), "price_3m_ago".to_string()), + _3y: _0sdUsdPattern::new(client.clone(), "price_3y_ago".to_string()), + _4y: _0sdUsdPattern::new(client.clone(), "price_4y_ago".to_string()), + _5y: _0sdUsdPattern::new(client.clone(), "price_5y_ago".to_string()), + _6m: _0sdUsdPattern::new(client.clone(), "price_6m_ago".to_string()), + _6y: _0sdUsdPattern::new(client.clone(), "price_6y_ago".to_string()), + _8y: _0sdUsdPattern::new(client.clone(), "price_8y_ago".to_string()), + } + } +} + /// Metrics tree node. pub struct MetricsTree_Market_MovingAverage { pub price_111d_sma: Price111dSmaPattern, @@ -4530,8 +4596,8 @@ pub struct MetricsTree_Market_MovingAverage { pub price_1y_sma: Price111dSmaPattern, pub price_200d_ema: Price111dSmaPattern, pub price_200d_sma: Price111dSmaPattern, - pub price_200d_sma_x0_8: MetricPattern4, - pub price_200d_sma_x2_4: MetricPattern4, + pub price_200d_sma_x0_8: _0sdUsdPattern, + pub price_200d_sma_x2_4: _0sdUsdPattern, pub price_200w_ema: Price111dSmaPattern, pub price_200w_sma: Price111dSmaPattern, pub price_21d_ema: Price111dSmaPattern, @@ -4542,7 +4608,7 @@ pub struct MetricsTree_Market_MovingAverage { pub price_34d_ema: Price111dSmaPattern, pub price_34d_sma: Price111dSmaPattern, pub price_350d_sma: Price111dSmaPattern, - pub price_350d_sma_x2: MetricPattern4, + pub price_350d_sma_x2: _0sdUsdPattern, pub price_4y_ema: Price111dSmaPattern, pub price_4y_sma: Price111dSmaPattern, pub price_55d_ema: Price111dSmaPattern, @@ -4570,8 +4636,8 @@ impl MetricsTree_Market_MovingAverage { price_1y_sma: Price111dSmaPattern::new(client.clone(), "price_1y_sma".to_string()), price_200d_ema: Price111dSmaPattern::new(client.clone(), "price_200d_ema".to_string()), price_200d_sma: Price111dSmaPattern::new(client.clone(), "price_200d_sma".to_string()), - price_200d_sma_x0_8: MetricPattern4::new(client.clone(), "price_200d_sma_x0_8".to_string()), - price_200d_sma_x2_4: MetricPattern4::new(client.clone(), "price_200d_sma_x2_4".to_string()), + price_200d_sma_x0_8: _0sdUsdPattern::new(client.clone(), "price_200d_sma_x0_8".to_string()), + price_200d_sma_x2_4: _0sdUsdPattern::new(client.clone(), "price_200d_sma_x2_4".to_string()), price_200w_ema: Price111dSmaPattern::new(client.clone(), "price_200w_ema".to_string()), price_200w_sma: Price111dSmaPattern::new(client.clone(), "price_200w_sma".to_string()), price_21d_ema: Price111dSmaPattern::new(client.clone(), "price_21d_ema".to_string()), @@ -4582,7 +4648,7 @@ impl MetricsTree_Market_MovingAverage { price_34d_ema: Price111dSmaPattern::new(client.clone(), "price_34d_ema".to_string()), price_34d_sma: Price111dSmaPattern::new(client.clone(), "price_34d_sma".to_string()), price_350d_sma: Price111dSmaPattern::new(client.clone(), "price_350d_sma".to_string()), - price_350d_sma_x2: MetricPattern4::new(client.clone(), "price_350d_sma_x2".to_string()), + price_350d_sma_x2: _0sdUsdPattern::new(client.clone(), "price_350d_sma_x2".to_string()), price_4y_ema: Price111dSmaPattern::new(client.clone(), "price_4y_ema".to_string()), price_4y_sma: Price111dSmaPattern::new(client.clone(), "price_4y_sma".to_string()), price_55d_ema: Price111dSmaPattern::new(client.clone(), "price_55d_ema".to_string()), @@ -4597,15 +4663,15 @@ impl MetricsTree_Market_MovingAverage { /// Metrics tree node. pub struct MetricsTree_Market_Range { - pub price_1m_max: MetricPattern4, - pub price_1m_min: MetricPattern4, - pub price_1w_max: MetricPattern4, - pub price_1w_min: MetricPattern4, - pub price_1y_max: MetricPattern4, - pub price_1y_min: MetricPattern4, + pub price_1m_max: _0sdUsdPattern, + pub price_1m_min: _0sdUsdPattern, + pub price_1w_max: _0sdUsdPattern, + pub price_1w_min: _0sdUsdPattern, + pub price_1y_max: _0sdUsdPattern, + pub price_1y_min: _0sdUsdPattern, pub price_2w_choppiness_index: MetricPattern4, - pub price_2w_max: MetricPattern4, - pub price_2w_min: MetricPattern4, + pub price_2w_max: _0sdUsdPattern, + pub price_2w_min: _0sdUsdPattern, pub price_true_range: MetricPattern6, pub price_true_range_2w_sum: MetricPattern6, } @@ -4613,15 +4679,15 @@ pub struct MetricsTree_Market_Range { impl MetricsTree_Market_Range { pub fn new(client: Arc, base_path: String) -> Self { Self { - price_1m_max: MetricPattern4::new(client.clone(), "price_1m_max".to_string()), - price_1m_min: MetricPattern4::new(client.clone(), "price_1m_min".to_string()), - price_1w_max: MetricPattern4::new(client.clone(), "price_1w_max".to_string()), - price_1w_min: MetricPattern4::new(client.clone(), "price_1w_min".to_string()), - price_1y_max: MetricPattern4::new(client.clone(), "price_1y_max".to_string()), - price_1y_min: MetricPattern4::new(client.clone(), "price_1y_min".to_string()), + price_1m_max: _0sdUsdPattern::new(client.clone(), "price_1m_max".to_string()), + price_1m_min: _0sdUsdPattern::new(client.clone(), "price_1m_min".to_string()), + price_1w_max: _0sdUsdPattern::new(client.clone(), "price_1w_max".to_string()), + price_1w_min: _0sdUsdPattern::new(client.clone(), "price_1w_min".to_string()), + price_1y_max: _0sdUsdPattern::new(client.clone(), "price_1y_max".to_string()), + price_1y_min: _0sdUsdPattern::new(client.clone(), "price_1y_min".to_string()), price_2w_choppiness_index: MetricPattern4::new(client.clone(), "price_2w_choppiness_index".to_string()), - price_2w_max: MetricPattern4::new(client.clone(), "price_2w_max".to_string()), - price_2w_min: MetricPattern4::new(client.clone(), "price_2w_min".to_string()), + price_2w_max: _0sdUsdPattern::new(client.clone(), "price_2w_max".to_string()), + price_2w_min: _0sdUsdPattern::new(client.clone(), "price_2w_min".to_string()), price_true_range: MetricPattern6::new(client.clone(), "price_true_range".to_string()), price_true_range_2w_sum: MetricPattern6::new(client.clone(), "price_true_range_2w_sum".to_string()), } @@ -5582,7 +5648,7 @@ pub struct BrkClient { impl BrkClient { /// Client version. - pub const VERSION: &'static str = "v0.1.0-beta.0"; + pub const VERSION: &'static str = "v0.1.0-beta.1"; /// Create a new client with the given base URL. pub fn new(base_url: impl Into) -> Self { diff --git a/crates/brk_computer/src/cointime/pricing/import.rs b/crates/brk_computer/src/cointime/pricing/import.rs index adf645ad1..c6957f3e1 100644 --- a/crates/brk_computer/src/cointime/pricing/import.rs +++ b/crates/brk_computer/src/cointime/pricing/import.rs @@ -5,7 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedFromHeightLast, ComputedFromDateRatio}, + internal::{ComputedFromDateRatio, PriceFromHeight}, price, }; @@ -16,41 +16,61 @@ impl Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, ) -> Result { - macro_rules! computed_h { - ($name:expr) => { - ComputedFromHeightLast::forced_import(db, $name, version, indexes)? - }; - } + let vaulted_price = PriceFromHeight::forced_import(db, "vaulted_price", version, indexes)?; + let vaulted_price_ratio = ComputedFromDateRatio::forced_import( + db, + "vaulted_price", + Some(&vaulted_price), + version, + indexes, + true, + price, + )?; - // Extract price vecs before struct literal so they can be used as sources for ratios - let vaulted_price = computed_h!("vaulted_price"); - let active_price = computed_h!("active_price"); - let true_market_mean = computed_h!("true_market_mean"); - let cointime_price = computed_h!("cointime_price"); + let active_price = PriceFromHeight::forced_import(db, "active_price", version, indexes)?; + let active_price_ratio = ComputedFromDateRatio::forced_import( + db, + "active_price", + Some(&active_price), + version, + indexes, + true, + price, + )?; - macro_rules! ratio_di { - ($name:expr, $source:expr) => { - ComputedFromDateRatio::forced_import( - db, - $name, - Some($source), - version, - indexes, - true, - price, - )? - }; - } + let true_market_mean = + PriceFromHeight::forced_import(db, "true_market_mean", version, indexes)?; + let true_market_mean_ratio = ComputedFromDateRatio::forced_import( + db, + "true_market_mean", + Some(&true_market_mean), + version, + indexes, + true, + price, + )?; + + let cointime_price = + PriceFromHeight::forced_import(db, "cointime_price", version, indexes)?; + let cointime_price_ratio = ComputedFromDateRatio::forced_import( + db, + "cointime_price", + Some(&cointime_price), + version, + indexes, + true, + price, + )?; Ok(Self { - vaulted_price_ratio: ratio_di!("vaulted_price", &vaulted_price), vaulted_price, - active_price_ratio: ratio_di!("active_price", &active_price), + vaulted_price_ratio, active_price, - true_market_mean_ratio: ratio_di!("true_market_mean", &true_market_mean), + active_price_ratio, true_market_mean, - cointime_price_ratio: ratio_di!("cointime_price", &cointime_price), + true_market_mean_ratio, cointime_price, + cointime_price_ratio, }) } } diff --git a/crates/brk_computer/src/cointime/pricing/vecs.rs b/crates/brk_computer/src/cointime/pricing/vecs.rs index 145cd0de6..4756849bc 100644 --- a/crates/brk_computer/src/cointime/pricing/vecs.rs +++ b/crates/brk_computer/src/cointime/pricing/vecs.rs @@ -1,16 +1,15 @@ use brk_traversable::Traversable; -use brk_types::Dollars; -use crate::internal::{ComputedFromHeightLast, ComputedFromDateRatio}; +use crate::internal::{ComputedFromDateRatio, PriceFromHeight}; #[derive(Clone, Traversable)] pub struct Vecs { - pub vaulted_price: ComputedFromHeightLast, + pub vaulted_price: PriceFromHeight, pub vaulted_price_ratio: ComputedFromDateRatio, - pub active_price: ComputedFromHeightLast, + pub active_price: PriceFromHeight, pub active_price_ratio: ComputedFromDateRatio, - pub true_market_mean: ComputedFromHeightLast, + pub true_market_mean: PriceFromHeight, pub true_market_mean_ratio: ComputedFromDateRatio, - pub cointime_price: ComputedFromHeightLast, + pub cointime_price: PriceFromHeight, pub cointime_price_ratio: ComputedFromDateRatio, } diff --git a/crates/brk_computer/src/distribution/metrics/cost_basis.rs b/crates/brk_computer/src/distribution/metrics/cost_basis.rs index 25fe0bca6..73c53f47b 100644 --- a/crates/brk_computer/src/distribution/metrics/cost_basis.rs +++ b/crates/brk_computer/src/distribution/metrics/cost_basis.rs @@ -8,7 +8,7 @@ use crate::{ ComputeIndexes, distribution::state::CohortState, indexes, - internal::{ComputedFromHeightLast, CostBasisPercentiles}, + internal::{CostBasisPercentiles, PriceFromHeight}, }; use super::ImportConfig; @@ -17,10 +17,10 @@ use super::ImportConfig; #[derive(Clone, Traversable)] pub struct CostBasisMetrics { /// Minimum cost basis for any UTXO at this height - pub min: ComputedFromHeightLast, + pub min: PriceFromHeight, /// Maximum cost basis for any UTXO at this height - pub max: ComputedFromHeightLast, + pub max: PriceFromHeight, /// Cost basis distribution percentiles (median, quartiles, etc.) pub percentiles: Option, @@ -32,13 +32,13 @@ impl CostBasisMetrics { let extended = cfg.extended(); Ok(Self { - min: ComputedFromHeightLast::forced_import( + min: PriceFromHeight::forced_import( cfg.db, &cfg.name("min_cost_basis"), cfg.version, cfg.indexes, )?, - max: ComputedFromHeightLast::forced_import( + max: PriceFromHeight::forced_import( cfg.db, &cfg.name("max_cost_basis"), cfg.version, diff --git a/crates/brk_computer/src/distribution/metrics/realized.rs b/crates/brk_computer/src/distribution/metrics/realized.rs index cae98efb2..1f0ffde9f 100644 --- a/crates/brk_computer/src/distribution/metrics/realized.rs +++ b/crates/brk_computer/src/distribution/metrics/realized.rs @@ -14,7 +14,8 @@ use crate::{ internal::{ ComputedFromHeightLast, ComputedFromHeightSum, ComputedFromHeightSumCum, ComputedFromDateLast, ComputedFromDateRatio, DollarsMinus, LazyBinaryFromHeightSum, LazyBinaryFromHeightSumCum, - LazyFromHeightSum, LazyFromHeightSumCum, LazyFromDateLast, PercentageDollarsF32, StoredF32Identity, + LazyFromHeightSum, LazyFromHeightSumCum, LazyFromDateLast, PercentageDollarsF32, + PriceFromHeight, StoredF32Identity, }, price, }; @@ -26,7 +27,7 @@ use super::ImportConfig; pub struct RealizedMetrics { // === Realized Cap === pub realized_cap: ComputedFromHeightLast, - pub realized_price: ComputedFromHeightLast, + pub realized_price: PriceFromHeight, pub realized_price_extra: ComputedFromDateRatio, pub realized_cap_rel_to_own_market_cap: Option>, pub realized_cap_30d_delta: ComputedFromDateLast, @@ -169,7 +170,7 @@ impl RealizedMetrics { &realized_cap, ); - let realized_price = ComputedFromHeightLast::forced_import( + let realized_price = PriceFromHeight::forced_import( cfg.db, &cfg.name("realized_price"), cfg.version + v1, diff --git a/crates/brk_computer/src/internal/multi/from_date/lazy_binary_price.rs b/crates/brk_computer/src/internal/multi/from_date/lazy_binary_price.rs new file mode 100644 index 000000000..4eda54f6d --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_date/lazy_binary_price.rs @@ -0,0 +1,135 @@ +//! Lazy binary price wrapper with both USD and sats representations. +//! +//! For binary operations (e.g., price × ratio) that produce price values. +//! Both dollars and sats are computed lazily from the same sources. + +use brk_traversable::Traversable; +use brk_types::{Dollars, SatsFract, Version}; +use derive_more::{Deref, DerefMut}; +use schemars::JsonSchema; +use vecdb::{BinaryTransform, IterableCloneableVec, LazyVecFrom1}; + +use super::{ComputedFromDateLast, LazyBinaryFromDateLast}; +use crate::internal::{ComputedFromHeightLast, ComputedVecValue, DollarsToSatsFract, LazyTransformLast, NumericValue}; + +/// Lazy binary price with both USD and sats representations. +/// +/// Wraps a binary operation that produces Dollars and lazily converts to sats. +/// Derefs to the dollars metric. +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyBinaryPrice +where + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dollars: LazyBinaryFromDateLast, + pub sats: LazyUnaryFromBinaryLast, +} + +/// Lazy unary transform chain on a LazyBinaryFromDateLast output. +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyUnaryFromBinaryLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + ST: ComputedVecValue, + S1T: ComputedVecValue, + S2T: ComputedVecValue, +{ + pub dateindex: LazyVecFrom1, + pub weekindex: LazyTransformLast, + pub monthindex: LazyTransformLast, + pub quarterindex: LazyTransformLast, + pub semesterindex: LazyTransformLast, + pub yearindex: LazyTransformLast, + pub decadeindex: LazyTransformLast, + _phantom: std::marker::PhantomData<(S1T, S2T)>, +} + +impl LazyBinaryPrice +where + S1T: ComputedVecValue + JsonSchema + 'static, + S2T: ComputedVecValue + JsonSchema + 'static, +{ + /// Create from height-based price and dateindex-based ratio sources. + pub fn from_height_and_dateindex_last>( + name: &str, + version: Version, + source1: &ComputedFromHeightLast, + source2: &ComputedFromDateLast, + ) -> Self + where + S1T: NumericValue, + { + let dollars = LazyBinaryFromDateLast::from_height_and_dateindex_last::( + name, version, source1, source2, + ); + Self::from_dollars(name, version, dollars) + } + + /// Create from two computed dateindex sources. + pub fn from_computed_both_last>( + name: &str, + version: Version, + source1: &ComputedFromDateLast, + source2: &ComputedFromDateLast, + ) -> Self { + let dollars = LazyBinaryFromDateLast::from_computed_both_last::( + name, version, source1, source2, + ); + Self::from_dollars(name, version, dollars) + } + + /// Create sats version from dollars. + fn from_dollars( + name: &str, + version: Version, + dollars: LazyBinaryFromDateLast, + ) -> Self { + let sats_name = format!("{name}_sats"); + let sats = LazyUnaryFromBinaryLast { + dateindex: LazyVecFrom1::transformed::( + &sats_name, + version, + dollars.dateindex.boxed_clone(), + ), + weekindex: LazyTransformLast::from_boxed::( + &sats_name, + version, + dollars.weekindex.boxed_clone(), + ), + monthindex: LazyTransformLast::from_boxed::( + &sats_name, + version, + dollars.monthindex.boxed_clone(), + ), + quarterindex: LazyTransformLast::from_boxed::( + &sats_name, + version, + dollars.quarterindex.boxed_clone(), + ), + semesterindex: LazyTransformLast::from_boxed::( + &sats_name, + version, + dollars.semesterindex.boxed_clone(), + ), + yearindex: LazyTransformLast::from_boxed::( + &sats_name, + version, + dollars.yearindex.boxed_clone(), + ), + decadeindex: LazyTransformLast::from_boxed::( + &sats_name, + version, + dollars.decadeindex.boxed_clone(), + ), + _phantom: std::marker::PhantomData, + }; + + Self { dollars, sats } + } +} diff --git a/crates/brk_computer/src/internal/multi/from_date/lazy_price.rs b/crates/brk_computer/src/internal/multi/from_date/lazy_price.rs new file mode 100644 index 000000000..4203ce193 --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_date/lazy_price.rs @@ -0,0 +1,60 @@ +//! Lazy price wrapper with both USD and sats representations. +//! +//! Both dollars and sats are computed from the same source. + +use brk_traversable::Traversable; +use brk_types::{Dollars, SatsFract, Version}; +use derive_more::{Deref, DerefMut}; +use vecdb::UnaryTransform; + +use super::{ComputedFromDateLast, LazyFromDateLast}; +use crate::internal::{ComputedVecValue, DollarsToSatsFract}; + +/// Lazy price with both USD and sats representations. +/// +/// Both are computed from the same source via separate transforms. +/// Derefs to the dollars metric. +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct LazyPrice +where + ST: ComputedVecValue, +{ + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dollars: LazyFromDateLast, + pub sats: LazyFromDateLast, +} + +/// Composed transform: ST -> Dollars -> SatsFract +pub struct ComposedDollarsToSatsFract(std::marker::PhantomData); + +impl UnaryTransform for ComposedDollarsToSatsFract +where + F: UnaryTransform, +{ + #[inline(always)] + fn apply(source: ST) -> SatsFract { + DollarsToSatsFract::apply(F::apply(source)) + } +} + +impl LazyPrice +where + ST: ComputedVecValue + schemars::JsonSchema + 'static, +{ + pub fn from_source>( + name: &str, + version: Version, + source: &ComputedFromDateLast, + ) -> Self { + let dollars = LazyFromDateLast::from_source::(name, version, source); + let sats = LazyFromDateLast::from_source::>( + &format!("{name}_sats"), + version, + source, + ); + Self { dollars, sats } + } +} diff --git a/crates/brk_computer/src/internal/multi/from_date/mod.rs b/crates/brk_computer/src/internal/multi/from_date/mod.rs index 06949abb4..24c0a8406 100644 --- a/crates/brk_computer/src/internal/multi/from_date/mod.rs +++ b/crates/brk_computer/src/internal/multi/from_date/mod.rs @@ -5,16 +5,20 @@ mod binary_sum_cum; mod first; mod last; mod lazy; +mod lazy_binary_price; mod lazy_distribution; mod lazy_full; mod lazy_last; +mod lazy_price; mod lazy_sum; mod lazy_sum_cum; mod max; mod min; mod percentiles; +mod price; mod ratio; mod stddev; +mod unary_last; mod value_derived_last; mod value_last; mod value_lazy_last; @@ -26,16 +30,20 @@ pub use binary_sum_cum::*; pub use first::*; pub use last::*; pub use lazy::*; +pub use lazy_binary_price::*; pub use lazy_distribution::*; pub use lazy_full::*; pub use lazy_last::*; +pub use lazy_price::*; pub use lazy_sum::*; pub use lazy_sum_cum::*; pub use max::*; pub use min::*; pub use percentiles::*; +pub use price::*; pub use ratio::*; pub use stddev::*; +pub use unary_last::*; pub use value_derived_last::*; pub use value_last::*; pub use value_lazy_last::*; diff --git a/crates/brk_computer/src/internal/multi/from_date/percentiles.rs b/crates/brk_computer/src/internal/multi/from_date/percentiles.rs index dfc37d3dd..f9c7f3bf4 100644 --- a/crates/brk_computer/src/internal/multi/from_date/percentiles.rs +++ b/crates/brk_computer/src/internal/multi/from_date/percentiles.rs @@ -8,7 +8,7 @@ use vecdb::{ use crate::{ComputeIndexes, indexes}; -use super::ComputedFromDateLast; +use super::Price; pub const PERCENTILES: [u8; 19] = [ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, @@ -17,7 +17,7 @@ pub const PERCENTILES_LEN: usize = PERCENTILES.len(); #[derive(Clone)] pub struct CostBasisPercentiles { - pub vecs: [Option>; PERCENTILES_LEN], + pub vecs: [Option; PERCENTILES_LEN], } const VERSION: Version = Version::ZERO; @@ -37,8 +37,7 @@ impl CostBasisPercentiles { } else { format!("{name}_cost_basis_pct{p:02}") }; - ComputedFromDateLast::forced_import(db, &metric_name, version + VERSION, indexes) - .unwrap() + Price::forced_import(db, &metric_name, version + VERSION, indexes).unwrap() }) }); @@ -81,7 +80,7 @@ impl CostBasisPercentiles { Ok(()) } - pub fn get(&self, percentile: u8) -> Option<&ComputedFromDateLast> { + pub fn get(&self, percentile: u8) -> Option<&Price> { PERCENTILES .iter() .position(|&p| p == percentile) diff --git a/crates/brk_computer/src/internal/multi/from_date/price.rs b/crates/brk_computer/src/internal/multi/from_date/price.rs new file mode 100644 index 000000000..d879c144e --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_date/price.rs @@ -0,0 +1,48 @@ +//! Price wrapper that provides both USD and sats representations. +//! +//! The struct derefs to dollars, making it transparent for existing code. +//! Access `.sats` for the sats representation. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Dollars, SatsFract, Version}; +use derive_more::{Deref, DerefMut}; +use vecdb::Database; + +use super::{ComputedFromDateLast, LazyUnaryFromDateLast}; +use crate::{indexes, internal::DollarsToSatsFract}; + +/// Price metric with both USD and sats representations. +/// +/// Derefs to the dollars metric, so existing code works unchanged. +/// Access `.sats` for the sats exchange rate version. +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct Price { + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dollars: ComputedFromDateLast, + pub sats: LazyUnaryFromDateLast, +} + +impl Price { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dollars = ComputedFromDateLast::forced_import(db, name, version, indexes)?; + Ok(Self::from_computed(name, version, dollars)) + } + + pub fn from_computed(name: &str, version: Version, dollars: ComputedFromDateLast) -> Self { + let sats = LazyUnaryFromDateLast::from_computed_last::( + &format!("{name}_sats"), + version, + &dollars, + ); + Self { dollars, sats } + } +} diff --git a/crates/brk_computer/src/internal/multi/from_date/ratio.rs b/crates/brk_computer/src/internal/multi/from_date/ratio.rs index e484fadb1..0751ffc29 100644 --- a/crates/brk_computer/src/internal/multi/from_date/ratio.rs +++ b/crates/brk_computer/src/internal/multi/from_date/ratio.rs @@ -9,19 +9,19 @@ use vecdb::{ use crate::{ ComputeIndexes, indexes, internal::{ - ComputedFromDateStdDev, LazyBinaryFromDateLast, PriceTimesRatio, + ComputedFromDateStdDev, LazyBinaryPrice, PriceTimesRatio, StandardDeviationVecsOptions, }, price, utils::get_percentile, }; -use super::ComputedFromDateLast; +use super::{ComputedFromDateLast, Price}; use crate::internal::ComputedFromHeightLast; #[derive(Clone, Traversable)] pub struct ComputedFromDateRatio { - pub price: Option>, + pub price: Option, pub ratio: ComputedFromDateLast, pub ratio_1w_sma: Option>, @@ -32,12 +32,12 @@ pub struct ComputedFromDateRatio { pub ratio_pct5: Option>, pub ratio_pct2: Option>, pub ratio_pct1: Option>, - pub ratio_pct99_usd: Option>, - pub ratio_pct98_usd: Option>, - pub ratio_pct95_usd: Option>, - pub ratio_pct5_usd: Option>, - pub ratio_pct2_usd: Option>, - pub ratio_pct1_usd: Option>, + pub ratio_pct99_usd: Option>, + pub ratio_pct98_usd: Option>, + pub ratio_pct95_usd: Option>, + pub ratio_pct5_usd: Option>, + pub ratio_pct2_usd: Option>, + pub ratio_pct1_usd: Option>, pub ratio_sd: Option, pub ratio_4y_sd: Option, @@ -70,7 +70,7 @@ impl ComputedFromDateRatio { // Only compute internally when metric_price is None let price = metric_price .is_none() - .then(|| ComputedFromDateLast::forced_import(db, name, v, indexes).unwrap()); + .then(|| Price::forced_import(db, name, v, indexes).unwrap()); macro_rules! import_sd { ($suffix:expr, $days:expr) => { @@ -98,7 +98,7 @@ impl ComputedFromDateRatio { ($ratio:expr, $suffix:expr) => { if let Some(mp) = metric_price { $ratio.as_ref().map(|r| { - LazyBinaryFromDateLast::from_height_and_dateindex_last::( + LazyBinaryPrice::from_height_and_dateindex_last::( &format!("{name}_{}", $suffix), v, mp, @@ -107,7 +107,7 @@ impl ComputedFromDateRatio { }) } else { price.as_ref().zip($ratio.as_ref()).map(|(p, r)| { - LazyBinaryFromDateLast::from_computed_both_last::( + LazyBinaryPrice::from_computed_both_last::( &format!("{name}_{}", $suffix), v, p, diff --git a/crates/brk_computer/src/internal/multi/from_date/stddev.rs b/crates/brk_computer/src/internal/multi/from_date/stddev.rs index d2a699349..b05dd197a 100644 --- a/crates/brk_computer/src/internal/multi/from_date/stddev.rs +++ b/crates/brk_computer/src/internal/multi/from_date/stddev.rs @@ -10,7 +10,7 @@ use vecdb::{ use crate::{ComputeIndexes, indexes, price}; -use crate::internal::{ClosePriceTimesRatio, ComputedFromDateLast, LazyBinaryFromDateLast}; +use crate::internal::{ClosePriceTimesRatio, ComputedFromDateLast, LazyBinaryPrice}; #[derive(Clone, Traversable)] pub struct ComputedFromDateStdDev { @@ -35,19 +35,19 @@ pub struct ComputedFromDateStdDev { pub m2_5sd: Option>, pub m3sd: Option>, - pub _0sd_usd: Option, StoredF32>>, - pub p0_5sd_usd: Option, StoredF32>>, - pub p1sd_usd: Option, StoredF32>>, - pub p1_5sd_usd: Option, StoredF32>>, - pub p2sd_usd: Option, StoredF32>>, - pub p2_5sd_usd: Option, StoredF32>>, - pub p3sd_usd: Option, StoredF32>>, - pub m0_5sd_usd: Option, StoredF32>>, - pub m1sd_usd: Option, StoredF32>>, - pub m1_5sd_usd: Option, StoredF32>>, - pub m2sd_usd: Option, StoredF32>>, - pub m2_5sd_usd: Option, StoredF32>>, - pub m3sd_usd: Option, StoredF32>>, + pub _0sd_usd: Option, StoredF32>>, + pub p0_5sd_usd: Option, StoredF32>>, + pub p1sd_usd: Option, StoredF32>>, + pub p1_5sd_usd: Option, StoredF32>>, + pub p2sd_usd: Option, StoredF32>>, + pub p2_5sd_usd: Option, StoredF32>>, + pub p3sd_usd: Option, StoredF32>>, + pub m0_5sd_usd: Option, StoredF32>>, + pub m1sd_usd: Option, StoredF32>>, + pub m1_5sd_usd: Option, StoredF32>>, + pub m2sd_usd: Option, StoredF32>>, + pub m2_5sd_usd: Option, StoredF32>>, + pub m3sd_usd: Option, StoredF32>>, } #[derive(Debug, Default)] @@ -140,7 +140,7 @@ impl ComputedFromDateStdDev { .zip($band.as_ref()) .filter(|_| options.price_bands()) .map(|(p, b)| { - LazyBinaryFromDateLast::from_computed_both_last::( + LazyBinaryPrice::from_computed_both_last::( &format!("{name}_{}", $suffix), version, p, diff --git a/crates/brk_computer/src/internal/multi/from_date/unary_last.rs b/crates/brk_computer/src/internal/multi/from_date/unary_last.rs new file mode 100644 index 000000000..21cd3f98b --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_date/unary_last.rs @@ -0,0 +1,58 @@ +//! Unary transform composite from DateIndex - Last aggregation only. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex, Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, LazyVecFrom1, UnaryTransform}; + +use crate::internal::{ComputedFromDateLast, ComputedVecValue, LazyTransformLast}; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyUnaryFromDateLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + ST: ComputedVecValue, +{ + pub dateindex: LazyVecFrom1, + pub weekindex: LazyTransformLast, + pub monthindex: LazyTransformLast, + pub quarterindex: LazyTransformLast, + pub semesterindex: LazyTransformLast, + pub yearindex: LazyTransformLast, + pub decadeindex: LazyTransformLast, +} + +impl LazyUnaryFromDateLast +where + T: ComputedVecValue + JsonSchema + 'static, + ST: ComputedVecValue + JsonSchema, +{ + pub fn from_computed_last>( + name: &str, + version: Version, + source: &ComputedFromDateLast, + ) -> Self { + let v = version + VERSION; + + macro_rules! period { + ($p:ident) => { + LazyTransformLast::from_lazy_last::(name, v, &source.$p) + }; + } + + Self { + dateindex: LazyVecFrom1::transformed::(name, v, source.dateindex.boxed_clone()), + weekindex: period!(weekindex), + monthindex: period!(monthindex), + quarterindex: period!(quarterindex), + semesterindex: period!(semesterindex), + yearindex: period!(yearindex), + decadeindex: period!(decadeindex), + } + } +} diff --git a/crates/brk_computer/src/internal/multi/from_height/mod.rs b/crates/brk_computer/src/internal/multi/from_height/mod.rs index 364201773..986b4587c 100644 --- a/crates/brk_computer/src/internal/multi/from_height/mod.rs +++ b/crates/brk_computer/src/internal/multi/from_height/mod.rs @@ -15,6 +15,8 @@ mod lazy_computed_full; mod lazy_computed_sum_cum; mod lazy_last; mod lazy_sum; +mod price; +mod unary_last; mod lazy_sum_cum; mod sum; mod sum_cum; @@ -46,6 +48,8 @@ pub use lazy_computed_full::*; pub use lazy_computed_sum_cum::*; pub use lazy_last::*; pub use lazy_sum::*; +pub use price::*; +pub use unary_last::*; pub use lazy_sum_cum::*; pub use sum::*; pub use sum_cum::*; diff --git a/crates/brk_computer/src/internal/multi/from_height/price.rs b/crates/brk_computer/src/internal/multi/from_height/price.rs new file mode 100644 index 000000000..b9a249678 --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_height/price.rs @@ -0,0 +1,49 @@ +//! Price wrapper for height-based metrics with both USD and sats representations. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Dollars, SatsFract, Version}; +use derive_more::{Deref, DerefMut}; +use vecdb::Database; + +use super::{ComputedFromHeightLast, LazyUnaryFromHeightLast}; +use crate::{indexes, internal::DollarsToSatsFract}; + +/// Price metric (height-based) with both USD and sats representations. +/// +/// Derefs to the dollars metric, so existing code works unchanged. +/// Access `.sats` for the sats exchange rate version. +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct PriceFromHeight { + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dollars: ComputedFromHeightLast, + pub sats: LazyUnaryFromHeightLast, +} + +impl PriceFromHeight { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dollars = ComputedFromHeightLast::forced_import(db, name, version, indexes)?; + Ok(Self::from_computed(name, version, dollars)) + } + + pub fn from_computed( + name: &str, + version: Version, + dollars: ComputedFromHeightLast, + ) -> Self { + let sats = LazyUnaryFromHeightLast::from_computed_last::( + &format!("{name}_sats"), + version, + &dollars, + ); + Self { dollars, sats } + } +} diff --git a/crates/brk_computer/src/internal/multi/from_height/unary_last.rs b/crates/brk_computer/src/internal/multi/from_height/unary_last.rs new file mode 100644 index 000000000..1ded1006e --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_height/unary_last.rs @@ -0,0 +1,65 @@ +//! Unary transform composite from Height - Last aggregation only. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex, + Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, LazyVecFrom1, UnaryTransform}; + +use crate::internal::{ + ComputedFromHeightLast, ComputedVecValue, LazyTransformLast, NumericValue, +}; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyUnaryFromHeightLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + ST: ComputedVecValue, +{ + pub height: LazyVecFrom1, + pub dateindex: LazyTransformLast, + pub weekindex: LazyTransformLast, + pub monthindex: LazyTransformLast, + pub quarterindex: LazyTransformLast, + pub semesterindex: LazyTransformLast, + pub yearindex: LazyTransformLast, + pub decadeindex: LazyTransformLast, + pub difficultyepoch: LazyTransformLast, +} + +impl LazyUnaryFromHeightLast +where + T: ComputedVecValue + JsonSchema + 'static, + ST: NumericValue + JsonSchema, +{ + pub fn from_computed_last>( + name: &str, + version: Version, + source: &ComputedFromHeightLast, + ) -> Self { + let v = version + VERSION; + + macro_rules! period { + ($p:ident) => { + LazyTransformLast::from_lazy_last::(name, v, &source.$p) + }; + } + + Self { + height: LazyVecFrom1::transformed::(name, v, source.height.boxed_clone()), + dateindex: LazyTransformLast::from_last_vec::(name, v, &source.rest.dateindex), + weekindex: period!(weekindex), + monthindex: period!(monthindex), + quarterindex: period!(quarterindex), + semesterindex: period!(semesterindex), + yearindex: period!(yearindex), + decadeindex: period!(decadeindex), + difficultyepoch: period!(difficultyepoch), + } + } +} diff --git a/crates/brk_computer/src/internal/multi/from_height_and_date/mod.rs b/crates/brk_computer/src/internal/multi/from_height_and_date/mod.rs index 4ac3aafd2..d6b91de82 100644 --- a/crates/brk_computer/src/internal/multi/from_height_and_date/mod.rs +++ b/crates/brk_computer/src/internal/multi/from_height_and_date/mod.rs @@ -6,6 +6,8 @@ mod last; mod lazy_ohlc; mod max; mod min; +mod price; +mod unary_last; mod value_last; pub use binary_last::*; @@ -16,4 +18,6 @@ pub use last::*; pub use lazy_ohlc::*; pub use max::*; pub use min::*; +pub use price::*; +pub use unary_last::*; pub use value_last::*; diff --git a/crates/brk_computer/src/internal/multi/from_height_and_date/price.rs b/crates/brk_computer/src/internal/multi/from_height_and_date/price.rs new file mode 100644 index 000000000..60f497771 --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_height_and_date/price.rs @@ -0,0 +1,49 @@ +//! Price wrapper for height+date-based metrics with both USD and sats representations. + +use brk_error::Result; +use brk_traversable::Traversable; +use brk_types::{Dollars, SatsFract, Version}; +use derive_more::{Deref, DerefMut}; +use vecdb::Database; + +use super::{ComputedFromHeightAndDateLast, LazyUnaryFromHeightAndDateLast}; +use crate::{indexes, internal::DollarsToSatsFract}; + +/// Price metric (height+date-based) with both USD and sats representations. +/// +/// Derefs to the dollars metric, so existing code works unchanged. +/// Access `.sats` for the sats exchange rate version. +#[derive(Clone, Deref, DerefMut, Traversable)] +#[traversable(merge)] +pub struct PriceFromHeightAndDate { + #[deref] + #[deref_mut] + #[traversable(flatten)] + pub dollars: ComputedFromHeightAndDateLast, + pub sats: LazyUnaryFromHeightAndDateLast, +} + +impl PriceFromHeightAndDate { + pub fn forced_import( + db: &Database, + name: &str, + version: Version, + indexes: &indexes::Vecs, + ) -> Result { + let dollars = ComputedFromHeightAndDateLast::forced_import(db, name, version, indexes)?; + Ok(Self::from_computed(name, version, dollars)) + } + + pub fn from_computed( + name: &str, + version: Version, + dollars: ComputedFromHeightAndDateLast, + ) -> Self { + let sats = LazyUnaryFromHeightAndDateLast::from_computed_last::( + &format!("{name}_sats"), + version, + &dollars, + ); + Self { dollars, sats } + } +} diff --git a/crates/brk_computer/src/internal/multi/from_height_and_date/unary_last.rs b/crates/brk_computer/src/internal/multi/from_height_and_date/unary_last.rs new file mode 100644 index 000000000..5330a5561 --- /dev/null +++ b/crates/brk_computer/src/internal/multi/from_height_and_date/unary_last.rs @@ -0,0 +1,71 @@ +//! Unary transform composite from Height+Date - Last aggregation only. + +use brk_traversable::Traversable; +use brk_types::{ + DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex, + Version, WeekIndex, YearIndex, +}; +use schemars::JsonSchema; +use vecdb::{IterableCloneableVec, LazyVecFrom1, UnaryTransform}; + +use crate::internal::{ComputedFromHeightAndDateLast, ComputedVecValue, LazyTransformLast}; + +const VERSION: Version = Version::ZERO; + +#[derive(Clone, Traversable)] +#[traversable(merge)] +pub struct LazyUnaryFromHeightAndDateLast +where + T: ComputedVecValue + PartialOrd + JsonSchema, + ST: ComputedVecValue, +{ + pub height: LazyVecFrom1, + pub dateindex: LazyTransformLast, + pub weekindex: LazyTransformLast, + pub monthindex: LazyTransformLast, + pub quarterindex: LazyTransformLast, + pub semesterindex: LazyTransformLast, + pub yearindex: LazyTransformLast, + pub decadeindex: LazyTransformLast, + pub difficultyepoch: LazyTransformLast, +} + +impl LazyUnaryFromHeightAndDateLast +where + T: ComputedVecValue + JsonSchema + 'static, + ST: ComputedVecValue + JsonSchema, +{ + pub fn from_computed_last>( + name: &str, + version: Version, + source: &ComputedFromHeightAndDateLast, + ) -> Self { + let v = version + VERSION; + + macro_rules! period { + ($p:ident) => { + LazyTransformLast::from_lazy_last::(name, v, &source.rest.$p) + }; + } + + Self { + height: LazyVecFrom1::transformed::(name, v, source.height.boxed_clone()), + dateindex: LazyTransformLast(LazyVecFrom1::transformed::( + name, + v, + source.rest.dateindex.boxed_clone(), + )), + weekindex: period!(weekindex), + monthindex: period!(monthindex), + quarterindex: period!(quarterindex), + semesterindex: period!(semesterindex), + yearindex: period!(yearindex), + decadeindex: period!(decadeindex), + difficultyepoch: LazyTransformLast::from_lazy_last::( + name, + v, + &source.difficultyepoch, + ), + } + } +} diff --git a/crates/brk_computer/src/internal/single/transform/dollars_to_sats_fract.rs b/crates/brk_computer/src/internal/single/transform/dollars_to_sats_fract.rs index c84502f24..9e6209a07 100644 --- a/crates/brk_computer/src/internal/single/transform/dollars_to_sats_fract.rs +++ b/crates/brk_computer/src/internal/single/transform/dollars_to_sats_fract.rs @@ -1,4 +1,4 @@ -use brk_types::{Close, Dollars, SatsFract}; +use brk_types::{Dollars, SatsFract}; use vecdb::UnaryTransform; /// Dollars -> SatsFract (exchange rate: sats per dollar at this price level) @@ -8,21 +8,6 @@ pub struct DollarsToSatsFract; impl UnaryTransform for DollarsToSatsFract { #[inline(always)] fn apply(usd: Dollars) -> SatsFract { - let usd_f64 = f64::from(usd); - if usd_f64 == 0.0 { - SatsFract::NAN - } else { - SatsFract::from(SatsFract::SATS_PER_BTC / usd_f64) - } - } -} - -/// Close -> SatsFract -pub struct CloseDollarsToSatsFract; - -impl UnaryTransform, SatsFract> for CloseDollarsToSatsFract { - #[inline(always)] - fn apply(usd: Close) -> SatsFract { - DollarsToSatsFract::apply(*usd) + SatsFract::ONE_BTC / usd } } diff --git a/crates/brk_computer/src/internal/single/transform/mod.rs b/crates/brk_computer/src/internal/single/transform/mod.rs index 851aaf3c8..c5abb1152 100644 --- a/crates/brk_computer/src/internal/single/transform/mod.rs +++ b/crates/brk_computer/src/internal/single/transform/mod.rs @@ -4,6 +4,7 @@ mod close_price_times_sats; mod difference_f32; mod dollar_halve; mod dollar_identity; +mod dollars_to_sats_fract; mod dollar_minus; mod dollar_plus; mod dollar_times_tenths; @@ -44,6 +45,7 @@ pub use close_price_times_sats::*; pub use difference_f32::*; pub use dollar_halve::*; pub use dollar_identity::*; +pub use dollars_to_sats_fract::*; pub use dollar_minus::*; pub use dollar_plus::*; pub use dollar_times_tenths::*; diff --git a/crates/brk_computer/src/market/ath/import.rs b/crates/brk_computer/src/market/ath/import.rs index a99c01836..6efa8390b 100644 --- a/crates/brk_computer/src/market/ath/import.rs +++ b/crates/brk_computer/src/market/ath/import.rs @@ -6,8 +6,8 @@ use super::Vecs; use crate::{ indexes, internal::{ - ComputedFromDateLast, ComputedFromHeightAndDateLast, LazyBinaryFromHeightAndDateLast, LazyFromDateLast, - PercentageDiffCloseDollars, StoredU16ToYears, + ComputedFromDateLast, LazyBinaryFromHeightAndDateLast, LazyFromDateLast, + PercentageDiffCloseDollars, PriceFromHeightAndDate, StoredU16ToYears, }, price, }; @@ -19,7 +19,7 @@ impl Vecs { indexes: &indexes::Vecs, price: &price::Vecs, ) -> Result { - let price_ath = ComputedFromHeightAndDateLast::forced_import(db, "price_ath", version, indexes)?; + let price_ath = PriceFromHeightAndDate::forced_import(db, "price_ath", version, indexes)?; let max_days_between_price_aths = ComputedFromDateLast::forced_import(db, "max_days_between_price_aths", version, indexes)?; diff --git a/crates/brk_computer/src/market/ath/vecs.rs b/crates/brk_computer/src/market/ath/vecs.rs index 8174c6d9c..5ff4281b1 100644 --- a/crates/brk_computer/src/market/ath/vecs.rs +++ b/crates/brk_computer/src/market/ath/vecs.rs @@ -2,13 +2,13 @@ use brk_traversable::Traversable; use brk_types::{Close, Dollars, StoredF32, StoredU16}; use crate::internal::{ - ComputedFromDateLast, ComputedFromHeightAndDateLast, LazyBinaryFromHeightAndDateLast, LazyFromDateLast, + ComputedFromDateLast, LazyBinaryFromHeightAndDateLast, LazyFromDateLast, PriceFromHeightAndDate, }; /// All-time high related metrics #[derive(Clone, Traversable)] pub struct Vecs { - pub price_ath: ComputedFromHeightAndDateLast, + pub price_ath: PriceFromHeightAndDate, pub price_drawdown: LazyBinaryFromHeightAndDateLast, Dollars>, pub days_since_price_ath: ComputedFromDateLast, pub years_since_price_ath: LazyFromDateLast, diff --git a/crates/brk_computer/src/market/dca/import.rs b/crates/brk_computer/src/market/dca/import.rs index 856de19f5..91b265901 100644 --- a/crates/brk_computer/src/market/dca/import.rs +++ b/crates/brk_computer/src/market/dca/import.rs @@ -6,7 +6,7 @@ use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod, DCA_CLASS_NAMES, DCA_PERIOD_NAME use crate::{ indexes, internal::{ - ComputedFromDateLast, LazyBinaryFromDateLast, PercentageDiffCloseDollars, + ComputedFromDateLast, LazyBinaryFromDateLast, PercentageDiffCloseDollars, Price, ValueFromDateLast, }, market::lookback, @@ -28,12 +28,7 @@ impl Vecs { // DCA by period - average price let period_average_price = ByDcaPeriod::try_new(|name, _days| { - ComputedFromDateLast::forced_import( - db, - &format!("{name}_dca_average_price"), - version, - indexes, - ) + Price::forced_import(db, &format!("{name}_dca_average_price"), version, indexes) })?; let period_returns = @@ -160,7 +155,7 @@ impl Vecs { // DCA by year class - average price let class_average_price = ByDcaClass::try_new(|name, _year, _dateindex| { - ComputedFromDateLast::forced_import(db, &format!("{name}_average_price"), version, indexes) + Price::forced_import(db, &format!("{name}_average_price"), version, indexes) })?; let class_returns = diff --git a/crates/brk_computer/src/market/dca/vecs.rs b/crates/brk_computer/src/market/dca/vecs.rs index b1badcb48..f4de22fc8 100644 --- a/crates/brk_computer/src/market/dca/vecs.rs +++ b/crates/brk_computer/src/market/dca/vecs.rs @@ -2,14 +2,14 @@ use brk_traversable::Traversable; use brk_types::{Close, Dollars, StoredF32, StoredU32}; use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod}; -use crate::internal::{ComputedFromDateLast, LazyBinaryFromDateLast, ValueFromDateLast}; +use crate::internal::{ComputedFromDateLast, LazyBinaryFromDateLast, Price, ValueFromDateLast}; /// Dollar-cost averaging metrics by time period and year class #[derive(Clone, Traversable)] pub struct Vecs { // DCA by period - KISS types pub period_stack: ByDcaPeriod, - pub period_average_price: ByDcaPeriod>, + pub period_average_price: ByDcaPeriod, pub period_returns: ByDcaPeriod, Dollars>>, pub period_cagr: ByDcaCagr>, @@ -31,7 +31,7 @@ pub struct Vecs { // DCA by year class - KISS types pub class_stack: ByDcaClass, - pub class_average_price: ByDcaClass>, + pub class_average_price: ByDcaClass, pub class_returns: ByDcaClass, Dollars>>, // DCA by year class - profitability diff --git a/crates/brk_computer/src/market/lookback/import.rs b/crates/brk_computer/src/market/lookback/import.rs index b60d6e45a..b0cb986cc 100644 --- a/crates/brk_computer/src/market/lookback/import.rs +++ b/crates/brk_computer/src/market/lookback/import.rs @@ -3,12 +3,12 @@ use brk_types::Version; use vecdb::Database; use super::{ByLookbackPeriod, Vecs}; -use crate::{indexes, internal::ComputedFromDateLast}; +use crate::{indexes, internal::Price}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { let price_ago = ByLookbackPeriod::try_new(|name, _days| { - ComputedFromDateLast::forced_import(db, &format!("price_{name}_ago"), version, indexes) + Price::forced_import(db, &format!("price_{name}_ago"), version, indexes) })?; Ok(Self { price_ago }) diff --git a/crates/brk_computer/src/market/lookback/vecs.rs b/crates/brk_computer/src/market/lookback/vecs.rs index cb9a0b5b6..5eaa236f0 100644 --- a/crates/brk_computer/src/market/lookback/vecs.rs +++ b/crates/brk_computer/src/market/lookback/vecs.rs @@ -1,12 +1,11 @@ use brk_traversable::Traversable; -use brk_types::Dollars; use super::ByLookbackPeriod; -use crate::internal::ComputedFromDateLast; +use crate::internal::Price; /// Price lookback metrics #[derive(Clone, Traversable)] pub struct Vecs { #[traversable(flatten)] - pub price_ago: ByLookbackPeriod>, + pub price_ago: ByLookbackPeriod, } diff --git a/crates/brk_computer/src/market/moving_average/import.rs b/crates/brk_computer/src/market/moving_average/import.rs index 8b16ef06d..9313ec91d 100644 --- a/crates/brk_computer/src/market/moving_average/import.rs +++ b/crates/brk_computer/src/market/moving_average/import.rs @@ -5,7 +5,7 @@ use vecdb::Database; use super::Vecs; use crate::{ indexes, - internal::{ComputedFromDateRatio, DollarsTimesTenths, LazyFromDateLast}, + internal::{ComputedFromDateRatio, DollarsTimesTenths, LazyPrice}, price, }; @@ -307,19 +307,19 @@ impl Vecs { )?; let price_200d_sma_source = price_200d_sma.price.as_ref().unwrap(); - let price_200d_sma_x2_4 = LazyFromDateLast::from_source::>( + let price_200d_sma_x2_4 = LazyPrice::from_source::>( "price_200d_sma_x2_4", version, price_200d_sma_source, ); - let price_200d_sma_x0_8 = LazyFromDateLast::from_source::>( + let price_200d_sma_x0_8 = LazyPrice::from_source::>( "price_200d_sma_x0_8", version, price_200d_sma_source, ); let price_350d_sma_source = price_350d_sma.price.as_ref().unwrap(); - let price_350d_sma_x2 = LazyFromDateLast::from_source::>( + let price_350d_sma_x2 = LazyPrice::from_source::>( "price_350d_sma_x2", version, price_350d_sma_source, diff --git a/crates/brk_computer/src/market/moving_average/vecs.rs b/crates/brk_computer/src/market/moving_average/vecs.rs index 6128a803e..e86a20260 100644 --- a/crates/brk_computer/src/market/moving_average/vecs.rs +++ b/crates/brk_computer/src/market/moving_average/vecs.rs @@ -1,7 +1,7 @@ use brk_traversable::Traversable; use brk_types::Dollars; -use crate::internal::{ComputedFromDateRatio, LazyFromDateLast}; +use crate::internal::{ComputedFromDateRatio, LazyPrice}; /// Simple and exponential moving average metrics #[derive(Clone, Traversable)] @@ -40,7 +40,7 @@ pub struct Vecs { pub price_200w_ema: ComputedFromDateRatio, pub price_4y_ema: ComputedFromDateRatio, - pub price_200d_sma_x2_4: LazyFromDateLast, - pub price_200d_sma_x0_8: LazyFromDateLast, - pub price_350d_sma_x2: LazyFromDateLast, + pub price_200d_sma_x2_4: LazyPrice, + pub price_200d_sma_x0_8: LazyPrice, + pub price_350d_sma_x2: LazyPrice, } diff --git a/crates/brk_computer/src/market/range/import.rs b/crates/brk_computer/src/market/range/import.rs index 96f2bb9d5..e039668b1 100644 --- a/crates/brk_computer/src/market/range/import.rs +++ b/crates/brk_computer/src/market/range/import.rs @@ -3,67 +3,23 @@ use brk_types::Version; use vecdb::{Database, EagerVec, ImportableVec}; use super::Vecs; -use crate::{indexes, internal::ComputedFromDateLast}; +use crate::{indexes, internal::{ComputedFromDateLast, Price}}; impl Vecs { pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result { let v1 = Version::ONE; Ok(Self { - price_1w_min: ComputedFromDateLast::forced_import( - db, - "price_1w_min", - version + v1, - indexes, - )?, - price_1w_max: ComputedFromDateLast::forced_import( - db, - "price_1w_max", - version + v1, - indexes, - )?, - price_2w_min: ComputedFromDateLast::forced_import( - db, - "price_2w_min", - version + v1, - indexes, - )?, - price_2w_max: ComputedFromDateLast::forced_import( - db, - "price_2w_max", - version + v1, - indexes, - )?, - price_1m_min: ComputedFromDateLast::forced_import( - db, - "price_1m_min", - version + v1, - indexes, - )?, - price_1m_max: ComputedFromDateLast::forced_import( - db, - "price_1m_max", - version + v1, - indexes, - )?, - price_1y_min: ComputedFromDateLast::forced_import( - db, - "price_1y_min", - version + v1, - indexes, - )?, - price_1y_max: ComputedFromDateLast::forced_import( - db, - "price_1y_max", - version + v1, - indexes, - )?, + price_1w_min: Price::forced_import(db, "price_1w_min", version + v1, indexes)?, + price_1w_max: Price::forced_import(db, "price_1w_max", version + v1, indexes)?, + price_2w_min: Price::forced_import(db, "price_2w_min", version + v1, indexes)?, + price_2w_max: Price::forced_import(db, "price_2w_max", version + v1, indexes)?, + price_1m_min: Price::forced_import(db, "price_1m_min", version + v1, indexes)?, + price_1m_max: Price::forced_import(db, "price_1m_max", version + v1, indexes)?, + price_1y_min: Price::forced_import(db, "price_1y_min", version + v1, indexes)?, + price_1y_max: Price::forced_import(db, "price_1y_max", version + v1, indexes)?, price_true_range: EagerVec::forced_import(db, "price_true_range", version)?, - price_true_range_2w_sum: EagerVec::forced_import( - db, - "price_true_range_2w_sum", - version, - )?, + price_true_range_2w_sum: EagerVec::forced_import(db, "price_true_range_2w_sum", version)?, price_2w_choppiness_index: ComputedFromDateLast::forced_import( db, "price_2w_choppiness_index", diff --git a/crates/brk_computer/src/market/range/vecs.rs b/crates/brk_computer/src/market/range/vecs.rs index 46205928c..34ed47a80 100644 --- a/crates/brk_computer/src/market/range/vecs.rs +++ b/crates/brk_computer/src/market/range/vecs.rs @@ -1,20 +1,20 @@ use brk_traversable::Traversable; -use brk_types::{DateIndex, Dollars, StoredF32}; +use brk_types::{DateIndex, StoredF32}; use vecdb::{EagerVec, PcoVec}; -use crate::internal::ComputedFromDateLast; +use crate::internal::{ComputedFromDateLast, Price}; /// Price range and choppiness metrics #[derive(Clone, Traversable)] pub struct Vecs { - pub price_1w_min: ComputedFromDateLast, - pub price_1w_max: ComputedFromDateLast, - pub price_2w_min: ComputedFromDateLast, - pub price_2w_max: ComputedFromDateLast, - pub price_1m_min: ComputedFromDateLast, - pub price_1m_max: ComputedFromDateLast, - pub price_1y_min: ComputedFromDateLast, - pub price_1y_max: ComputedFromDateLast, + pub price_1w_min: Price, + pub price_1w_max: Price, + pub price_2w_min: Price, + pub price_2w_max: Price, + pub price_1m_min: Price, + pub price_1m_max: Price, + pub price_1y_min: Price, + pub price_1y_max: Price, pub price_true_range: EagerVec>, pub price_true_range_2w_sum: EagerVec>, pub price_2w_choppiness_index: ComputedFromDateLast, diff --git a/crates/brk_types/src/satsfract.rs b/crates/brk_types/src/satsfract.rs index 509a45a25..b238b05d7 100644 --- a/crates/brk_types/src/satsfract.rs +++ b/crates/brk_types/src/satsfract.rs @@ -26,6 +26,7 @@ pub struct SatsFract(f64); impl SatsFract { pub const ZERO: Self = Self(0.0); pub const NAN: Self = Self(f64::NAN); + pub const ONE_BTC: Self = Self(100_000_000.0); pub const SATS_PER_BTC: f64 = 100_000_000.0; pub const fn new(sats: f64) -> Self { @@ -191,3 +192,22 @@ impl Formattable for SatsFract { false } } + +impl Div for SatsFract { + type Output = Self; + fn div(self, rhs: Dollars) -> Self::Output { + let rhs = f64::from(rhs); + if rhs == 0.0 { + Self::NAN + } else { + Self(self.0 / rhs) + } + } +} + +impl Div> for SatsFract { + type Output = Self; + fn div(self, rhs: Close) -> Self::Output { + self / *rhs + } +} diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js index 2b762f679..15d13d98d 100644 --- a/modules/brk-client/index.js +++ b/modules/brk-client/index.js @@ -604,6 +604,18 @@ * * @typedef {number} Sats */ +/** + * Fractional satoshis (f64) - for representing USD prices in sats + * + * Formula: `sats_fract = usd_value * 100_000_000 / btc_price` + * + * When BTC is $100,000: + * - $1 = 1,000 sats + * - $0.001 = 1 sat + * - $0.0001 = 0.1 sats (fractional) + * + * @typedef {number} SatsFract + */ /** @typedef {number} SemesterIndex */ /** * Fixed-size boolean value optimized for on-disk storage (stored as u8) @@ -1252,7 +1264,7 @@ function createMetricPattern33(client, name) { return _mp(client, name, _i33); } * @property {MetricPattern1} realizedCapRelToOwnMarketCap * @property {BlockCountPattern} realizedLoss * @property {BlockCountPattern} realizedLossRelToRealizedCap - * @property {MetricPattern1} realizedPrice + * @property {ActivePricePattern} realizedPrice * @property {ActivePriceRatioPattern} realizedPriceExtra * @property {BlockCountPattern} realizedProfit * @property {BlockCountPattern} realizedProfitRelToRealizedCap @@ -1294,7 +1306,7 @@ function createRealizedPattern3(client, acc) { realizedCapRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')), realizedLoss: createBlockCountPattern(client, _m(acc, 'realized_loss')), realizedLossRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), - realizedPrice: createMetricPattern1(client, _m(acc, 'realized_price')), + realizedPrice: createActivePricePattern(client, _m(acc, 'realized_price')), realizedPriceExtra: createActivePriceRatioPattern(client, _m(acc, 'realized_price_ratio')), realizedProfit: createBlockCountPattern(client, _m(acc, 'realized_profit')), realizedProfitRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), @@ -1330,7 +1342,7 @@ function createRealizedPattern3(client, acc) { * @property {MetricPattern4} realizedCap30dDelta * @property {BlockCountPattern} realizedLoss * @property {BlockCountPattern} realizedLossRelToRealizedCap - * @property {MetricPattern1} realizedPrice + * @property {ActivePricePattern} realizedPrice * @property {RealizedPriceExtraPattern} realizedPriceExtra * @property {BlockCountPattern} realizedProfit * @property {BlockCountPattern} realizedProfitRelToRealizedCap @@ -1370,7 +1382,7 @@ function createRealizedPattern4(client, acc) { realizedCap30dDelta: createMetricPattern4(client, _m(acc, 'realized_cap_30d_delta')), realizedLoss: createBlockCountPattern(client, _m(acc, 'realized_loss')), realizedLossRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), - realizedPrice: createMetricPattern1(client, _m(acc, 'realized_price')), + realizedPrice: createActivePricePattern(client, _m(acc, 'realized_price')), realizedPriceExtra: createRealizedPriceExtraPattern(client, _m(acc, 'realized_price_ratio')), realizedProfit: createBlockCountPattern(client, _m(acc, 'realized_profit')), realizedProfitRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), @@ -1389,31 +1401,31 @@ function createRealizedPattern4(client, acc) { /** * @typedef {Object} Ratio1ySdPattern - * @property {MetricPattern4} _0sdUsd + * @property {_0sdUsdPattern} _0sdUsd * @property {MetricPattern4} m05sd - * @property {MetricPattern4} m05sdUsd + * @property {_0sdUsdPattern} m05sdUsd * @property {MetricPattern4} m15sd - * @property {MetricPattern4} m15sdUsd + * @property {_0sdUsdPattern} m15sdUsd * @property {MetricPattern4} m1sd - * @property {MetricPattern4} m1sdUsd + * @property {_0sdUsdPattern} m1sdUsd * @property {MetricPattern4} m25sd - * @property {MetricPattern4} m25sdUsd + * @property {_0sdUsdPattern} m25sdUsd * @property {MetricPattern4} m2sd - * @property {MetricPattern4} m2sdUsd + * @property {_0sdUsdPattern} m2sdUsd * @property {MetricPattern4} m3sd - * @property {MetricPattern4} m3sdUsd + * @property {_0sdUsdPattern} m3sdUsd * @property {MetricPattern4} p05sd - * @property {MetricPattern4} p05sdUsd + * @property {_0sdUsdPattern} p05sdUsd * @property {MetricPattern4} p15sd - * @property {MetricPattern4} p15sdUsd + * @property {_0sdUsdPattern} p15sdUsd * @property {MetricPattern4} p1sd - * @property {MetricPattern4} p1sdUsd + * @property {_0sdUsdPattern} p1sdUsd * @property {MetricPattern4} p25sd - * @property {MetricPattern4} p25sdUsd + * @property {_0sdUsdPattern} p25sdUsd * @property {MetricPattern4} p2sd - * @property {MetricPattern4} p2sdUsd + * @property {_0sdUsdPattern} p2sdUsd * @property {MetricPattern4} p3sd - * @property {MetricPattern4} p3sdUsd + * @property {_0sdUsdPattern} p3sdUsd * @property {MetricPattern4} sd * @property {MetricPattern4} sma * @property {MetricPattern4} zscore @@ -1427,31 +1439,31 @@ function createRealizedPattern4(client, acc) { */ function createRatio1ySdPattern(client, acc) { return { - _0sdUsd: createMetricPattern4(client, _m(acc, '0sd_usd')), + _0sdUsd: create_0sdUsdPattern(client, _m(acc, '0sd_usd')), m05sd: createMetricPattern4(client, _m(acc, 'm0_5sd')), - m05sdUsd: createMetricPattern4(client, _m(acc, 'm0_5sd_usd')), + m05sdUsd: create_0sdUsdPattern(client, _m(acc, 'm0_5sd_usd')), m15sd: createMetricPattern4(client, _m(acc, 'm1_5sd')), - m15sdUsd: createMetricPattern4(client, _m(acc, 'm1_5sd_usd')), + m15sdUsd: create_0sdUsdPattern(client, _m(acc, 'm1_5sd_usd')), m1sd: createMetricPattern4(client, _m(acc, 'm1sd')), - m1sdUsd: createMetricPattern4(client, _m(acc, 'm1sd_usd')), + m1sdUsd: create_0sdUsdPattern(client, _m(acc, 'm1sd_usd')), m25sd: createMetricPattern4(client, _m(acc, 'm2_5sd')), - m25sdUsd: createMetricPattern4(client, _m(acc, 'm2_5sd_usd')), + m25sdUsd: create_0sdUsdPattern(client, _m(acc, 'm2_5sd_usd')), m2sd: createMetricPattern4(client, _m(acc, 'm2sd')), - m2sdUsd: createMetricPattern4(client, _m(acc, 'm2sd_usd')), + m2sdUsd: create_0sdUsdPattern(client, _m(acc, 'm2sd_usd')), m3sd: createMetricPattern4(client, _m(acc, 'm3sd')), - m3sdUsd: createMetricPattern4(client, _m(acc, 'm3sd_usd')), + m3sdUsd: create_0sdUsdPattern(client, _m(acc, 'm3sd_usd')), p05sd: createMetricPattern4(client, _m(acc, 'p0_5sd')), - p05sdUsd: createMetricPattern4(client, _m(acc, 'p0_5sd_usd')), + p05sdUsd: create_0sdUsdPattern(client, _m(acc, 'p0_5sd_usd')), p15sd: createMetricPattern4(client, _m(acc, 'p1_5sd')), - p15sdUsd: createMetricPattern4(client, _m(acc, 'p1_5sd_usd')), + p15sdUsd: create_0sdUsdPattern(client, _m(acc, 'p1_5sd_usd')), p1sd: createMetricPattern4(client, _m(acc, 'p1sd')), - p1sdUsd: createMetricPattern4(client, _m(acc, 'p1sd_usd')), + p1sdUsd: create_0sdUsdPattern(client, _m(acc, 'p1sd_usd')), p25sd: createMetricPattern4(client, _m(acc, 'p2_5sd')), - p25sdUsd: createMetricPattern4(client, _m(acc, 'p2_5sd_usd')), + p25sdUsd: create_0sdUsdPattern(client, _m(acc, 'p2_5sd_usd')), p2sd: createMetricPattern4(client, _m(acc, 'p2sd')), - p2sdUsd: createMetricPattern4(client, _m(acc, 'p2sd_usd')), + p2sdUsd: create_0sdUsdPattern(client, _m(acc, 'p2sd_usd')), p3sd: createMetricPattern4(client, _m(acc, 'p3sd')), - p3sdUsd: createMetricPattern4(client, _m(acc, 'p3sd_usd')), + p3sdUsd: create_0sdUsdPattern(client, _m(acc, 'p3sd_usd')), sd: createMetricPattern4(client, _m(acc, 'sd')), sma: createMetricPattern4(client, _m(acc, 'sma')), zscore: createMetricPattern4(client, _m(acc, 'zscore')), @@ -1472,7 +1484,7 @@ function createRatio1ySdPattern(client, acc) { * @property {MetricPattern1} realizedCapRelToOwnMarketCap * @property {BlockCountPattern} realizedLoss * @property {BlockCountPattern} realizedLossRelToRealizedCap - * @property {MetricPattern1} realizedPrice + * @property {ActivePricePattern} realizedPrice * @property {ActivePriceRatioPattern} realizedPriceExtra * @property {BlockCountPattern} realizedProfit * @property {BlockCountPattern} realizedProfitRelToRealizedCap @@ -1509,7 +1521,7 @@ function createRealizedPattern2(client, acc) { realizedCapRelToOwnMarketCap: createMetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')), realizedLoss: createBlockCountPattern(client, _m(acc, 'realized_loss')), realizedLossRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), - realizedPrice: createMetricPattern1(client, _m(acc, 'realized_price')), + realizedPrice: createActivePricePattern(client, _m(acc, 'realized_price')), realizedPriceExtra: createActivePriceRatioPattern(client, _m(acc, 'realized_price_ratio')), realizedProfit: createBlockCountPattern(client, _m(acc, 'realized_profit')), realizedProfitRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), @@ -1540,7 +1552,7 @@ function createRealizedPattern2(client, acc) { * @property {MetricPattern4} realizedCap30dDelta * @property {BlockCountPattern} realizedLoss * @property {BlockCountPattern} realizedLossRelToRealizedCap - * @property {MetricPattern1} realizedPrice + * @property {ActivePricePattern} realizedPrice * @property {RealizedPriceExtraPattern} realizedPriceExtra * @property {BlockCountPattern} realizedProfit * @property {BlockCountPattern} realizedProfitRelToRealizedCap @@ -1575,7 +1587,7 @@ function createRealizedPattern(client, acc) { realizedCap30dDelta: createMetricPattern4(client, _m(acc, 'realized_cap_30d_delta')), realizedLoss: createBlockCountPattern(client, _m(acc, 'realized_loss')), realizedLossRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')), - realizedPrice: createMetricPattern1(client, _m(acc, 'realized_price')), + realizedPrice: createActivePricePattern(client, _m(acc, 'realized_price')), realizedPriceExtra: createRealizedPriceExtraPattern(client, _m(acc, 'realized_price_ratio')), realizedProfit: createBlockCountPattern(client, _m(acc, 'realized_profit')), realizedProfitRelToRealizedCap: createBlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')), @@ -1594,7 +1606,7 @@ function createRealizedPattern(client, acc) { /** * @typedef {Object} Price111dSmaPattern - * @property {MetricPattern4} price + * @property {_0sdUsdPattern} price * @property {MetricPattern4} ratio * @property {MetricPattern4} ratio1mSma * @property {MetricPattern4} ratio1wSma @@ -1602,17 +1614,17 @@ function createRealizedPattern(client, acc) { * @property {Ratio1ySdPattern} ratio2ySd * @property {Ratio1ySdPattern} ratio4ySd * @property {MetricPattern4} ratioPct1 - * @property {MetricPattern4} ratioPct1Usd + * @property {_0sdUsdPattern} ratioPct1Usd * @property {MetricPattern4} ratioPct2 - * @property {MetricPattern4} ratioPct2Usd + * @property {_0sdUsdPattern} ratioPct2Usd * @property {MetricPattern4} ratioPct5 - * @property {MetricPattern4} ratioPct5Usd + * @property {_0sdUsdPattern} ratioPct5Usd * @property {MetricPattern4} ratioPct95 - * @property {MetricPattern4} ratioPct95Usd + * @property {_0sdUsdPattern} ratioPct95Usd * @property {MetricPattern4} ratioPct98 - * @property {MetricPattern4} ratioPct98Usd + * @property {_0sdUsdPattern} ratioPct98Usd * @property {MetricPattern4} ratioPct99 - * @property {MetricPattern4} ratioPct99Usd + * @property {_0sdUsdPattern} ratioPct99Usd * @property {Ratio1ySdPattern} ratioSd */ @@ -1624,7 +1636,7 @@ function createRealizedPattern(client, acc) { */ function createPrice111dSmaPattern(client, acc) { return { - price: createMetricPattern4(client, acc), + price: create_0sdUsdPattern(client, acc), ratio: createMetricPattern4(client, _m(acc, 'ratio')), ratio1mSma: createMetricPattern4(client, _m(acc, 'ratio_1m_sma')), ratio1wSma: createMetricPattern4(client, _m(acc, 'ratio_1w_sma')), @@ -1632,17 +1644,17 @@ function createPrice111dSmaPattern(client, acc) { ratio2ySd: createRatio1ySdPattern(client, _m(acc, 'ratio_2y')), ratio4ySd: createRatio1ySdPattern(client, _m(acc, 'ratio_4y')), ratioPct1: createMetricPattern4(client, _m(acc, 'ratio_pct1')), - ratioPct1Usd: createMetricPattern4(client, _m(acc, 'ratio_pct1_usd')), + ratioPct1Usd: create_0sdUsdPattern(client, _m(acc, 'ratio_pct1_usd')), ratioPct2: createMetricPattern4(client, _m(acc, 'ratio_pct2')), - ratioPct2Usd: createMetricPattern4(client, _m(acc, 'ratio_pct2_usd')), + ratioPct2Usd: create_0sdUsdPattern(client, _m(acc, 'ratio_pct2_usd')), ratioPct5: createMetricPattern4(client, _m(acc, 'ratio_pct5')), - ratioPct5Usd: createMetricPattern4(client, _m(acc, 'ratio_pct5_usd')), + ratioPct5Usd: create_0sdUsdPattern(client, _m(acc, 'ratio_pct5_usd')), ratioPct95: createMetricPattern4(client, _m(acc, 'ratio_pct95')), - ratioPct95Usd: createMetricPattern4(client, _m(acc, 'ratio_pct95_usd')), + ratioPct95Usd: create_0sdUsdPattern(client, _m(acc, 'ratio_pct95_usd')), ratioPct98: createMetricPattern4(client, _m(acc, 'ratio_pct98')), - ratioPct98Usd: createMetricPattern4(client, _m(acc, 'ratio_pct98_usd')), + ratioPct98Usd: create_0sdUsdPattern(client, _m(acc, 'ratio_pct98_usd')), ratioPct99: createMetricPattern4(client, _m(acc, 'ratio_pct99')), - ratioPct99Usd: createMetricPattern4(client, _m(acc, 'ratio_pct99_usd')), + ratioPct99Usd: create_0sdUsdPattern(client, _m(acc, 'ratio_pct99_usd')), ratioSd: createRatio1ySdPattern(client, _m(acc, 'ratio')), }; } @@ -1656,17 +1668,17 @@ function createPrice111dSmaPattern(client, acc) { * @property {Ratio1ySdPattern} ratio2ySd * @property {Ratio1ySdPattern} ratio4ySd * @property {MetricPattern4} ratioPct1 - * @property {MetricPattern4} ratioPct1Usd + * @property {_0sdUsdPattern} ratioPct1Usd * @property {MetricPattern4} ratioPct2 - * @property {MetricPattern4} ratioPct2Usd + * @property {_0sdUsdPattern} ratioPct2Usd * @property {MetricPattern4} ratioPct5 - * @property {MetricPattern4} ratioPct5Usd + * @property {_0sdUsdPattern} ratioPct5Usd * @property {MetricPattern4} ratioPct95 - * @property {MetricPattern4} ratioPct95Usd + * @property {_0sdUsdPattern} ratioPct95Usd * @property {MetricPattern4} ratioPct98 - * @property {MetricPattern4} ratioPct98Usd + * @property {_0sdUsdPattern} ratioPct98Usd * @property {MetricPattern4} ratioPct99 - * @property {MetricPattern4} ratioPct99Usd + * @property {_0sdUsdPattern} ratioPct99Usd * @property {Ratio1ySdPattern} ratioSd */ @@ -1685,42 +1697,42 @@ function createActivePriceRatioPattern(client, acc) { ratio2ySd: createRatio1ySdPattern(client, _m(acc, '2y')), ratio4ySd: createRatio1ySdPattern(client, _m(acc, '4y')), ratioPct1: createMetricPattern4(client, _m(acc, 'pct1')), - ratioPct1Usd: createMetricPattern4(client, _m(acc, 'pct1_usd')), + ratioPct1Usd: create_0sdUsdPattern(client, _m(acc, 'pct1_usd')), ratioPct2: createMetricPattern4(client, _m(acc, 'pct2')), - ratioPct2Usd: createMetricPattern4(client, _m(acc, 'pct2_usd')), + ratioPct2Usd: create_0sdUsdPattern(client, _m(acc, 'pct2_usd')), ratioPct5: createMetricPattern4(client, _m(acc, 'pct5')), - ratioPct5Usd: createMetricPattern4(client, _m(acc, 'pct5_usd')), + ratioPct5Usd: create_0sdUsdPattern(client, _m(acc, 'pct5_usd')), ratioPct95: createMetricPattern4(client, _m(acc, 'pct95')), - ratioPct95Usd: createMetricPattern4(client, _m(acc, 'pct95_usd')), + ratioPct95Usd: create_0sdUsdPattern(client, _m(acc, 'pct95_usd')), ratioPct98: createMetricPattern4(client, _m(acc, 'pct98')), - ratioPct98Usd: createMetricPattern4(client, _m(acc, 'pct98_usd')), + ratioPct98Usd: create_0sdUsdPattern(client, _m(acc, 'pct98_usd')), ratioPct99: createMetricPattern4(client, _m(acc, 'pct99')), - ratioPct99Usd: createMetricPattern4(client, _m(acc, 'pct99_usd')), + ratioPct99Usd: create_0sdUsdPattern(client, _m(acc, 'pct99_usd')), ratioSd: createRatio1ySdPattern(client, acc), }; } /** * @typedef {Object} PercentilesPattern - * @property {MetricPattern4} pct05 - * @property {MetricPattern4} pct10 - * @property {MetricPattern4} pct15 - * @property {MetricPattern4} pct20 - * @property {MetricPattern4} pct25 - * @property {MetricPattern4} pct30 - * @property {MetricPattern4} pct35 - * @property {MetricPattern4} pct40 - * @property {MetricPattern4} pct45 - * @property {MetricPattern4} pct50 - * @property {MetricPattern4} pct55 - * @property {MetricPattern4} pct60 - * @property {MetricPattern4} pct65 - * @property {MetricPattern4} pct70 - * @property {MetricPattern4} pct75 - * @property {MetricPattern4} pct80 - * @property {MetricPattern4} pct85 - * @property {MetricPattern4} pct90 - * @property {MetricPattern4} pct95 + * @property {_0sdUsdPattern} pct05 + * @property {_0sdUsdPattern} pct10 + * @property {_0sdUsdPattern} pct15 + * @property {_0sdUsdPattern} pct20 + * @property {_0sdUsdPattern} pct25 + * @property {_0sdUsdPattern} pct30 + * @property {_0sdUsdPattern} pct35 + * @property {_0sdUsdPattern} pct40 + * @property {_0sdUsdPattern} pct45 + * @property {_0sdUsdPattern} pct50 + * @property {_0sdUsdPattern} pct55 + * @property {_0sdUsdPattern} pct60 + * @property {_0sdUsdPattern} pct65 + * @property {_0sdUsdPattern} pct70 + * @property {_0sdUsdPattern} pct75 + * @property {_0sdUsdPattern} pct80 + * @property {_0sdUsdPattern} pct85 + * @property {_0sdUsdPattern} pct90 + * @property {_0sdUsdPattern} pct95 */ /** @@ -1731,25 +1743,25 @@ function createActivePriceRatioPattern(client, acc) { */ function createPercentilesPattern(client, acc) { return { - pct05: createMetricPattern4(client, _m(acc, 'pct05')), - pct10: createMetricPattern4(client, _m(acc, 'pct10')), - pct15: createMetricPattern4(client, _m(acc, 'pct15')), - pct20: createMetricPattern4(client, _m(acc, 'pct20')), - pct25: createMetricPattern4(client, _m(acc, 'pct25')), - pct30: createMetricPattern4(client, _m(acc, 'pct30')), - pct35: createMetricPattern4(client, _m(acc, 'pct35')), - pct40: createMetricPattern4(client, _m(acc, 'pct40')), - pct45: createMetricPattern4(client, _m(acc, 'pct45')), - pct50: createMetricPattern4(client, _m(acc, 'pct50')), - pct55: createMetricPattern4(client, _m(acc, 'pct55')), - pct60: createMetricPattern4(client, _m(acc, 'pct60')), - pct65: createMetricPattern4(client, _m(acc, 'pct65')), - pct70: createMetricPattern4(client, _m(acc, 'pct70')), - pct75: createMetricPattern4(client, _m(acc, 'pct75')), - pct80: createMetricPattern4(client, _m(acc, 'pct80')), - pct85: createMetricPattern4(client, _m(acc, 'pct85')), - pct90: createMetricPattern4(client, _m(acc, 'pct90')), - pct95: createMetricPattern4(client, _m(acc, 'pct95')), + pct05: create_0sdUsdPattern(client, _m(acc, 'pct05')), + pct10: create_0sdUsdPattern(client, _m(acc, 'pct10')), + pct15: create_0sdUsdPattern(client, _m(acc, 'pct15')), + pct20: create_0sdUsdPattern(client, _m(acc, 'pct20')), + pct25: create_0sdUsdPattern(client, _m(acc, 'pct25')), + pct30: create_0sdUsdPattern(client, _m(acc, 'pct30')), + pct35: create_0sdUsdPattern(client, _m(acc, 'pct35')), + pct40: create_0sdUsdPattern(client, _m(acc, 'pct40')), + pct45: create_0sdUsdPattern(client, _m(acc, 'pct45')), + pct50: create_0sdUsdPattern(client, _m(acc, 'pct50')), + pct55: create_0sdUsdPattern(client, _m(acc, 'pct55')), + pct60: create_0sdUsdPattern(client, _m(acc, 'pct60')), + pct65: create_0sdUsdPattern(client, _m(acc, 'pct65')), + pct70: create_0sdUsdPattern(client, _m(acc, 'pct70')), + pct75: create_0sdUsdPattern(client, _m(acc, 'pct75')), + pct80: create_0sdUsdPattern(client, _m(acc, 'pct80')), + pct85: create_0sdUsdPattern(client, _m(acc, 'pct85')), + pct90: create_0sdUsdPattern(client, _m(acc, 'pct90')), + pct95: create_0sdUsdPattern(client, _m(acc, 'pct95')), }; } @@ -1849,49 +1861,6 @@ function createAaopoolPattern(client, acc) { }; } -/** - * @template T - * @typedef {Object} LookbackPattern - * @property {MetricPattern4} _10y - * @property {MetricPattern4} _1d - * @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 LookbackPattern pattern node - * @template T - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {LookbackPattern} - */ -function createLookbackPattern(client, acc) { - return { - _10y: createMetricPattern4(client, _m(acc, '10y_ago')), - _1d: createMetricPattern4(client, _m(acc, '1d_ago')), - _1m: createMetricPattern4(client, _m(acc, '1m_ago')), - _1w: createMetricPattern4(client, _m(acc, '1w_ago')), - _1y: createMetricPattern4(client, _m(acc, '1y_ago')), - _2y: createMetricPattern4(client, _m(acc, '2y_ago')), - _3m: createMetricPattern4(client, _m(acc, '3m_ago')), - _3y: createMetricPattern4(client, _m(acc, '3y_ago')), - _4y: createMetricPattern4(client, _m(acc, '4y_ago')), - _5y: createMetricPattern4(client, _m(acc, '5y_ago')), - _6m: createMetricPattern4(client, _m(acc, '6m_ago')), - _6y: createMetricPattern4(client, _m(acc, '6y_ago')), - _8y: createMetricPattern4(client, _m(acc, '8y_ago')), - }; -} - /** * @typedef {Object} PeriodLumpSumStackPattern * @property {_2015Pattern} _10y @@ -1933,7 +1902,7 @@ function createPeriodLumpSumStackPattern(client, acc) { /** * @template T - * @typedef {Object} ClassAveragePricePattern + * @typedef {Object} ClassDaysInLossPattern * @property {MetricPattern4} _2015 * @property {MetricPattern4} _2016 * @property {MetricPattern4} _2017 @@ -1949,32 +1918,32 @@ function createPeriodLumpSumStackPattern(client, acc) { */ /** - * Create a ClassAveragePricePattern pattern node + * Create a ClassDaysInLossPattern pattern node * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {ClassAveragePricePattern} + * @returns {ClassDaysInLossPattern} */ -function createClassAveragePricePattern(client, acc) { +function createClassDaysInLossPattern(client, acc) { return { - _2015: createMetricPattern4(client, _m(acc, '2015_average_price')), - _2016: createMetricPattern4(client, _m(acc, '2016_average_price')), - _2017: createMetricPattern4(client, _m(acc, '2017_average_price')), - _2018: createMetricPattern4(client, _m(acc, '2018_average_price')), - _2019: createMetricPattern4(client, _m(acc, '2019_average_price')), - _2020: createMetricPattern4(client, _m(acc, '2020_average_price')), - _2021: createMetricPattern4(client, _m(acc, '2021_average_price')), - _2022: createMetricPattern4(client, _m(acc, '2022_average_price')), - _2023: createMetricPattern4(client, _m(acc, '2023_average_price')), - _2024: createMetricPattern4(client, _m(acc, '2024_average_price')), - _2025: createMetricPattern4(client, _m(acc, '2025_average_price')), - _2026: createMetricPattern4(client, _m(acc, '2026_average_price')), + _2015: createMetricPattern4(client, _m(acc, '2015_max_return')), + _2016: createMetricPattern4(client, _m(acc, '2016_max_return')), + _2017: createMetricPattern4(client, _m(acc, '2017_max_return')), + _2018: createMetricPattern4(client, _m(acc, '2018_max_return')), + _2019: createMetricPattern4(client, _m(acc, '2019_max_return')), + _2020: createMetricPattern4(client, _m(acc, '2020_max_return')), + _2021: createMetricPattern4(client, _m(acc, '2021_max_return')), + _2022: createMetricPattern4(client, _m(acc, '2022_max_return')), + _2023: createMetricPattern4(client, _m(acc, '2023_max_return')), + _2024: createMetricPattern4(client, _m(acc, '2024_max_return')), + _2025: createMetricPattern4(client, _m(acc, '2025_max_return')), + _2026: createMetricPattern4(client, _m(acc, '2026_max_return')), }; } /** * @template T - * @typedef {Object} PeriodAveragePricePattern + * @typedef {Object} PeriodDaysInLossPattern * @property {MetricPattern4} _10y * @property {MetricPattern4} _1m * @property {MetricPattern4} _1w @@ -1990,13 +1959,13 @@ function createClassAveragePricePattern(client, acc) { */ /** - * Create a PeriodAveragePricePattern pattern node + * Create a PeriodDaysInLossPattern pattern node * @template T * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {PeriodAveragePricePattern} + * @returns {PeriodDaysInLossPattern} */ -function createPeriodAveragePricePattern(client, acc) { +function createPeriodDaysInLossPattern(client, acc) { return { _10y: createMetricPattern4(client, _p('10y', acc)), _1m: createMetricPattern4(client, _p('1m', acc)), @@ -2364,29 +2333,58 @@ function createPhaseDailyCentsPattern(client, acc) { } /** - * @typedef {Object} _0satsPattern2 + * @typedef {Object} UnrealizedPattern + * @property {MetricPattern1} negUnrealizedLoss + * @property {MetricPattern1} netUnrealizedPnl + * @property {ActiveSupplyPattern} supplyInLoss + * @property {ActiveSupplyPattern} supplyInProfit + * @property {MetricPattern1} totalUnrealizedPnl + * @property {MetricPattern1} unrealizedLoss + * @property {MetricPattern1} unrealizedProfit + */ + +/** + * Create a UnrealizedPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {UnrealizedPattern} + */ +function createUnrealizedPattern(client, acc) { + return { + negUnrealizedLoss: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss')), + netUnrealizedPnl: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl')), + supplyInLoss: createActiveSupplyPattern(client, _m(acc, 'supply_in_loss')), + supplyInProfit: createActiveSupplyPattern(client, _m(acc, 'supply_in_profit')), + totalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'total_unrealized_pnl')), + unrealizedLoss: createMetricPattern1(client, _m(acc, 'unrealized_loss')), + unrealizedProfit: createMetricPattern1(client, _m(acc, 'unrealized_profit')), + }; +} + +/** + * @typedef {Object} _10yPattern * @property {ActivityPattern2} activity * @property {CostBasisPattern} costBasis * @property {OutputsPattern} outputs - * @property {RealizedPattern} realized - * @property {RelativePattern4} relative + * @property {RealizedPattern4} realized + * @property {RelativePattern} relative * @property {SupplyPattern2} supply * @property {UnrealizedPattern} unrealized */ /** - * Create a _0satsPattern2 pattern node + * Create a _10yPattern pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {_0satsPattern2} + * @returns {_10yPattern} */ -function create_0satsPattern2(client, acc) { +function create_10yPattern(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')), + realized: createRealizedPattern4(client, acc), + relative: createRelativePattern(client, acc), supply: createSupplyPattern2(client, _m(acc, 'supply')), unrealized: createUnrealizedPattern(client, acc), }; @@ -2421,6 +2419,35 @@ function create_100btcPattern(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} PeriodCagrPattern * @property {MetricPattern4} _10y @@ -2479,64 +2506,6 @@ 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 - * @property {MetricPattern1} netUnrealizedPnl - * @property {ActiveSupplyPattern} supplyInLoss - * @property {ActiveSupplyPattern} supplyInProfit - * @property {MetricPattern1} totalUnrealizedPnl - * @property {MetricPattern1} unrealizedLoss - * @property {MetricPattern1} unrealizedProfit - */ - -/** - * Create a UnrealizedPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {UnrealizedPattern} - */ -function createUnrealizedPattern(client, acc) { - return { - negUnrealizedLoss: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss')), - netUnrealizedPnl: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl')), - supplyInLoss: createActiveSupplyPattern(client, _m(acc, 'supply_in_loss')), - supplyInProfit: createActiveSupplyPattern(client, _m(acc, 'supply_in_profit')), - totalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'total_unrealized_pnl')), - unrealizedLoss: createMetricPattern1(client, _m(acc, 'unrealized_loss')), - unrealizedProfit: createMetricPattern1(client, _m(acc, 'unrealized_profit')), - }; -} - /** * @typedef {Object} ActivityPattern2 * @property {BlockCountPattern} coinblocksDestroyed @@ -2589,8 +2558,8 @@ function createSplitPattern2(client, acc) { /** * @typedef {Object} CostBasisPattern2 - * @property {MetricPattern1} max - * @property {MetricPattern1} min + * @property {ActivePricePattern} max + * @property {ActivePricePattern} min * @property {PercentilesPattern} percentiles */ @@ -2602,8 +2571,8 @@ function createSplitPattern2(client, acc) { */ function createCostBasisPattern2(client, acc) { return { - max: createMetricPattern1(client, _m(acc, 'max_cost_basis')), - min: createMetricPattern1(client, _m(acc, 'min_cost_basis')), + max: createActivePricePattern(client, _m(acc, 'max_cost_basis')), + min: createActivePricePattern(client, _m(acc, 'min_cost_basis')), percentiles: createPercentilesPattern(client, _m(acc, 'cost_basis')), }; } @@ -2629,6 +2598,27 @@ function createActiveSupplyPattern(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} SegwitAdoptionPattern * @property {MetricPattern11} base @@ -2692,27 +2682,6 @@ 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,63 +2703,6 @@ function create_2015Pattern(client, acc) { }; } -/** - * @typedef {Object} RelativePattern4 - * @property {MetricPattern1} supplyInLossRelToOwnSupply - * @property {MetricPattern1} supplyInProfitRelToOwnSupply - */ - -/** - * Create a RelativePattern4 pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {RelativePattern4} - */ -function createRelativePattern4(client, acc) { - return { - supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'loss_rel_to_own_supply')), - supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'profit_rel_to_own_supply')), - }; -} - -/** - * @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 - * @property {MetricPattern1} min - */ - -/** - * Create a CostBasisPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {CostBasisPattern} - */ -function createCostBasisPattern(client, acc) { - return { - max: createMetricPattern1(client, _m(acc, 'max_cost_basis')), - min: createMetricPattern1(client, _m(acc, 'min_cost_basis')), - }; -} - /** * @typedef {Object} _1dReturns1mSdPattern * @property {MetricPattern4} sd @@ -2811,23 +2723,97 @@ function create_1dReturns1mSdPattern(client, acc) { } /** - * @template T - * @typedef {Object} BitcoinPattern2 - * @property {MetricPattern2} cumulative - * @property {MetricPattern1} sum + * @typedef {Object} SupplyPattern2 + * @property {ActiveSupplyPattern} halved + * @property {ActiveSupplyPattern} total */ /** - * Create a BitcoinPattern2 pattern node - * @template T + * Create a SupplyPattern2 pattern node * @param {BrkClientBase} client * @param {string} acc - Accumulated metric name - * @returns {BitcoinPattern2} + * @returns {SupplyPattern2} */ -function createBitcoinPattern2(client, acc) { +function createSupplyPattern2(client, acc) { return { - cumulative: createMetricPattern2(client, _m(acc, 'cumulative')), - sum: createMetricPattern1(client, acc), + halved: createActiveSupplyPattern(client, _m(acc, 'halved')), + total: createActiveSupplyPattern(client, acc), + }; +} + +/** + * @typedef {Object} RelativePattern4 + * @property {MetricPattern1} supplyInLossRelToOwnSupply + * @property {MetricPattern1} supplyInProfitRelToOwnSupply + */ + +/** + * Create a RelativePattern4 pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {RelativePattern4} + */ +function createRelativePattern4(client, acc) { + return { + supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'loss_rel_to_own_supply')), + supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'profit_rel_to_own_supply')), + }; +} + +/** + * @typedef {Object} CostBasisPattern + * @property {ActivePricePattern} max + * @property {ActivePricePattern} min + */ + +/** + * Create a CostBasisPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {CostBasisPattern} + */ +function createCostBasisPattern(client, acc) { + return { + max: createActivePricePattern(client, _m(acc, 'max_cost_basis')), + min: createActivePricePattern(client, _m(acc, 'min_cost_basis')), + }; +} + +/** + * @typedef {Object} _0sdUsdPattern + * @property {MetricPattern4} dollars + * @property {MetricPattern4} sats + */ + +/** + * Create a _0sdUsdPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {_0sdUsdPattern} + */ +function create_0sdUsdPattern(client, acc) { + return { + dollars: createMetricPattern4(client, acc), + sats: createMetricPattern4(client, _m(acc, 'sats')), + }; +} + +/** + * @typedef {Object} ActivePricePattern + * @property {MetricPattern1} dollars + * @property {MetricPattern1} sats + */ + +/** + * Create a ActivePricePattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {ActivePricePattern} + */ +function createActivePricePattern(client, acc) { + return { + dollars: createMetricPattern1(client, acc), + sats: createMetricPattern1(client, _m(acc, 'sats')), }; } @@ -2852,6 +2838,27 @@ function createBlockCountPattern(client, acc) { }; } +/** + * @template T + * @typedef {Object} BitcoinPattern2 + * @property {MetricPattern2} cumulative + * @property {MetricPattern1} sum + */ + +/** + * Create a BitcoinPattern2 pattern node + * @template T + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {BitcoinPattern2} + */ +function createBitcoinPattern2(client, acc) { + return { + cumulative: createMetricPattern2(client, _m(acc, 'cumulative')), + sum: createMetricPattern1(client, acc), + }; +} + /** * @template T * @typedef {Object} SatsPattern @@ -2873,23 +2880,6 @@ function createSatsPattern(client, acc) { }; } -/** - * @typedef {Object} RealizedPriceExtraPattern - * @property {MetricPattern4} ratio - */ - -/** - * Create a RealizedPriceExtraPattern pattern node - * @param {BrkClientBase} client - * @param {string} acc - Accumulated metric name - * @returns {RealizedPriceExtraPattern} - */ -function createRealizedPriceExtraPattern(client, acc) { - return { - ratio: createMetricPattern4(client, acc), - }; -} - /** * @typedef {Object} OutputsPattern * @property {MetricPattern1} utxoCount @@ -2907,6 +2897,23 @@ function createOutputsPattern(client, acc) { }; } +/** + * @typedef {Object} RealizedPriceExtraPattern + * @property {MetricPattern4} ratio + */ + +/** + * Create a RealizedPriceExtraPattern pattern node + * @param {BrkClientBase} client + * @param {string} acc - Accumulated metric name + * @returns {RealizedPriceExtraPattern} + */ +function createRealizedPriceExtraPattern(client, acc) { + return { + ratio: createMetricPattern4(client, acc), + }; +} + // Catalog tree typedefs /** @@ -3092,13 +3099,13 @@ function createOutputsPattern(client, acc) { /** * @typedef {Object} MetricsTree_Cointime_Pricing - * @property {MetricPattern1} activePrice + * @property {ActivePricePattern} activePrice * @property {ActivePriceRatioPattern} activePriceRatio - * @property {MetricPattern1} cointimePrice + * @property {ActivePricePattern} cointimePrice * @property {ActivePriceRatioPattern} cointimePriceRatio - * @property {MetricPattern1} trueMarketMean + * @property {ActivePricePattern} trueMarketMean * @property {ActivePriceRatioPattern} trueMarketMeanRatio - * @property {MetricPattern1} vaultedPrice + * @property {ActivePricePattern} vaultedPrice * @property {ActivePriceRatioPattern} vaultedPriceRatio */ @@ -3289,8 +3296,8 @@ function createOutputsPattern(client, acc) { /** * @typedef {Object} MetricsTree_Distribution_UtxoCohorts_All_CostBasis - * @property {MetricPattern1} max - * @property {MetricPattern1} min + * @property {ActivePricePattern} max + * @property {ActivePricePattern} min * @property {PercentilesPattern} percentiles */ @@ -3692,7 +3699,7 @@ function createOutputsPattern(client, acc) { * @property {MetricsTree_Market_Ath} ath * @property {MetricsTree_Market_Dca} dca * @property {MetricsTree_Market_Indicators} indicators - * @property {LookbackPattern} lookback + * @property {MetricsTree_Market_Lookback} lookback * @property {MetricsTree_Market_MovingAverage} movingAverage * @property {MetricsTree_Market_Range} range * @property {MetricsTree_Market_Returns} returns @@ -3704,36 +3711,52 @@ function createOutputsPattern(client, acc) { * @property {MetricPattern4} daysSincePriceAth * @property {MetricPattern4} maxDaysBetweenPriceAths * @property {MetricPattern4} maxYearsBetweenPriceAths - * @property {MetricPattern1} priceAth + * @property {ActivePricePattern} priceAth * @property {MetricPattern3} priceDrawdown * @property {MetricPattern4} yearsSincePriceAth */ /** * @typedef {Object} MetricsTree_Market_Dca - * @property {ClassAveragePricePattern} classAveragePrice + * @property {MetricsTree_Market_Dca_ClassAveragePrice} 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 {ClassDaysInLossPattern} classMaxReturn * @property {MetricsTree_Market_Dca_ClassReturns} classReturns * @property {MetricsTree_Market_Dca_ClassStack} classStack - * @property {PeriodAveragePricePattern} periodAveragePrice + * @property {MetricsTree_Market_Dca_PeriodAveragePrice} 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 {PeriodDaysInLossPattern} periodDaysInLoss + * @property {PeriodDaysInLossPattern} periodDaysInProfit + * @property {PeriodDaysInLossPattern} periodLumpSumDaysInLoss + * @property {PeriodDaysInLossPattern} periodLumpSumDaysInProfit + * @property {PeriodDaysInLossPattern} periodLumpSumMaxDrawdown + * @property {PeriodDaysInLossPattern} periodLumpSumMaxReturn + * @property {PeriodDaysInLossPattern} periodLumpSumReturns * @property {PeriodLumpSumStackPattern} periodLumpSumStack - * @property {PeriodAveragePricePattern} periodMaxDrawdown - * @property {PeriodAveragePricePattern} periodMaxReturn - * @property {PeriodAveragePricePattern} periodReturns + * @property {PeriodDaysInLossPattern} periodMaxDrawdown + * @property {PeriodDaysInLossPattern} periodMaxReturn + * @property {PeriodDaysInLossPattern} periodReturns * @property {PeriodLumpSumStackPattern} periodStack */ +/** + * @typedef {Object} MetricsTree_Market_Dca_ClassAveragePrice + * @property {_0sdUsdPattern} _2015 + * @property {_0sdUsdPattern} _2016 + * @property {_0sdUsdPattern} _2017 + * @property {_0sdUsdPattern} _2018 + * @property {_0sdUsdPattern} _2019 + * @property {_0sdUsdPattern} _2020 + * @property {_0sdUsdPattern} _2021 + * @property {_0sdUsdPattern} _2022 + * @property {_0sdUsdPattern} _2023 + * @property {_0sdUsdPattern} _2024 + * @property {_0sdUsdPattern} _2025 + * @property {_0sdUsdPattern} _2026 + */ + /** * @typedef {Object} MetricsTree_Market_Dca_ClassDaysInLoss * @property {MetricPattern4} _2015 @@ -3782,22 +3805,6 @@ function createOutputsPattern(client, acc) { * @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 @@ -3830,6 +3837,22 @@ function createOutputsPattern(client, acc) { * @property {_2015Pattern} _2026 */ +/** + * @typedef {Object} MetricsTree_Market_Dca_PeriodAveragePrice + * @property {_0sdUsdPattern} _10y + * @property {_0sdUsdPattern} _1m + * @property {_0sdUsdPattern} _1w + * @property {_0sdUsdPattern} _1y + * @property {_0sdUsdPattern} _2y + * @property {_0sdUsdPattern} _3m + * @property {_0sdUsdPattern} _3y + * @property {_0sdUsdPattern} _4y + * @property {_0sdUsdPattern} _5y + * @property {_0sdUsdPattern} _6m + * @property {_0sdUsdPattern} _6y + * @property {_0sdUsdPattern} _8y + */ + /** * @typedef {Object} MetricsTree_Market_Indicators * @property {MetricPattern6} gini @@ -3853,6 +3876,23 @@ function createOutputsPattern(client, acc) { * @property {MetricPattern6} stochRsiK */ +/** + * @typedef {Object} MetricsTree_Market_Lookback + * @property {_0sdUsdPattern} _10y + * @property {_0sdUsdPattern} _1d + * @property {_0sdUsdPattern} _1m + * @property {_0sdUsdPattern} _1w + * @property {_0sdUsdPattern} _1y + * @property {_0sdUsdPattern} _2y + * @property {_0sdUsdPattern} _3m + * @property {_0sdUsdPattern} _3y + * @property {_0sdUsdPattern} _4y + * @property {_0sdUsdPattern} _5y + * @property {_0sdUsdPattern} _6m + * @property {_0sdUsdPattern} _6y + * @property {_0sdUsdPattern} _8y + */ + /** * @typedef {Object} MetricsTree_Market_MovingAverage * @property {Price111dSmaPattern} price111dSma @@ -3869,8 +3909,8 @@ function createOutputsPattern(client, acc) { * @property {Price111dSmaPattern} price1ySma * @property {Price111dSmaPattern} price200dEma * @property {Price111dSmaPattern} price200dSma - * @property {MetricPattern4} price200dSmaX08 - * @property {MetricPattern4} price200dSmaX24 + * @property {_0sdUsdPattern} price200dSmaX08 + * @property {_0sdUsdPattern} price200dSmaX24 * @property {Price111dSmaPattern} price200wEma * @property {Price111dSmaPattern} price200wSma * @property {Price111dSmaPattern} price21dEma @@ -3881,7 +3921,7 @@ function createOutputsPattern(client, acc) { * @property {Price111dSmaPattern} price34dEma * @property {Price111dSmaPattern} price34dSma * @property {Price111dSmaPattern} price350dSma - * @property {MetricPattern4} price350dSmaX2 + * @property {_0sdUsdPattern} price350dSmaX2 * @property {Price111dSmaPattern} price4yEma * @property {Price111dSmaPattern} price4ySma * @property {Price111dSmaPattern} price55dEma @@ -3894,15 +3934,15 @@ function createOutputsPattern(client, acc) { /** * @typedef {Object} MetricsTree_Market_Range - * @property {MetricPattern4} price1mMax - * @property {MetricPattern4} price1mMin - * @property {MetricPattern4} price1wMax - * @property {MetricPattern4} price1wMin - * @property {MetricPattern4} price1yMax - * @property {MetricPattern4} price1yMin + * @property {_0sdUsdPattern} price1mMax + * @property {_0sdUsdPattern} price1mMin + * @property {_0sdUsdPattern} price1wMax + * @property {_0sdUsdPattern} price1wMin + * @property {_0sdUsdPattern} price1yMax + * @property {_0sdUsdPattern} price1yMin * @property {MetricPattern4} price2wChoppinessIndex - * @property {MetricPattern4} price2wMax - * @property {MetricPattern4} price2wMin + * @property {_0sdUsdPattern} price2wMax + * @property {_0sdUsdPattern} price2wMin * @property {MetricPattern6} priceTrueRange * @property {MetricPattern6} priceTrueRange2wSum */ @@ -4343,7 +4383,7 @@ function createOutputsPattern(client, acc) { * @extends BrkClientBase */ class BrkClient extends BrkClientBase { - VERSION = "v0.1.0-beta.0"; + VERSION = "v0.1.0-beta.1"; INDEXES = /** @type {const} */ ([ "dateindex", @@ -5372,13 +5412,13 @@ class BrkClient extends BrkClientBase { vaultedCap: createMetricPattern1(this, 'vaulted_cap'), }, pricing: { - activePrice: createMetricPattern1(this, 'active_price'), + activePrice: createActivePricePattern(this, 'active_price'), activePriceRatio: createActivePriceRatioPattern(this, 'active_price_ratio'), - cointimePrice: createMetricPattern1(this, 'cointime_price'), + cointimePrice: createActivePricePattern(this, 'cointime_price'), cointimePriceRatio: createActivePriceRatioPattern(this, 'cointime_price_ratio'), - trueMarketMean: createMetricPattern1(this, 'true_market_mean'), + trueMarketMean: createActivePricePattern(this, 'true_market_mean'), trueMarketMeanRatio: createActivePriceRatioPattern(this, 'true_market_mean_ratio'), - vaultedPrice: createMetricPattern1(this, 'vaulted_price'), + vaultedPrice: createActivePricePattern(this, 'vaulted_price'), vaultedPriceRatio: createActivePriceRatioPattern(this, 'vaulted_price_ratio'), }, reserveRisk: { @@ -5513,8 +5553,8 @@ class BrkClient extends BrkClientBase { all: { activity: createActivityPattern2(this, ''), costBasis: { - max: createMetricPattern1(this, 'max_cost_basis'), - min: createMetricPattern1(this, 'min_cost_basis'), + max: createActivePricePattern(this, 'max_cost_basis'), + min: createActivePricePattern(this, 'min_cost_basis'), percentiles: createPercentilesPattern(this, 'cost_basis'), }, outputs: createOutputsPattern(this, 'utxo_count'), @@ -5811,12 +5851,25 @@ class BrkClient extends BrkClientBase { daysSincePriceAth: createMetricPattern4(this, 'days_since_price_ath'), maxDaysBetweenPriceAths: createMetricPattern4(this, 'max_days_between_price_aths'), maxYearsBetweenPriceAths: createMetricPattern4(this, 'max_years_between_price_aths'), - priceAth: createMetricPattern1(this, 'price_ath'), + priceAth: createActivePricePattern(this, 'price_ath'), priceDrawdown: createMetricPattern3(this, 'price_drawdown'), yearsSincePriceAth: createMetricPattern4(this, 'years_since_price_ath'), }, dca: { - classAveragePrice: createClassAveragePricePattern(this, 'dca_class'), + classAveragePrice: { + _2015: create_0sdUsdPattern(this, 'dca_class_2015_average_price'), + _2016: create_0sdUsdPattern(this, 'dca_class_2016_average_price'), + _2017: create_0sdUsdPattern(this, 'dca_class_2017_average_price'), + _2018: create_0sdUsdPattern(this, 'dca_class_2018_average_price'), + _2019: create_0sdUsdPattern(this, 'dca_class_2019_average_price'), + _2020: create_0sdUsdPattern(this, 'dca_class_2020_average_price'), + _2021: create_0sdUsdPattern(this, 'dca_class_2021_average_price'), + _2022: create_0sdUsdPattern(this, 'dca_class_2022_average_price'), + _2023: create_0sdUsdPattern(this, 'dca_class_2023_average_price'), + _2024: create_0sdUsdPattern(this, 'dca_class_2024_average_price'), + _2025: create_0sdUsdPattern(this, 'dca_class_2025_average_price'), + _2026: create_0sdUsdPattern(this, 'dca_class_2026_average_price'), + }, classDaysInLoss: { _2015: createMetricPattern4(this, 'dca_class_2015_days_in_loss'), _2016: createMetricPattern4(this, 'dca_class_2016_days_in_loss'), @@ -5859,20 +5912,7 @@ class BrkClient extends BrkClientBase { _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'), - }, + classMaxReturn: createClassDaysInLossPattern(this, 'dca_class'), classReturns: { _2015: createMetricPattern4(this, 'dca_class_2015_returns'), _2016: createMetricPattern4(this, 'dca_class_2016_returns'), @@ -5901,19 +5941,32 @@ class BrkClient extends BrkClientBase { _2025: create_2015Pattern(this, 'dca_class_2025_stack'), _2026: create_2015Pattern(this, 'dca_class_2026_stack'), }, - periodAveragePrice: createPeriodAveragePricePattern(this, 'dca_average_price'), + periodAveragePrice: { + _10y: create_0sdUsdPattern(this, '10y_dca_average_price'), + _1m: create_0sdUsdPattern(this, '1m_dca_average_price'), + _1w: create_0sdUsdPattern(this, '1w_dca_average_price'), + _1y: create_0sdUsdPattern(this, '1y_dca_average_price'), + _2y: create_0sdUsdPattern(this, '2y_dca_average_price'), + _3m: create_0sdUsdPattern(this, '3m_dca_average_price'), + _3y: create_0sdUsdPattern(this, '3y_dca_average_price'), + _4y: create_0sdUsdPattern(this, '4y_dca_average_price'), + _5y: create_0sdUsdPattern(this, '5y_dca_average_price'), + _6m: create_0sdUsdPattern(this, '6m_dca_average_price'), + _6y: create_0sdUsdPattern(this, '6y_dca_average_price'), + _8y: create_0sdUsdPattern(this, '8y_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'), + periodDaysInLoss: createPeriodDaysInLossPattern(this, 'dca_days_in_loss'), + periodDaysInProfit: createPeriodDaysInLossPattern(this, 'dca_days_in_profit'), + periodLumpSumDaysInLoss: createPeriodDaysInLossPattern(this, 'lump_sum_days_in_loss'), + periodLumpSumDaysInProfit: createPeriodDaysInLossPattern(this, 'lump_sum_days_in_profit'), + periodLumpSumMaxDrawdown: createPeriodDaysInLossPattern(this, 'lump_sum_max_drawdown'), + periodLumpSumMaxReturn: createPeriodDaysInLossPattern(this, 'lump_sum_max_return'), + periodLumpSumReturns: createPeriodDaysInLossPattern(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'), + periodMaxDrawdown: createPeriodDaysInLossPattern(this, 'dca_max_drawdown'), + periodMaxReturn: createPeriodDaysInLossPattern(this, 'dca_max_return'), + periodReturns: createPeriodDaysInLossPattern(this, 'dca_returns'), periodStack: createPeriodLumpSumStackPattern(this, 'dca_stack'), }, indicators: { @@ -5937,7 +5990,21 @@ class BrkClient extends BrkClientBase { stochRsiD: createMetricPattern6(this, 'stoch_rsi_d'), stochRsiK: createMetricPattern6(this, 'stoch_rsi_k'), }, - lookback: createLookbackPattern(this, 'price'), + lookback: { + _10y: create_0sdUsdPattern(this, 'price_10y_ago'), + _1d: create_0sdUsdPattern(this, 'price_1d_ago'), + _1m: create_0sdUsdPattern(this, 'price_1m_ago'), + _1w: create_0sdUsdPattern(this, 'price_1w_ago'), + _1y: create_0sdUsdPattern(this, 'price_1y_ago'), + _2y: create_0sdUsdPattern(this, 'price_2y_ago'), + _3m: create_0sdUsdPattern(this, 'price_3m_ago'), + _3y: create_0sdUsdPattern(this, 'price_3y_ago'), + _4y: create_0sdUsdPattern(this, 'price_4y_ago'), + _5y: create_0sdUsdPattern(this, 'price_5y_ago'), + _6m: create_0sdUsdPattern(this, 'price_6m_ago'), + _6y: create_0sdUsdPattern(this, 'price_6y_ago'), + _8y: create_0sdUsdPattern(this, 'price_8y_ago'), + }, movingAverage: { price111dSma: createPrice111dSmaPattern(this, 'price_111d_sma'), price12dEma: createPrice111dSmaPattern(this, 'price_12d_ema'), @@ -5953,8 +6020,8 @@ class BrkClient extends BrkClientBase { price1ySma: createPrice111dSmaPattern(this, 'price_1y_sma'), price200dEma: createPrice111dSmaPattern(this, 'price_200d_ema'), price200dSma: createPrice111dSmaPattern(this, 'price_200d_sma'), - price200dSmaX08: createMetricPattern4(this, 'price_200d_sma_x0_8'), - price200dSmaX24: createMetricPattern4(this, 'price_200d_sma_x2_4'), + price200dSmaX08: create_0sdUsdPattern(this, 'price_200d_sma_x0_8'), + price200dSmaX24: create_0sdUsdPattern(this, 'price_200d_sma_x2_4'), price200wEma: createPrice111dSmaPattern(this, 'price_200w_ema'), price200wSma: createPrice111dSmaPattern(this, 'price_200w_sma'), price21dEma: createPrice111dSmaPattern(this, 'price_21d_ema'), @@ -5965,7 +6032,7 @@ class BrkClient extends BrkClientBase { price34dEma: createPrice111dSmaPattern(this, 'price_34d_ema'), price34dSma: createPrice111dSmaPattern(this, 'price_34d_sma'), price350dSma: createPrice111dSmaPattern(this, 'price_350d_sma'), - price350dSmaX2: createMetricPattern4(this, 'price_350d_sma_x2'), + price350dSmaX2: create_0sdUsdPattern(this, 'price_350d_sma_x2'), price4yEma: createPrice111dSmaPattern(this, 'price_4y_ema'), price4ySma: createPrice111dSmaPattern(this, 'price_4y_sma'), price55dEma: createPrice111dSmaPattern(this, 'price_55d_ema'), @@ -5976,15 +6043,15 @@ class BrkClient extends BrkClientBase { price8dSma: createPrice111dSmaPattern(this, 'price_8d_sma'), }, range: { - price1mMax: createMetricPattern4(this, 'price_1m_max'), - price1mMin: createMetricPattern4(this, 'price_1m_min'), - price1wMax: createMetricPattern4(this, 'price_1w_max'), - price1wMin: createMetricPattern4(this, 'price_1w_min'), - price1yMax: createMetricPattern4(this, 'price_1y_max'), - price1yMin: createMetricPattern4(this, 'price_1y_min'), + price1mMax: create_0sdUsdPattern(this, 'price_1m_max'), + price1mMin: create_0sdUsdPattern(this, 'price_1m_min'), + price1wMax: create_0sdUsdPattern(this, 'price_1w_max'), + price1wMin: create_0sdUsdPattern(this, 'price_1w_min'), + price1yMax: create_0sdUsdPattern(this, 'price_1y_max'), + price1yMin: create_0sdUsdPattern(this, 'price_1y_min'), price2wChoppinessIndex: createMetricPattern4(this, 'price_2w_choppiness_index'), - price2wMax: createMetricPattern4(this, 'price_2w_max'), - price2wMin: createMetricPattern4(this, 'price_2w_min'), + price2wMax: create_0sdUsdPattern(this, 'price_2w_max'), + price2wMin: create_0sdUsdPattern(this, 'price_2w_min'), priceTrueRange: createMetricPattern6(this, 'price_true_range'), priceTrueRange2wSum: createMetricPattern6(this, 'price_true_range_2w_sum'), }, diff --git a/modules/brk-client/package.json b/modules/brk-client/package.json index 0f12ac9c6..93f8a6ac1 100644 --- a/modules/brk-client/package.json +++ b/modules/brk-client/package.json @@ -34,5 +34,5 @@ "url": "git+https://github.com/bitcoinresearchkit/brk.git" }, "type": "module", - "version": "0.1.0-beta.0" + "version": "0.1.0-beta.1" } diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py index 5f9002139..cce80794d 100644 --- a/packages/brk_client/brk_client/__init__.py +++ b/packages/brk_client/brk_client/__init__.py @@ -107,6 +107,15 @@ PoolSlug = Literal["unknown", "blockfills", "ultimuspool", "terrapool", "luxor", QuarterIndex = int # Transaction locktime RawLockTime = int +# Fractional satoshis (f64) - for representing USD prices in sats +# +# Formula: `sats_fract = usd_value * 100_000_000 / btc_price` +# +# When BTC is $100,000: +# - $1 = 1,000 sats +# - $0.001 = 1 sat +# - $0.0001 = 0.1 sats (fractional) +SatsFract = float SemesterIndex = int # Fixed-size boolean value optimized for on-disk storage (stored as u8) StoredBool = int @@ -1746,7 +1755,7 @@ class RealizedPattern3: self.realized_cap_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')) self.realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_loss')) self.realized_loss_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) - self.realized_price: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_price')) + self.realized_price: ActivePricePattern = ActivePricePattern(client, _m(acc, 'realized_price')) self.realized_price_extra: ActivePriceRatioPattern = ActivePriceRatioPattern(client, _m(acc, 'realized_price_ratio')) self.realized_profit: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_profit')) self.realized_profit_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) @@ -1783,7 +1792,7 @@ class RealizedPattern4: self.realized_cap_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_cap_30d_delta')) self.realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_loss')) self.realized_loss_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) - self.realized_price: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_price')) + self.realized_price: ActivePricePattern = ActivePricePattern(client, _m(acc, 'realized_price')) self.realized_price_extra: RealizedPriceExtraPattern = RealizedPriceExtraPattern(client, _m(acc, 'realized_price_ratio')) self.realized_profit: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_profit')) self.realized_profit_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) @@ -1803,31 +1812,31 @@ class Ratio1ySdPattern: def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self._0sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, '0sd_usd')) + self._0sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, '0sd_usd')) self.m0_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm0_5sd')) - self.m0_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm0_5sd_usd')) + self.m0_5sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'm0_5sd_usd')) self.m1_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm1_5sd')) - self.m1_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm1_5sd_usd')) + self.m1_5sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'm1_5sd_usd')) self.m1sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm1sd')) - self.m1sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm1sd_usd')) + self.m1sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'm1sd_usd')) self.m2_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm2_5sd')) - self.m2_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm2_5sd_usd')) + self.m2_5sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'm2_5sd_usd')) self.m2sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm2sd')) - self.m2sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm2sd_usd')) + self.m2sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'm2sd_usd')) self.m3sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'm3sd')) - self.m3sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'm3sd_usd')) + self.m3sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'm3sd_usd')) self.p0_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p0_5sd')) - self.p0_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p0_5sd_usd')) + self.p0_5sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'p0_5sd_usd')) self.p1_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p1_5sd')) - self.p1_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p1_5sd_usd')) + self.p1_5sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'p1_5sd_usd')) self.p1sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p1sd')) - self.p1sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p1sd_usd')) + self.p1sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'p1sd_usd')) self.p2_5sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p2_5sd')) - self.p2_5sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p2_5sd_usd')) + self.p2_5sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'p2_5sd_usd')) self.p2sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p2sd')) - self.p2sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p2sd_usd')) + self.p2sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'p2sd_usd')) self.p3sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'p3sd')) - self.p3sd_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'p3sd_usd')) + self.p3sd_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'p3sd_usd')) self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd')) self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma')) self.zscore: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'zscore')) @@ -1849,7 +1858,7 @@ class RealizedPattern2: self.realized_cap_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'realized_cap_rel_to_own_market_cap')) self.realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_loss')) self.realized_loss_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) - self.realized_price: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_price')) + self.realized_price: ActivePricePattern = ActivePricePattern(client, _m(acc, 'realized_price')) self.realized_price_extra: ActivePriceRatioPattern = ActivePriceRatioPattern(client, _m(acc, 'realized_price_ratio')) self.realized_profit: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_profit')) self.realized_profit_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) @@ -1881,7 +1890,7 @@ class RealizedPattern: self.realized_cap_30d_delta: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'realized_cap_30d_delta')) self.realized_loss: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_loss')) self.realized_loss_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_loss_rel_to_realized_cap')) - self.realized_price: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'realized_price')) + self.realized_price: ActivePricePattern = ActivePricePattern(client, _m(acc, 'realized_price')) self.realized_price_extra: RealizedPriceExtraPattern = RealizedPriceExtraPattern(client, _m(acc, 'realized_price_ratio')) self.realized_profit: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'realized_profit')) self.realized_profit_rel_to_realized_cap: BlockCountPattern[StoredF32] = BlockCountPattern(client, _m(acc, 'realized_profit_rel_to_realized_cap')) @@ -1901,7 +1910,7 @@ class Price111dSmaPattern: def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.price: MetricPattern4[Dollars] = MetricPattern4(client, acc) + self.price: _0sdUsdPattern = _0sdUsdPattern(client, acc) self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio')) self.ratio_1m_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_1m_sma')) self.ratio_1w_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_1w_sma')) @@ -1909,17 +1918,17 @@ class Price111dSmaPattern: self.ratio_2y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, 'ratio_2y')) self.ratio_4y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, 'ratio_4y')) self.ratio_pct1: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct1')) - self.ratio_pct1_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct1_usd')) + self.ratio_pct1_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'ratio_pct1_usd')) self.ratio_pct2: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct2')) - self.ratio_pct2_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct2_usd')) + self.ratio_pct2_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'ratio_pct2_usd')) self.ratio_pct5: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct5')) - self.ratio_pct5_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct5_usd')) + self.ratio_pct5_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'ratio_pct5_usd')) self.ratio_pct95: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct95')) - self.ratio_pct95_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct95_usd')) + self.ratio_pct95_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'ratio_pct95_usd')) self.ratio_pct98: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct98')) - self.ratio_pct98_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct98_usd')) + self.ratio_pct98_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'ratio_pct98_usd')) self.ratio_pct99: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'ratio_pct99')) - self.ratio_pct99_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct99_usd')) + self.ratio_pct99_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'ratio_pct99_usd')) self.ratio_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, 'ratio')) class ActivePriceRatioPattern: @@ -1934,17 +1943,17 @@ class ActivePriceRatioPattern: self.ratio_2y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '2y')) self.ratio_4y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '4y')) self.ratio_pct1: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct1')) - self.ratio_pct1_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct1_usd')) + self.ratio_pct1_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct1_usd')) self.ratio_pct2: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct2')) - self.ratio_pct2_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct2_usd')) + self.ratio_pct2_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct2_usd')) self.ratio_pct5: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct5')) - self.ratio_pct5_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct5_usd')) + self.ratio_pct5_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct5_usd')) self.ratio_pct95: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct95')) - self.ratio_pct95_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct95_usd')) + self.ratio_pct95_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct95_usd')) self.ratio_pct98: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct98')) - self.ratio_pct98_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct98_usd')) + self.ratio_pct98_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct98_usd')) self.ratio_pct99: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct99')) - self.ratio_pct99_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct99_usd')) + self.ratio_pct99_usd: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct99_usd')) self.ratio_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, acc) class PercentilesPattern: @@ -1952,25 +1961,25 @@ class PercentilesPattern: def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.pct05: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct05')) - self.pct10: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct10')) - self.pct15: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct15')) - self.pct20: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct20')) - self.pct25: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct25')) - self.pct30: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct30')) - self.pct35: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct35')) - self.pct40: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct40')) - self.pct45: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct45')) - self.pct50: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct50')) - self.pct55: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct55')) - self.pct60: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct60')) - self.pct65: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct65')) - self.pct70: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct70')) - self.pct75: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct75')) - self.pct80: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct80')) - self.pct85: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct85')) - self.pct90: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct90')) - self.pct95: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct95')) + self.pct05: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct05')) + self.pct10: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct10')) + self.pct15: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct15')) + self.pct20: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct20')) + self.pct25: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct25')) + self.pct30: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct30')) + self.pct35: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct35')) + self.pct40: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct40')) + self.pct45: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct45')) + self.pct50: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct50')) + self.pct55: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct55')) + self.pct60: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct60')) + self.pct65: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct65')) + self.pct70: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct70')) + self.pct75: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct75')) + self.pct80: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct80')) + self.pct85: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct85')) + self.pct90: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct90')) + self.pct95: _0sdUsdPattern = _0sdUsdPattern(client, _m(acc, 'pct95')) class RelativePattern5: """Pattern struct for repeated tree structure.""" @@ -2017,25 +2026,6 @@ class AaopoolPattern: self.fee: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, _m(acc, 'fee')) self.subsidy: UnclaimedRewardsPattern = UnclaimedRewardsPattern(client, _m(acc, 'subsidy')) -class LookbackPattern(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, _m(acc, '10y_ago')) - self._1d: MetricPattern4[T] = MetricPattern4(client, _m(acc, '1d_ago')) - self._1m: MetricPattern4[T] = MetricPattern4(client, _m(acc, '1m_ago')) - self._1w: MetricPattern4[T] = MetricPattern4(client, _m(acc, '1w_ago')) - self._1y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '1y_ago')) - self._2y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2y_ago')) - self._3m: MetricPattern4[T] = MetricPattern4(client, _m(acc, '3m_ago')) - self._3y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '3y_ago')) - self._4y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '4y_ago')) - self._5y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '5y_ago')) - self._6m: MetricPattern4[T] = MetricPattern4(client, _m(acc, '6m_ago')) - self._6y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '6y_ago')) - self._8y: MetricPattern4[T] = MetricPattern4(client, _m(acc, '8y_ago')) - class PeriodLumpSumStackPattern: """Pattern struct for repeated tree structure.""" @@ -2054,25 +2044,25 @@ class PeriodLumpSumStackPattern: self._6y: _2015Pattern = _2015Pattern(client, _p('6y', acc)) self._8y: _2015Pattern = _2015Pattern(client, _p('8y', acc)) -class ClassAveragePricePattern(Generic[T]): +class ClassDaysInLossPattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self._2015: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2015_average_price')) - self._2016: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2016_average_price')) - self._2017: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2017_average_price')) - self._2018: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2018_average_price')) - self._2019: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2019_average_price')) - self._2020: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2020_average_price')) - self._2021: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2021_average_price')) - self._2022: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2022_average_price')) - self._2023: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2023_average_price')) - self._2024: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2024_average_price')) - self._2025: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2025_average_price')) - self._2026: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2026_average_price')) + self._2015: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2015_max_return')) + self._2016: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2016_max_return')) + self._2017: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2017_max_return')) + self._2018: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2018_max_return')) + self._2019: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2019_max_return')) + self._2020: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2020_max_return')) + self._2021: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2021_max_return')) + self._2022: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2022_max_return')) + self._2023: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2023_max_return')) + self._2024: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2024_max_return')) + self._2025: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2025_max_return')) + self._2026: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2026_max_return')) -class PeriodAveragePricePattern(Generic[T]): +class PeriodDaysInLossPattern(Generic[T]): """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): @@ -2245,7 +2235,20 @@ class PhaseDailyCentsPattern(Generic[T]): self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75')) self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90')) -class _0satsPattern2: +class UnrealizedPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.neg_unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss')) + self.net_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl')) + self.supply_in_loss: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'supply_in_loss')) + self.supply_in_profit: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'supply_in_profit')) + self.total_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_unrealized_pnl')) + 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): @@ -2253,8 +2256,8 @@ class _0satsPattern2: 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.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) @@ -2271,6 +2274,19 @@ class _100btcPattern: self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply')) self.unrealized: UnrealizedPattern = UnrealizedPattern(client, 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 PeriodCagrPattern: """Pattern struct for repeated tree structure.""" @@ -2297,32 +2313,6 @@ 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.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.neg_unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss')) - self.net_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl')) - self.supply_in_loss: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'supply_in_loss')) - self.supply_in_profit: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'supply_in_profit')) - self.total_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_unrealized_pnl')) - self.unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_loss')) - self.unrealized_profit: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_profit')) - class ActivityPattern2: """Pattern struct for repeated tree structure.""" @@ -2349,8 +2339,8 @@ class CostBasisPattern2: def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis')) - self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis')) + self.max: ActivePricePattern = ActivePricePattern(client, _m(acc, 'max_cost_basis')) + self.min: ActivePricePattern = ActivePricePattern(client, _m(acc, 'min_cost_basis')) self.percentiles: PercentilesPattern = PercentilesPattern(client, _m(acc, 'cost_basis')) class ActiveSupplyPattern: @@ -2362,6 +2352,15 @@ class ActiveSupplyPattern: self.dollars: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'usd')) self.sats: MetricPattern1[Sats] = MetricPattern1(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 SegwitAdoptionPattern: """Pattern struct for repeated tree structure.""" @@ -2389,15 +2388,6 @@ 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,13 +2397,13 @@ class _2015Pattern: self.dollars: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'usd')) self.sats: MetricPattern4[Sats] = MetricPattern4(client, acc) -class RelativePattern4: +class _1dReturns1mSdPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - 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')) + self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd')) + self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma')) class SupplyPattern2: """Pattern struct for repeated tree structure.""" @@ -2423,29 +2413,37 @@ class SupplyPattern2: self.halved: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'halved')) self.total: ActiveSupplyPattern = ActiveSupplyPattern(client, acc) +class RelativePattern4: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + 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 CostBasisPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis')) - self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis')) + self.max: ActivePricePattern = ActivePricePattern(client, _m(acc, 'max_cost_basis')) + self.min: ActivePricePattern = ActivePricePattern(client, _m(acc, 'min_cost_basis')) -class _1dReturns1mSdPattern: +class _0sdUsdPattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd')) - self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma')) + self.dollars: MetricPattern4[Dollars] = MetricPattern4(client, acc) + self.sats: MetricPattern4[SatsFract] = MetricPattern4(client, _m(acc, 'sats')) -class BitcoinPattern2(Generic[T]): +class ActivePricePattern: """Pattern struct for repeated tree structure.""" def __init__(self, client: BrkClientBase, acc: str): """Create pattern node with accumulated metric name.""" - self.cumulative: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'cumulative')) - self.sum: MetricPattern1[T] = MetricPattern1(client, acc) + self.dollars: MetricPattern1[Dollars] = MetricPattern1(client, acc) + self.sats: MetricPattern1[SatsFract] = MetricPattern1(client, _m(acc, 'sats')) class BlockCountPattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2455,6 +2453,14 @@ class BlockCountPattern(Generic[T]): self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative')) self.sum: MetricPattern1[T] = MetricPattern1(client, acc) +class BitcoinPattern2(Generic[T]): + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.cumulative: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'cumulative')) + self.sum: MetricPattern1[T] = MetricPattern1(client, acc) + class SatsPattern(Generic[T]): """Pattern struct for repeated tree structure.""" @@ -2463,13 +2469,6 @@ class SatsPattern(Generic[T]): self.ohlc: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'ohlc')) self.split: SplitPattern2[T] = SplitPattern2(client, acc) -class RealizedPriceExtraPattern: - """Pattern struct for repeated tree structure.""" - - def __init__(self, client: BrkClientBase, acc: str): - """Create pattern node with accumulated metric name.""" - self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, acc) - class OutputsPattern: """Pattern struct for repeated tree structure.""" @@ -2477,6 +2476,13 @@ class OutputsPattern: """Create pattern node with accumulated metric name.""" self.utxo_count: MetricPattern1[StoredU64] = MetricPattern1(client, acc) +class RealizedPriceExtraPattern: + """Pattern struct for repeated tree structure.""" + + def __init__(self, client: BrkClientBase, acc: str): + """Create pattern node with accumulated metric name.""" + self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, acc) + # Metrics tree classes class MetricsTree_Addresses: @@ -2647,13 +2653,13 @@ class MetricsTree_Cointime_Pricing: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.active_price: MetricPattern1[Dollars] = MetricPattern1(client, 'active_price') + self.active_price: ActivePricePattern = ActivePricePattern(client, 'active_price') self.active_price_ratio: ActivePriceRatioPattern = ActivePriceRatioPattern(client, 'active_price_ratio') - self.cointime_price: MetricPattern1[Dollars] = MetricPattern1(client, 'cointime_price') + self.cointime_price: ActivePricePattern = ActivePricePattern(client, 'cointime_price') self.cointime_price_ratio: ActivePriceRatioPattern = ActivePriceRatioPattern(client, 'cointime_price_ratio') - self.true_market_mean: MetricPattern1[Dollars] = MetricPattern1(client, 'true_market_mean') + self.true_market_mean: ActivePricePattern = ActivePricePattern(client, 'true_market_mean') self.true_market_mean_ratio: ActivePriceRatioPattern = ActivePriceRatioPattern(client, 'true_market_mean_ratio') - self.vaulted_price: MetricPattern1[Dollars] = MetricPattern1(client, 'vaulted_price') + self.vaulted_price: ActivePricePattern = ActivePricePattern(client, 'vaulted_price') self.vaulted_price_ratio: ActivePriceRatioPattern = ActivePriceRatioPattern(client, 'vaulted_price_ratio') class MetricsTree_Cointime_ReserveRisk: @@ -2829,8 +2835,8 @@ class MetricsTree_Distribution_UtxoCohorts_All_CostBasis: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.max: MetricPattern1[Dollars] = MetricPattern1(client, 'max_cost_basis') - self.min: MetricPattern1[Dollars] = MetricPattern1(client, 'min_cost_basis') + self.max: ActivePricePattern = ActivePricePattern(client, 'max_cost_basis') + self.min: ActivePricePattern = ActivePricePattern(client, 'min_cost_basis') self.percentiles: PercentilesPattern = PercentilesPattern(client, 'cost_basis') class MetricsTree_Distribution_UtxoCohorts_All_Relative: @@ -3316,10 +3322,27 @@ class MetricsTree_Market_Ath: self.days_since_price_ath: MetricPattern4[StoredU16] = MetricPattern4(client, 'days_since_price_ath') self.max_days_between_price_aths: MetricPattern4[StoredU16] = MetricPattern4(client, 'max_days_between_price_aths') self.max_years_between_price_aths: MetricPattern4[StoredF32] = MetricPattern4(client, 'max_years_between_price_aths') - self.price_ath: MetricPattern1[Dollars] = MetricPattern1(client, 'price_ath') + self.price_ath: ActivePricePattern = ActivePricePattern(client, 'price_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_ClassAveragePrice: + """Metrics tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self._2015: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2015_average_price') + self._2016: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2016_average_price') + self._2017: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2017_average_price') + self._2018: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2018_average_price') + self._2019: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2019_average_price') + self._2020: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2020_average_price') + self._2021: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2021_average_price') + self._2022: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2022_average_price') + self._2023: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2023_average_price') + self._2024: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2024_average_price') + self._2025: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2025_average_price') + self._2026: _0sdUsdPattern = _0sdUsdPattern(client, 'dca_class_2026_average_price') + class MetricsTree_Market_Dca_ClassDaysInLoss: """Metrics tree node.""" @@ -3371,23 +3394,6 @@ class MetricsTree_Market_Dca_ClassMaxDrawdown: 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.""" @@ -3422,30 +3428,47 @@ class MetricsTree_Market_Dca_ClassStack: self._2025: _2015Pattern = _2015Pattern(client, 'dca_class_2025_stack') self._2026: _2015Pattern = _2015Pattern(client, 'dca_class_2026_stack') +class MetricsTree_Market_Dca_PeriodAveragePrice: + """Metrics tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self._10y: _0sdUsdPattern = _0sdUsdPattern(client, '10y_dca_average_price') + self._1m: _0sdUsdPattern = _0sdUsdPattern(client, '1m_dca_average_price') + self._1w: _0sdUsdPattern = _0sdUsdPattern(client, '1w_dca_average_price') + self._1y: _0sdUsdPattern = _0sdUsdPattern(client, '1y_dca_average_price') + self._2y: _0sdUsdPattern = _0sdUsdPattern(client, '2y_dca_average_price') + self._3m: _0sdUsdPattern = _0sdUsdPattern(client, '3m_dca_average_price') + self._3y: _0sdUsdPattern = _0sdUsdPattern(client, '3y_dca_average_price') + self._4y: _0sdUsdPattern = _0sdUsdPattern(client, '4y_dca_average_price') + self._5y: _0sdUsdPattern = _0sdUsdPattern(client, '5y_dca_average_price') + self._6m: _0sdUsdPattern = _0sdUsdPattern(client, '6m_dca_average_price') + self._6y: _0sdUsdPattern = _0sdUsdPattern(client, '6y_dca_average_price') + self._8y: _0sdUsdPattern = _0sdUsdPattern(client, '8y_dca_average_price') + class MetricsTree_Market_Dca: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.class_average_price: ClassAveragePricePattern[Dollars] = ClassAveragePricePattern(client, 'dca_class') + self.class_average_price: MetricsTree_Market_Dca_ClassAveragePrice = MetricsTree_Market_Dca_ClassAveragePrice(client) 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_max_return: ClassDaysInLossPattern[StoredF32] = ClassDaysInLossPattern(client, 'dca_class') 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_average_price: MetricsTree_Market_Dca_PeriodAveragePrice = MetricsTree_Market_Dca_PeriodAveragePrice(client) 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_days_in_loss: PeriodDaysInLossPattern[StoredU32] = PeriodDaysInLossPattern(client, 'dca_days_in_loss') + self.period_days_in_profit: PeriodDaysInLossPattern[StoredU32] = PeriodDaysInLossPattern(client, 'dca_days_in_profit') + self.period_lump_sum_days_in_loss: PeriodDaysInLossPattern[StoredU32] = PeriodDaysInLossPattern(client, 'lump_sum_days_in_loss') + self.period_lump_sum_days_in_profit: PeriodDaysInLossPattern[StoredU32] = PeriodDaysInLossPattern(client, 'lump_sum_days_in_profit') + self.period_lump_sum_max_drawdown: PeriodDaysInLossPattern[StoredF32] = PeriodDaysInLossPattern(client, 'lump_sum_max_drawdown') + self.period_lump_sum_max_return: PeriodDaysInLossPattern[StoredF32] = PeriodDaysInLossPattern(client, 'lump_sum_max_return') + self.period_lump_sum_returns: PeriodDaysInLossPattern[StoredF32] = PeriodDaysInLossPattern(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_max_drawdown: PeriodDaysInLossPattern[StoredF32] = PeriodDaysInLossPattern(client, 'dca_max_drawdown') + self.period_max_return: PeriodDaysInLossPattern[StoredF32] = PeriodDaysInLossPattern(client, 'dca_max_return') + self.period_returns: PeriodDaysInLossPattern[StoredF32] = PeriodDaysInLossPattern(client, 'dca_returns') self.period_stack: PeriodLumpSumStackPattern = PeriodLumpSumStackPattern(client, 'dca_stack') class MetricsTree_Market_Indicators: @@ -3472,6 +3495,24 @@ class MetricsTree_Market_Indicators: self.stoch_rsi_d: MetricPattern6[StoredF32] = MetricPattern6(client, 'stoch_rsi_d') self.stoch_rsi_k: MetricPattern6[StoredF32] = MetricPattern6(client, 'stoch_rsi_k') +class MetricsTree_Market_Lookback: + """Metrics tree node.""" + + def __init__(self, client: BrkClientBase, base_path: str = ''): + self._10y: _0sdUsdPattern = _0sdUsdPattern(client, 'price_10y_ago') + self._1d: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1d_ago') + self._1m: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1m_ago') + self._1w: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1w_ago') + self._1y: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1y_ago') + self._2y: _0sdUsdPattern = _0sdUsdPattern(client, 'price_2y_ago') + self._3m: _0sdUsdPattern = _0sdUsdPattern(client, 'price_3m_ago') + self._3y: _0sdUsdPattern = _0sdUsdPattern(client, 'price_3y_ago') + self._4y: _0sdUsdPattern = _0sdUsdPattern(client, 'price_4y_ago') + self._5y: _0sdUsdPattern = _0sdUsdPattern(client, 'price_5y_ago') + self._6m: _0sdUsdPattern = _0sdUsdPattern(client, 'price_6m_ago') + self._6y: _0sdUsdPattern = _0sdUsdPattern(client, 'price_6y_ago') + self._8y: _0sdUsdPattern = _0sdUsdPattern(client, 'price_8y_ago') + class MetricsTree_Market_MovingAverage: """Metrics tree node.""" @@ -3490,8 +3531,8 @@ class MetricsTree_Market_MovingAverage: self.price_1y_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_1y_sma') self.price_200d_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_200d_ema') self.price_200d_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_200d_sma') - self.price_200d_sma_x0_8: MetricPattern4[Dollars] = MetricPattern4(client, 'price_200d_sma_x0_8') - self.price_200d_sma_x2_4: MetricPattern4[Dollars] = MetricPattern4(client, 'price_200d_sma_x2_4') + self.price_200d_sma_x0_8: _0sdUsdPattern = _0sdUsdPattern(client, 'price_200d_sma_x0_8') + self.price_200d_sma_x2_4: _0sdUsdPattern = _0sdUsdPattern(client, 'price_200d_sma_x2_4') self.price_200w_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_200w_ema') self.price_200w_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_200w_sma') self.price_21d_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_21d_ema') @@ -3502,7 +3543,7 @@ class MetricsTree_Market_MovingAverage: self.price_34d_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_34d_ema') self.price_34d_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_34d_sma') self.price_350d_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_350d_sma') - self.price_350d_sma_x2: MetricPattern4[Dollars] = MetricPattern4(client, 'price_350d_sma_x2') + self.price_350d_sma_x2: _0sdUsdPattern = _0sdUsdPattern(client, 'price_350d_sma_x2') self.price_4y_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_4y_ema') self.price_4y_sma: Price111dSmaPattern = Price111dSmaPattern(client, 'price_4y_sma') self.price_55d_ema: Price111dSmaPattern = Price111dSmaPattern(client, 'price_55d_ema') @@ -3516,15 +3557,15 @@ class MetricsTree_Market_Range: """Metrics tree node.""" def __init__(self, client: BrkClientBase, base_path: str = ''): - self.price_1m_max: MetricPattern4[Dollars] = MetricPattern4(client, 'price_1m_max') - self.price_1m_min: MetricPattern4[Dollars] = MetricPattern4(client, 'price_1m_min') - self.price_1w_max: MetricPattern4[Dollars] = MetricPattern4(client, 'price_1w_max') - self.price_1w_min: MetricPattern4[Dollars] = MetricPattern4(client, 'price_1w_min') - self.price_1y_max: MetricPattern4[Dollars] = MetricPattern4(client, 'price_1y_max') - self.price_1y_min: MetricPattern4[Dollars] = MetricPattern4(client, 'price_1y_min') + self.price_1m_max: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1m_max') + self.price_1m_min: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1m_min') + self.price_1w_max: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1w_max') + self.price_1w_min: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1w_min') + self.price_1y_max: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1y_max') + self.price_1y_min: _0sdUsdPattern = _0sdUsdPattern(client, 'price_1y_min') self.price_2w_choppiness_index: MetricPattern4[StoredF32] = MetricPattern4(client, 'price_2w_choppiness_index') - self.price_2w_max: MetricPattern4[Dollars] = MetricPattern4(client, 'price_2w_max') - self.price_2w_min: MetricPattern4[Dollars] = MetricPattern4(client, 'price_2w_min') + self.price_2w_max: _0sdUsdPattern = _0sdUsdPattern(client, 'price_2w_max') + self.price_2w_min: _0sdUsdPattern = _0sdUsdPattern(client, 'price_2w_min') self.price_true_range: MetricPattern6[StoredF32] = MetricPattern6(client, 'price_true_range') self.price_true_range_2w_sum: MetricPattern6[StoredF32] = MetricPattern6(client, 'price_true_range_2w_sum') @@ -3581,7 +3622,7 @@ class MetricsTree_Market: self.ath: MetricsTree_Market_Ath = MetricsTree_Market_Ath(client) self.dca: MetricsTree_Market_Dca = MetricsTree_Market_Dca(client) self.indicators: MetricsTree_Market_Indicators = MetricsTree_Market_Indicators(client) - self.lookback: LookbackPattern[Dollars] = LookbackPattern(client, 'price') + self.lookback: MetricsTree_Market_Lookback = MetricsTree_Market_Lookback(client) self.moving_average: MetricsTree_Market_MovingAverage = MetricsTree_Market_MovingAverage(client) self.range: MetricsTree_Market_Range = MetricsTree_Market_Range(client) self.returns: MetricsTree_Market_Returns = MetricsTree_Market_Returns(client) @@ -4023,7 +4064,7 @@ class MetricsTree: class BrkClient(BrkClientBase): """Main BRK client with metrics tree and API methods.""" - VERSION = "v0.1.0-beta.0" + VERSION = "v0.1.0-beta.1" INDEXES = [ "dateindex", diff --git a/packages/brk_client/pyproject.toml b/packages/brk_client/pyproject.toml index fd72d6f51..10f07a953 100644 --- a/packages/brk_client/pyproject.toml +++ b/packages/brk_client/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "brk-client" -version = "0.1.0-beta.0" +version = "0.1.0-beta.1" description = "Python client for the Bitcoin Research Kit" readme = "README.md" requires-python = ">=3.9" diff --git a/website/scripts/options/chain.js b/website/scripts/options/chain.js index 3d586a2bf..6ff5b5067 100644 --- a/website/scripts/options/chain.js +++ b/website/scripts/options/chain.js @@ -5,6 +5,36 @@ import { priceLine } from "./constants.js"; import { line, baseline, dots } from "./series.js"; import { satsBtcUsd } from "./shared.js"; +/** Major pools to show in Compare section (by current hashrate dominance) */ +const MAJOR_POOL_IDS = [ + "foundryusa", // ~32% - largest pool + "antpool", // ~18% - Bitmain-owned + "viabtc", // ~14% - independent + "f2pool", // ~10% - one of the oldest pools + "marapool", // MARA Holdings + "braiinspool", // formerly Slush Pool + "spiderpool", // growing Asian pool + "ocean", // decentralization-focused +]; + +/** + * AntPool & friends - pools sharing AntPool's block templates + * Based on b10c's research: https://b10c.me/blog/015-bitcoin-mining-centralization/ + * Collectively ~35-40% of network hashrate + */ +const ANTPOOL_AND_FRIENDS_IDS = [ + "antpool", // Bitmain-owned, template source + "poolin", // shares AntPool templates + "btccom", // CloverPool (formerly BTC.com) + "braiinspool", // shares AntPool templates + "ultimuspool", // shares AntPool templates + "binancepool", // shares AntPool templates + "secpool", // shares AntPool templates + "sigmapoolcom", // SigmaPool + "rawpool", // shares AntPool templates + "luxor", // shares AntPool templates +]; + /** * Create Chain section * @param {PartialContext} ctx @@ -77,7 +107,7 @@ export function createChainSection(ctx) { }), line({ metric: pool.dominance, - name: "all time", + name: "All Time", color: colors.teal, unit: Unit.percentage, defaultActive: false, @@ -233,7 +263,7 @@ export function createChainSection(ctx) { ...fromSizePattern(blocks.size, Unit.bytes), line({ metric: blocks.totalSize, - name: "total", + name: "Total", color: colors.purple, unit: Unit.bytes, defaultActive: false, @@ -242,14 +272,14 @@ export function createChainSection(ctx) { ...fromFullnessPattern(blocks.weight, Unit.wu), line({ metric: blocks.weight.sum, - name: "sum", + name: "Sum", color: colors.stat.sum, unit: Unit.wu, defaultActive: false, }), line({ metric: blocks.weight.cumulative, - name: "cumulative", + name: "Cumulative", color: colors.stat.cumulative, unit: Unit.wu, defaultActive: false, @@ -297,27 +327,7 @@ export function createChainSection(ctx) { defaultActive: false, }, ), - line({ - metric: transactions.volume.annualizedVolume.bitcoin, - name: "annualized", - color: colors.red, - unit: Unit.btc, - defaultActive: false, - }), - line({ - metric: transactions.volume.annualizedVolume.sats, - name: "annualized", - color: colors.red, - unit: Unit.sats, - defaultActive: false, - }), - line({ - metric: transactions.volume.annualizedVolume.dollars, - name: "annualized", - color: colors.lime, - unit: Unit.usd, - defaultActive: false, - }), + ...satsBtcUsd(transactions.volume.annualizedVolume, "Annualized", colors.red, { defaultActive: false }), ], }, { @@ -366,12 +376,12 @@ export function createChainSection(ctx) { bottom: [ line({ metric: supply.velocity.btc, - name: "bitcoin", + name: "Bitcoin", unit: Unit.ratio, }), line({ metric: supply.velocity.usd, - name: "dollars", + name: "Dollars", color: colors.emerald, unit: Unit.ratio, }), @@ -489,18 +499,18 @@ export function createChainSection(ctx) { name: "SegWit", title: "SegWit Adoption", bottom: [ - line({ metric: scripts.count.segwitAdoption.base, name: "base", unit: Unit.percentage }), - line({ metric: scripts.count.segwitAdoption.sum, name: "sum", color: colors.stat.sum, unit: Unit.percentage }), - line({ metric: scripts.count.segwitAdoption.cumulative, name: "cumulative", color: colors.stat.cumulative, unit: Unit.percentage, defaultActive: false }), + line({ metric: scripts.count.segwitAdoption.base, name: "Base", unit: Unit.percentage }), + line({ metric: scripts.count.segwitAdoption.sum, name: "Sum", color: colors.stat.sum, unit: Unit.percentage }), + line({ metric: scripts.count.segwitAdoption.cumulative, name: "Cumulative", color: colors.stat.cumulative, unit: Unit.percentage, defaultActive: false }), ], }, { name: "Taproot", title: "Taproot Adoption", bottom: [ - line({ metric: scripts.count.taprootAdoption.base, name: "base", unit: Unit.percentage }), - line({ metric: scripts.count.taprootAdoption.sum, name: "sum", color: colors.stat.sum, unit: Unit.percentage }), - line({ metric: scripts.count.taprootAdoption.cumulative, name: "cumulative", color: colors.stat.cumulative, unit: Unit.percentage, defaultActive: false }), + line({ metric: scripts.count.taprootAdoption.base, name: "Base", unit: Unit.percentage }), + line({ metric: scripts.count.taprootAdoption.sum, name: "Sum", color: colors.stat.sum, unit: Unit.percentage }), + line({ metric: scripts.count.taprootAdoption.cumulative, name: "Cumulative", color: colors.stat.cumulative, unit: Unit.percentage, defaultActive: false }), ], }, ], @@ -750,6 +760,7 @@ export function createChainSection(ctx) { { name: "Mining", tree: [ + // Hashrate { name: "Hashrate", title: "Network Hashrate", @@ -796,123 +807,145 @@ export function createChainSection(ctx) { }), ], }, + + // Difficulty group { name: "Difficulty", - title: "Network Difficulty", - bottom: [ - line({ - metric: blocks.difficulty.raw, - name: "Difficulty", - unit: Unit.difficulty, - }), - line({ - metric: blocks.difficulty.epoch, - name: "Epoch", - color: colors.teal, - unit: Unit.epoch, - }), - line({ - metric: blocks.difficulty.blocksBeforeNextAdjustment, - name: "before next", - color: colors.indigo, - unit: Unit.blocks, - }), - line({ - metric: blocks.difficulty.daysBeforeNextAdjustment, - name: "before next", - color: colors.purple, - unit: Unit.days, - }), + tree: [ + { + name: "Level", + title: "Network Difficulty", + bottom: [ + line({ + metric: blocks.difficulty.raw, + name: "Difficulty", + unit: Unit.difficulty, + }), + line({ + metric: blocks.difficulty.epoch, + name: "Epoch", + color: colors.teal, + unit: Unit.epoch, + }), + ], + }, + { + name: "Adjustment", + title: "Difficulty Adjustment", + bottom: [ + baseline({ + metric: blocks.difficulty.adjustment, + name: "Difficulty Change", + unit: Unit.percentage, + }), + priceLine({ ctx, number: 0, unit: Unit.percentage }), + ], + }, + { + name: "Countdown", + title: "Next Adjustment", + bottom: [ + line({ + metric: blocks.difficulty.blocksBeforeNextAdjustment, + name: "Before Next", + color: colors.indigo, + unit: Unit.blocks, + }), + line({ + metric: blocks.difficulty.daysBeforeNextAdjustment, + name: "Before Next", + color: colors.purple, + unit: Unit.days, + }), + ], + }, ], }, + + // Economics group { - name: "Adjustment", - title: "Difficulty Adjustment", - bottom: [ - baseline({ - metric: blocks.difficulty.adjustment, - name: "Difficulty Change", - unit: Unit.percentage, - }), - priceLine({ ctx, number: 0, unit: Unit.percentage }), - ], - }, - { - name: "Hash Price", - title: "Hash Price", - bottom: [ - line({ - metric: blocks.mining.hashPriceThs, - name: "TH/s", - color: colors.emerald, - unit: Unit.usdPerThsPerDay, - }), - line({ - metric: blocks.mining.hashPricePhs, - name: "PH/s", - color: colors.emerald, - unit: Unit.usdPerPhsPerDay, - }), - line({ - metric: blocks.mining.hashPriceRebound, - name: "Rebound", - color: colors.yellow, - unit: Unit.percentage, - }), - line({ - metric: blocks.mining.hashPriceThsMin, - name: "TH/s Min", - color: colors.red, - unit: Unit.usdPerThsPerDay, - options: { lineStyle: 1 }, - }), - line({ - metric: blocks.mining.hashPricePhsMin, - name: "PH/s Min", - color: colors.red, - unit: Unit.usdPerPhsPerDay, - options: { lineStyle: 1 }, - }), - ], - }, - { - name: "Hash Value", - title: "Hash Value", - bottom: [ - line({ - metric: blocks.mining.hashValueThs, - name: "TH/s", - color: colors.orange, - unit: Unit.satsPerThsPerDay, - }), - line({ - metric: blocks.mining.hashValuePhs, - name: "PH/s", - color: colors.orange, - unit: Unit.satsPerPhsPerDay, - }), - line({ - metric: blocks.mining.hashValueRebound, - name: "Rebound", - color: colors.yellow, - unit: Unit.percentage, - }), - line({ - metric: blocks.mining.hashValueThsMin, - name: "TH/s Min", - color: colors.red, - unit: Unit.satsPerThsPerDay, - options: { lineStyle: 1 }, - }), - line({ - metric: blocks.mining.hashValuePhsMin, - name: "PH/s Min", - color: colors.red, - unit: Unit.satsPerPhsPerDay, - options: { lineStyle: 1 }, - }), + name: "Economics", + tree: [ + { + name: "Hash Price", + title: "Hash Price", + bottom: [ + line({ + metric: blocks.mining.hashPriceThs, + name: "TH/s", + color: colors.emerald, + unit: Unit.usdPerThsPerDay, + }), + line({ + metric: blocks.mining.hashPricePhs, + name: "PH/s", + color: colors.emerald, + unit: Unit.usdPerPhsPerDay, + }), + line({ + metric: blocks.mining.hashPriceRebound, + name: "Rebound", + color: colors.yellow, + unit: Unit.percentage, + }), + line({ + metric: blocks.mining.hashPriceThsMin, + name: "TH/s Min", + color: colors.red, + unit: Unit.usdPerThsPerDay, + options: { lineStyle: 1 }, + }), + line({ + metric: blocks.mining.hashPricePhsMin, + name: "PH/s Min", + color: colors.red, + unit: Unit.usdPerPhsPerDay, + options: { lineStyle: 1 }, + }), + ], + }, + { + name: "Hash Value", + title: "Hash Value", + bottom: [ + line({ + metric: blocks.mining.hashValueThs, + name: "TH/s", + color: colors.orange, + unit: Unit.satsPerThsPerDay, + }), + line({ + metric: blocks.mining.hashValuePhs, + name: "PH/s", + color: colors.orange, + unit: Unit.satsPerPhsPerDay, + }), + line({ + metric: blocks.mining.hashValueRebound, + name: "Rebound", + color: colors.yellow, + unit: Unit.percentage, + }), + line({ + metric: blocks.mining.hashValueThsMin, + name: "TH/s Min", + color: colors.red, + unit: Unit.satsPerThsPerDay, + options: { lineStyle: 1 }, + }), + line({ + metric: blocks.mining.hashValuePhsMin, + name: "PH/s Min", + color: colors.red, + unit: Unit.satsPerPhsPerDay, + options: { lineStyle: 1 }, + }), + ], + }, ], }, + + // Halving (at top level for quick access) { name: "Halving", title: "Halving", @@ -925,12 +958,12 @@ export function createChainSection(ctx) { }), line({ metric: blocks.halving.blocksBeforeNextHalving, - name: "before next", + name: "Before Next", unit: Unit.blocks, }), line({ metric: blocks.halving.daysBeforeNextHalving, - name: "before next", + name: "Before Next", color: colors.blue, unit: Unit.days, }), @@ -942,7 +975,90 @@ export function createChainSection(ctx) { // Pools { name: "Pools", - tree: poolsTree, + tree: [ + // Compare section (major pools only) + { + name: "Compare", + tree: [ + { + name: "Dominance", + title: "Pool Dominance (Major Pools)", + bottom: poolEntries + .filter(([key]) => MAJOR_POOL_IDS.includes(key.toLowerCase())) + .map(([key, pool]) => { + const poolName = + brk.POOL_ID_TO_POOL_NAME[ + /** @type {keyof typeof brk.POOL_ID_TO_POOL_NAME} */ (key.toLowerCase()) + ] || key; + return line({ + metric: pool._1mDominance, + name: poolName, + unit: Unit.percentage, + }); + }), + }, + { + name: "Blocks Mined", + title: "Blocks Mined - 1m (Major Pools)", + bottom: poolEntries + .filter(([key]) => MAJOR_POOL_IDS.includes(key.toLowerCase())) + .map(([key, pool]) => { + const poolName = + brk.POOL_ID_TO_POOL_NAME[ + /** @type {keyof typeof brk.POOL_ID_TO_POOL_NAME} */ (key.toLowerCase()) + ] || key; + return line({ + metric: pool._1mBlocksMined, + name: poolName, + unit: Unit.count, + }); + }), + }, + ], + }, + // AntPool & friends - pools sharing block templates + { + name: "AntPool & Friends", + tree: [ + { + name: "Dominance", + title: "AntPool & Friends Dominance", + bottom: poolEntries + .filter(([key]) => ANTPOOL_AND_FRIENDS_IDS.includes(key.toLowerCase())) + .map(([key, pool]) => { + const poolName = + brk.POOL_ID_TO_POOL_NAME[ + /** @type {keyof typeof brk.POOL_ID_TO_POOL_NAME} */ (key.toLowerCase()) + ] || key; + return line({ + metric: pool._1mDominance, + name: poolName, + unit: Unit.percentage, + }); + }), + }, + { + name: "Blocks Mined", + title: "AntPool & Friends Blocks Mined (1m)", + bottom: poolEntries + .filter(([key]) => ANTPOOL_AND_FRIENDS_IDS.includes(key.toLowerCase())) + .map(([key, pool]) => { + const poolName = + brk.POOL_ID_TO_POOL_NAME[ + /** @type {keyof typeof brk.POOL_ID_TO_POOL_NAME} */ (key.toLowerCase()) + ] || key; + return line({ + metric: pool._1mBlocksMined, + name: poolName, + unit: Unit.count, + }); + }), + }, + ], + }, + // Individual pools + ...poolsTree, + ], }, ], }; diff --git a/website/scripts/options/cointime.js b/website/scripts/options/cointime.js index 622c7b220..6649f3bab 100644 --- a/website/scripts/options/cointime.js +++ b/website/scripts/options/cointime.js @@ -1,5 +1,5 @@ import { Unit } from "../utils/units.js"; -import { line } from "./series.js"; +import { line, price } from "./series.js"; import { satsBtcUsd, createRatioChart, @@ -13,23 +13,23 @@ import { * @param {Object} args * @param {string} args.title * @param {string} args.legend - * @param {AnyMetricPattern} args.price + * @param {AnyPricePattern} args.pricePattern * @param {ActivePriceRatioPattern} args.ratio * @param {Color} args.color * @returns {PartialOptionsTree} */ function createCointimePriceWithRatioOptions( ctx, - { title, legend, price, ratio, color }, + { title, legend, pricePattern, ratio, color }, ) { return [ { name: "Price", title, - top: [line({ metric: price, name: legend, color, unit: Unit.usd })], + top: [price({ metric: pricePattern, name: legend, color })], }, - createRatioChart(ctx, { title: formatCohortTitle(title), price, ratio, color }), - createZScoresFolder(ctx, { title, legend, price, ratio, color }), + createRatioChart(ctx, { title: formatCohortTitle(title), pricePattern, ratio, color }), + createZScoresFolder(ctx, { title, legend, pricePattern, ratio, color }), ]; } @@ -55,28 +55,28 @@ export function createCointimeSection(ctx) { // Cointime prices data const cointimePrices = [ { - price: pricing.trueMarketMean, + pricePattern: pricing.trueMarketMean, ratio: pricing.trueMarketMeanRatio, - name: "True market mean", + name: "True Market Mean", title: "True Market Mean", color: colors.blue, }, { - price: pricing.vaultedPrice, + pricePattern: pricing.vaultedPrice, ratio: pricing.vaultedPriceRatio, name: "Vaulted", title: "Vaulted Price", color: colors.lime, }, { - price: pricing.activePrice, + pricePattern: pricing.activePrice, ratio: pricing.activePriceRatio, name: "Active", title: "Active Price", color: colors.rose, }, { - price: pricing.cointimePrice, + pricePattern: pricing.cointimePrice, ratio: pricing.cointimePriceRatio, name: "Cointime", title: "Cointime Price", @@ -128,14 +128,14 @@ export function createCointimeSection(ctx) { { name: "Compare", title: "Cointime Prices", - top: cointimePrices.map(({ price, name, color }) => - line({ metric: price, name, color, unit: Unit.usd }), + top: cointimePrices.map(({ pricePattern, name, color }) => + price({ metric: pricePattern, name, color }), ), }, - ...cointimePrices.map(({ price, ratio, name, color, title }) => ({ + ...cointimePrices.map(({ pricePattern, ratio, name, color, title }) => ({ name, tree: createCointimePriceWithRatioOptions(ctx, { - price, + pricePattern, ratio, legend: name, color, diff --git a/website/scripts/options/distribution/address.js b/website/scripts/options/distribution/address.js index 29296a1c0..7db0b14eb 100644 --- a/website/scripts/options/distribution/address.js +++ b/website/scripts/options/distribution/address.js @@ -6,7 +6,7 @@ import { Unit } from "../../utils/units.js"; import { priceLine } from "../constants.js"; -import { line, baseline } from "../series.js"; +import { line, baseline, price } from "../series.js"; import { formatCohortTitle } from "../shared.js"; import { createSingleSupplySeries, @@ -24,6 +24,9 @@ import { createGroupedSentDollarsSeries, groupedSupplyRelativeGenerators, createSingleSupplyRelativeOptions, + createSingleSellSideRiskSeries, + createSingleValueCreatedDestroyedSeries, + createSingleSoprSeries, } from "./shared.js"; /** @@ -51,10 +54,17 @@ export function createAddressCohortFolder(ctx, args) { bottom: createSingleSupplySeries( ctx, /** @type {AddressCohortObject} */ (args), - createSingleSupplyRelativeOptions(ctx, /** @type {AddressCohortObject} */ (args)), + createSingleSupplyRelativeOptions( + ctx, + /** @type {AddressCohortObject} */ (args), + ), ), } - : createGroupedSupplySection(list, title, groupedSupplyRelativeGenerators), + : createGroupedSupplySection( + list, + title, + groupedSupplyRelativeGenerators, + ), // UTXO count { @@ -144,11 +154,10 @@ function createRealizedPriceOptions(args, title) { name: "Price", title: title("Realized Price"), top: [ - line({ + price({ metric: tree.realized.realizedPrice, name: "Realized", color, - unit: Unit.usd, }), ], }, @@ -177,7 +186,7 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName) { ? [ baseline({ metric: tree.realized.realizedCap30dDelta, - name: "1m Change", + name: "30d Change", unit: Unit.usd, defaultActive: false, }), @@ -295,7 +304,7 @@ function createRealizedPnlSection(ctx, args, title) { }), baseline({ metric: realized.netRealizedPnlCumulative30dDelta, - name: "Cumulative 1m Change", + name: "Cumulative 30d Change", unit: Unit.usd, defaultActive: false, }), @@ -312,13 +321,13 @@ function createRealizedPnlSection(ctx, args, title) { }), baseline({ metric: realized.netRealizedPnlCumulative30dDeltaRelToRealizedCap, - name: "Cumulative 1m Change", + name: "Cumulative 30d Change", unit: Unit.pctRcap, defaultActive: false, }), baseline({ metric: realized.netRealizedPnlCumulative30dDeltaRelToMarketCap, - name: "Cumulative 1m Change", + name: "Cumulative 30d Change", unit: Unit.pctMcap, }), priceLine({ @@ -340,28 +349,7 @@ function createRealizedPnlSection(ctx, args, title) { name: "SOPR", title: title("SOPR"), bottom: [ - baseline({ - metric: realized.sopr, - name: "SOPR", - unit: Unit.ratio, - base: 1, - }), - baseline({ - metric: realized.sopr7dEma, - name: "7d EMA", - color: [colors.lime, colors.rose], - unit: Unit.ratio, - defaultActive: false, - base: 1, - }), - baseline({ - metric: realized.sopr30dEma, - name: "30d EMA", - color: [colors.avocado, colors.pink], - unit: Unit.ratio, - defaultActive: false, - base: 1, - }), + ...createSingleSoprSeries(colors, args.tree), priceLine({ ctx, unit: Unit.ratio, @@ -372,46 +360,12 @@ function createRealizedPnlSection(ctx, args, title) { { name: "Sell Side Risk", title: title("Sell Side Risk Ratio"), - bottom: [ - line({ - metric: realized.sellSideRiskRatio, - name: "Raw", - color: colors.orange, - unit: Unit.ratio, - }), - line({ - metric: realized.sellSideRiskRatio7dEma, - name: "7d EMA", - color: colors.red, - unit: Unit.ratio, - defaultActive: false, - }), - line({ - metric: realized.sellSideRiskRatio30dEma, - name: "30d EMA", - color: colors.rose, - unit: Unit.ratio, - defaultActive: false, - }), - ], + bottom: createSingleSellSideRiskSeries(colors, args.tree), }, { name: "Value", title: title("Value Created & Destroyed"), - bottom: [ - line({ - metric: realized.valueCreated, - name: "Created", - color: colors.emerald, - unit: Unit.usd, - }), - line({ - metric: realized.valueDestroyed, - name: "Destroyed", - color: colors.red, - unit: Unit.usd, - }), - ], + bottom: createSingleValueCreatedDestroyedSeries(colors, args.tree), }, ]; } @@ -582,23 +536,21 @@ function createCostBasisSection(list, useGroupName, title) { name: "Min", title: title("Min Cost Basis"), top: list.map(({ color, name, tree }) => - line({ + price({ metric: tree.costBasis.min, name: useGroupName ? name : "Min", color, - unit: Unit.usd, }), ), }, { - name: "max", + name: "Max", title: title("Max Cost Basis"), top: list.map(({ color, name, tree }) => - line({ + price({ metric: tree.costBasis.max, name: useGroupName ? name : "Max", color, - unit: Unit.usd, }), ), }, @@ -645,12 +597,12 @@ function createActivitySection(args, title) { name: "Activity", tree: [ { - name: "coinblocks destroyed", + name: "Coinblocks Destroyed", title: title("Coinblocks Destroyed"), bottom: createGroupedCoinblocksDestroyedSeries(list), }, { - name: "coindays destroyed", + name: "Coindays Destroyed", title: title("Coindays Destroyed"), bottom: createGroupedCoindaysDestroyedSeries(list), }, @@ -658,17 +610,17 @@ function createActivitySection(args, title) { name: "Sent", tree: [ { - name: "sats", + name: "Sats", title: title("Sent (Sats)"), bottom: createGroupedSentSatsSeries(list), }, { - name: "bitcoin", + name: "Bitcoin", title: title("Sent (BTC)"), bottom: createGroupedSentBitcoinSeries(list), }, { - name: "dollars", + name: "Dollars", title: title("Sent ($)"), bottom: createGroupedSentDollarsSeries(list), }, diff --git a/website/scripts/options/distribution/shared.js b/website/scripts/options/distribution/shared.js index 3bfda83eb..a3466cb27 100644 --- a/website/scripts/options/distribution/shared.js +++ b/website/scripts/options/distribution/shared.js @@ -2,7 +2,7 @@ import { Unit } from "../../utils/units.js"; import { priceLine } from "../constants.js"; -import { baseline, line } from "../series.js"; +import { baseline, dots, line, price } from "../series.js"; import { satsBtcUsd } from "../shared.js"; /** @@ -285,11 +285,11 @@ export function createAddressCountSeries(ctx, list, useGroupName) { /** * Create realized price series for grouped cohorts * @param {readonly CohortObject[]} list - * @returns {AnyFetchedSeriesBlueprint[]} + * @returns {FetchedPriceSeriesBlueprint[]} */ export function createRealizedPriceSeries(list) { return list.map(({ color, name, tree }) => - line({ metric: tree.realized.realizedPrice, name, color, unit: Unit.usd }), + price({ metric: tree.realized.realizedPrice, name, color }), ); } @@ -332,7 +332,7 @@ export function createRealizedCapSeries(list, useGroupName) { * @param {Colors} colors * @param {readonly CohortWithCostBasisPercentiles[]} list * @param {boolean} useGroupName - * @returns {AnyFetchedSeriesBlueprint[]} + * @returns {FetchedPriceSeriesBlueprint[]} */ export function createCostBasisPercentilesSeries(colors, list, useGroupName) { return list.flatMap(({ name, tree }) => { @@ -340,27 +340,27 @@ export function createCostBasisPercentilesSeries(colors, list, useGroupName) { const p = cb.percentiles; const n = (/** @type {number} */ pct) => (useGroupName ? `${name} p${pct}` : `p${pct}`); return [ - line({ metric: cb.max, name: n(100), color: colors.purple, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct95, name: n(95), color: colors.fuchsia, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct90, name: n(90), color: colors.pink, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct85, name: n(85), color: colors.pink, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct80, name: n(80), color: colors.rose, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct75, name: n(75), color: colors.red, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct70, name: n(70), color: colors.orange, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct65, name: n(65), color: colors.amber, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct60, name: n(60), color: colors.yellow, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct55, name: n(55), color: colors.yellow, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct50, name: n(50), color: colors.avocado, unit: Unit.usd }), - line({ metric: p.pct45, name: n(45), color: colors.lime, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct40, name: n(40), color: colors.green, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct35, name: n(35), color: colors.emerald, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct30, name: n(30), color: colors.teal, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct25, name: n(25), color: colors.teal, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct20, name: n(20), color: colors.cyan, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct15, name: n(15), color: colors.sky, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct10, name: n(10), color: colors.blue, unit: Unit.usd, defaultActive: false }), - line({ metric: p.pct05, name: n(5), color: colors.indigo, unit: Unit.usd, defaultActive: false }), - line({ metric: cb.min, name: n(0), color: colors.violet, unit: Unit.usd, defaultActive: false }), + price({ metric: cb.max, name: n(100), color: colors.purple, defaultActive: false }), + price({ metric: p.pct95, name: n(95), color: colors.fuchsia, defaultActive: false }), + price({ metric: p.pct90, name: n(90), color: colors.pink, defaultActive: false }), + price({ metric: p.pct85, name: n(85), color: colors.pink, defaultActive: false }), + price({ metric: p.pct80, name: n(80), color: colors.rose, defaultActive: false }), + price({ metric: p.pct75, name: n(75), color: colors.red, defaultActive: false }), + price({ metric: p.pct70, name: n(70), color: colors.orange, defaultActive: false }), + price({ metric: p.pct65, name: n(65), color: colors.amber, defaultActive: false }), + price({ metric: p.pct60, name: n(60), color: colors.yellow, defaultActive: false }), + price({ metric: p.pct55, name: n(55), color: colors.yellow, defaultActive: false }), + price({ metric: p.pct50, name: n(50), color: colors.avocado }), + price({ metric: p.pct45, name: n(45), color: colors.lime, defaultActive: false }), + price({ metric: p.pct40, name: n(40), color: colors.green, defaultActive: false }), + price({ metric: p.pct35, name: n(35), color: colors.emerald, defaultActive: false }), + price({ metric: p.pct30, name: n(30), color: colors.teal, defaultActive: false }), + price({ metric: p.pct25, name: n(25), color: colors.teal, defaultActive: false }), + price({ metric: p.pct20, name: n(20), color: colors.cyan, defaultActive: false }), + price({ metric: p.pct15, name: n(15), color: colors.sky, defaultActive: false }), + price({ metric: p.pct10, name: n(10), color: colors.blue, defaultActive: false }), + price({ metric: p.pct05, name: n(5), color: colors.indigo, defaultActive: false }), + price({ metric: cb.min, name: n(0), color: colors.violet, defaultActive: false }), ]; }); } @@ -536,3 +536,116 @@ export function createGroupedSentDollarsSeries(list) { }), ]); } + +// ============================================================================ +// Sell Side Risk Ratio Helpers +// ============================================================================ + +/** + * Create sell side risk ratio series for single cohort + * @param {Colors} colors + * @param {{ realized: AnyRealizedPattern }} tree + * @returns {AnyFetchedSeriesBlueprint[]} + */ +export function createSingleSellSideRiskSeries(colors, tree) { + return [ + dots({ + metric: tree.realized.sellSideRiskRatio, + name: "Raw", + color: colors.orange, + unit: Unit.ratio, + }), + line({ + metric: tree.realized.sellSideRiskRatio7dEma, + name: "7d EMA", + color: colors.red, + unit: Unit.ratio, + }), + line({ + metric: tree.realized.sellSideRiskRatio30dEma, + name: "30d EMA", + color: colors.pink, + unit: Unit.ratio, + }), + ]; +} + +/** + * Create sell side risk ratio series for grouped cohorts + * @param {readonly CohortObject[]} list + * @returns {AnyFetchedSeriesBlueprint[]} + */ +export function createGroupedSellSideRiskSeries(list) { + return list.flatMap(({ color, name, tree }) => [ + line({ + metric: tree.realized.sellSideRiskRatio, + name, + color, + unit: Unit.ratio, + }), + ]); +} + +// ============================================================================ +// Value Created & Destroyed Helpers +// ============================================================================ + +/** + * Create value created & destroyed series for single cohort + * @param {Colors} colors + * @param {{ realized: AnyRealizedPattern }} tree + * @returns {AnyFetchedSeriesBlueprint[]} + */ +export function createSingleValueCreatedDestroyedSeries(colors, tree) { + return [ + line({ + metric: tree.realized.valueCreated, + name: "Created", + color: colors.emerald, + unit: Unit.usd, + }), + line({ + metric: tree.realized.valueDestroyed, + name: "Destroyed", + color: colors.red, + unit: Unit.usd, + }), + ]; +} + +// ============================================================================ +// SOPR Helpers +// ============================================================================ + +/** + * Create base SOPR series for single cohort (all cohorts have base SOPR) + * @param {Colors} colors + * @param {{ realized: AnyRealizedPattern }} tree + * @returns {AnyFetchedSeriesBlueprint[]} + */ +export function createSingleSoprSeries(colors, tree) { + return [ + baseline({ + metric: tree.realized.sopr, + name: "SOPR", + unit: Unit.ratio, + base: 1, + }), + baseline({ + metric: tree.realized.sopr7dEma, + name: "7d EMA", + color: [colors.lime, colors.rose], + unit: Unit.ratio, + defaultActive: false, + base: 1, + }), + baseline({ + metric: tree.realized.sopr30dEma, + name: "30d EMA", + color: [colors.avocado, colors.pink], + unit: Unit.ratio, + defaultActive: false, + base: 1, + }), + ]; +} diff --git a/website/scripts/options/distribution/utxo.js b/website/scripts/options/distribution/utxo.js index 00ed4abea..81381ef35 100644 --- a/website/scripts/options/distribution/utxo.js +++ b/website/scripts/options/distribution/utxo.js @@ -32,6 +32,11 @@ import { createCostBasisPercentilesSeries, groupedSupplyRelativeGenerators, createSingleSupplyRelativeOptions, + createSingleSellSideRiskSeries, + createGroupedSellSideRiskSeries, + createSingleValueCreatedDestroyedSeries, + createSingleSoprSeries, + createSingleCoinsDestroyedSeries, } from "./shared.js"; import { createRatioChart, @@ -39,7 +44,7 @@ import { formatCohortTitle, } from "../shared.js"; import { Unit } from "../../utils/units.js"; -import { line, baseline } from "../series.js"; +import { line, baseline, price } from "../series.js"; import { priceLine } from "../constants.js"; // ============================================================================ @@ -81,7 +86,11 @@ export function createCohortFolderFull(ctx, args) { return { name: args.name || "all", tree: [ - createGroupedSupplySection(list, title, groupedSupplyRelativeGenerators), + createGroupedSupplySection( + list, + title, + groupedSupplyRelativeGenerators, + ), createGroupedUtxoCountChart(list, title), createGroupedRealizedSectionWithAdjusted(ctx, list, title, { ratioMetrics: createGroupedRealizedPnlRatioMetrics, @@ -96,7 +105,12 @@ export function createCohortFolderFull(ctx, args) { return { name: args.name || "all", tree: [ - createSingleSupplyChart(ctx, args, title, createSingleSupplyRelativeOptions(ctx, args)), + createSingleSupplyChart( + ctx, + args, + title, + createSingleSupplyRelativeOptions(ctx, args), + ), createSingleUtxoCountChart(args, title), createSingleRealizedSectionFull(ctx, args, title), createSingleUnrealizedSectionFull(ctx, args, title), @@ -119,7 +133,11 @@ export function createCohortFolderWithAdjusted(ctx, args) { return { name: args.name || "all", tree: [ - createGroupedSupplySection(list, title, groupedSupplyRelativeGenerators), + createGroupedSupplySection( + list, + title, + groupedSupplyRelativeGenerators, + ), createGroupedUtxoCountChart(list, title), createGroupedRealizedSectionWithAdjusted(ctx, list, title), createGroupedUnrealizedSectionWithMarketCap(ctx, list, title), @@ -132,7 +150,12 @@ export function createCohortFolderWithAdjusted(ctx, args) { return { name: args.name || "all", tree: [ - createSingleSupplyChart(ctx, args, title, createSingleSupplyRelativeOptions(ctx, args)), + createSingleSupplyChart( + ctx, + args, + title, + createSingleSupplyRelativeOptions(ctx, args), + ), createSingleUtxoCountChart(args, title), createSingleRealizedSectionWithAdjusted(ctx, args, title), createSingleUnrealizedSectionWithMarketCap(ctx, args, title), @@ -155,7 +178,11 @@ export function createCohortFolderWithNupl(ctx, args) { return { name: args.name || "all", tree: [ - createGroupedSupplySection(list, title, groupedSupplyRelativeGenerators), + createGroupedSupplySection( + list, + title, + groupedSupplyRelativeGenerators, + ), createGroupedUtxoCountChart(list, title), createGroupedRealizedSectionBasic(ctx, list, title, { ratioMetrics: createGroupedRealizedPnlRatioMetrics, @@ -170,7 +197,12 @@ export function createCohortFolderWithNupl(ctx, args) { return { name: args.name || "all", tree: [ - createSingleSupplyChart(ctx, args, title, createSingleSupplyRelativeOptions(ctx, args)), + createSingleSupplyChart( + ctx, + args, + title, + createSingleSupplyRelativeOptions(ctx, args), + ), createSingleUtxoCountChart(args, title), createSingleRealizedSectionWithPercentiles(ctx, args, title), createSingleUnrealizedSectionWithNupl({ ctx, cohort: args, title }), @@ -180,7 +212,6 @@ export function createCohortFolderWithNupl(ctx, args) { }; } - /** * Age range folder: ageRange.* (no nupl via RelativePattern2) * @param {PartialContext} ctx @@ -232,7 +263,11 @@ export function createCohortFolderBasicWithMarketCap(ctx, args) { return { name: args.name || "all", tree: [ - createGroupedSupplySection(list, title, groupedSupplyRelativeGenerators), + createGroupedSupplySection( + list, + title, + groupedSupplyRelativeGenerators, + ), createGroupedUtxoCountChart(list, title), createGroupedRealizedSectionBasic(ctx, list, title), createGroupedUnrealizedSectionWithMarketCapOnly(ctx, list, title), @@ -245,7 +280,12 @@ export function createCohortFolderBasicWithMarketCap(ctx, args) { return { name: args.name || "all", tree: [ - createSingleSupplyChart(ctx, args, title, createSingleSupplyRelativeOptions(ctx, args)), + createSingleSupplyChart( + ctx, + args, + title, + createSingleSupplyRelativeOptions(ctx, args), + ), createSingleUtxoCountChart(args, title), createSingleRealizedSectionBasic(ctx, args, title), createSingleUnrealizedSectionWithMarketCapOnly(ctx, args, title), @@ -474,7 +514,12 @@ function createSingleRealizedSectionWithAdjusted(ctx, cohort, title) { * @param {(cohort: T[number]) => AnyFetchedSeriesBlueprint[]} [options.ratioMetrics] - Generator for ratio metrics per cohort * @returns {PartialOptionsGroup} */ -function createGroupedRealizedSectionWithAdjusted(ctx, list, title, { ratioMetrics } = {}) { +function createGroupedRealizedSectionWithAdjusted( + ctx, + list, + title, + { ratioMetrics } = {}, +) { return { name: "Realized", tree: [ @@ -559,7 +604,12 @@ function createSingleRealizedSectionBasic(ctx, cohort, title) { * @param {(cohort: T[number]) => AnyFetchedSeriesBlueprint[]} [options.ratioMetrics] - Generator for ratio metrics per cohort * @returns {PartialOptionsGroup} */ -function createGroupedRealizedSectionBasic(ctx, list, title, { ratioMetrics } = {}) { +function createGroupedRealizedSectionBasic( + ctx, + list, + title, + { ratioMetrics } = {}, +) { return { name: "Realized", tree: [ @@ -596,11 +646,10 @@ function createSingleRealizedPriceChart(cohort, title) { name: "Price", title: title("Realized Price"), top: [ - line({ + price({ metric: tree.realized.realizedPrice, - name: "realized", + name: "Realized", color, - unit: Unit.usd, }), ], }; @@ -623,7 +672,7 @@ function createSingleRealizedPriceChartsWithRatio(ctx, cohort, title) { createSingleRealizedPriceChart(cohort, title), createRatioChart(ctx, { title, - price: tree.realized.realizedPrice, + pricePattern: tree.realized.realizedPrice, ratio, color, name: "MVRV", @@ -631,7 +680,7 @@ function createSingleRealizedPriceChartsWithRatio(ctx, cohort, title) { createZScoresFolder(ctx, { title: title("Realized Price"), legend: "price", - price: tree.realized.realizedPrice, + pricePattern: tree.realized.realizedPrice, ratio, color, }), @@ -693,7 +742,7 @@ function createSingleRealizedCapSeries(ctx, cohort, { extra = [] } = {}) { }), baseline({ metric: tree.realized.realizedCap30dDelta, - name: "1m Change", + name: "30d Change", unit: Unit.usd, defaultActive: false, }), @@ -712,7 +761,7 @@ function createRealizedCapRatioSeries(ctx, tree) { return [ baseline({ metric: tree.realized.realizedCapRelToOwnMarketCap, - name: "ratio", + name: "Ratio", unit: Unit.pctOwnMcap, options: { baseValue: { price: 100 } }, }), @@ -751,7 +800,7 @@ function createRealizedPnlRatioSeries(colors, tree) { return [ line({ metric: tree.realized.realizedProfitToLossRatio, - name: "Profit / Loss", + name: "P/L Ratio", color: colors.yellow, unit: Unit.ratio, }), @@ -783,7 +832,12 @@ function createGroupedRealizedPnlRatioMetrics(cohort) { * @param {AnyFetchedSeriesBlueprint[]} [options.extra] - Extra series (e.g., pnl ratio for cohorts with RealizedWithPnlRatio) * @returns {PartialOptionsTree} */ -function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) { +function createSingleRealizedPnlSection( + ctx, + cohort, + title, + { extra = [] } = {}, +) { const { colors, fromBlockCountWithUnit, fromBitcoinPatternWithUnit } = ctx; const { tree } = cohort; @@ -859,7 +913,7 @@ function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) ), baseline({ metric: tree.realized.netRealizedPnlCumulative30dDelta, - name: "Cumulative 1m Change", + name: "Cumulative 30d Change", unit: Unit.usd, defaultActive: false, }), @@ -877,13 +931,13 @@ function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) baseline({ metric: tree.realized.netRealizedPnlCumulative30dDeltaRelToRealizedCap, - name: "Cumulative 1m Change", + name: "Cumulative 30d Change", unit: Unit.pctRcap, defaultActive: false, }), baseline({ metric: tree.realized.netRealizedPnlCumulative30dDeltaRelToMarketCap, - name: "Cumulative 1m Change", + name: "Cumulative 30d Change", unit: Unit.pctMcap, }), priceLine({ ctx, unit: Unit.pctMcap }), @@ -904,7 +958,12 @@ function createSingleRealizedPnlSection(ctx, cohort, title, { extra = [] } = {}) * @param {(cohort: T[number]) => AnyFetchedSeriesBlueprint[]} [options.ratioMetrics] - Generator for ratio metrics per cohort * @returns {PartialOptionsTree} */ -function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = {}) { +function createGroupedRealizedPnlSections( + ctx, + list, + title, + { ratioMetrics } = {}, +) { return [ { name: "Profit", @@ -1028,8 +1087,8 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { ], }, { - name: "Net P&L 1m Change", - title: title("Net Realized P&L 1m Change"), + name: "Net P&L 30d Change", + title: title("Net Realized P&L 30d Change"), bottom: [ ...list.flatMap(({ color, name, tree }) => [ baseline({ @@ -1076,36 +1135,10 @@ function createGroupedRealizedPnlSections(ctx, list, title, { ratioMetrics } = { * @returns {PartialChartOption} */ function createSingleBaseSoprChart(ctx, cohort, title) { - const { colors } = ctx; - const { tree } = cohort; - return { name: "Normal", title: title("SOPR"), - bottom: [ - baseline({ - metric: tree.realized.sopr, - name: "SOPR", - unit: Unit.ratio, - base: 1, - }), - baseline({ - metric: tree.realized.sopr7dEma, - name: "7d EMA", - color: [colors.lime, colors.rose], - unit: Unit.ratio, - defaultActive: false, - base: 1, - }), - baseline({ - metric: tree.realized.sopr30dEma, - name: "30d EMA", - color: [colors.avocado, colors.pink], - unit: Unit.ratio, - defaultActive: false, - base: 1, - }), - ], + bottom: createSingleSoprSeries(ctx.colors, cohort.tree), }; } @@ -1547,7 +1580,14 @@ function createGroupedNuplChart(ctx, list, title) { * @param {PartialChartOption[]} [args.charts] - Extra charts (e.g., nupl) * @returns {PartialOptionsGroup} */ -function createUnrealizedSection({ ctx, tree, title, pnl = [], netPnl = [], charts = [] }) { +function createUnrealizedSection({ + ctx, + tree, + title, + pnl = [], + netPnl = [], + charts = [], +}) { return { name: "Unrealized", tree: [ @@ -1584,7 +1624,12 @@ function createUnrealizedSection({ ctx, tree, title, pnl = [], netPnl = [], char * @param {PartialChartOption[]} [args.charts] - Extra charts * @returns {PartialOptionsGroup} */ -function createGroupedUnrealizedSection({ list, title, netPnlMetrics, charts = [] }) { +function createGroupedUnrealizedSection({ + list, + title, + netPnlMetrics, + charts = [], +}) { return { name: "Unrealized", tree: [ @@ -1682,7 +1727,6 @@ function createSingleUnrealizedSectionWithMarketCap(ctx, cohort, title) { }); } - /** * Unrealized section WITH RelToMarketCap metrics (for CohortBasicWithMarketCap) * @param {PartialContext} ctx @@ -1774,9 +1818,24 @@ function createGroupedUnrealizedSectionFull(ctx, list, title) { list, title, netPnlMetrics: ({ color, name, tree }) => [ - baseline({ metric: tree.relative.netUnrealizedPnlRelToMarketCap, name, color, unit: Unit.pctMcap }), - baseline({ metric: tree.relative.netUnrealizedPnlRelToOwnMarketCap, name, color, unit: Unit.pctOwnMcap }), - baseline({ metric: tree.relative.netUnrealizedPnlRelToOwnTotalUnrealizedPnl, name, color, unit: Unit.pctOwnPnl }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToMarketCap, + name, + color, + unit: Unit.pctMcap, + }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToOwnMarketCap, + name, + color, + unit: Unit.pctOwnMcap, + }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToOwnTotalUnrealizedPnl, + name, + color, + unit: Unit.pctOwnPnl, + }), ], charts: [createGroupedNuplChart(ctx, list, title)], }); @@ -1793,13 +1852,17 @@ function createGroupedUnrealizedSectionWithMarketCap(ctx, list, title) { list, title, netPnlMetrics: ({ color, name, tree }) => [ - baseline({ metric: tree.relative.netUnrealizedPnlRelToMarketCap, name, color, unit: Unit.pctMcap }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToMarketCap, + name, + color, + unit: Unit.pctMcap, + }), ], charts: [createGroupedNuplChart(ctx, list, title)], }); } - /** * Grouped unrealized section WITH RelToMarketCap (for CohortBasicWithMarketCap) * @param {PartialContext} ctx @@ -1811,7 +1874,12 @@ function createGroupedUnrealizedSectionWithMarketCapOnly(ctx, list, title) { list, title, netPnlMetrics: ({ color, name, tree }) => [ - baseline({ metric: tree.relative.netUnrealizedPnlRelToMarketCap, name, color, unit: Unit.pctMcap }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToMarketCap, + name, + color, + unit: Unit.pctMcap, + }), ], charts: [createGroupedNuplChart(ctx, list, title)], }); @@ -1865,9 +1933,24 @@ function createGroupedUnrealizedSectionWithNupl({ ctx, list, title }) { list, title, netPnlMetrics: ({ color, name, tree }) => [ - baseline({ metric: tree.relative.netUnrealizedPnlRelToMarketCap, name, color, unit: Unit.pctMcap }), - baseline({ metric: tree.relative.netUnrealizedPnlRelToOwnMarketCap, name, color, unit: Unit.pctOwnMcap }), - baseline({ metric: tree.relative.netUnrealizedPnlRelToOwnTotalUnrealizedPnl, name, color, unit: Unit.pctOwnPnl }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToMarketCap, + name, + color, + unit: Unit.pctMcap, + }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToOwnMarketCap, + name, + color, + unit: Unit.pctOwnMcap, + }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToOwnTotalUnrealizedPnl, + name, + color, + unit: Unit.pctOwnPnl, + }), ], charts: [createGroupedNuplChart(ctx, list, title)], }); @@ -1906,8 +1989,18 @@ function createGroupedUnrealizedSectionAgeRange(list, title) { list, title, netPnlMetrics: ({ color, name, tree }) => [ - baseline({ metric: tree.relative.netUnrealizedPnlRelToOwnMarketCap, name, color, unit: Unit.pctOwnMcap }), - baseline({ metric: tree.relative.netUnrealizedPnlRelToOwnTotalUnrealizedPnl, name, color, unit: Unit.pctOwnPnl }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToOwnMarketCap, + name, + color, + unit: Unit.pctOwnMcap, + }), + baseline({ + metric: tree.relative.netUnrealizedPnlRelToOwnTotalUnrealizedPnl, + name, + color, + unit: Unit.pctOwnPnl, + }), ], }); } @@ -1935,24 +2028,21 @@ function createCostBasisSection(ctx, { cohort, title, charts = [] }) { name: "Average", title: title("Cost Basis"), top: [ - line({ + price({ metric: tree.realized.realizedPrice, name: "Average", color, - unit: Unit.usd, }), - line({ + price({ metric: tree.costBasis.max, name: "Max", color: colors.green, - unit: Unit.usd, defaultActive: false, }), - line({ + price({ metric: tree.costBasis.min, name: "Min", color: colors.red, - unit: Unit.usd, defaultActive: false, }), ], @@ -1961,11 +2051,10 @@ function createCostBasisSection(ctx, { cohort, title, charts = [] }) { name: "Max", title: title("Max Cost Basis"), top: [ - line({ + price({ metric: tree.costBasis.max, name: "Max", color: colors.green, - unit: Unit.usd, }), ], }, @@ -1973,11 +2062,10 @@ function createCostBasisSection(ctx, { cohort, title, charts = [] }) { name: "Min", title: title("Min Cost Basis"), top: [ - line({ + price({ metric: tree.costBasis.min, name: "Min", color: colors.red, - unit: Unit.usd, }), ], }, @@ -2003,11 +2091,10 @@ function createGroupedCostBasisSection({ list, title, charts = [] }) { name: "Average", title: title("Average Cost Basis"), top: list.map(({ color, name, tree }) => - line({ + price({ metric: tree.realized.realizedPrice, name, color, - unit: Unit.usd, }), ), }, @@ -2015,14 +2102,14 @@ function createGroupedCostBasisSection({ list, title, charts = [] }) { name: "Max", title: title("Max Cost Basis"), top: list.map(({ color, name, tree }) => - line({ metric: tree.costBasis.max, name, color, unit: Unit.usd }), + price({ metric: tree.costBasis.max, name, color }), ), }, { name: "Min", title: title("Min Cost Basis"), top: list.map(({ color, name, tree }) => - line({ metric: tree.costBasis.min, name, color, unit: Unit.usd }), + price({ metric: tree.costBasis.min, name, color }), ), }, ...charts, @@ -2078,7 +2165,6 @@ function createGroupedCostBasisSectionWithPercentiles(ctx, list, title) { }); } - // ============================================================================ // Activity Section Builders (generic, type-safe composition) // ============================================================================ @@ -2103,38 +2189,43 @@ function createActivitySection({ ctx, cohort, title, valueMetrics = [] }) { name: "Sent", title: title("Sent"), bottom: [ - ...fromBlockCountWithUnit(tree.activity.sent.sats, Unit.sats, undefined, color), - ...fromBitcoinPatternWithUnit(tree.activity.sent.bitcoin, Unit.btc, undefined, color), - ...fromBlockCountWithUnit(tree.activity.sent.dollars, Unit.usd, undefined, color), + ...fromBlockCountWithUnit( + tree.activity.sent.sats, + Unit.sats, + undefined, + color, + ), + ...fromBitcoinPatternWithUnit( + tree.activity.sent.bitcoin, + Unit.btc, + undefined, + color, + ), + ...fromBlockCountWithUnit( + tree.activity.sent.dollars, + Unit.usd, + undefined, + color, + ), ], }, { name: "Sell Side Risk", title: title("Sell Side Risk Ratio"), - bottom: [ - line({ metric: tree.realized.sellSideRiskRatio, name: "Raw", color: colors.orange, unit: Unit.ratio }), - line({ metric: tree.realized.sellSideRiskRatio7dEma, name: "7d EMA", color: colors.red, unit: Unit.ratio, defaultActive: false }), - line({ metric: tree.realized.sellSideRiskRatio30dEma, name: "30d EMA", color: colors.rose, unit: Unit.ratio, defaultActive: false }), - ], + bottom: createSingleSellSideRiskSeries(colors, tree), }, { name: "Value", title: title("Value Created & Destroyed"), bottom: [ - line({ metric: tree.realized.valueCreated, name: "Created", color: colors.emerald, unit: Unit.usd }), - line({ metric: tree.realized.valueDestroyed, name: "Destroyed", color: colors.red, unit: Unit.usd }), + ...createSingleValueCreatedDestroyedSeries(colors, tree), ...valueMetrics, ], }, { name: "Coins Destroyed", title: title("Coins Destroyed"), - bottom: [ - line({ metric: tree.activity.coinblocksDestroyed.sum, name: "Coinblocks", color, unit: Unit.coinblocks }), - 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 }), - ], + bottom: createSingleCoinsDestroyedSeries(cohort), }, ], }; @@ -2156,9 +2247,7 @@ function createGroupedActivitySection({ list, title, valueTree }) { { name: "Sell Side Risk", title: title("Sell Side Risk Ratio"), - bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.realized.sellSideRiskRatio, name, color, unit: Unit.ratio }), - ]), + bottom: createGroupedSellSideRiskSeries(list), }, { name: "Value", @@ -2167,14 +2256,24 @@ function createGroupedActivitySection({ list, title, valueTree }) { name: "Created", title: title("Value Created"), bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.realized.valueCreated, name, color, unit: Unit.usd }), + line({ + metric: tree.realized.valueCreated, + name, + color, + unit: Unit.usd, + }), ]), }, { name: "Destroyed", title: title("Value Destroyed"), bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.realized.valueDestroyed, name, color, unit: Unit.usd }), + line({ + metric: tree.realized.valueDestroyed, + name, + color, + unit: Unit.usd, + }), ]), }, ], @@ -2186,16 +2285,36 @@ function createGroupedActivitySection({ list, title, valueTree }) { name: "Sum", title: title("Coins Destroyed"), bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.activity.coinblocksDestroyed.sum, name, color, unit: Unit.coinblocks }), - line({ metric: tree.activity.coindaysDestroyed.sum, name, color, unit: Unit.coindays }), + line({ + metric: tree.activity.coinblocksDestroyed.sum, + name, + color, + unit: Unit.coinblocks, + }), + line({ + metric: tree.activity.coindaysDestroyed.sum, + name, + color, + unit: Unit.coindays, + }), ]), }, { name: "Cumulative", title: title("Cumulative Coins Destroyed"), bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.activity.coinblocksDestroyed.cumulative, name, color, unit: Unit.coinblocks }), - line({ metric: tree.activity.coindaysDestroyed.cumulative, name, color, unit: Unit.coindays }), + line({ + metric: tree.activity.coinblocksDestroyed.cumulative, + name, + color, + unit: Unit.coinblocks, + }), + line({ + metric: tree.activity.coindaysDestroyed.cumulative, + name, + color, + unit: Unit.coindays, + }), ]), }, ], @@ -2223,8 +2342,18 @@ function createSingleActivitySectionWithAdjusted(ctx, cohort, title) { cohort, title, valueMetrics: [ - line({ metric: tree.realized.adjustedValueCreated, name: "Adjusted Created", color: colors.lime, unit: Unit.usd }), - line({ metric: tree.realized.adjustedValueDestroyed, name: "Adjusted Destroyed", color: colors.pink, unit: Unit.usd }), + line({ + metric: tree.realized.adjustedValueCreated, + name: "Adjusted Created", + color: colors.lime, + unit: Unit.usd, + }), + line({ + metric: tree.realized.adjustedValueDestroyed, + name: "Adjusted Destroyed", + color: colors.pink, + unit: Unit.usd, + }), ], }); } @@ -2247,14 +2376,24 @@ function createGroupedActivitySectionWithAdjusted(list, title) { name: "Normal", title: title("Value Created"), bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.realized.valueCreated, name, color, unit: Unit.usd }), + line({ + metric: tree.realized.valueCreated, + name, + color, + unit: Unit.usd, + }), ]), }, { name: "Adjusted", title: title("Adjusted Value Created"), bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.realized.adjustedValueCreated, name, color, unit: Unit.usd }), + line({ + metric: tree.realized.adjustedValueCreated, + name, + color, + unit: Unit.usd, + }), ]), }, ], @@ -2266,14 +2405,24 @@ function createGroupedActivitySectionWithAdjusted(list, title) { name: "Normal", title: title("Value Destroyed"), bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.realized.valueDestroyed, name, color, unit: Unit.usd }), + line({ + metric: tree.realized.valueDestroyed, + name, + color, + unit: Unit.usd, + }), ]), }, { name: "Adjusted", title: title("Adjusted Value Destroyed"), bottom: list.flatMap(({ color, name, tree }) => [ - line({ metric: tree.realized.adjustedValueDestroyed, name, color, unit: Unit.usd }), + line({ + metric: tree.realized.adjustedValueDestroyed, + name, + color, + unit: Unit.usd, + }), ]), }, ], @@ -2281,4 +2430,3 @@ function createGroupedActivitySectionWithAdjusted(list, title) { ], }); } - diff --git a/website/scripts/options/full.js b/website/scripts/options/full.js index c8d0c0055..3adb4b202 100644 --- a/website/scripts/options/full.js +++ b/website/scripts/options/full.js @@ -7,6 +7,7 @@ import { collect, markUsed, logUnused } from "./unused.js"; import { setQr } from "../panes/share.js"; import { getConstant } from "./constants.js"; import { colors } from "../chart/colors.js"; +import { Unit } from "../utils/units.js"; /** * @param {BrkClient} brk @@ -83,7 +84,23 @@ export function initOptions(brk) { } /** - * @param {AnyFetchedSeriesBlueprint[]} [arr] + * Check if a metric is an ActivePricePattern (has dollars and sats sub-metrics) + * @param {any} metric + * @returns {metric is ActivePricePattern} + */ + function isActivePricePattern(metric) { + return ( + metric && + typeof metric === "object" && + "dollars" in metric && + "sats" in metric && + metric.dollars?.by && + metric.sats?.by + ); + } + + /** + * @param {(AnyFetchedSeriesBlueprint | FetchedPriceSeriesBlueprint)[]} [arr] */ function arrayToMap(arr = []) { /** @type {Map} */ @@ -97,29 +114,50 @@ export function initOptions(brk) { `Blueprint missing metric: ${JSON.stringify(blueprint)}`, ); } - if (!blueprint.unit) { - throw new Error(`Blueprint missing unit: ${blueprint.title}`); + + // Auto-expand ActivePricePattern into USD and sats versions + if (isActivePricePattern(blueprint.metric)) { + const pricePattern = /** @type {AnyPricePattern} */ (blueprint.metric); + + // USD version + markUsed(pricePattern.dollars); + if (!map.has(Unit.usd)) map.set(Unit.usd, []); + map.get(Unit.usd)?.push({ ...blueprint, metric: pricePattern.dollars, unit: Unit.usd }); + + // Sats version + markUsed(pricePattern.sats); + if (!map.has(Unit.sats)) map.set(Unit.sats, []); + map.get(Unit.sats)?.push({ ...blueprint, metric: pricePattern.sats, unit: Unit.sats }); + + continue; } - markUsed(blueprint.metric); - const unit = blueprint.unit; + + // At this point, blueprint is definitely an AnyFetchedSeriesBlueprint (not a price pattern) + const regularBlueprint = /** @type {AnyFetchedSeriesBlueprint} */ (blueprint); + + if (!regularBlueprint.unit) { + throw new Error(`Blueprint missing unit: ${regularBlueprint.title}`); + } + markUsed(regularBlueprint.metric); + const unit = regularBlueprint.unit; if (!map.has(unit)) { map.set(unit, []); } - map.get(unit)?.push(blueprint); + map.get(unit)?.push(regularBlueprint); // Track baseline base values for auto price lines - if (blueprint.type === "Baseline") { - const baseValue = blueprint.options?.baseValue?.price ?? 0; + if (regularBlueprint.type === "Baseline") { + const baseValue = regularBlueprint.options?.baseValue?.price ?? 0; if (!priceLines.has(unit)) priceLines.set(unit, new Set()); priceLines.get(unit)?.add(baseValue); } // Remove from set if manual price line already exists // 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 (regularBlueprint.type === "Line" || regularBlueprint.type === undefined) { + const path = Object.values(regularBlueprint.metric.by)[0]?.path ?? ""; if (path.includes("constant_")) { - priceLines.get(unit)?.delete(parseFloat(blueprint.title)); + priceLines.get(unit)?.delete(parseFloat(regularBlueprint.title)); } } } diff --git a/website/scripts/options/market/averages.js b/website/scripts/options/market/averages.js index 9ae5e7029..c86c1623e 100644 --- a/website/scripts/options/market/averages.js +++ b/website/scripts/options/market/averages.js @@ -1,7 +1,6 @@ /** Moving averages section */ -import { Unit } from "../../utils/units.js"; -import { line } from "../series.js"; +import { price } from "../series.js"; import { createRatioChart, createZScoresFolder, formatCohortTitle } from "../shared.js"; import { periodIdToName } from "./utils.js"; @@ -81,19 +80,19 @@ export function createPriceWithRatioOptions( ctx, { title, legend, ratio, color }, ) { - const priceMetric = ratio.price; + const pricePattern = ratio.price; return [ { name: "Price", title, - top: [line({ metric: priceMetric, name: legend, color, unit: Unit.usd })], + top: [price({ metric: pricePattern, name: legend, color })], }, - createRatioChart(ctx, { title: formatCohortTitle(title), price: priceMetric, ratio, color }), + createRatioChart(ctx, { title: formatCohortTitle(title), pricePattern, ratio, color }), createZScoresFolder(ctx, { title, legend, - price: priceMetric, + pricePattern, ratio, color, }), @@ -103,6 +102,46 @@ export function createPriceWithRatioOptions( /** Common period IDs to show at top level */ const COMMON_PERIODS = ["1w", "1m", "200d", "1y", "200w", "4y"]; +/** Periods to compare SMA vs EMA */ +const COMPARISON_PERIODS = ["1w", "1m", "200d", "1y", "200w", "4y"]; + +/** + * Create SMA vs EMA comparison section + * @param {ReturnType} smaAverages + * @param {ReturnType} emaAverages + */ +function createCompareSection(smaAverages, emaAverages) { + // Find matching SMA/EMA pairs + const pairs = COMPARISON_PERIODS.map(id => { + const sma = smaAverages.find(a => a.id === id); + const ema = emaAverages.find(a => a.id === id); + if (!sma || !ema) return null; + return { id, sma, ema }; + }).filter(/** @type {(p: any) => p is { id: string, sma: ReturnType[number], ema: ReturnType[number] }} */ (p) => p !== null); + + return { + name: "Compare", + tree: [ + { + name: "All Periods", + title: "SMA vs EMA Comparison", + top: pairs.flatMap(({ sma, ema }) => [ + price({ metric: sma.ratio.price, name: `${sma.id} SMA`, color: sma.color }), + price({ metric: ema.ratio.price, name: `${ema.id} EMA`, color: ema.color, options: { lineStyle: 1 } }), + ]), + }, + ...pairs.map(({ id, sma, ema }) => ({ + name: periodIdToName(id, true), + title: `${periodIdToName(id, true)} SMA vs EMA`, + top: [ + price({ metric: sma.ratio.price, name: "SMA", color: sma.color }), + price({ metric: ema.ratio.price, name: "EMA", color: ema.color, options: { lineStyle: 1 } }), + ], + })), + ], + }; +} + /** * @param {PartialContext} ctx * @param {MarketMovingAverage} movingAverage @@ -127,11 +166,10 @@ export function createAveragesSection(ctx, movingAverage) { name: "Compare", title: `Price ${label}s`, top: averages.map(({ id, color, ratio }) => - line({ + price({ metric: ratio.price, name: id, color, - unit: Unit.usd, }), ), }, @@ -165,6 +203,7 @@ export function createAveragesSection(ctx, movingAverage) { return { name: "Moving Averages", tree: [ + createCompareSection(smaAverages, emaAverages), createSubSection("SMA", smaAverages), createSubSection("EMA", emaAverages), ], diff --git a/website/scripts/options/market/bands.js b/website/scripts/options/market/bands.js index a9422de24..f3bf5ec02 100644 --- a/website/scripts/options/market/bands.js +++ b/website/scripts/options/market/bands.js @@ -1,7 +1,4 @@ -/** Bands indicators (MinMax, Mayer Multiple) */ - -import { Unit } from "../../utils/units.js"; -import { line } from "../series.js"; +import { price } from "../series.js"; /** * Create Bands section @@ -47,19 +44,17 @@ export function createBandsSection(ctx, { range, movingAverage }) { name: id, title: `${title} MinMax`, top: [ - line({ + price({ metric: min, name: "Min", key: `price-min`, color: colors.red, - unit: Unit.usd, }), - line({ + price({ metric: max, name: "Max", key: `price-max`, color: colors.green, - unit: Unit.usd, }), ], })), @@ -68,23 +63,20 @@ export function createBandsSection(ctx, { range, movingAverage }) { name: "Mayer Multiple", title: "Mayer Multiple", top: [ - line({ + price({ metric: movingAverage.price200dSma.price, name: "200d SMA", color: colors.yellow, - unit: Unit.usd, }), - line({ + price({ metric: movingAverage.price200dSmaX24, name: "200d SMA x2.4", color: colors.green, - unit: Unit.usd, }), - line({ + price({ metric: movingAverage.price200dSmaX08, name: "200d SMA x0.8", color: colors.red, - unit: Unit.usd, }), ], }, diff --git a/website/scripts/options/market/index.js b/website/scripts/options/market/index.js index d746a7550..2b6b1bfae 100644 --- a/website/scripts/options/market/index.js +++ b/website/scripts/options/market/index.js @@ -2,7 +2,7 @@ import { localhost } from "../../utils/env.js"; import { Unit } from "../../utils/units.js"; -import { candlestick, line } from "../series.js"; +import { candlestick, line, price } from "../series.js"; import { createAveragesSection } from "./averages.js"; import { createReturnsSection } from "./performance.js"; import { createMomentumSection } from "./momentum.js"; @@ -18,7 +18,7 @@ import { createDcaVsLumpSumSection, createDcaByYearSection } from "./investing.j */ export function createMarketSection(ctx) { const { colors, brk } = ctx; - const { market, supply, price } = brk.metrics; + const { market, supply, price: priceMetrics } = brk.metrics; const { movingAverage, ath, @@ -39,79 +39,80 @@ export function createMarketSection(ctx) { name: "Price", title: "Bitcoin Price", }, + // Oracle section is localhost-only debug - uses non-price-pattern metrics ...(localhost - ? [ + ? /** @type {PartialOptionsTree} */ ([ { name: "Oracle", title: "Oracle Price", - top: [ + top: /** @type {any} */ ([ candlestick({ - metric: price.oracle.closeOhlcDollars, - name: "close", + metric: priceMetrics.oracle.closeOhlcDollars, + name: "Close", unit: Unit.usd, }), candlestick({ - metric: price.oracle.midOhlcDollars, - name: "mid", + metric: priceMetrics.oracle.midOhlcDollars, + name: "Mid", unit: Unit.usd, }), line({ - metric: price.oracle.phaseDailyDollars.median, + metric: priceMetrics.oracle.phaseDailyDollars.median, name: "o. p50", unit: Unit.usd, color: colors.yellow, }), line({ - metric: price.oracle.phaseV2DailyDollars.median, + metric: priceMetrics.oracle.phaseV2DailyDollars.median, name: "o2. p50", unit: Unit.usd, color: colors.orange, }), line({ - metric: price.oracle.phaseV2PeakDailyDollars.median, + metric: priceMetrics.oracle.phaseV2PeakDailyDollars.median, name: "o2.2 p50", unit: Unit.usd, color: colors.orange, }), line({ - metric: price.oracle.phaseV3DailyDollars.median, + metric: priceMetrics.oracle.phaseV3DailyDollars.median, name: "o3. p50", unit: Unit.usd, color: colors.red, }), line({ - metric: price.oracle.phaseV3PeakDailyDollars.median, + metric: priceMetrics.oracle.phaseV3PeakDailyDollars.median, name: "o3.2 p50", unit: Unit.usd, color: colors.red, }), line({ - metric: price.oracle.phaseDailyDollars.max, + metric: priceMetrics.oracle.phaseDailyDollars.max, name: "o. max", unit: Unit.usd, color: colors.lime, }), line({ - metric: price.oracle.phaseV2DailyDollars.max, + metric: priceMetrics.oracle.phaseV2DailyDollars.max, name: "o.2 max", unit: Unit.usd, color: colors.emerald, }), line({ - metric: price.oracle.phaseDailyDollars.min, + metric: priceMetrics.oracle.phaseDailyDollars.min, name: "o. min", unit: Unit.usd, color: colors.rose, }), line({ - metric: price.oracle.phaseV2DailyDollars.min, + metric: priceMetrics.oracle.phaseV2DailyDollars.min, name: "o.2 min", unit: Unit.usd, color: colors.purple, }), - ], + ]), }, - ] + ]) : []), // Capitalization @@ -131,7 +132,7 @@ export function createMarketSection(ctx) { { name: "All Time High", title: "All Time High", - top: [line({ metric: ath.priceAth, name: "ATH", unit: Unit.usd })], + top: [price({ metric: ath.priceAth, name: "ATH" })], bottom: [ line({ metric: ath.priceDrawdown, diff --git a/website/scripts/options/market/investing.js b/website/scripts/options/market/investing.js index 580579f1a..076db5b29 100644 --- a/website/scripts/options/market/investing.js +++ b/website/scripts/options/market/investing.js @@ -2,7 +2,7 @@ import { Unit } from "../../utils/units.js"; import { priceLine } from "../constants.js"; -import { line, baseline } from "../series.js"; +import { line, baseline, price } from "../series.js"; import { satsBtcUsd } from "../shared.js"; import { periodIdToName } from "./utils.js"; @@ -58,17 +58,15 @@ export function createDcaVsLumpSumSection(ctx, { dca, lookback, returns }) { name: "Cost Basis", title: `${name} Cost Basis`, top: [ - line({ + price({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, - unit: Unit.usd, }), - line({ + price({ metric: lookback[key], name: "Lump sum", color: colors.orange, - unit: Unit.usd, }), ], }); @@ -78,8 +76,8 @@ export function createDcaVsLumpSumSection(ctx, { dca, lookback, returns }) { 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 }), + price({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green }), + price({ metric: lookback[key], name: "Lump sum", color: colors.orange }), ], bottom: [ line({ metric: dca.periodDaysInProfit[key], name: "DCA", color: colors.green, unit: Unit.days }), @@ -92,8 +90,8 @@ export function createDcaVsLumpSumSection(ctx, { dca, lookback, returns }) { 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 }), + price({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green }), + price({ metric: lookback[key], name: "Lump sum", color: colors.orange }), ], bottom: [ line({ metric: dca.periodDaysInLoss[key], name: "DCA", color: colors.red, unit: Unit.days }), @@ -106,8 +104,8 @@ export function createDcaVsLumpSumSection(ctx, { dca, lookback, returns }) { 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 }), + price({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green }), + price({ metric: lookback[key], name: "Lump sum", color: colors.orange }), ], bottom: [ line({ metric: dca.periodMaxDrawdown[key], name: "DCA", color: colors.green, unit: Unit.percentage }), @@ -120,8 +118,8 @@ export function createDcaVsLumpSumSection(ctx, { dca, lookback, returns }) { 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 }), + price({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green }), + price({ metric: lookback[key], name: "Lump sum", color: colors.orange }), ], bottom: [ line({ metric: dca.periodMaxReturn[key], name: "DCA", color: colors.green, unit: Unit.percentage }), @@ -279,12 +277,11 @@ export function createDcaByYearSection(ctx, { dca }) { name: "Cost basis", title: "DCA Cost Basis", top: dcaClasses.map(({ year, color, defaultActive, costBasis }) => - line({ + price({ metric: costBasis, name: `${year}`, color, defaultActive, - unit: Unit.usd, }), ), }, @@ -353,11 +350,10 @@ export function createDcaByYearSection(ctx, { dca }) { name: "Cost Basis", title: `${year} Cost Basis`, top: [ - line({ + price({ metric: costBasis, name: "Cost Basis", color, - unit: Unit.usd, }), ], }, diff --git a/website/scripts/options/market/onchain.js b/website/scripts/options/market/onchain.js index def96d2b5..02359b146 100644 --- a/website/scripts/options/market/onchain.js +++ b/website/scripts/options/market/onchain.js @@ -1,7 +1,7 @@ /** On-chain indicators (Pi Cycle, Puell, NVT, Gini) */ import { Unit } from "../../utils/units.js"; -import { baseline, line } from "../series.js"; +import { baseline, line, price } from "../series.js"; /** * Create Valuation section @@ -20,17 +20,15 @@ export function createValuationSection(ctx, { indicators, movingAverage }) { name: "Pi Cycle", title: "Pi Cycle", top: [ - line({ + price({ metric: movingAverage.price111dSma.price, name: "111d SMA", color: colors.green, - unit: Unit.usd, }), - line({ + price({ metric: movingAverage.price350dSmaX2, name: "350d SMA x2", color: colors.red, - unit: Unit.usd, }), ], bottom: [ diff --git a/website/scripts/options/partial.js b/website/scripts/options/partial.js index 32ee3579e..4d7dae76a 100644 --- a/website/scripts/options/partial.js +++ b/website/scripts/options/partial.js @@ -282,9 +282,9 @@ export function createPartialOptions({ brk }) { ], }, - // Research section + // Frameworks section { - name: "Research", + name: "Frameworks", tree: [ createCointimeSection(ctx), ], diff --git a/website/scripts/options/series.js b/website/scripts/options/series.js index b12b95979..477b0f1c9 100644 --- a/website/scripts/options/series.js +++ b/website/scripts/options/series.js @@ -2,6 +2,44 @@ import { Unit } from "../utils/units.js"; +// ============================================================================ +// Price helper for top pane (auto-expands to USD + sats) +// ============================================================================ + +/** + * Create a price series for the top pane (auto-expands to USD + sats versions) + * @param {Object} args + * @param {AnyPricePattern} args.metric - Price pattern with dollars and sats + * @param {string} args.name + * @param {string} [args.key] + * @param {LineStyle} [args.style] + * @param {Color} [args.color] + * @param {boolean} [args.defaultActive] + * @param {LineSeriesPartialOptions} [args.options] + * @returns {FetchedPriceSeriesBlueprint} + */ +export function price({ + metric, + name, + key, + style, + color, + defaultActive, + options, +}) { + return { + metric, + title: name, + key, + color, + defaultActive, + options: { + lineStyle: style, + ...options, + }, + }; +} + // ============================================================================ // Shared percentile helper // ============================================================================ diff --git a/website/scripts/options/shared.js b/website/scripts/options/shared.js index b664c52e6..d2c0ae828 100644 --- a/website/scripts/options/shared.js +++ b/website/scripts/options/shared.js @@ -1,7 +1,7 @@ /** Shared helpers for options */ import { Unit } from "../utils/units.js"; -import { line, baseline } from "./series.js"; +import { line, baseline, price } from "./series.js"; import { priceLine, priceLines } from "./constants.js"; /** @@ -153,27 +153,26 @@ export function ratioSmas(colors, ratio) { * @param {PartialContext} ctx * @param {Object} args * @param {(metric: string) => string} args.title - * @param {AnyMetricPattern} args.price - The price metric to show in top pane + * @param {AnyPricePattern} args.pricePattern - The price pattern to show in top pane * @param {ActivePriceRatioPattern} args.ratio - The ratio pattern * @param {Color} args.color * @param {string} [args.name] - Optional name override (default: "ratio") * @returns {PartialChartOption} */ -export function createRatioChart(ctx, { title, price, ratio, color, name }) { +export function createRatioChart(ctx, { title, pricePattern, ratio, color, name }) { const { colors } = ctx; return { name: name ?? "ratio", title: title(name ?? "Ratio"), top: [ - line({ metric: price, name: "Price", color, unit: Unit.usd }), + price({ metric: pricePattern, name: "Price", color }), ...percentileUsdMap(colors, ratio).map(({ name, prop, color }) => - line({ + price({ metric: prop, name, color, defaultActive: false, - unit: Unit.usd, options: { lineStyle: 1 }, }), ), @@ -208,14 +207,14 @@ export function createRatioChart(ctx, { title, price, ratio, color, name }) { * @param {Object} args * @param {string} args.title * @param {string} args.legend - * @param {AnyMetricPattern} args.price - The price metric to show in top pane + * @param {AnyPricePattern} args.pricePattern - The price pattern to show in top pane * @param {ActivePriceRatioPattern} args.ratio - The ratio pattern * @param {Color} args.color * @returns {PartialOptionsGroup} */ export function createZScoresFolder( ctx, - { title, legend, price, ratio, color }, + { title, legend, pricePattern, ratio, color }, ) { const { colors } = ctx; const sdPats = sdPatterns(ratio); @@ -227,40 +226,36 @@ export function createZScoresFolder( name: "Compare", title: `${title} Z-Scores`, top: [ - line({ metric: price, name: legend, color, unit: Unit.usd }), - line({ + price({ metric: pricePattern, name: legend, color }), + price({ metric: ratio.ratio1ySd._0sdUsd, name: "1y 0σ", color: colors.orange, defaultActive: false, - unit: Unit.usd, }), - line({ + price({ metric: ratio.ratio2ySd._0sdUsd, name: "2y 0σ", color: colors.yellow, defaultActive: false, - unit: Unit.usd, }), - line({ + price({ metric: ratio.ratio4ySd._0sdUsd, name: "4y 0σ", color: colors.lime, defaultActive: false, - unit: Unit.usd, }), - line({ + price({ metric: ratio.ratioSd._0sdUsd, name: "all 0σ", color: colors.blue, defaultActive: false, - unit: Unit.usd, }), ], bottom: [ line({ metric: ratio.ratioSd.zscore, - name: "all", + name: "All", color: colors.blue, unit: Unit.sd, }), @@ -294,14 +289,13 @@ export function createZScoresFolder( name: nameAddon, title: `${title} ${titleAddon} Z-Score`, top: [ - line({ metric: price, name: legend, color, unit: Unit.usd }), + price({ metric: pricePattern, name: legend, color }), ...sdBandsUsd(colors, sd).map( ({ name: bandName, prop, color: bandColor }) => - line({ + price({ metric: prop, name: bandName, color: bandColor, - unit: Unit.usd, defaultActive: false, }), ), diff --git a/website/scripts/options/types.js b/website/scripts/options/types.js index d4730a822..7212929ed 100644 --- a/website/scripts/options/types.js +++ b/website/scripts/options/types.js @@ -48,6 +48,13 @@ * @typedef {DotsSeriesBlueprint & FetchedAnySeriesOptions} FetchedDotsSeriesBlueprint * @typedef {AnySeriesBlueprint & FetchedAnySeriesOptions} AnyFetchedSeriesBlueprint * + * Any pattern with dollars and sats sub-metrics (auto-expands to USD + sats) + * @typedef {{ dollars: AnyMetricPattern, sats: AnyMetricPattern }} AnyPricePattern + * + * Top pane price series - requires a price pattern with dollars/sats, auto-expands to USD + sats + * @typedef {{ metric: AnyPricePattern }} FetchedPriceSeriesOptions + * @typedef {LineSeriesBlueprint & FetchedPriceSeriesOptions} FetchedPriceSeriesBlueprint + * * @typedef {Object} PartialOption * @property {string} name * @@ -66,7 +73,7 @@ * @typedef {Object} PartialChartOptionSpecific * @property {"chart"} [kind] * @property {string} title - * @property {AnyFetchedSeriesBlueprint[]} [top] + * @property {FetchedPriceSeriesBlueprint[]} [top] * @property {AnyFetchedSeriesBlueprint[]} [bottom] * * @typedef {PartialOption & PartialChartOptionSpecific} PartialChartOption diff --git a/website/scripts/types.js b/website/scripts/types.js index 62c367e75..ac79fd53c 100644 --- a/website/scripts/types.js +++ b/website/scripts/types.js @@ -14,7 +14,7 @@ * * @import { WebSockets } from "./utils/ws.js" * - * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedBaselineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, PatternAll, PatternFull, PatternWithAdjusted, PatternWithPercentiles, PatternBasic, PatternBasicWithMarketCap, PatternBasicWithoutMarketCap, CohortAll, CohortFull, CohortWithAdjusted, CohortWithPercentiles, CohortBasic, CohortBasicWithMarketCap, CohortBasicWithoutMarketCap, CohortAddress, CohortLongTerm, CohortAgeRange, CohortGroupFull, CohortGroupWithAdjusted, CohortGroupWithPercentiles, CohortGroupLongTerm, CohortGroupAgeRange, CohortGroupBasic, CohortGroupBasicWithMarketCap, CohortGroupBasicWithoutMarketCap, CohortGroupAddress, UtxoCohortGroupObject, AddressCohortGroupObject, FetchedDotsSeriesBlueprint, FetchedCandlestickSeriesBlueprint } from "./options/partial.js" + * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType, AnyFetchedSeriesBlueprint, TableOption, ExplorerOption, UrlOption, PartialOptionsGroup, OptionsGroup, PartialOptionsTree, UtxoCohortObject, AddressCohortObject, CohortObject, CohortGroupObject, FetchedLineSeriesBlueprint, FetchedBaselineSeriesBlueprint, FetchedHistogramSeriesBlueprint, PartialContext, PatternAll, PatternFull, PatternWithAdjusted, PatternWithPercentiles, PatternBasic, PatternBasicWithMarketCap, PatternBasicWithoutMarketCap, CohortAll, CohortFull, CohortWithAdjusted, CohortWithPercentiles, CohortBasic, CohortBasicWithMarketCap, CohortBasicWithoutMarketCap, CohortAddress, CohortLongTerm, CohortAgeRange, CohortGroupFull, CohortGroupWithAdjusted, CohortGroupWithPercentiles, CohortGroupLongTerm, CohortGroupAgeRange, CohortGroupBasic, CohortGroupBasicWithMarketCap, CohortGroupBasicWithoutMarketCap, CohortGroupAddress, UtxoCohortGroupObject, AddressCohortGroupObject, FetchedDotsSeriesBlueprint, FetchedCandlestickSeriesBlueprint, FetchedPriceSeriesBlueprint, AnyPricePattern } from "./options/partial.js" * * * @import { UnitObject as Unit } from "./utils/units.js" @@ -50,6 +50,7 @@ * @typedef {Brk.ActivePriceRatioPattern} ActivePriceRatioPattern * @typedef {Brk.UnclaimedRewardsPattern} ValuePattern * @typedef {Brk.AnyMetricPattern} AnyMetricPattern + * @typedef {Brk.ActivePricePattern} ActivePricePattern * @typedef {Brk.AnyMetricEndpointBuilder} AnyMetricEndpoint * @typedef {Brk.AnyMetricData} AnyMetricData * @typedef {Brk.AddrCountPattern} AddrCountPattern @@ -132,6 +133,9 @@ * Realized pattern capability types (RealizedPattern2 and RealizedPattern3 have extra metrics) * @typedef {Brk.RealizedPattern2 | Brk.RealizedPattern3} RealizedWithExtras * + * Any realized pattern (all have sellSideRiskRatio, valueCreated, valueDestroyed, etc.) + * @typedef {Brk.RealizedPattern | Brk.RealizedPattern2 | Brk.RealizedPattern3 | Brk.RealizedPattern4} AnyRealizedPattern + * * Capability-based pattern groupings (patterns that have specific properties) * @typedef {AllUtxoPattern | AgeRangePattern | UtxoAmountPattern} PatternWithRealizedPrice * @typedef {AllUtxoPattern} PatternWithFullRealized diff --git a/website/styles/components.css b/website/styles/components.css index 6f81998ee..f954948bc 100644 --- a/website/styles/components.css +++ b/website/styles/components.css @@ -123,7 +123,11 @@ search { .shadow-top { position: absolute; - background-image: linear-gradient(to top, transparent, var(--background-color)); + background-image: linear-gradient( + to top, + transparent, + var(--background-color) + ); height: var(--main-padding); top: 0; left: 0; @@ -134,7 +138,12 @@ search { .shadow-bottom { position: absolute; - background-image: linear-gradient(to bottom, transparent, var(--background-color) 90%, var(--background-color)); + background-image: linear-gradient( + to bottom, + transparent, + var(--background-color) 90%, + var(--background-color) + ); height: 21rem; bottom: 0; left: 0; @@ -145,7 +154,11 @@ search { .shadow-left { position: absolute; - background-image: linear-gradient(to left, transparent, var(--background-color)); + background-image: linear-gradient( + to left, + transparent, + var(--background-color) + ); width: var(--main-padding); left: 0; top: 0; @@ -156,7 +169,11 @@ search { .shadow-right { position: absolute; - background-image: linear-gradient(to right, transparent, var(--background-color)); + background-image: linear-gradient( + to right, + transparent, + var(--background-color) + ); width: var(--main-padding); right: 0; top: 0; @@ -290,6 +307,7 @@ fieldset { padding-right: 0.375rem; margin-left: -0.375rem; margin-right: -0.375rem; + margin-top: 0.1rem; } } }