global: snapshot

This commit is contained in:
nym21
2026-03-19 12:15:03 +01:00
parent d8b55340f7
commit b18cca92ab
24 changed files with 571 additions and 575 deletions

View File

@@ -1369,32 +1369,6 @@ pub struct BaseCumulativeDistributionSumToValuePattern {
pub value_destroyed: BaseCumulativeSumPattern<Cents>, pub value_destroyed: BaseCumulativeSumPattern<Cents>,
} }
/// Pattern struct for repeated tree structure.
pub struct BaseCumulativeNegativeSumToPattern2 {
pub base: CentsUsdPattern2,
pub cumulative: CentsUsdPattern2,
pub negative: SeriesPattern1<Dollars>,
pub sum: _1m1w1y24hPattern4,
pub to_mcap: BpsPercentRatioPattern3,
pub to_own_gross_pnl: BpsPercentRatioPattern3,
pub to_own_mcap: BpsPercentRatioPattern4,
}
impl BaseCumulativeNegativeSumToPattern2 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
base: CentsUsdPattern2::new(client.clone(), _m(&acc, "unrealized_loss")),
cumulative: CentsUsdPattern2::new(client.clone(), _m(&acc, "unrealized_loss_cumulative")),
negative: SeriesPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")),
sum: _1m1w1y24hPattern4::new(client.clone(), _m(&acc, "unrealized_loss_sum")),
to_mcap: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "unrealized_loss_to_mcap")),
to_own_gross_pnl: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "unrealized_loss_to_own_gross_pnl")),
to_own_mcap: BpsPercentRatioPattern4::new(client.clone(), _m(&acc, "unrealized_loss_to_own_mcap")),
}
}
}
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct CapLossMvrvNetPriceProfitSoprPattern { pub struct CapLossMvrvNetPriceProfitSoprPattern {
pub cap: CentsDeltaUsdPattern, pub cap: CentsDeltaUsdPattern,
@@ -1411,7 +1385,7 @@ impl CapLossMvrvNetPriceProfitSoprPattern {
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
cap: CentsDeltaUsdPattern::new(client.clone(), _m(&acc, "realized_cap")), cap: CentsDeltaUsdPattern::new(client.clone(), _m(&acc, "realized_cap")),
loss: BaseCumulativeNegativeSumPattern::new(client.clone(), acc.clone(), "realized_loss".to_string()), loss: BaseCumulativeNegativeSumPattern::new(client.clone(), acc.clone()),
mvrv: SeriesPattern1::new(client.clone(), _m(&acc, "mvrv")), mvrv: SeriesPattern1::new(client.clone(), _m(&acc, "mvrv")),
net_pnl: BaseCumulativeDeltaSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl")), net_pnl: BaseCumulativeDeltaSumPattern::new(client.clone(), _m(&acc, "net_realized_pnl")),
price: BpsCentsRatioSatsUsdPattern::new(client.clone(), _m(&acc, "realized_price")), price: BpsCentsRatioSatsUsdPattern::new(client.clone(), _m(&acc, "realized_price")),
@@ -1425,10 +1399,10 @@ impl CapLossMvrvNetPriceProfitSoprPattern {
pub struct GrossInvestedLossNetNuplProfitSentimentPattern2 { pub struct GrossInvestedLossNetNuplProfitSentimentPattern2 {
pub gross_pnl: CentsUsdPattern2, pub gross_pnl: CentsUsdPattern2,
pub invested_capital: InPattern, pub invested_capital: InPattern,
pub loss: BaseCumulativeNegativeSumToPattern2, pub loss: CentsNegativeToUsdPattern2,
pub net_pnl: CentsToUsdPattern2, pub net_pnl: CentsToUsdPattern3,
pub nupl: BpsRatioPattern, pub nupl: BpsRatioPattern,
pub profit: BaseCumulativeSumToPattern2, pub profit: CentsToUsdPattern4,
pub sentiment: GreedNetPainPattern, pub sentiment: GreedNetPainPattern,
} }
@@ -1480,30 +1454,6 @@ impl BaseChangeCumulativeDeltaSumToPattern {
} }
} }
/// Pattern struct for repeated tree structure.
pub struct BaseCumulativeSumToPattern2 {
pub base: CentsUsdPattern2,
pub cumulative: CentsUsdPattern2,
pub sum: _1m1w1y24hPattern4,
pub to_mcap: BpsPercentRatioPattern3,
pub to_own_gross_pnl: BpsPercentRatioPattern3,
pub to_own_mcap: BpsPercentRatioPattern3,
}
impl BaseCumulativeSumToPattern2 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
base: CentsUsdPattern2::new(client.clone(), acc.clone()),
cumulative: CentsUsdPattern2::new(client.clone(), _m(&acc, "cumulative")),
sum: _1m1w1y24hPattern4::new(client.clone(), _m(&acc, "sum")),
to_mcap: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "to_mcap")),
to_own_gross_pnl: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "to_own_gross_pnl")),
to_own_mcap: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "to_own_mcap")),
}
}
}
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct BpsCentsPercentilesRatioSatsUsdPattern { pub struct BpsCentsPercentilesRatioSatsUsdPattern {
pub bps: SeriesPattern1<BasisPoints32>, pub bps: SeriesPattern1<BasisPoints32>,
@@ -1576,6 +1526,30 @@ impl CapLossMvrvPriceProfitSoprPattern {
} }
} }
/// Pattern struct for repeated tree structure.
pub struct CentsNegativeToUsdPattern2 {
pub cents: SeriesPattern1<Cents>,
pub negative: SeriesPattern1<Dollars>,
pub to_mcap: BpsPercentRatioPattern3,
pub to_own_gross_pnl: BpsPercentRatioPattern3,
pub to_own_mcap: BpsPercentRatioPattern4,
pub usd: SeriesPattern1<Dollars>,
}
impl CentsNegativeToUsdPattern2 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
cents: SeriesPattern1::new(client.clone(), _m(&acc, "unrealized_loss_cents")),
negative: SeriesPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")),
to_mcap: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "unrealized_loss_to_mcap")),
to_own_gross_pnl: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "unrealized_loss_to_own_gross_pnl")),
to_own_mcap: BpsPercentRatioPattern4::new(client.clone(), _m(&acc, "unrealized_loss_to_own_mcap")),
usd: SeriesPattern1::new(client.clone(), _m(&acc, "unrealized_loss")),
}
}
}
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct DeltaHalfInToTotalPattern { pub struct DeltaHalfInToTotalPattern {
pub delta: AbsoluteRatePattern, pub delta: AbsoluteRatePattern,
@@ -1802,6 +1776,28 @@ impl BtcCentsSatsToUsdPattern2 {
} }
} }
/// Pattern struct for repeated tree structure.
pub struct CentsToUsdPattern4 {
pub cents: SeriesPattern1<Cents>,
pub to_mcap: BpsPercentRatioPattern3,
pub to_own_gross_pnl: BpsPercentRatioPattern3,
pub to_own_mcap: BpsPercentRatioPattern3,
pub usd: SeriesPattern1<Dollars>,
}
impl CentsToUsdPattern4 {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
cents: SeriesPattern1::new(client.clone(), _m(&acc, "cents")),
to_mcap: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "to_mcap")),
to_own_gross_pnl: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "to_own_gross_pnl")),
to_own_mcap: BpsPercentRatioPattern3::new(client.clone(), _m(&acc, "to_own_mcap")),
usd: SeriesPattern1::new(client.clone(), acc.clone()),
}
}
}
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct DeltaHalfInTotalPattern2 { pub struct DeltaHalfInTotalPattern2 {
pub delta: AbsoluteRatePattern, pub delta: AbsoluteRatePattern,
@@ -2052,12 +2048,12 @@ pub struct BaseCumulativeNegativeSumPattern {
impl BaseCumulativeNegativeSumPattern { impl BaseCumulativeNegativeSumPattern {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String, disc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
base: CentsUsdPattern2::new(client.clone(), _m(&acc, &disc)), base: CentsUsdPattern2::new(client.clone(), _m(&acc, "realized_loss")),
cumulative: CentsUsdPattern2::new(client.clone(), _m(&acc, &format!("{disc}_cumulative", disc=disc))), cumulative: CentsUsdPattern2::new(client.clone(), _m(&acc, "realized_loss_cumulative")),
negative: SeriesPattern1::new(client.clone(), _m(&acc, &format!("neg_{disc}", disc=disc))), negative: SeriesPattern1::new(client.clone(), _m(&acc, "neg_realized_loss")),
sum: _1m1w1y24hPattern4::new(client.clone(), _m(&acc, &format!("{disc}_sum", disc=disc))), sum: _1m1w1y24hPattern4::new(client.clone(), _m(&acc, "realized_loss_sum")),
} }
} }
} }
@@ -2123,14 +2119,14 @@ impl CentsDeltaToUsdPattern {
} }
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct CentsToUsdPattern2 { pub struct CentsToUsdPattern3 {
pub cents: SeriesPattern1<CentsSigned>, pub cents: SeriesPattern1<CentsSigned>,
pub to_own_gross_pnl: BpsPercentRatioPattern, pub to_own_gross_pnl: BpsPercentRatioPattern,
pub to_own_mcap: BpsPercentRatioPattern, pub to_own_mcap: BpsPercentRatioPattern,
pub usd: SeriesPattern1<Dollars>, pub usd: SeriesPattern1<Dollars>,
} }
impl CentsToUsdPattern2 { impl CentsToUsdPattern3 {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
@@ -2152,20 +2148,20 @@ pub struct CoindaysCoinyearsDormancyTransferPattern {
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct LossNetNuplProfitPattern { pub struct LossNetNuplProfitPattern {
pub loss: BaseCumulativeNegativeSumPattern, pub loss: CentsNegativeUsdPattern,
pub net_pnl: CentsUsdPattern, pub net_pnl: CentsUsdPattern,
pub nupl: BpsRatioPattern, pub nupl: BpsRatioPattern,
pub profit: BaseCumulativeSumPattern3, pub profit: CentsUsdPattern2,
} }
impl LossNetNuplProfitPattern { impl LossNetNuplProfitPattern {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
loss: BaseCumulativeNegativeSumPattern::new(client.clone(), acc.clone(), "unrealized_loss".to_string()), loss: CentsNegativeUsdPattern::new(client.clone(), acc.clone()),
net_pnl: CentsUsdPattern::new(client.clone(), _m(&acc, "net_unrealized_pnl")), net_pnl: CentsUsdPattern::new(client.clone(), _m(&acc, "net_unrealized_pnl")),
nupl: BpsRatioPattern::new(client.clone(), _m(&acc, "nupl")), nupl: BpsRatioPattern::new(client.clone(), _m(&acc, "nupl")),
profit: BaseCumulativeSumPattern3::new(client.clone(), _m(&acc, "unrealized_profit")), profit: CentsUsdPattern2::new(client.clone(), _m(&acc, "unrealized_profit")),
} }
} }
} }
@@ -2446,6 +2442,24 @@ impl CentsDeltaUsdPattern {
} }
} }
/// Pattern struct for repeated tree structure.
pub struct CentsNegativeUsdPattern {
pub cents: SeriesPattern1<Cents>,
pub negative: SeriesPattern1<Dollars>,
pub usd: SeriesPattern1<Dollars>,
}
impl CentsNegativeUsdPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
cents: SeriesPattern1::new(client.clone(), _m(&acc, "unrealized_loss_cents")),
negative: SeriesPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")),
usd: SeriesPattern1::new(client.clone(), _m(&acc, "unrealized_loss")),
}
}
}
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct CentsSatsUsdPattern { pub struct CentsSatsUsdPattern {
pub cents: SeriesPattern1<Cents>, pub cents: SeriesPattern1<Cents>,
@@ -2509,18 +2523,18 @@ pub struct GreedNetPainPattern {
/// Pattern struct for repeated tree structure. /// Pattern struct for repeated tree structure.
pub struct LossNuplProfitPattern { pub struct LossNuplProfitPattern {
pub loss: BaseCumulativeNegativeSumPattern, pub loss: CentsNegativeUsdPattern,
pub nupl: BpsRatioPattern, pub nupl: BpsRatioPattern,
pub profit: BaseCumulativeSumPattern3, pub profit: CentsUsdPattern2,
} }
impl LossNuplProfitPattern { impl LossNuplProfitPattern {
/// Create a new pattern node with accumulated series name. /// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self { pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self { Self {
loss: BaseCumulativeNegativeSumPattern::new(client.clone(), acc.clone(), "unrealized_loss".to_string()), loss: CentsNegativeUsdPattern::new(client.clone(), acc.clone()),
nupl: BpsRatioPattern::new(client.clone(), _m(&acc, "nupl")), nupl: BpsRatioPattern::new(client.clone(), _m(&acc, "nupl")),
profit: BaseCumulativeSumPattern3::new(client.clone(), _m(&acc, "unrealized_profit")), profit: CentsUsdPattern2::new(client.clone(), _m(&acc, "unrealized_profit")),
} }
} }
} }
@@ -6678,9 +6692,8 @@ impl SeriesTree_Cohorts_Utxo_All_Unrealized {
/// Series tree node. /// Series tree node.
pub struct SeriesTree_Cohorts_Utxo_All_Unrealized_Profit { pub struct SeriesTree_Cohorts_Utxo_All_Unrealized_Profit {
pub base: CentsUsdPattern2, pub usd: SeriesPattern1<Dollars>,
pub cumulative: CentsUsdPattern2, pub cents: SeriesPattern1<Cents>,
pub sum: _1m1w1y24hPattern4,
pub to_mcap: BpsPercentRatioPattern3, pub to_mcap: BpsPercentRatioPattern3,
pub to_own_gross_pnl: BpsPercentRatioPattern3, pub to_own_gross_pnl: BpsPercentRatioPattern3,
} }
@@ -6688,9 +6701,8 @@ pub struct SeriesTree_Cohorts_Utxo_All_Unrealized_Profit {
impl SeriesTree_Cohorts_Utxo_All_Unrealized_Profit { impl SeriesTree_Cohorts_Utxo_All_Unrealized_Profit {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
base: CentsUsdPattern2::new(client.clone(), "unrealized_profit".to_string()), usd: SeriesPattern1::new(client.clone(), "unrealized_profit".to_string()),
cumulative: CentsUsdPattern2::new(client.clone(), "unrealized_profit_cumulative".to_string()), cents: SeriesPattern1::new(client.clone(), "unrealized_profit_cents".to_string()),
sum: _1m1w1y24hPattern4::new(client.clone(), "unrealized_profit_sum".to_string()),
to_mcap: BpsPercentRatioPattern3::new(client.clone(), "unrealized_profit_to_mcap".to_string()), to_mcap: BpsPercentRatioPattern3::new(client.clone(), "unrealized_profit_to_mcap".to_string()),
to_own_gross_pnl: BpsPercentRatioPattern3::new(client.clone(), "unrealized_profit_to_own_gross_pnl".to_string()), to_own_gross_pnl: BpsPercentRatioPattern3::new(client.clone(), "unrealized_profit_to_own_gross_pnl".to_string()),
} }
@@ -6699,9 +6711,8 @@ impl SeriesTree_Cohorts_Utxo_All_Unrealized_Profit {
/// Series tree node. /// Series tree node.
pub struct SeriesTree_Cohorts_Utxo_All_Unrealized_Loss { pub struct SeriesTree_Cohorts_Utxo_All_Unrealized_Loss {
pub base: CentsUsdPattern2, pub usd: SeriesPattern1<Dollars>,
pub cumulative: CentsUsdPattern2, pub cents: SeriesPattern1<Cents>,
pub sum: _1m1w1y24hPattern4,
pub negative: SeriesPattern1<Dollars>, pub negative: SeriesPattern1<Dollars>,
pub to_mcap: BpsPercentRatioPattern3, pub to_mcap: BpsPercentRatioPattern3,
pub to_own_gross_pnl: BpsPercentRatioPattern3, pub to_own_gross_pnl: BpsPercentRatioPattern3,
@@ -6710,9 +6721,8 @@ pub struct SeriesTree_Cohorts_Utxo_All_Unrealized_Loss {
impl SeriesTree_Cohorts_Utxo_All_Unrealized_Loss { impl SeriesTree_Cohorts_Utxo_All_Unrealized_Loss {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
base: CentsUsdPattern2::new(client.clone(), "unrealized_loss".to_string()), usd: SeriesPattern1::new(client.clone(), "unrealized_loss".to_string()),
cumulative: CentsUsdPattern2::new(client.clone(), "unrealized_loss_cumulative".to_string()), cents: SeriesPattern1::new(client.clone(), "unrealized_loss_cents".to_string()),
sum: _1m1w1y24hPattern4::new(client.clone(), "unrealized_loss_sum".to_string()),
negative: SeriesPattern1::new(client.clone(), "neg_unrealized_loss".to_string()), negative: SeriesPattern1::new(client.clone(), "neg_unrealized_loss".to_string()),
to_mcap: BpsPercentRatioPattern3::new(client.clone(), "unrealized_loss_to_mcap".to_string()), to_mcap: BpsPercentRatioPattern3::new(client.clone(), "unrealized_loss_to_mcap".to_string()),
to_own_gross_pnl: BpsPercentRatioPattern3::new(client.clone(), "unrealized_loss_to_own_gross_pnl".to_string()), to_own_gross_pnl: BpsPercentRatioPattern3::new(client.clone(), "unrealized_loss_to_own_gross_pnl".to_string()),
@@ -7153,9 +7163,9 @@ impl SeriesTree_Cohorts_Utxo_Sth_CostBasis {
/// Series tree node. /// Series tree node.
pub struct SeriesTree_Cohorts_Utxo_Sth_Unrealized { pub struct SeriesTree_Cohorts_Utxo_Sth_Unrealized {
pub nupl: BpsRatioPattern, pub nupl: BpsRatioPattern,
pub profit: BaseCumulativeSumToPattern2, pub profit: CentsToUsdPattern4,
pub loss: BaseCumulativeNegativeSumToPattern2, pub loss: CentsNegativeToUsdPattern2,
pub net_pnl: CentsToUsdPattern2, pub net_pnl: CentsToUsdPattern3,
pub gross_pnl: CentsUsdPattern2, pub gross_pnl: CentsUsdPattern2,
pub invested_capital: InPattern, pub invested_capital: InPattern,
pub sentiment: SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment, pub sentiment: SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment,
@@ -7165,9 +7175,9 @@ impl SeriesTree_Cohorts_Utxo_Sth_Unrealized {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
nupl: BpsRatioPattern::new(client.clone(), "sth_nupl".to_string()), nupl: BpsRatioPattern::new(client.clone(), "sth_nupl".to_string()),
profit: BaseCumulativeSumToPattern2::new(client.clone(), "sth_unrealized_profit".to_string()), profit: CentsToUsdPattern4::new(client.clone(), "sth_unrealized_profit".to_string()),
loss: BaseCumulativeNegativeSumToPattern2::new(client.clone(), "sth".to_string()), loss: CentsNegativeToUsdPattern2::new(client.clone(), "sth".to_string()),
net_pnl: CentsToUsdPattern2::new(client.clone(), "sth_net_unrealized_pnl".to_string()), net_pnl: CentsToUsdPattern3::new(client.clone(), "sth_net_unrealized_pnl".to_string()),
gross_pnl: CentsUsdPattern2::new(client.clone(), "sth_unrealized_gross_pnl".to_string()), gross_pnl: CentsUsdPattern2::new(client.clone(), "sth_unrealized_gross_pnl".to_string()),
invested_capital: InPattern::new(client.clone(), "sth_invested_capital_in".to_string()), invested_capital: InPattern::new(client.clone(), "sth_invested_capital_in".to_string()),
sentiment: SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment::new(client.clone(), format!("{base_path}_sentiment")), sentiment: SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment::new(client.clone(), format!("{base_path}_sentiment")),
@@ -7572,9 +7582,9 @@ impl SeriesTree_Cohorts_Utxo_Lth_CostBasis {
/// Series tree node. /// Series tree node.
pub struct SeriesTree_Cohorts_Utxo_Lth_Unrealized { pub struct SeriesTree_Cohorts_Utxo_Lth_Unrealized {
pub nupl: BpsRatioPattern, pub nupl: BpsRatioPattern,
pub profit: BaseCumulativeSumToPattern2, pub profit: CentsToUsdPattern4,
pub loss: BaseCumulativeNegativeSumToPattern2, pub loss: CentsNegativeToUsdPattern2,
pub net_pnl: CentsToUsdPattern2, pub net_pnl: CentsToUsdPattern3,
pub gross_pnl: CentsUsdPattern2, pub gross_pnl: CentsUsdPattern2,
pub invested_capital: InPattern, pub invested_capital: InPattern,
pub sentiment: SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment, pub sentiment: SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment,
@@ -7584,9 +7594,9 @@ impl SeriesTree_Cohorts_Utxo_Lth_Unrealized {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self { pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self { Self {
nupl: BpsRatioPattern::new(client.clone(), "lth_nupl".to_string()), nupl: BpsRatioPattern::new(client.clone(), "lth_nupl".to_string()),
profit: BaseCumulativeSumToPattern2::new(client.clone(), "lth_unrealized_profit".to_string()), profit: CentsToUsdPattern4::new(client.clone(), "lth_unrealized_profit".to_string()),
loss: BaseCumulativeNegativeSumToPattern2::new(client.clone(), "lth".to_string()), loss: CentsNegativeToUsdPattern2::new(client.clone(), "lth".to_string()),
net_pnl: CentsToUsdPattern2::new(client.clone(), "lth_net_unrealized_pnl".to_string()), net_pnl: CentsToUsdPattern3::new(client.clone(), "lth_net_unrealized_pnl".to_string()),
gross_pnl: CentsUsdPattern2::new(client.clone(), "lth_unrealized_gross_pnl".to_string()), gross_pnl: CentsUsdPattern2::new(client.clone(), "lth_unrealized_gross_pnl".to_string()),
invested_capital: InPattern::new(client.clone(), "lth_invested_capital_in".to_string()), invested_capital: InPattern::new(client.clone(), "lth_invested_capital_in".to_string()),
sentiment: SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment::new(client.clone(), format!("{base_path}_sentiment")), sentiment: SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment::new(client.clone(), format!("{base_path}_sentiment")),

View File

@@ -61,8 +61,6 @@ impl TypeCohortMetrics {
self.supply.compute(prices, starting_indexes.height, exit)?; self.supply.compute(prices, starting_indexes.height, exit)?;
self.realized self.realized
.compute_rest_part1(starting_indexes, exit)?; .compute_rest_part1(starting_indexes, exit)?;
self.unrealized
.compute_rest(starting_indexes.height, exit)?;
Ok(()) Ok(())
} }

View File

@@ -42,14 +42,14 @@ impl RelativeExtendedOwnMarketCap {
self.unrealized_profit_to_own_mcap self.unrealized_profit_to_own_mcap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>( .compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from, max_from,
&unrealized.profit.base.usd.height, &unrealized.profit.usd.height,
own_market_cap, own_market_cap,
exit, exit,
)?; )?;
self.unrealized_loss_to_own_mcap self.unrealized_loss_to_own_mcap
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>( .compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
max_from, max_from,
&unrealized.loss.base.usd.height, &unrealized.loss.usd.height,
own_market_cap, own_market_cap,
exit, exit,
)?; )?;

View File

@@ -43,14 +43,14 @@ impl RelativeExtendedOwnPnl {
self.unrealized_profit_to_own_gross_pnl self.unrealized_profit_to_own_gross_pnl
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>( .compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from, max_from,
&unrealized.profit.base.usd.height, &unrealized.profit.usd.height,
gross_pnl_usd, gross_pnl_usd,
exit, exit,
)?; )?;
self.unrealized_loss_to_own_gross_pnl self.unrealized_loss_to_own_gross_pnl
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>( .compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from, max_from,
&unrealized.loss.base.usd.height, &unrealized.loss.usd.height,
gross_pnl_usd, gross_pnl_usd,
exit, exit,
)?; )?;

View File

@@ -64,14 +64,14 @@ impl RelativeFull {
self.unrealized_profit_to_mcap self.unrealized_profit_to_mcap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>( .compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from, max_from,
&unrealized.profit.base.usd.height, &unrealized.profit.usd.height,
market_cap, market_cap,
exit, exit,
)?; )?;
self.unrealized_loss_to_mcap self.unrealized_loss_to_mcap
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>( .compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
max_from, max_from,
&unrealized.loss.base.usd.height, &unrealized.loss.usd.height,
market_cap, market_cap,
exit, exit,
)?; )?;

View File

@@ -1,12 +1,12 @@
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{Cents, Dollars, Height, Indexes, Version}; use brk_types::{Cents, Dollars, Indexes, Version};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, Rw, StorageMode, WritableVec}; use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableCloneableVec, Rw, StorageMode, WritableVec};
use crate::{ use crate::{
distribution::{metrics::ImportConfig, state::UnrealizedState}, distribution::{metrics::ImportConfig, state::UnrealizedState},
internal::{FiatPerBlockCumulativeWithSums, LazyPerBlock, NegCentsUnsignedToDollars}, internal::{FiatPerBlock, LazyPerBlock, NegCentsUnsignedToDollars},
}; };
use super::UnrealizedMinimal; use super::UnrealizedMinimal;
@@ -17,8 +17,8 @@ pub struct UnrealizedBasic<M: StorageMode = Rw> {
#[deref_mut] #[deref_mut]
#[traversable(flatten)] #[traversable(flatten)]
pub minimal: UnrealizedMinimal<M>, pub minimal: UnrealizedMinimal<M>,
pub profit: FiatPerBlockCumulativeWithSums<Cents, M>, pub profit: FiatPerBlock<Cents, M>,
pub loss: FiatPerBlockCumulativeWithSums<Cents, M>, pub loss: FiatPerBlock<Cents, M>,
#[traversable(wrap = "loss", rename = "negative")] #[traversable(wrap = "loss", rename = "negative")]
pub neg_loss: LazyPerBlock<Dollars, Cents>, pub neg_loss: LazyPerBlock<Dollars, Cents>,
} }
@@ -27,13 +27,13 @@ impl UnrealizedBasic {
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> { pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
let v1 = Version::ONE; let v1 = Version::ONE;
let loss: FiatPerBlockCumulativeWithSums<Cents> = cfg.import("unrealized_loss", v1)?; let loss: FiatPerBlock<Cents> = cfg.import("unrealized_loss", v1)?;
let neg_loss = LazyPerBlock::from_computed::<NegCentsUnsignedToDollars>( let neg_loss = LazyPerBlock::from_computed::<NegCentsUnsignedToDollars>(
&cfg.name("neg_unrealized_loss"), &cfg.name("neg_unrealized_loss"),
cfg.version, cfg.version,
loss.base.cents.height.read_only_boxed_clone(), loss.cents.height.read_only_boxed_clone(),
&loss.base.cents, &loss.cents,
); );
Ok(Self { Ok(Self {
@@ -46,22 +46,19 @@ impl UnrealizedBasic {
pub(crate) fn min_stateful_len(&self) -> usize { pub(crate) fn min_stateful_len(&self) -> usize {
self.profit self.profit
.base
.cents .cents
.height .height
.len() .len()
.min(self.loss.base.cents.height.len()) .min(self.loss.cents.height.len())
} }
#[inline(always)] #[inline(always)]
pub(crate) fn push_state(&mut self, state: &UnrealizedState) { pub(crate) fn push_state(&mut self, state: &UnrealizedState) {
self.profit self.profit
.base
.cents .cents
.height .height
.push(state.unrealized_profit); .push(state.unrealized_profit);
self.loss self.loss
.base
.cents .cents
.height .height
.push(state.unrealized_loss); .push(state.unrealized_loss);
@@ -69,8 +66,8 @@ impl UnrealizedBasic {
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> { pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
vec![ vec![
&mut self.profit.base.cents.height as &mut dyn AnyStoredVec, &mut self.profit.cents.height as &mut dyn AnyStoredVec,
&mut self.loss.base.cents.height, &mut self.loss.cents.height,
] ]
} }
@@ -80,18 +77,8 @@ impl UnrealizedBasic {
others: &[&Self], others: &[&Self],
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
sum_others!(self, starting_indexes, others, exit; profit.base.cents.height); sum_others!(self, starting_indexes, others, exit; profit.cents.height);
sum_others!(self, starting_indexes, others, exit; loss.base.cents.height); sum_others!(self, starting_indexes, others, exit; loss.cents.height);
Ok(())
}
pub(crate) fn compute_rest(
&mut self,
max_from: Height,
exit: &Exit,
) -> Result<()> {
self.profit.compute_rest(max_from, exit)?;
self.loss.compute_rest(max_from, exit)?;
Ok(()) Ok(())
} }
} }

View File

@@ -65,16 +65,13 @@ impl UnrealizedCore {
starting_indexes: &Indexes, starting_indexes: &Indexes,
exit: &Exit, exit: &Exit,
) -> Result<()> { ) -> Result<()> {
self.basic
.compute_rest(starting_indexes.height, exit)?;
self.net_pnl self.net_pnl
.cents .cents
.height .height
.compute_binary::<Cents, Cents, CentsSubtractToCentsSigned>( .compute_binary::<Cents, Cents, CentsSubtractToCentsSigned>(
starting_indexes.height, starting_indexes.height,
&self.basic.profit.base.cents.height, &self.basic.profit.cents.height,
&self.basic.loss.base.cents.height, &self.basic.loss.cents.height,
exit, exit,
)?; )?;

View File

@@ -92,8 +92,8 @@ impl UnrealizedFull {
self.gross_pnl.cents.height.compute_add( self.gross_pnl.cents.height.compute_add(
starting_indexes.height, starting_indexes.height,
&self.inner.core.basic.profit.base.cents.height, &self.inner.core.basic.profit.cents.height,
&self.inner.core.basic.loss.base.cents.height, &self.inner.core.basic.loss.cents.height,
exit, exit,
)?; )?;

View File

@@ -22,8 +22,8 @@ mod bulk;
mod data; mod data;
pub mod legacy; pub mod legacy;
/// Maximum allowed request weight in bytes (650KB) /// Maximum allowed request weight in bytes (320KB)
const MAX_WEIGHT: usize = 65 * 10_000; const MAX_WEIGHT: usize = 4 * 8 * 10_000;
/// Maximum allowed request weight for localhost (50MB) /// Maximum allowed request weight for localhost (50MB)
const MAX_WEIGHT_LOCALHOST: usize = 50 * 1_000_000; const MAX_WEIGHT_LOCALHOST: usize = 50 * 1_000_000;
/// Cache control header for series data responses /// Cache control header for series data responses

View File

@@ -3,13 +3,14 @@ use std::ops::{Add, AddAssign, Div};
use derive_more::Deref; use derive_more::Deref;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use vecdb::{CheckedSub, Formattable, Pco}; use vecdb::{unlikely, CheckedSub, Formattable, Pco};
use super::StoredF32; use super::StoredF32;
/// Unsigned basis points stored as u32. /// Unsigned basis points stored as u32.
/// 1 bp = 0.0001. Range: 0429,496.7295. /// 1 bp = 0.0001. Range: 0429,496.7295.
/// Use for unbounded unsigned ratios (MVRV, NVT, SOPR, etc.). /// Use for unbounded unsigned ratios (MVRV, NVT, SOPR, etc.).
/// `u32::MAX` is reserved as a NaN sentinel.
#[derive( #[derive(
Debug, Debug,
Deref, Deref,
@@ -30,9 +31,12 @@ pub struct BasisPoints32(u32);
impl BasisPoints32 { impl BasisPoints32 {
pub const ZERO: Self = Self(0); pub const ZERO: Self = Self(0);
/// NaN sentinel — uses u32::MAX which is outside the practical range.
pub const NAN: Self = Self(u32::MAX);
#[inline] #[inline]
pub const fn new(value: u32) -> Self { pub const fn new(value: u32) -> Self {
debug_assert!(value != u32::MAX, "u32::MAX is reserved as NaN sentinel");
Self(value) Self(value)
} }
@@ -41,10 +45,19 @@ impl BasisPoints32 {
self.0 self.0
} }
/// Convert to f32: divide by 10000. #[inline]
pub fn is_nan(self) -> bool {
self.0 == u32::MAX
}
/// Convert to f32: divide by 10000. Returns NaN for sentinel value.
#[inline] #[inline]
pub fn to_f32(self) -> f32 { pub fn to_f32(self) -> f32 {
self.0 as f32 / 10000.0 if unlikely(self.0 == u32::MAX) {
f32::NAN
} else {
self.0 as f32 / 10000.0
}
} }
} }
@@ -52,7 +65,7 @@ impl From<usize> for BasisPoints32 {
#[inline] #[inline]
fn from(value: usize) -> Self { fn from(value: usize) -> Self {
debug_assert!( debug_assert!(
value <= u32::MAX as usize, value < u32::MAX as usize,
"usize out of BasisPoints32 range: {value}" "usize out of BasisPoints32 range: {value}"
); );
Self(value as u32) Self(value as u32)
@@ -62,6 +75,7 @@ impl From<usize> for BasisPoints32 {
impl From<u32> for BasisPoints32 { impl From<u32> for BasisPoints32 {
#[inline] #[inline]
fn from(value: u32) -> Self { fn from(value: u32) -> Self {
debug_assert!(value != u32::MAX, "u32::MAX is reserved as NaN sentinel");
Self(value) Self(value)
} }
} }
@@ -75,10 +89,14 @@ impl From<BasisPoints32> for u32 {
/// Convert from float: multiply by 10000 and round. /// Convert from float: multiply by 10000 and round.
/// Input is in ratio form (e.g., 2.5 for MVRV of 2.5). /// Input is in ratio form (e.g., 2.5 for MVRV of 2.5).
/// NaN/Inf → NaN sentinel.
impl From<f64> for BasisPoints32 { impl From<f64> for BasisPoints32 {
#[inline] #[inline]
fn from(value: f64) -> Self { fn from(value: f64) -> Self {
let scaled = (value * 10000.0).round().clamp(0.0, u32::MAX as f64); if unlikely(!value.is_finite()) {
return Self::NAN;
}
let scaled = (value * 10000.0).round().clamp(0.0, u32::MAX as f64 - 1.0);
Self(scaled as u32) Self(scaled as u32)
} }
} }
@@ -86,13 +104,20 @@ impl From<f64> for BasisPoints32 {
impl From<BasisPoints32> for f64 { impl From<BasisPoints32> for f64 {
#[inline] #[inline]
fn from(value: BasisPoints32) -> Self { fn from(value: BasisPoints32) -> Self {
value.0 as f64 / 10000.0 if unlikely(value.0 == u32::MAX) {
f64::NAN
} else {
value.0 as f64 / 10000.0
}
} }
} }
impl From<f32> for BasisPoints32 { impl From<f32> for BasisPoints32 {
#[inline] #[inline]
fn from(value: f32) -> Self { fn from(value: f32) -> Self {
if unlikely(!value.is_finite()) {
return Self::NAN;
}
Self::from(value as f64) Self::from(value as f64)
} }
} }
@@ -107,7 +132,11 @@ impl From<StoredF32> for BasisPoints32 {
impl From<BasisPoints32> for f32 { impl From<BasisPoints32> for f32 {
#[inline] #[inline]
fn from(value: BasisPoints32) -> Self { fn from(value: BasisPoints32) -> Self {
value.0 as f32 / 10000.0 if unlikely(value.0 == u32::MAX) {
f32::NAN
} else {
value.0 as f32 / 10000.0
}
} }
} }
@@ -122,14 +151,18 @@ impl Add for BasisPoints32 {
type Output = Self; type Output = Self;
#[inline] #[inline]
fn add(self, rhs: Self) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0) if unlikely(self.0 == u32::MAX || rhs.0 == u32::MAX) {
Self::NAN
} else {
Self(self.0 + rhs.0)
}
} }
} }
impl AddAssign for BasisPoints32 { impl AddAssign for BasisPoints32 {
#[inline] #[inline]
fn add_assign(&mut self, rhs: Self) { fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0; *self = *self + rhs;
} }
} }
@@ -137,14 +170,22 @@ impl Div<usize> for BasisPoints32 {
type Output = Self; type Output = Self;
#[inline] #[inline]
fn div(self, rhs: usize) -> Self::Output { fn div(self, rhs: usize) -> Self::Output {
debug_assert!(rhs <= u32::MAX as usize, "divisor out of u32 range: {rhs}"); if unlikely(self.0 == u32::MAX) {
Self(self.0 / rhs as u32) Self::NAN
} else {
debug_assert!(rhs <= u32::MAX as usize, "divisor out of u32 range: {rhs}");
Self(self.0 / rhs as u32)
}
} }
} }
impl CheckedSub for BasisPoints32 { impl CheckedSub for BasisPoints32 {
fn checked_sub(self, rhs: Self) -> Option<Self> { fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self) if unlikely(self.0 == u32::MAX || rhs.0 == u32::MAX) {
Some(Self::NAN)
} else {
self.0.checked_sub(rhs.0).map(Self)
}
} }
} }
@@ -162,4 +203,13 @@ impl Formattable for BasisPoints32 {
let mut b = itoa::Buffer::new(); let mut b = itoa::Buffer::new();
buf.extend_from_slice(b.format(self.0).as_bytes()); buf.extend_from_slice(b.format(self.0).as_bytes());
} }
#[inline(always)]
fn fmt_json(&self, buf: &mut Vec<u8>) {
if unlikely(self.0 == u32::MAX) {
buf.extend_from_slice(b"null");
} else {
self.write_to(buf);
}
}
} }

View File

@@ -3,13 +3,14 @@ use std::ops::{Add, AddAssign, Div, Sub, SubAssign};
use derive_more::Deref; use derive_more::Deref;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use vecdb::{CheckedSub, Formattable, Pco}; use vecdb::{unlikely, CheckedSub, Formattable, Pco};
use super::StoredF32; use super::StoredF32;
/// Signed basis points stored as i32. /// Signed basis points stored as i32.
/// 1 bp = 0.0001. Range: -214,748.3647 to +214,748.3647. /// 1 bp = 0.0001. Range: -214,748.3647 to +214,748.3647.
/// Use for unbounded signed values (returns, growth rates, volatility, z-scores, etc.). /// Use for unbounded signed values (returns, growth rates, volatility, z-scores, etc.).
/// `i32::MIN` is reserved as a NaN sentinel.
#[derive( #[derive(
Debug, Debug,
Deref, Deref,
@@ -30,9 +31,12 @@ pub struct BasisPointsSigned32(i32);
impl BasisPointsSigned32 { impl BasisPointsSigned32 {
pub const ZERO: Self = Self(0); pub const ZERO: Self = Self(0);
/// NaN sentinel — uses i32::MIN which is outside the documented range.
pub const NAN: Self = Self(i32::MIN);
#[inline] #[inline]
pub const fn new(value: i32) -> Self { pub const fn new(value: i32) -> Self {
debug_assert!(value != i32::MIN, "i32::MIN is reserved as NaN sentinel");
Self(value) Self(value)
} }
@@ -42,14 +46,23 @@ impl BasisPointsSigned32 {
} }
#[inline] #[inline]
pub fn is_negative(self) -> bool { pub fn is_nan(self) -> bool {
self.0 < 0 self.0 == i32::MIN
} }
/// Convert to f32: divide by 10000. #[inline]
pub fn is_negative(self) -> bool {
self.0 < 0 && self.0 != i32::MIN
}
/// Convert to f32: divide by 10000. Returns NaN for sentinel value.
#[inline] #[inline]
pub fn to_f32(self) -> f32 { pub fn to_f32(self) -> f32 {
self.0 as f32 / 10000.0 if unlikely(self.0 == i32::MIN) {
f32::NAN
} else {
self.0 as f32 / 10000.0
}
} }
} }
@@ -67,6 +80,7 @@ impl From<usize> for BasisPointsSigned32 {
impl From<i32> for BasisPointsSigned32 { impl From<i32> for BasisPointsSigned32 {
#[inline] #[inline]
fn from(value: i32) -> Self { fn from(value: i32) -> Self {
debug_assert!(value != i32::MIN, "i32::MIN is reserved as NaN sentinel");
Self(value) Self(value)
} }
} }
@@ -80,24 +94,32 @@ impl From<BasisPointsSigned32> for i32 {
/// Convert from float: multiply by 10000 and round. /// Convert from float: multiply by 10000 and round.
/// Input is in ratio form (e.g., 50.0 for +5000%). /// Input is in ratio form (e.g., 50.0 for +5000%).
/// NaN/Inf → NaN sentinel.
impl From<f64> for BasisPointsSigned32 { impl From<f64> for BasisPointsSigned32 {
#[inline] #[inline]
fn from(value: f64) -> Self { fn from(value: f64) -> Self {
if unlikely(!value.is_finite()) {
return Self::NAN;
}
let scaled = (value * 10000.0) let scaled = (value * 10000.0)
.round() .round()
.clamp(i32::MIN as f64, i32::MAX as f64); .clamp(i32::MIN as f64 + 1.0, i32::MAX as f64);
Self(scaled as i32) Self(scaled as i32)
} }
} }
/// Convert from f32 ratio form: multiply by 10000 and round. /// Convert from f32 ratio form: multiply by 10000 and round.
/// Input is in ratio form (e.g., 0.5 for +50% → 5000 bps). /// Input is in ratio form (e.g., 0.5 for +50% → 5000 bps).
/// NaN/Inf → NaN sentinel.
impl From<f32> for BasisPointsSigned32 { impl From<f32> for BasisPointsSigned32 {
#[inline] #[inline]
fn from(value: f32) -> Self { fn from(value: f32) -> Self {
if unlikely(!value.is_finite()) {
return Self::NAN;
}
let scaled = (value * 10000.0) let scaled = (value * 10000.0)
.round() .round()
.clamp(i32::MIN as f32, i32::MAX as f32); .clamp(i32::MIN as f32 + 1.0, i32::MAX as f32);
Self(scaled as i32) Self(scaled as i32)
} }
} }
@@ -105,7 +127,11 @@ impl From<f32> for BasisPointsSigned32 {
impl From<BasisPointsSigned32> for f64 { impl From<BasisPointsSigned32> for f64 {
#[inline] #[inline]
fn from(value: BasisPointsSigned32) -> Self { fn from(value: BasisPointsSigned32) -> Self {
value.0 as f64 / 10000.0 if unlikely(value.0 == i32::MIN) {
f64::NAN
} else {
value.0 as f64 / 10000.0
}
} }
} }
@@ -120,14 +146,18 @@ impl Add for BasisPointsSigned32 {
type Output = Self; type Output = Self;
#[inline] #[inline]
fn add(self, rhs: Self) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0) if unlikely(self.0 == i32::MIN || rhs.0 == i32::MIN) {
Self::NAN
} else {
Self(self.0 + rhs.0)
}
} }
} }
impl AddAssign for BasisPointsSigned32 { impl AddAssign for BasisPointsSigned32 {
#[inline] #[inline]
fn add_assign(&mut self, rhs: Self) { fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0; *self = *self + rhs;
} }
} }
@@ -135,14 +165,18 @@ impl Sub for BasisPointsSigned32 {
type Output = Self; type Output = Self;
#[inline] #[inline]
fn sub(self, rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0) if unlikely(self.0 == i32::MIN || rhs.0 == i32::MIN) {
Self::NAN
} else {
Self(self.0 - rhs.0)
}
} }
} }
impl SubAssign for BasisPointsSigned32 { impl SubAssign for BasisPointsSigned32 {
#[inline] #[inline]
fn sub_assign(&mut self, rhs: Self) { fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0; *self = *self - rhs;
} }
} }
@@ -150,14 +184,22 @@ impl Div<usize> for BasisPointsSigned32 {
type Output = Self; type Output = Self;
#[inline] #[inline]
fn div(self, rhs: usize) -> Self::Output { fn div(self, rhs: usize) -> Self::Output {
debug_assert!(rhs <= i32::MAX as usize, "divisor out of i32 range: {rhs}"); if unlikely(self.0 == i32::MIN) {
Self(self.0 / rhs as i32) Self::NAN
} else {
debug_assert!(rhs <= i32::MAX as usize, "divisor out of i32 range: {rhs}");
Self(self.0 / rhs as i32)
}
} }
} }
impl CheckedSub for BasisPointsSigned32 { impl CheckedSub for BasisPointsSigned32 {
fn checked_sub(self, rhs: Self) -> Option<Self> { fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self) if unlikely(self.0 == i32::MIN || rhs.0 == i32::MIN) {
Some(Self::NAN)
} else {
self.0.checked_sub(rhs.0).map(Self)
}
} }
} }
@@ -175,4 +217,13 @@ impl Formattable for BasisPointsSigned32 {
let mut b = itoa::Buffer::new(); let mut b = itoa::Buffer::new();
buf.extend_from_slice(b.format(self.0).as_bytes()); buf.extend_from_slice(b.format(self.0).as_bytes());
} }
#[inline(always)]
fn fmt_json(&self, buf: &mut Vec<u8>) {
if unlikely(self.0 == i32::MIN) {
buf.extend_from_slice(b"null");
} else {
self.write_to(buf);
}
}
} }

View File

@@ -77,6 +77,7 @@
* Unsigned basis points stored as u32. * Unsigned basis points stored as u32.
* 1 bp = 0.0001. Range: 0429,496.7295. * 1 bp = 0.0001. Range: 0429,496.7295.
* Use for unbounded unsigned ratios (MVRV, NVT, SOPR, etc.). * Use for unbounded unsigned ratios (MVRV, NVT, SOPR, etc.).
* `u32::MAX` is reserved as a NaN sentinel.
* *
* @typedef {number} BasisPoints32 * @typedef {number} BasisPoints32
*/ */
@@ -91,6 +92,7 @@
* Signed basis points stored as i32. * Signed basis points stored as i32.
* 1 bp = 0.0001. Range: -214,748.3647 to +214,748.3647. * 1 bp = 0.0001. Range: -214,748.3647 to +214,748.3647.
* Use for unbounded signed values (returns, growth rates, volatility, z-scores, etc.). * Use for unbounded signed values (returns, growth rates, volatility, z-scores, etc.).
* `i32::MIN` is reserved as a NaN sentinel.
* *
* @typedef {number} BasisPointsSigned32 * @typedef {number} BasisPointsSigned32
*/ */
@@ -2107,35 +2109,6 @@ function create_1m1w1y24hBpsPercentRatioPattern(client, acc) {
* @property {BaseCumulativeSumPattern<Cents>} valueDestroyed * @property {BaseCumulativeSumPattern<Cents>} valueDestroyed
*/ */
/**
* @typedef {Object} BaseCumulativeNegativeSumToPattern2
* @property {CentsUsdPattern2} base
* @property {CentsUsdPattern2} cumulative
* @property {SeriesPattern1<Dollars>} negative
* @property {_1m1w1y24hPattern4} sum
* @property {BpsPercentRatioPattern3} toMcap
* @property {BpsPercentRatioPattern3} toOwnGrossPnl
* @property {BpsPercentRatioPattern4} toOwnMcap
*/
/**
* Create a BaseCumulativeNegativeSumToPattern2 pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {BaseCumulativeNegativeSumToPattern2}
*/
function createBaseCumulativeNegativeSumToPattern2(client, acc) {
return {
base: createCentsUsdPattern2(client, _m(acc, 'unrealized_loss')),
cumulative: createCentsUsdPattern2(client, _m(acc, 'unrealized_loss_cumulative')),
negative: createSeriesPattern1(client, _m(acc, 'neg_unrealized_loss')),
sum: create_1m1w1y24hPattern4(client, _m(acc, 'unrealized_loss_sum')),
toMcap: createBpsPercentRatioPattern3(client, _m(acc, 'unrealized_loss_to_mcap')),
toOwnGrossPnl: createBpsPercentRatioPattern3(client, _m(acc, 'unrealized_loss_to_own_gross_pnl')),
toOwnMcap: createBpsPercentRatioPattern4(client, _m(acc, 'unrealized_loss_to_own_mcap')),
};
}
/** /**
* @typedef {Object} CapLossMvrvNetPriceProfitSoprPattern * @typedef {Object} CapLossMvrvNetPriceProfitSoprPattern
* @property {CentsDeltaUsdPattern} cap * @property {CentsDeltaUsdPattern} cap
@@ -2156,7 +2129,7 @@ function createBaseCumulativeNegativeSumToPattern2(client, acc) {
function createCapLossMvrvNetPriceProfitSoprPattern(client, acc) { function createCapLossMvrvNetPriceProfitSoprPattern(client, acc) {
return { return {
cap: createCentsDeltaUsdPattern(client, _m(acc, 'realized_cap')), cap: createCentsDeltaUsdPattern(client, _m(acc, 'realized_cap')),
loss: createBaseCumulativeNegativeSumPattern(client, acc, 'realized_loss'), loss: createBaseCumulativeNegativeSumPattern(client, acc),
mvrv: createSeriesPattern1(client, _m(acc, 'mvrv')), mvrv: createSeriesPattern1(client, _m(acc, 'mvrv')),
netPnl: createBaseCumulativeDeltaSumPattern(client, _m(acc, 'net_realized_pnl')), netPnl: createBaseCumulativeDeltaSumPattern(client, _m(acc, 'net_realized_pnl')),
price: createBpsCentsRatioSatsUsdPattern(client, _m(acc, 'realized_price')), price: createBpsCentsRatioSatsUsdPattern(client, _m(acc, 'realized_price')),
@@ -2169,10 +2142,10 @@ function createCapLossMvrvNetPriceProfitSoprPattern(client, acc) {
* @typedef {Object} GrossInvestedLossNetNuplProfitSentimentPattern2 * @typedef {Object} GrossInvestedLossNetNuplProfitSentimentPattern2
* @property {CentsUsdPattern2} grossPnl * @property {CentsUsdPattern2} grossPnl
* @property {InPattern} investedCapital * @property {InPattern} investedCapital
* @property {BaseCumulativeNegativeSumToPattern2} loss * @property {CentsNegativeToUsdPattern2} loss
* @property {CentsToUsdPattern2} netPnl * @property {CentsToUsdPattern3} netPnl
* @property {BpsRatioPattern} nupl * @property {BpsRatioPattern} nupl
* @property {BaseCumulativeSumToPattern2} profit * @property {CentsToUsdPattern4} profit
* @property {GreedNetPainPattern} sentiment * @property {GreedNetPainPattern} sentiment
*/ */
@@ -2230,33 +2203,6 @@ function createBaseChangeCumulativeDeltaSumToPattern(client, acc) {
}; };
} }
/**
* @typedef {Object} BaseCumulativeSumToPattern2
* @property {CentsUsdPattern2} base
* @property {CentsUsdPattern2} cumulative
* @property {_1m1w1y24hPattern4} sum
* @property {BpsPercentRatioPattern3} toMcap
* @property {BpsPercentRatioPattern3} toOwnGrossPnl
* @property {BpsPercentRatioPattern3} toOwnMcap
*/
/**
* Create a BaseCumulativeSumToPattern2 pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {BaseCumulativeSumToPattern2}
*/
function createBaseCumulativeSumToPattern2(client, acc) {
return {
base: createCentsUsdPattern2(client, acc),
cumulative: createCentsUsdPattern2(client, _m(acc, 'cumulative')),
sum: create_1m1w1y24hPattern4(client, _m(acc, 'sum')),
toMcap: createBpsPercentRatioPattern3(client, _m(acc, 'to_mcap')),
toOwnGrossPnl: createBpsPercentRatioPattern3(client, _m(acc, 'to_own_gross_pnl')),
toOwnMcap: createBpsPercentRatioPattern3(client, _m(acc, 'to_own_mcap')),
};
}
/** /**
* @typedef {Object} BpsCentsPercentilesRatioSatsUsdPattern * @typedef {Object} BpsCentsPercentilesRatioSatsUsdPattern
* @property {SeriesPattern1<BasisPoints32>} bps * @property {SeriesPattern1<BasisPoints32>} bps
@@ -2338,6 +2284,33 @@ function createCapLossMvrvPriceProfitSoprPattern(client, acc) {
}; };
} }
/**
* @typedef {Object} CentsNegativeToUsdPattern2
* @property {SeriesPattern1<Cents>} cents
* @property {SeriesPattern1<Dollars>} negative
* @property {BpsPercentRatioPattern3} toMcap
* @property {BpsPercentRatioPattern3} toOwnGrossPnl
* @property {BpsPercentRatioPattern4} toOwnMcap
* @property {SeriesPattern1<Dollars>} usd
*/
/**
* Create a CentsNegativeToUsdPattern2 pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {CentsNegativeToUsdPattern2}
*/
function createCentsNegativeToUsdPattern2(client, acc) {
return {
cents: createSeriesPattern1(client, _m(acc, 'unrealized_loss_cents')),
negative: createSeriesPattern1(client, _m(acc, 'neg_unrealized_loss')),
toMcap: createBpsPercentRatioPattern3(client, _m(acc, 'unrealized_loss_to_mcap')),
toOwnGrossPnl: createBpsPercentRatioPattern3(client, _m(acc, 'unrealized_loss_to_own_gross_pnl')),
toOwnMcap: createBpsPercentRatioPattern4(client, _m(acc, 'unrealized_loss_to_own_mcap')),
usd: createSeriesPattern1(client, _m(acc, 'unrealized_loss')),
};
}
/** /**
* @typedef {Object} DeltaHalfInToTotalPattern * @typedef {Object} DeltaHalfInToTotalPattern
* @property {AbsoluteRatePattern} delta * @property {AbsoluteRatePattern} delta
@@ -2594,6 +2567,31 @@ function createBtcCentsSatsToUsdPattern2(client, acc) {
}; };
} }
/**
* @typedef {Object} CentsToUsdPattern4
* @property {SeriesPattern1<Cents>} cents
* @property {BpsPercentRatioPattern3} toMcap
* @property {BpsPercentRatioPattern3} toOwnGrossPnl
* @property {BpsPercentRatioPattern3} toOwnMcap
* @property {SeriesPattern1<Dollars>} usd
*/
/**
* Create a CentsToUsdPattern4 pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {CentsToUsdPattern4}
*/
function createCentsToUsdPattern4(client, acc) {
return {
cents: createSeriesPattern1(client, _m(acc, 'cents')),
toMcap: createBpsPercentRatioPattern3(client, _m(acc, 'to_mcap')),
toOwnGrossPnl: createBpsPercentRatioPattern3(client, _m(acc, 'to_own_gross_pnl')),
toOwnMcap: createBpsPercentRatioPattern3(client, _m(acc, 'to_own_mcap')),
usd: createSeriesPattern1(client, acc),
};
}
/** /**
* @typedef {Object} DeltaHalfInTotalPattern2 * @typedef {Object} DeltaHalfInTotalPattern2
* @property {AbsoluteRatePattern} delta * @property {AbsoluteRatePattern} delta
@@ -2878,15 +2876,14 @@ function createBaseCumulativeDeltaSumPattern(client, acc) {
* Create a BaseCumulativeNegativeSumPattern pattern node * Create a BaseCumulativeNegativeSumPattern pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated series name * @param {string} acc - Accumulated series name
* @param {string} disc - Discriminator suffix
* @returns {BaseCumulativeNegativeSumPattern} * @returns {BaseCumulativeNegativeSumPattern}
*/ */
function createBaseCumulativeNegativeSumPattern(client, acc, disc) { function createBaseCumulativeNegativeSumPattern(client, acc) {
return { return {
base: createCentsUsdPattern2(client, _m(acc, disc)), base: createCentsUsdPattern2(client, _m(acc, 'realized_loss')),
cumulative: createCentsUsdPattern2(client, _m(acc, `${disc}_cumulative`)), cumulative: createCentsUsdPattern2(client, _m(acc, 'realized_loss_cumulative')),
negative: createSeriesPattern1(client, _m(_m(acc, 'neg'), disc)), negative: createSeriesPattern1(client, _m(acc, 'neg_realized_loss')),
sum: create_1m1w1y24hPattern4(client, _m(acc, `${disc}_sum`)), sum: create_1m1w1y24hPattern4(client, _m(acc, 'realized_loss_sum')),
}; };
} }
@@ -2960,7 +2957,7 @@ function createCentsDeltaToUsdPattern(client, acc) {
} }
/** /**
* @typedef {Object} CentsToUsdPattern2 * @typedef {Object} CentsToUsdPattern3
* @property {SeriesPattern1<CentsSigned>} cents * @property {SeriesPattern1<CentsSigned>} cents
* @property {BpsPercentRatioPattern} toOwnGrossPnl * @property {BpsPercentRatioPattern} toOwnGrossPnl
* @property {BpsPercentRatioPattern} toOwnMcap * @property {BpsPercentRatioPattern} toOwnMcap
@@ -2968,12 +2965,12 @@ function createCentsDeltaToUsdPattern(client, acc) {
*/ */
/** /**
* Create a CentsToUsdPattern2 pattern node * Create a CentsToUsdPattern3 pattern node
* @param {BrkClientBase} client * @param {BrkClientBase} client
* @param {string} acc - Accumulated series name * @param {string} acc - Accumulated series name
* @returns {CentsToUsdPattern2} * @returns {CentsToUsdPattern3}
*/ */
function createCentsToUsdPattern2(client, acc) { function createCentsToUsdPattern3(client, acc) {
return { return {
cents: createSeriesPattern1(client, _m(acc, 'cents')), cents: createSeriesPattern1(client, _m(acc, 'cents')),
toOwnGrossPnl: createBpsPercentRatioPattern(client, _m(acc, 'to_own_gross_pnl')), toOwnGrossPnl: createBpsPercentRatioPattern(client, _m(acc, 'to_own_gross_pnl')),
@@ -2992,10 +2989,10 @@ function createCentsToUsdPattern2(client, acc) {
/** /**
* @typedef {Object} LossNetNuplProfitPattern * @typedef {Object} LossNetNuplProfitPattern
* @property {BaseCumulativeNegativeSumPattern} loss * @property {CentsNegativeUsdPattern} loss
* @property {CentsUsdPattern} netPnl * @property {CentsUsdPattern} netPnl
* @property {BpsRatioPattern} nupl * @property {BpsRatioPattern} nupl
* @property {BaseCumulativeSumPattern3} profit * @property {CentsUsdPattern2} profit
*/ */
/** /**
@@ -3006,10 +3003,10 @@ function createCentsToUsdPattern2(client, acc) {
*/ */
function createLossNetNuplProfitPattern(client, acc) { function createLossNetNuplProfitPattern(client, acc) {
return { return {
loss: createBaseCumulativeNegativeSumPattern(client, acc, 'unrealized_loss'), loss: createCentsNegativeUsdPattern(client, acc),
netPnl: createCentsUsdPattern(client, _m(acc, 'net_unrealized_pnl')), netPnl: createCentsUsdPattern(client, _m(acc, 'net_unrealized_pnl')),
nupl: createBpsRatioPattern(client, _m(acc, 'nupl')), nupl: createBpsRatioPattern(client, _m(acc, 'nupl')),
profit: createBaseCumulativeSumPattern3(client, _m(acc, 'unrealized_profit')), profit: createCentsUsdPattern2(client, _m(acc, 'unrealized_profit')),
}; };
} }
@@ -3337,6 +3334,27 @@ function createCentsDeltaUsdPattern(client, acc) {
}; };
} }
/**
* @typedef {Object} CentsNegativeUsdPattern
* @property {SeriesPattern1<Cents>} cents
* @property {SeriesPattern1<Dollars>} negative
* @property {SeriesPattern1<Dollars>} usd
*/
/**
* Create a CentsNegativeUsdPattern pattern node
* @param {BrkClientBase} client
* @param {string} acc - Accumulated series name
* @returns {CentsNegativeUsdPattern}
*/
function createCentsNegativeUsdPattern(client, acc) {
return {
cents: createSeriesPattern1(client, _m(acc, 'unrealized_loss_cents')),
negative: createSeriesPattern1(client, _m(acc, 'neg_unrealized_loss')),
usd: createSeriesPattern1(client, _m(acc, 'unrealized_loss')),
};
}
/** /**
* @typedef {Object} CentsSatsUsdPattern * @typedef {Object} CentsSatsUsdPattern
* @property {SeriesPattern1<Cents>} cents * @property {SeriesPattern1<Cents>} cents
@@ -3409,9 +3427,9 @@ function createDeltaHalfTotalPattern(client, acc) {
/** /**
* @typedef {Object} LossNuplProfitPattern * @typedef {Object} LossNuplProfitPattern
* @property {BaseCumulativeNegativeSumPattern} loss * @property {CentsNegativeUsdPattern} loss
* @property {BpsRatioPattern} nupl * @property {BpsRatioPattern} nupl
* @property {BaseCumulativeSumPattern3} profit * @property {CentsUsdPattern2} profit
*/ */
/** /**
@@ -3422,9 +3440,9 @@ function createDeltaHalfTotalPattern(client, acc) {
*/ */
function createLossNuplProfitPattern(client, acc) { function createLossNuplProfitPattern(client, acc) {
return { return {
loss: createBaseCumulativeNegativeSumPattern(client, acc, 'unrealized_loss'), loss: createCentsNegativeUsdPattern(client, acc),
nupl: createBpsRatioPattern(client, _m(acc, 'nupl')), nupl: createBpsRatioPattern(client, _m(acc, 'nupl')),
profit: createBaseCumulativeSumPattern3(client, _m(acc, 'unrealized_profit')), profit: createCentsUsdPattern2(client, _m(acc, 'unrealized_profit')),
}; };
} }
@@ -5534,18 +5552,16 @@ function createUnspentPattern(client, acc) {
/** /**
* @typedef {Object} SeriesTree_Cohorts_Utxo_All_Unrealized_Profit * @typedef {Object} SeriesTree_Cohorts_Utxo_All_Unrealized_Profit
* @property {CentsUsdPattern2} base * @property {SeriesPattern1<Dollars>} usd
* @property {CentsUsdPattern2} cumulative * @property {SeriesPattern1<Cents>} cents
* @property {_1m1w1y24hPattern4} sum
* @property {BpsPercentRatioPattern3} toMcap * @property {BpsPercentRatioPattern3} toMcap
* @property {BpsPercentRatioPattern3} toOwnGrossPnl * @property {BpsPercentRatioPattern3} toOwnGrossPnl
*/ */
/** /**
* @typedef {Object} SeriesTree_Cohorts_Utxo_All_Unrealized_Loss * @typedef {Object} SeriesTree_Cohorts_Utxo_All_Unrealized_Loss
* @property {CentsUsdPattern2} base * @property {SeriesPattern1<Dollars>} usd
* @property {CentsUsdPattern2} cumulative * @property {SeriesPattern1<Cents>} cents
* @property {_1m1w1y24hPattern4} sum
* @property {SeriesPattern1<Dollars>} negative * @property {SeriesPattern1<Dollars>} negative
* @property {BpsPercentRatioPattern3} toMcap * @property {BpsPercentRatioPattern3} toMcap
* @property {BpsPercentRatioPattern3} toOwnGrossPnl * @property {BpsPercentRatioPattern3} toOwnGrossPnl
@@ -5745,9 +5761,9 @@ function createUnspentPattern(client, acc) {
/** /**
* @typedef {Object} SeriesTree_Cohorts_Utxo_Sth_Unrealized * @typedef {Object} SeriesTree_Cohorts_Utxo_Sth_Unrealized
* @property {BpsRatioPattern} nupl * @property {BpsRatioPattern} nupl
* @property {BaseCumulativeSumToPattern2} profit * @property {CentsToUsdPattern4} profit
* @property {BaseCumulativeNegativeSumToPattern2} loss * @property {CentsNegativeToUsdPattern2} loss
* @property {CentsToUsdPattern2} netPnl * @property {CentsToUsdPattern3} netPnl
* @property {CentsUsdPattern2} grossPnl * @property {CentsUsdPattern2} grossPnl
* @property {InPattern} investedCapital * @property {InPattern} investedCapital
* @property {SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment} sentiment * @property {SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment} sentiment
@@ -5932,9 +5948,9 @@ function createUnspentPattern(client, acc) {
/** /**
* @typedef {Object} SeriesTree_Cohorts_Utxo_Lth_Unrealized * @typedef {Object} SeriesTree_Cohorts_Utxo_Lth_Unrealized
* @property {BpsRatioPattern} nupl * @property {BpsRatioPattern} nupl
* @property {BaseCumulativeSumToPattern2} profit * @property {CentsToUsdPattern4} profit
* @property {BaseCumulativeNegativeSumToPattern2} loss * @property {CentsNegativeToUsdPattern2} loss
* @property {CentsToUsdPattern2} netPnl * @property {CentsToUsdPattern3} netPnl
* @property {CentsUsdPattern2} grossPnl * @property {CentsUsdPattern2} grossPnl
* @property {InPattern} investedCapital * @property {InPattern} investedCapital
* @property {SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment} sentiment * @property {SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment} sentiment
@@ -8610,16 +8626,14 @@ class BrkClient extends BrkClientBase {
unrealized: { unrealized: {
nupl: createBpsRatioPattern(this, 'nupl'), nupl: createBpsRatioPattern(this, 'nupl'),
profit: { profit: {
base: createCentsUsdPattern2(this, 'unrealized_profit'), usd: createSeriesPattern1(this, 'unrealized_profit'),
cumulative: createCentsUsdPattern2(this, 'unrealized_profit_cumulative'), cents: createSeriesPattern1(this, 'unrealized_profit_cents'),
sum: create_1m1w1y24hPattern4(this, 'unrealized_profit_sum'),
toMcap: createBpsPercentRatioPattern3(this, 'unrealized_profit_to_mcap'), toMcap: createBpsPercentRatioPattern3(this, 'unrealized_profit_to_mcap'),
toOwnGrossPnl: createBpsPercentRatioPattern3(this, 'unrealized_profit_to_own_gross_pnl'), toOwnGrossPnl: createBpsPercentRatioPattern3(this, 'unrealized_profit_to_own_gross_pnl'),
}, },
loss: { loss: {
base: createCentsUsdPattern2(this, 'unrealized_loss'), usd: createSeriesPattern1(this, 'unrealized_loss'),
cumulative: createCentsUsdPattern2(this, 'unrealized_loss_cumulative'), cents: createSeriesPattern1(this, 'unrealized_loss_cents'),
sum: create_1m1w1y24hPattern4(this, 'unrealized_loss_sum'),
negative: createSeriesPattern1(this, 'neg_unrealized_loss'), negative: createSeriesPattern1(this, 'neg_unrealized_loss'),
toMcap: createBpsPercentRatioPattern3(this, 'unrealized_loss_to_mcap'), toMcap: createBpsPercentRatioPattern3(this, 'unrealized_loss_to_mcap'),
toOwnGrossPnl: createBpsPercentRatioPattern3(this, 'unrealized_loss_to_own_gross_pnl'), toOwnGrossPnl: createBpsPercentRatioPattern3(this, 'unrealized_loss_to_own_gross_pnl'),
@@ -8774,9 +8788,9 @@ class BrkClient extends BrkClientBase {
}, },
unrealized: { unrealized: {
nupl: createBpsRatioPattern(this, 'sth_nupl'), nupl: createBpsRatioPattern(this, 'sth_nupl'),
profit: createBaseCumulativeSumToPattern2(this, 'sth_unrealized_profit'), profit: createCentsToUsdPattern4(this, 'sth_unrealized_profit'),
loss: createBaseCumulativeNegativeSumToPattern2(this, 'sth'), loss: createCentsNegativeToUsdPattern2(this, 'sth'),
netPnl: createCentsToUsdPattern2(this, 'sth_net_unrealized_pnl'), netPnl: createCentsToUsdPattern3(this, 'sth_net_unrealized_pnl'),
grossPnl: createCentsUsdPattern2(this, 'sth_unrealized_gross_pnl'), grossPnl: createCentsUsdPattern2(this, 'sth_unrealized_gross_pnl'),
investedCapital: createInPattern(this, 'sth_invested_capital_in'), investedCapital: createInPattern(this, 'sth_invested_capital_in'),
sentiment: { sentiment: {
@@ -8917,9 +8931,9 @@ class BrkClient extends BrkClientBase {
}, },
unrealized: { unrealized: {
nupl: createBpsRatioPattern(this, 'lth_nupl'), nupl: createBpsRatioPattern(this, 'lth_nupl'),
profit: createBaseCumulativeSumToPattern2(this, 'lth_unrealized_profit'), profit: createCentsToUsdPattern4(this, 'lth_unrealized_profit'),
loss: createBaseCumulativeNegativeSumToPattern2(this, 'lth'), loss: createCentsNegativeToUsdPattern2(this, 'lth'),
netPnl: createCentsToUsdPattern2(this, 'lth_net_unrealized_pnl'), netPnl: createCentsToUsdPattern3(this, 'lth_net_unrealized_pnl'),
grossPnl: createCentsUsdPattern2(this, 'lth_unrealized_gross_pnl'), grossPnl: createCentsUsdPattern2(this, 'lth_unrealized_gross_pnl'),
investedCapital: createInPattern(this, 'lth_invested_capital_in'), investedCapital: createInPattern(this, 'lth_invested_capital_in'),
sentiment: { sentiment: {

View File

@@ -34,6 +34,7 @@ BasisPoints16 = int
# Unsigned basis points stored as u32. # Unsigned basis points stored as u32.
# 1 bp = 0.0001. Range: 0429,496.7295. # 1 bp = 0.0001. Range: 0429,496.7295.
# Use for unbounded unsigned ratios (MVRV, NVT, SOPR, etc.). # Use for unbounded unsigned ratios (MVRV, NVT, SOPR, etc.).
# `u32::MAX` is reserved as a NaN sentinel.
BasisPoints32 = int BasisPoints32 = int
# Signed basis points stored as i16. # Signed basis points stored as i16.
# 1 bp = 0.0001. Range: -3.2767 to +3.2767. # 1 bp = 0.0001. Range: -3.2767 to +3.2767.
@@ -42,6 +43,7 @@ BasisPointsSigned16 = int
# Signed basis points stored as i32. # Signed basis points stored as i32.
# 1 bp = 0.0001. Range: -214,748.3647 to +214,748.3647. # 1 bp = 0.0001. Range: -214,748.3647 to +214,748.3647.
# Use for unbounded signed values (returns, growth rates, volatility, z-scores, etc.). # Use for unbounded signed values (returns, growth rates, volatility, z-scores, etc.).
# `i32::MIN` is reserved as a NaN sentinel.
BasisPointsSigned32 = int BasisPointsSigned32 = int
# Bitcoin amount as floating point (1 BTC = 100,000,000 satoshis) # Bitcoin amount as floating point (1 BTC = 100,000,000 satoshis)
Bitcoin = float Bitcoin = float
@@ -2354,26 +2356,13 @@ class BaseCumulativeDistributionSumToValuePattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
pass pass
class BaseCumulativeNegativeSumToPattern2:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.base: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'unrealized_loss'))
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'unrealized_loss_cumulative'))
self.negative: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, 'neg_unrealized_loss'))
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, _m(acc, 'unrealized_loss_sum'))
self.to_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'unrealized_loss_to_mcap'))
self.to_own_gross_pnl: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'unrealized_loss_to_own_gross_pnl'))
self.to_own_mcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, _m(acc, 'unrealized_loss_to_own_mcap'))
class CapLossMvrvNetPriceProfitSoprPattern: class CapLossMvrvNetPriceProfitSoprPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name.""" """Create pattern node with accumulated series name."""
self.cap: CentsDeltaUsdPattern = CentsDeltaUsdPattern(client, _m(acc, 'realized_cap')) self.cap: CentsDeltaUsdPattern = CentsDeltaUsdPattern(client, _m(acc, 'realized_cap'))
self.loss: BaseCumulativeNegativeSumPattern = BaseCumulativeNegativeSumPattern(client, acc, 'realized_loss') self.loss: BaseCumulativeNegativeSumPattern = BaseCumulativeNegativeSumPattern(client, acc)
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, 'mvrv')) self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, 'mvrv'))
self.net_pnl: BaseCumulativeDeltaSumPattern = BaseCumulativeDeltaSumPattern(client, _m(acc, 'net_realized_pnl')) self.net_pnl: BaseCumulativeDeltaSumPattern = BaseCumulativeDeltaSumPattern(client, _m(acc, 'net_realized_pnl'))
self.price: BpsCentsRatioSatsUsdPattern = BpsCentsRatioSatsUsdPattern(client, _m(acc, 'realized_price')) self.price: BpsCentsRatioSatsUsdPattern = BpsCentsRatioSatsUsdPattern(client, _m(acc, 'realized_price'))
@@ -2408,18 +2397,6 @@ class BaseChangeCumulativeDeltaSumToPattern:
self.sum: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, _m(acc, 'realized_pnl_sum')) self.sum: _1m1w1y24hPattern3 = _1m1w1y24hPattern3(client, _m(acc, 'realized_pnl_sum'))
self.to_rcap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_pnl_to_rcap')) self.to_rcap: BpsPercentRatioPattern = BpsPercentRatioPattern(client, _m(acc, 'realized_pnl_to_rcap'))
class BaseCumulativeSumToPattern2:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.base: CentsUsdPattern2 = CentsUsdPattern2(client, acc)
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'cumulative'))
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, _m(acc, 'sum'))
self.to_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_mcap'))
self.to_own_gross_pnl: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_own_gross_pnl'))
self.to_own_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_own_mcap'))
class BpsCentsPercentilesRatioSatsUsdPattern: class BpsCentsPercentilesRatioSatsUsdPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2456,6 +2433,18 @@ class CapLossMvrvPriceProfitSoprPattern:
self.profit: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, _m(acc, 'realized_profit')) self.profit: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, _m(acc, 'realized_profit'))
self.sopr: ValuePattern = ValuePattern(client, _m(acc, 'value')) self.sopr: ValuePattern = ValuePattern(client, _m(acc, 'value'))
class CentsNegativeToUsdPattern2:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, _m(acc, 'unrealized_loss_cents'))
self.negative: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, 'neg_unrealized_loss'))
self.to_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'unrealized_loss_to_mcap'))
self.to_own_gross_pnl: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'unrealized_loss_to_own_gross_pnl'))
self.to_own_mcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, _m(acc, 'unrealized_loss_to_own_mcap'))
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, 'unrealized_loss'))
class DeltaHalfInToTotalPattern: class DeltaHalfInToTotalPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2569,6 +2558,17 @@ class BtcCentsSatsToUsdPattern2:
self.to_own: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_own')) self.to_own: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_own'))
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, 'usd')) self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, 'usd'))
class CentsToUsdPattern4:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, _m(acc, 'cents'))
self.to_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_mcap'))
self.to_own_gross_pnl: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_own_gross_pnl'))
self.to_own_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_own_mcap'))
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, acc)
class DeltaHalfInTotalPattern2: class DeltaHalfInTotalPattern2:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2691,12 +2691,12 @@ class BaseCumulativeDeltaSumPattern:
class BaseCumulativeNegativeSumPattern: class BaseCumulativeNegativeSumPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str, disc: str): def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name.""" """Create pattern node with accumulated series name."""
self.base: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, disc)) self.base: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'realized_loss'))
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, f'{disc}_cumulative')) self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'realized_loss_cumulative'))
self.negative: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, f'neg_{disc}')) self.negative: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, 'neg_realized_loss'))
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, _m(acc, f'{disc}_sum')) self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, _m(acc, 'realized_loss_sum'))
class BothReactivatedReceivingSendingPattern: class BothReactivatedReceivingSendingPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2728,7 +2728,7 @@ class CentsDeltaToUsdPattern:
self.to_own_mcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, _m(acc, 'to_own_mcap')) self.to_own_mcap: BpsPercentRatioPattern4 = BpsPercentRatioPattern4(client, _m(acc, 'to_own_mcap'))
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, acc) self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, acc)
class CentsToUsdPattern2: class CentsToUsdPattern3:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
@@ -2747,10 +2747,10 @@ class LossNetNuplProfitPattern:
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name.""" """Create pattern node with accumulated series name."""
self.loss: BaseCumulativeNegativeSumPattern = BaseCumulativeNegativeSumPattern(client, acc, 'unrealized_loss') self.loss: CentsNegativeUsdPattern = CentsNegativeUsdPattern(client, acc)
self.net_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'net_unrealized_pnl')) self.net_pnl: CentsUsdPattern = CentsUsdPattern(client, _m(acc, 'net_unrealized_pnl'))
self.nupl: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'nupl')) self.nupl: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'nupl'))
self.profit: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, _m(acc, 'unrealized_profit')) self.profit: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'unrealized_profit'))
class OutputsRealizedSupplyUnrealizedPattern2: class OutputsRealizedSupplyUnrealizedPattern2:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2890,6 +2890,15 @@ class CentsDeltaUsdPattern:
self.delta: AbsoluteRatePattern2 = AbsoluteRatePattern2(client, _m(acc, 'delta')) self.delta: AbsoluteRatePattern2 = AbsoluteRatePattern2(client, _m(acc, 'delta'))
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, acc) self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, acc)
class CentsNegativeUsdPattern:
"""Pattern struct for repeated tree structure."""
def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name."""
self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, _m(acc, 'unrealized_loss_cents'))
self.negative: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, 'neg_unrealized_loss'))
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, _m(acc, 'unrealized_loss'))
class CentsSatsUsdPattern: class CentsSatsUsdPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -2926,9 +2935,9 @@ class LossNuplProfitPattern:
def __init__(self, client: BrkClientBase, acc: str): def __init__(self, client: BrkClientBase, acc: str):
"""Create pattern node with accumulated series name.""" """Create pattern node with accumulated series name."""
self.loss: BaseCumulativeNegativeSumPattern = BaseCumulativeNegativeSumPattern(client, acc, 'unrealized_loss') self.loss: CentsNegativeUsdPattern = CentsNegativeUsdPattern(client, acc)
self.nupl: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'nupl')) self.nupl: BpsRatioPattern = BpsRatioPattern(client, _m(acc, 'nupl'))
self.profit: BaseCumulativeSumPattern3 = BaseCumulativeSumPattern3(client, _m(acc, 'unrealized_profit')) self.profit: CentsUsdPattern2 = CentsUsdPattern2(client, _m(acc, 'unrealized_profit'))
class NuplRealizedSupplyPattern: class NuplRealizedSupplyPattern:
"""Pattern struct for repeated tree structure.""" """Pattern struct for repeated tree structure."""
@@ -4862,9 +4871,8 @@ class SeriesTree_Cohorts_Utxo_All_Unrealized_Profit:
"""Series tree node.""" """Series tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.base: CentsUsdPattern2 = CentsUsdPattern2(client, 'unrealized_profit') self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, 'unrealized_profit')
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, 'unrealized_profit_cumulative') self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, 'unrealized_profit_cents')
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'unrealized_profit_sum')
self.to_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'unrealized_profit_to_mcap') self.to_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'unrealized_profit_to_mcap')
self.to_own_gross_pnl: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'unrealized_profit_to_own_gross_pnl') self.to_own_gross_pnl: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'unrealized_profit_to_own_gross_pnl')
@@ -4872,9 +4880,8 @@ class SeriesTree_Cohorts_Utxo_All_Unrealized_Loss:
"""Series tree node.""" """Series tree node."""
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.base: CentsUsdPattern2 = CentsUsdPattern2(client, 'unrealized_loss') self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, 'unrealized_loss')
self.cumulative: CentsUsdPattern2 = CentsUsdPattern2(client, 'unrealized_loss_cumulative') self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, 'unrealized_loss_cents')
self.sum: _1m1w1y24hPattern4 = _1m1w1y24hPattern4(client, 'unrealized_loss_sum')
self.negative: SeriesPattern1[Dollars] = SeriesPattern1(client, 'neg_unrealized_loss') self.negative: SeriesPattern1[Dollars] = SeriesPattern1(client, 'neg_unrealized_loss')
self.to_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'unrealized_loss_to_mcap') self.to_mcap: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'unrealized_loss_to_mcap')
self.to_own_gross_pnl: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'unrealized_loss_to_own_gross_pnl') self.to_own_gross_pnl: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, 'unrealized_loss_to_own_gross_pnl')
@@ -5111,9 +5118,9 @@ class SeriesTree_Cohorts_Utxo_Sth_Unrealized:
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.nupl: BpsRatioPattern = BpsRatioPattern(client, 'sth_nupl') self.nupl: BpsRatioPattern = BpsRatioPattern(client, 'sth_nupl')
self.profit: BaseCumulativeSumToPattern2 = BaseCumulativeSumToPattern2(client, 'sth_unrealized_profit') self.profit: CentsToUsdPattern4 = CentsToUsdPattern4(client, 'sth_unrealized_profit')
self.loss: BaseCumulativeNegativeSumToPattern2 = BaseCumulativeNegativeSumToPattern2(client, 'sth') self.loss: CentsNegativeToUsdPattern2 = CentsNegativeToUsdPattern2(client, 'sth')
self.net_pnl: CentsToUsdPattern2 = CentsToUsdPattern2(client, 'sth_net_unrealized_pnl') self.net_pnl: CentsToUsdPattern3 = CentsToUsdPattern3(client, 'sth_net_unrealized_pnl')
self.gross_pnl: CentsUsdPattern2 = CentsUsdPattern2(client, 'sth_unrealized_gross_pnl') self.gross_pnl: CentsUsdPattern2 = CentsUsdPattern2(client, 'sth_unrealized_gross_pnl')
self.invested_capital: InPattern = InPattern(client, 'sth_invested_capital_in') self.invested_capital: InPattern = InPattern(client, 'sth_invested_capital_in')
self.sentiment: SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment(client) self.sentiment: SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_Sth_Unrealized_Sentiment(client)
@@ -5313,9 +5320,9 @@ class SeriesTree_Cohorts_Utxo_Lth_Unrealized:
def __init__(self, client: BrkClientBase, base_path: str = ''): def __init__(self, client: BrkClientBase, base_path: str = ''):
self.nupl: BpsRatioPattern = BpsRatioPattern(client, 'lth_nupl') self.nupl: BpsRatioPattern = BpsRatioPattern(client, 'lth_nupl')
self.profit: BaseCumulativeSumToPattern2 = BaseCumulativeSumToPattern2(client, 'lth_unrealized_profit') self.profit: CentsToUsdPattern4 = CentsToUsdPattern4(client, 'lth_unrealized_profit')
self.loss: BaseCumulativeNegativeSumToPattern2 = BaseCumulativeNegativeSumToPattern2(client, 'lth') self.loss: CentsNegativeToUsdPattern2 = CentsNegativeToUsdPattern2(client, 'lth')
self.net_pnl: CentsToUsdPattern2 = CentsToUsdPattern2(client, 'lth_net_unrealized_pnl') self.net_pnl: CentsToUsdPattern3 = CentsToUsdPattern3(client, 'lth_net_unrealized_pnl')
self.gross_pnl: CentsUsdPattern2 = CentsUsdPattern2(client, 'lth_unrealized_gross_pnl') self.gross_pnl: CentsUsdPattern2 = CentsUsdPattern2(client, 'lth_unrealized_gross_pnl')
self.invested_capital: InPattern = InPattern(client, 'lth_invested_capital_in') self.invested_capital: InPattern = InPattern(client, 'lth_invested_capital_in')
self.sentiment: SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment(client) self.sentiment: SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment = SeriesTree_Cohorts_Utxo_Lth_Unrealized_Sentiment(client)

View File

@@ -71,7 +71,7 @@ import { Unit } from "../utils/units.js";
const lineWidth = /** @type {any} */ (1.5); const lineWidth = /** @type {any} */ (1.5);
const MAX_SIZE = 100_000; const MAX_SIZE = 10_000;
/** /**
* @param {Object} args * @param {Object} args

View File

@@ -165,7 +165,6 @@ export function createCointimeSection() {
return { return {
name: "Cointime", name: "Cointime",
tree: [ tree: [
// Prices - the core pricing models
{ {
name: "Prices", name: "Prices",
tree: [ tree: [
@@ -208,7 +207,6 @@ export function createCointimeSection() {
], ],
}, },
// Caps - market capitalizations from different models
{ {
name: "Caps", name: "Caps",
tree: [ tree: [
@@ -242,7 +240,6 @@ export function createCointimeSection() {
], ],
}, },
// Supply - active vs vaulted breakdown
{ {
name: "Supply", name: "Supply",
title: "Active vs Vaulted Supply", title: "Active vs Vaulted Supply",
@@ -251,7 +248,6 @@ export function createCointimeSection() {
), ),
}, },
// Liveliness - the foundational cointime ratios
{ {
name: "Activity", name: "Activity",
title: "Liveliness & Vaultedness", title: "Liveliness & Vaultedness",
@@ -278,7 +274,6 @@ export function createCointimeSection() {
], ],
}, },
// Coinblocks - created, destroyed, stored
{ {
name: "Coinblocks", name: "Coinblocks",
tree: [ tree: [
@@ -300,7 +295,7 @@ export function createCointimeSection() {
name, name,
tree: [ tree: [
{ {
name: "Base", name: "Per Block",
title, title,
bottom: [ bottom: [
line({ line({
@@ -329,7 +324,6 @@ export function createCointimeSection() {
], ],
}, },
// Value - cointime value flows
{ {
name: "Value", name: "Value",
tree: [ tree: [
@@ -360,7 +354,7 @@ export function createCointimeSection() {
name, name,
tree: [ tree: [
{ {
name: "Base", name: "Per Block",
title, title,
bottom: [ bottom: [
line({ series: pattern.base, name, color, unit: Unit.usd }), line({ series: pattern.base, name, color, unit: Unit.usd }),
@@ -385,7 +379,7 @@ export function createCointimeSection() {
name: vocdd.name, name: vocdd.name,
tree: [ tree: [
{ {
name: "Base", name: "Per Block",
title: vocdd.title, title: vocdd.title,
bottom: [ bottom: [
line({ line({
@@ -424,7 +418,6 @@ export function createCointimeSection() {
], ],
}, },
// Indicators - derived decision series
{ {
name: "Indicators", name: "Indicators",
tree: [ tree: [
@@ -446,7 +439,7 @@ export function createCointimeSection() {
bottom: [ bottom: [
line({ line({
series: cap.aviv.ratio, series: cap.aviv.ratio,
name: "aviv", name: "AVIV",
unit: Unit.ratio, unit: Unit.ratio,
}), }),
], ],
@@ -454,7 +447,6 @@ export function createCointimeSection() {
], ],
}, },
// Cointime-Adjusted - comparing base vs adjusted series
{ {
name: "Cointime-Adjusted", name: "Cointime-Adjusted",
tree: [ tree: [
@@ -476,44 +468,39 @@ export function createCointimeSection() {
], ],
}, },
{ {
name: "Velocity", name: "BTC Velocity",
tree: [ title: "Cointime-Adjusted BTC Velocity",
{ bottom: [
name: "BTC", line({
title: "Cointime-Adjusted BTC Velocity", series: supply.velocity.native,
bottom: [ name: "Base",
line({ color: colors.base,
series: supply.velocity.native, unit: Unit.ratio,
name: "Base", }),
color: colors.base, line({
unit: Unit.ratio, series: adjusted.txVelocityNative,
}), name: "Cointime-Adjusted",
line({ color: colors.adjusted,
series: adjusted.txVelocityNative, unit: Unit.ratio,
name: "Cointime-Adjusted", }),
color: colors.adjusted, ],
unit: Unit.ratio, },
}), {
], name: "USD Velocity",
}, title: "Cointime-Adjusted USD Velocity",
{ bottom: [
name: "USD", line({
title: "Cointime-Adjusted USD Velocity", series: supply.velocity.fiat,
bottom: [ name: "Base",
line({ color: colors.thermo,
series: supply.velocity.fiat, unit: Unit.ratio,
name: "Base", }),
color: colors.thermo, line({
unit: Unit.ratio, series: adjusted.txVelocityFiat,
}), name: "Cointime-Adjusted",
line({ color: colors.vaulted,
series: adjusted.txVelocityFiat, unit: Unit.ratio,
name: "Cointime-Adjusted", }),
color: colors.vaulted,
unit: Unit.ratio,
}),
],
},
], ],
}, },
], ],

View File

@@ -32,7 +32,7 @@ function volumeAndCoinsTree(activity, color, title) {
name: "Volume", name: "Volume",
tree: [ tree: [
{ {
name: "Sum", name: "Per Block",
title: title("Sent Volume"), title: title("Sent Volume"),
bottom: [ bottom: [
line({ series: activity.transferVolume.base.sats, name: "Sum", color, unit: Unit.sats }), line({ series: activity.transferVolume.base.sats, name: "Sum", color, unit: Unit.sats }),
@@ -52,10 +52,10 @@ function volumeAndCoinsTree(activity, color, title) {
], ],
}, },
{ {
name: "Coins Destroyed", name: "Coindays Destroyed",
tree: [ tree: [
{ {
name: "Base", name: "Per Block",
title: title("Coindays Destroyed"), title: title("Coindays Destroyed"),
bottom: [ bottom: [
line({ series: activity.coindaysDestroyed.base, name: "Base", color, unit: Unit.coindays }), line({ series: activity.coindaysDestroyed.base, name: "Base", color, unit: Unit.coindays }),
@@ -675,7 +675,7 @@ function groupedRollingSoprCharts(list, all, get24h, get7d, get30d, get1y, title
* @template {{ color: Color, name: string }} A * @template {{ color: Color, name: string }} A
* @param {readonly T[]} list * @param {readonly T[]} list
* @param {A} all * @param {A} all
* @param {readonly { name: string, getCreated: (item: T | A) => AnySeriesPattern, getDestroyed: (item: T | A) => AnySeriesPattern }[]} windows * @param {readonly { name: string, title: string, getCreated: (item: T | A) => AnySeriesPattern, getDestroyed: (item: T | A) => AnySeriesPattern }[]} windows
* @param {(name: string) => string} title * @param {(name: string) => string} title
* @param {string} [prefix] * @param {string} [prefix]
* @returns {PartialOptionsTree} * @returns {PartialOptionsTree}
@@ -686,7 +686,7 @@ function groupedRollingValueCharts(list, all, windows, title, prefix = "") {
name: "Created", name: "Created",
tree: windows.map((w) => ({ tree: windows.map((w) => ({
name: w.name, name: w.name,
title: title(`${prefix}Value Created (${w.name})`), title: title(`${prefix}Value Created (${w.title})`),
bottom: mapCohortsWithAll(list, all, (item) => bottom: mapCohortsWithAll(list, all, (item) =>
line({ series: w.getCreated(item), name: item.name, color: item.color, unit: Unit.usd }), line({ series: w.getCreated(item), name: item.name, color: item.color, unit: Unit.usd }),
), ),
@@ -696,7 +696,7 @@ function groupedRollingValueCharts(list, all, windows, title, prefix = "") {
name: "Destroyed", name: "Destroyed",
tree: windows.map((w) => ({ tree: windows.map((w) => ({
name: w.name, name: w.name,
title: title(`${prefix}Value Destroyed (${w.name})`), title: title(`${prefix}Value Destroyed (${w.title})`),
bottom: mapCohortsWithAll(list, all, (item) => bottom: mapCohortsWithAll(list, all, (item) =>
line({ series: w.getDestroyed(item), name: item.name, color: item.color, unit: Unit.usd }), line({ series: w.getDestroyed(item), name: item.name, color: item.color, unit: Unit.usd }),
), ),
@@ -711,10 +711,10 @@ function groupedRollingValueCharts(list, all, windows, title, prefix = "") {
*/ */
function valueWindows(list, all) { function valueWindows(list, all) {
return [ return [
{ name: "24h", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._24h, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._24h }, { name: "24h", title: "Daily", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._24h, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._24h },
{ name: "7d", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1w, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1w }, { name: "7d", title: "Weekly", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1w, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1w },
{ name: "30d", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1m, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1m }, { name: "30d", title: "Monthly", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1m, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1m },
{ name: "1y", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1y, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1y }, { name: "1y", title: "Yearly", getCreated: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueCreated.sum._1y, getDestroyed: (/** @type {typeof list[number] | typeof all} */ c) => c.tree.realized.sopr.valueDestroyed.sum._1y },
]; ];
} }
@@ -823,10 +823,10 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
tree: groupedRollingValueCharts( tree: groupedRollingValueCharts(
list, all, list, all,
[ [
{ name: "24h", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._24h, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._24h }, { name: "24h", title: "Daily", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._24h, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._24h },
{ name: "7d", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1w, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1w }, { name: "7d", title: "Weekly", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1w, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1w },
{ name: "30d", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1m, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1m }, { name: "30d", title: "Monthly", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1m, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1m },
{ name: "1y", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1y, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1y }, { name: "1y", title: "Yearly", getCreated: (c) => c.tree.realized.sopr.adjusted.valueCreated.sum._1y, getDestroyed: (c) => c.tree.realized.sopr.adjusted.valueDestroyed.sum._1y },
], ],
title, title,
"Adjusted ", "Adjusted ",
@@ -837,7 +837,7 @@ export function createGroupedActivitySectionWithAdjusted({ list, all, title }) {
], ],
}, },
{ {
name: "Coins Destroyed", name: "Coindays Destroyed",
title: title("Coindays Destroyed"), title: title("Coindays Destroyed"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [ bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }), line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),
@@ -914,7 +914,7 @@ export function createGroupedActivitySection({ list, all, title }) {
], ],
}, },
{ {
name: "Coins Destroyed", name: "Coindays Destroyed",
title: title("Coindays Destroyed"), title: title("Coindays Destroyed"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [ bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }), line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),
@@ -955,7 +955,7 @@ export function createGroupedActivitySectionWithActivity({ list, all, title }) {
], ],
}, },
{ {
name: "Coins Destroyed", name: "Coindays Destroyed",
title: title("Coindays Destroyed"), title: title("Coindays Destroyed"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [ bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => [
line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }), line({ series: tree.activity.coindaysDestroyed.sum._24h, name, color, unit: Unit.coindays }),

View File

@@ -199,7 +199,7 @@ function groupedDeltaTree(list, all, getDelta, unit, title, name) {
name: "Absolute", name: "Absolute",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`${name} Change (${w.name})`), title: title(`${name} Change (${w.title})`),
bottom: mapCohortsWithAll(list, all, (c) => bottom: mapCohortsWithAll(list, all, (c) =>
baseline({ series: getDelta(c).absolute[w.key], name: c.name, color: c.color, unit }), baseline({ series: getDelta(c).absolute[w.key], name: c.name, color: c.color, unit }),
), ),
@@ -209,7 +209,7 @@ function groupedDeltaTree(list, all, getDelta, unit, title, name) {
name: "Rate", name: "Rate",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`${name} Rate (${w.name})`), title: title(`${name} Rate (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, (c) => bottom: flatMapCohortsWithAll(list, all, (c) =>
percentRatio({ pattern: getDelta(c).rate[w.key], name: c.name, color: c.color }), percentRatio({ pattern: getDelta(c).rate[w.key], name: c.name, color: c.color }),
), ),

View File

@@ -677,7 +677,7 @@ function groupedBucketCharts(list, titlePrefix) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: `${titlePrefix}: Supply Change ${w.name}`, title: `${titlePrefix}: Supply Change (${w.title})`,
bottom: list.map(({ name, color, pattern }) => bottom: list.map(({ name, color, pattern }) =>
baseline({ series: pattern.supply.all.delta.absolute[w.key], name, color, unit: Unit.sats }), baseline({ series: pattern.supply.all.delta.absolute[w.key], name, color, unit: Unit.sats }),
), ),
@@ -698,7 +698,7 @@ function groupedBucketCharts(list, titlePrefix) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: `${titlePrefix}: Supply Rate ${w.name}`, title: `${titlePrefix}: Supply Rate (${w.title})`,
bottom: list.flatMap(({ name, color, pattern }) => bottom: list.flatMap(({ name, color, pattern }) =>
percentRatio({ pattern: pattern.supply.all.delta.rate[w.key], name, color }), percentRatio({ pattern: pattern.supply.all.delta.rate[w.key], name, color }),
), ),

View File

@@ -45,7 +45,7 @@ function pnlLines(m, unit) {
if (m.gross) { if (m.gross) {
series.push(line({ series: m.gross, name: "Total", color: colors.default, unit })); series.push(line({ series: m.gross, name: "Total", color: colors.default, unit }));
} }
series.push(line({ series: m.negLoss, name: "Negative Loss", color: colors.loss, unit, defaultActive: false })); series.push(line({ series: m.negLoss, name: "Loss (Inverted)", color: colors.loss, unit, defaultActive: false }));
return series; return series;
} }
@@ -63,13 +63,13 @@ function netBaseline(s, unit) {
// ============================================================================ // ============================================================================
/** /**
* @param {{ profit: { base: { usd: AnySeriesPattern } }, loss: { base: { usd: AnySeriesPattern }, negative: AnySeriesPattern }, grossPnl: { usd: AnySeriesPattern } }} u * @param {{ profit: { usd: AnySeriesPattern }, loss: { usd: AnySeriesPattern, negative: AnySeriesPattern }, grossPnl: { usd: AnySeriesPattern } }} u
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
function unrealizedUsdSeries(u) { function unrealizedUsdSeries(u) {
return [ return [
...pnlLines( ...pnlLines(
{ profit: u.profit.base.usd, loss: u.loss.base.usd, negLoss: u.loss.negative, gross: u.grossPnl.usd }, { profit: u.profit.usd, loss: u.loss.usd, negLoss: u.loss.negative, gross: u.grossPnl.usd },
Unit.usd, Unit.usd,
), ),
priceLine({ unit: Unit.usd, defaultActive: false }), priceLine({ unit: Unit.usd, defaultActive: false }),
@@ -105,7 +105,6 @@ function unrealizedPnlTreeAll(u, title) {
{ name: "USD", title: title("Unrealized P&L"), bottom: unrealizedUsdSeries(u) }, { name: "USD", title: title("Unrealized P&L"), bottom: unrealizedUsdSeries(u) },
relPnlChart(u.profit.toMcap, u.loss.toMcap, "% of Mcap", title), relPnlChart(u.profit.toMcap, u.loss.toMcap, "% of Mcap", title),
relPnlChart(u.profit.toOwnGrossPnl, u.loss.toOwnGrossPnl, "% of Own P&L", title), relPnlChart(u.profit.toOwnGrossPnl, u.loss.toOwnGrossPnl, "% of Own P&L", title),
...unrealizedCumulativeRollingTree(u.profit, u.loss, title),
]; ];
} }
@@ -121,7 +120,6 @@ function unrealizedPnlTreeFull(u, title) {
relPnlChart(u.profit.toMcap, u.loss.toMcap, "% of Mcap", title), relPnlChart(u.profit.toMcap, u.loss.toMcap, "% of Mcap", title),
relPnlChart(u.profit.toOwnMcap, u.loss.toOwnMcap, "% of Own Mcap", title), relPnlChart(u.profit.toOwnMcap, u.loss.toOwnMcap, "% of Own Mcap", title),
relPnlChart(u.profit.toOwnGrossPnl, u.loss.toOwnGrossPnl, "% of Own P&L", title), relPnlChart(u.profit.toOwnGrossPnl, u.loss.toOwnGrossPnl, "% of Own P&L", title),
...unrealizedCumulativeRollingTree(u.profit, u.loss, title),
]; ];
} }
@@ -141,7 +139,6 @@ function unrealizedPnlTreeLongTerm(u, title) {
}, },
relPnlChart(u.profit.toOwnMcap, u.loss.toOwnMcap, "% of Own Mcap", title), relPnlChart(u.profit.toOwnMcap, u.loss.toOwnMcap, "% of Own Mcap", title),
relPnlChart(u.profit.toOwnGrossPnl, u.loss.toOwnGrossPnl, "% of Own P&L", title), relPnlChart(u.profit.toOwnGrossPnl, u.loss.toOwnGrossPnl, "% of Own P&L", title),
...unrealizedCumulativeRollingTree(u.profit, u.loss, title),
]; ];
} }
@@ -158,72 +155,12 @@ function unrealizedPnlTreeMid(u, title) {
title: title("Unrealized P&L"), title: title("Unrealized P&L"),
bottom: [ bottom: [
...pnlLines( ...pnlLines(
{ profit: u.profit.base.usd, loss: u.loss.base.usd, negLoss: u.loss.negative }, { profit: u.profit.usd, loss: u.loss.usd, negLoss: u.loss.negative },
Unit.usd, Unit.usd,
), ),
priceLine({ unit: Unit.usd, defaultActive: false }), priceLine({ unit: Unit.usd, defaultActive: false }),
], ],
}, },
...unrealizedCumulativeRollingTree(u.profit, u.loss, title),
];
}
/**
* Unrealized cumulative + rolling P&L tree (profit and loss have cumulative.usd + sum[w].usd)
* @param {{ cumulative: { usd: AnySeriesPattern }, sum: { _24h: { usd: AnySeriesPattern }, _1w: { usd: AnySeriesPattern }, _1m: { usd: AnySeriesPattern }, _1y: { usd: AnySeriesPattern } } }} profit
* @param {{ cumulative: { usd: AnySeriesPattern }, sum: { _24h: { usd: AnySeriesPattern }, _1w: { usd: AnySeriesPattern }, _1m: { usd: AnySeriesPattern }, _1y: { usd: AnySeriesPattern } } }} loss
* @param {(name: string) => string} title
* @returns {PartialOptionsTree}
*/
function unrealizedCumulativeRollingTree(profit, loss, title) {
return [
{
name: "Cumulative",
title: title("Cumulative Unrealized P&L"),
bottom: [
line({ series: profit.cumulative.usd, name: "Profit", color: colors.profit, unit: Unit.usd }),
line({ series: loss.cumulative.usd, name: "Loss", color: colors.loss, unit: Unit.usd }),
],
},
{
name: "Rolling",
tree: [
{
name: "Profit",
tree: [
{
name: "Compare",
title: title("Rolling Unrealized Profit"),
bottom: ROLLING_WINDOWS.map((w) =>
line({ series: profit.sum[w.key].usd, name: w.name, color: w.color, unit: Unit.usd }),
),
},
...ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Unrealized Profit (${w.name})`),
bottom: [line({ series: profit.sum[w.key].usd, name: "Profit", color: colors.profit, unit: Unit.usd })],
})),
],
},
{
name: "Loss",
tree: [
{
name: "Compare",
title: title("Rolling Unrealized Loss"),
bottom: ROLLING_WINDOWS.map((w) =>
line({ series: loss.sum[w.key].usd, name: w.name, color: w.color, unit: Unit.usd }),
),
},
...ROLLING_WINDOWS.map((w) => ({
name: w.name,
title: title(`Unrealized Loss (${w.name})`),
bottom: [line({ series: loss.sum[w.key].usd, name: "Loss", color: colors.loss, unit: Unit.usd })],
})),
],
},
],
},
]; ];
} }
@@ -331,12 +268,12 @@ function realizedPnlSumTreeFull(r, title) {
title: title("Realized P&L"), title: title("Realized P&L"),
bottom: [ bottom: [
dots({ series: r.profit.base.usd, name: "Profit", color: colors.profit, unit: Unit.usd }), dots({ series: r.profit.base.usd, name: "Profit", color: colors.profit, unit: Unit.usd }),
dots({ series: r.loss.negative, name: "Negative Loss", color: colors.loss, unit: Unit.usd, defaultActive: false }), dots({ series: r.loss.negative, name: "Loss (Inverted)", color: colors.loss, unit: Unit.usd, defaultActive: false }),
dots({ series: r.loss.base.usd, name: "Loss", color: colors.loss, unit: Unit.usd, defaultActive: false }), dots({ series: r.loss.base.usd, name: "Loss", color: colors.loss, unit: Unit.usd, defaultActive: false }),
], ],
}, },
{ {
name: "% of Rcap", name: "% of Realized Cap",
title: title("Realized P&L (% of Realized Cap)"), title: title("Realized P&L (% of Realized Cap)"),
bottom: [ bottom: [
...percentRatioBaseline({ pattern: r.profit.toRcap, name: "Profit", color: colors.profit }), ...percentRatioBaseline({ pattern: r.profit.toRcap, name: "Profit", color: colors.profit }),
@@ -355,7 +292,7 @@ function realizedNetPnlSumTreeFull(r, title) {
return [ return [
{ name: "USD", title: title("Net Realized P&L"), bottom: [dotsBaseline({ series: r.netPnl.base.usd, name: "Net", unit: Unit.usd })] }, { name: "USD", title: title("Net Realized P&L"), bottom: [dotsBaseline({ series: r.netPnl.base.usd, name: "Net", unit: Unit.usd })] },
{ {
name: "% of Rcap", name: "% of Realized Cap",
title: title("Net Realized P&L (% of Realized Cap)"), title: title("Net Realized P&L (% of Realized Cap)"),
bottom: percentRatioBaseline({ pattern: r.netPnl.toRcap, name: "Net" }), bottom: percentRatioBaseline({ pattern: r.netPnl.toRcap, name: "Net" }),
}, },
@@ -375,11 +312,11 @@ function realizedPnlCumulativeTreeFull(r, title) {
bottom: [ bottom: [
line({ series: r.profit.cumulative.usd, name: "Profit", color: colors.profit, unit: Unit.usd }), line({ series: r.profit.cumulative.usd, name: "Profit", color: colors.profit, unit: Unit.usd }),
line({ series: r.loss.cumulative.usd, name: "Loss", color: colors.loss, unit: Unit.usd }), line({ series: r.loss.cumulative.usd, name: "Loss", color: colors.loss, unit: Unit.usd }),
line({ series: r.loss.negative, name: "Negative Loss", color: colors.loss, unit: Unit.usd, defaultActive: false }), line({ series: r.loss.negative, name: "Loss (Inverted)", color: colors.loss, unit: Unit.usd, defaultActive: false }),
], ],
}, },
{ {
name: "% of Rcap", name: "% of Realized Cap",
title: title("Cumulative Realized P&L (% of Realized Cap)"), title: title("Cumulative Realized P&L (% of Realized Cap)"),
bottom: [ bottom: [
...percentRatioBaseline({ pattern: r.profit.toRcap, name: "Profit", color: colors.profit }), ...percentRatioBaseline({ pattern: r.profit.toRcap, name: "Profit", color: colors.profit }),
@@ -411,7 +348,7 @@ function realizedNetPnlDeltaTree(netPnl, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Net Realized P&L Change (${w.name})`), title: title(`Net Realized P&L Change (${w.title})`),
bottom: [baseline({ series: netPnl.delta.absolute[w.key].usd, name: "Change", unit: Unit.usd })], bottom: [baseline({ series: netPnl.delta.absolute[w.key].usd, name: "Change", unit: Unit.usd })],
})), })),
], ],
@@ -428,7 +365,7 @@ function realizedNetPnlDeltaTree(netPnl, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Net Realized P&L Rate (${w.name})`), title: title(`Net Realized P&L Rate (${w.title})`),
bottom: percentRatioBaseline({ pattern: netPnl.delta.rate[w.key], name: "Rate" }), bottom: percentRatioBaseline({ pattern: netPnl.delta.rate[w.key], name: "Rate" }),
})), })),
], ],
@@ -455,8 +392,8 @@ function realizedNetPnlDeltaTreeFull(r, title) {
bottom: percentRatioBaseline({ pattern: r.netPnl.change1m.toMcap, name: "30d Change" }), bottom: percentRatioBaseline({ pattern: r.netPnl.change1m.toMcap, name: "30d Change" }),
}, },
{ {
name: "% of Rcap", name: "% of Realized Cap",
title: title("Net Realized P&L Change (% of Rcap)"), title: title("Net Realized P&L Change (% of Realized Cap)"),
bottom: percentRatioBaseline({ pattern: r.netPnl.change1m.toRcap, name: "30d Change" }), bottom: percentRatioBaseline({ pattern: r.netPnl.change1m.toRcap, name: "30d Change" }),
}, },
], ],
@@ -482,7 +419,7 @@ function rollingNetRealizedTree(netPnl, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Net Realized P&L (${w.name})`), title: title(`Net Realized P&L (${w.title})`),
bottom: [baseline({ series: netPnl.sum[w.key].usd, name: "Net", unit: Unit.usd })], bottom: [baseline({ series: netPnl.sum[w.key].usd, name: "Net", unit: Unit.usd })],
})), })),
], ],
@@ -509,7 +446,7 @@ function singleRollingRealizedTreeFull(r, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Profit (${w.name})`), title: title(`Realized Profit (${w.title})`),
bottom: [line({ series: r.profit.sum[w.key].usd, name: "Profit", color: colors.profit, unit: Unit.usd })], bottom: [line({ series: r.profit.sum[w.key].usd, name: "Profit", color: colors.profit, unit: Unit.usd })],
})), })),
], ],
@@ -526,7 +463,7 @@ function singleRollingRealizedTreeFull(r, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Loss (${w.name})`), title: title(`Realized Loss (${w.title})`),
bottom: [line({ series: r.loss.sum[w.key].usd, name: "Loss", color: colors.loss, unit: Unit.usd })], bottom: [line({ series: r.loss.sum[w.key].usd, name: "Loss", color: colors.loss, unit: Unit.usd })],
})), })),
], ],
@@ -544,7 +481,7 @@ function singleRollingRealizedTreeFull(r, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized P/L Ratio (${w.name})`), title: title(`Realized P/L Ratio (${w.title})`),
bottom: [baseline({ series: r.profitToLossRatio[w.key], name: "P/L Ratio", unit: Unit.ratio, base: 1 })], bottom: [baseline({ series: r.profitToLossRatio[w.key], name: "P/L Ratio", unit: Unit.ratio, base: 1 })],
})), })),
], ],
@@ -565,7 +502,7 @@ function singleRollingRealizedTreeBasic(profit, loss, title) {
name: "Profit", name: "Profit",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Profit (${w.name})`), title: title(`Realized Profit (${w.title})`),
bottom: [line({ series: profit.sum[w.key].usd, name: "Profit", color: colors.profit, unit: Unit.usd })], bottom: [line({ series: profit.sum[w.key].usd, name: "Profit", color: colors.profit, unit: Unit.usd })],
})), })),
}, },
@@ -573,7 +510,7 @@ function singleRollingRealizedTreeBasic(profit, loss, title) {
name: "Loss", name: "Loss",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Loss (${w.name})`), title: title(`Realized Loss (${w.title})`),
bottom: [line({ series: loss.sum[w.key].usd, name: "Loss", color: colors.loss, unit: Unit.usd })], bottom: [line({ series: loss.sum[w.key].usd, name: "Loss", color: colors.loss, unit: Unit.usd })],
})), })),
}, },
@@ -609,7 +546,7 @@ function realizedValueTree(valueCreated, valueDestroyed, label, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`${label} Value (${w.name})`), title: title(`${label} Value (${w.title})`),
bottom: [ bottom: [
line({ series: valueCreated.sum[w.key], name: "Created", color: colors.profit, unit: Unit.usd }), line({ series: valueCreated.sum[w.key], name: "Created", color: colors.profit, unit: Unit.usd }),
line({ series: valueDestroyed.sum[w.key], name: "Destroyed", color: colors.loss, unit: Unit.usd }), line({ series: valueDestroyed.sum[w.key], name: "Destroyed", color: colors.loss, unit: Unit.usd }),
@@ -690,7 +627,7 @@ function realizedSubfolderFull(r, title) {
{ {
name: "Gross P&L", name: "Gross P&L",
tree: [ tree: [
{ name: "Base", title: title("Gross Realized P&L"), bottom: [dots({ series: r.grossPnl.base.usd, name: "Gross P&L", color: colors.bitcoin, unit: Unit.usd })] }, { name: "Per Block", title: title("Gross Realized P&L"), bottom: [dots({ series: r.grossPnl.base.usd, name: "Gross P&L", color: colors.bitcoin, unit: Unit.usd })] },
{ {
name: "Rolling", name: "Rolling",
tree: [ tree: [
@@ -703,7 +640,7 @@ function realizedSubfolderFull(r, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Gross Realized P&L (${w.name})`), title: title(`Gross Realized P&L (${w.title})`),
bottom: [line({ series: r.grossPnl.sum[w.key].usd, name: "Gross P&L", color: colors.bitcoin, unit: Unit.usd })], bottom: [line({ series: r.grossPnl.sum[w.key].usd, name: "Gross P&L", color: colors.bitcoin, unit: Unit.usd })],
})), })),
], ],
@@ -744,7 +681,7 @@ function realizedSubfolderFull(r, title) {
tree: [ tree: [
{ name: "USD", title: title("Cumulative Net Realized P&L"), bottom: [baseline({ series: r.netPnl.cumulative.usd, name: "Net", unit: Unit.usd })] }, { name: "USD", title: title("Cumulative Net Realized P&L"), bottom: [baseline({ series: r.netPnl.cumulative.usd, name: "Net", unit: Unit.usd })] },
{ {
name: "% of Rcap", name: "% of Realized Cap",
title: title("Cumulative Net P&L (% of Realized Cap)"), title: title("Cumulative Net P&L (% of Realized Cap)"),
bottom: percentRatioBaseline({ pattern: r.netPnl.toRcap, name: "Net" }), bottom: percentRatioBaseline({ pattern: r.netPnl.toRcap, name: "Net" }),
}, },
@@ -755,7 +692,7 @@ function realizedSubfolderFull(r, title) {
tree: [ tree: [
{ name: "USD", title: title("Cumulative Peak Regret"), bottom: [line({ series: r.peakRegret.cumulative, name: "Peak Regret", unit: Unit.usd })] }, { name: "USD", title: title("Cumulative Peak Regret"), bottom: [line({ series: r.peakRegret.cumulative, name: "Peak Regret", unit: Unit.usd })] },
{ {
name: "% of Rcap", name: "% of Realized Cap",
title: title("Cumulative Peak Regret (% of Realized Cap)"), title: title("Cumulative Peak Regret (% of Realized Cap)"),
bottom: percentRatioBaseline({ pattern: r.peakRegret.toRcap, name: "Peak Regret" }), bottom: percentRatioBaseline({ pattern: r.peakRegret.toRcap, name: "Peak Regret" }),
}, },
@@ -782,7 +719,7 @@ function realizedSubfolderMid(r, title) {
title: title("Realized P&L"), title: title("Realized P&L"),
bottom: [ bottom: [
dots({ series: r.profit.base.usd, name: "Profit", color: colors.profit, unit: Unit.usd }), dots({ series: r.profit.base.usd, name: "Profit", color: colors.profit, unit: Unit.usd }),
dots({ series: r.loss.negative, name: "Negative Loss", color: colors.loss, unit: Unit.usd, defaultActive: false }), dots({ series: r.loss.negative, name: "Loss (Inverted)", color: colors.loss, unit: Unit.usd, defaultActive: false }),
dots({ series: r.loss.base.usd, name: "Loss", color: colors.loss, unit: Unit.usd, defaultActive: false }), dots({ series: r.loss.base.usd, name: "Loss", color: colors.loss, unit: Unit.usd, defaultActive: false }),
], ],
}, },
@@ -898,12 +835,11 @@ export function createProfitabilitySectionWithProfitLoss({ cohort, title }) {
name: "USD", name: "USD",
title: title("Unrealized P&L"), title: title("Unrealized P&L"),
bottom: [ bottom: [
...pnlLines({ profit: u.profit.base.usd, loss: u.loss.base.usd, negLoss: u.loss.negative }, Unit.usd), ...pnlLines({ profit: u.profit.usd, loss: u.loss.usd, negLoss: u.loss.negative }, Unit.usd),
priceLine({ unit: Unit.usd, defaultActive: false }), priceLine({ unit: Unit.usd, defaultActive: false }),
], ],
}, },
...unrealizedCumulativeRollingTree(u.profit, u.loss, title), ],
],
}, },
{ name: "NUPL", title: title("NUPL"), bottom: nuplSeries(u.nupl) }, { name: "NUPL", title: title("NUPL"), bottom: nuplSeries(u.nupl) },
], ],
@@ -1089,12 +1025,11 @@ export function createProfitabilitySectionAddress({ cohort, title }) {
name: "USD", name: "USD",
title: title("Unrealized P&L"), title: title("Unrealized P&L"),
bottom: [ bottom: [
...pnlLines({ profit: u.profit.base.usd, loss: u.loss.base.usd, negLoss: u.loss.negative }, Unit.usd), ...pnlLines({ profit: u.profit.usd, loss: u.loss.usd, negLoss: u.loss.negative }, Unit.usd),
priceLine({ unit: Unit.usd, defaultActive: false }), priceLine({ unit: Unit.usd, defaultActive: false }),
], ],
}, },
...unrealizedCumulativeRollingTree(u.profit, u.loss, title), ],
],
}, },
{ name: "NUPL", title: title("NUPL"), bottom: nuplSeries(u.nupl) }, { name: "NUPL", title: title("NUPL"), bottom: nuplSeries(u.nupl) },
], ],
@@ -1178,7 +1113,7 @@ function groupedRollingRealizedCharts(list, all, title) {
name: "Profit", name: "Profit",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Profit (${w.name})`), title: title(`Realized Profit (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.profit.sum[w.key].usd, name, color, unit: Unit.usd })), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.profit.sum[w.key].usd, name, color, unit: Unit.usd })),
})), })),
}, },
@@ -1186,7 +1121,7 @@ function groupedRollingRealizedCharts(list, all, title) {
name: "Loss", name: "Loss",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Loss (${w.name})`), title: title(`Realized Loss (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.loss.sum[w.key].usd, name, color, unit: Unit.usd })), bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => line({ series: tree.realized.loss.sum[w.key].usd, name, color, unit: Unit.usd })),
})), })),
}, },
@@ -1207,7 +1142,7 @@ function groupedRollingRealizedChartsFull(list, all, title) {
name: "P/L Ratio", name: "P/L Ratio",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized P/L Ratio (${w.name})`), title: title(`Realized P/L Ratio (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.profitToLossRatio[w.key], name, color, unit: Unit.ratio, base: 1 }), baseline({ series: tree.realized.profitToLossRatio[w.key], name, color, unit: Unit.ratio, base: 1 }),
), ),
@@ -1279,7 +1214,7 @@ function groupedRealizedNetPnlDeltaTree(list, all, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Net Realized P&L Change (${w.name})`), title: title(`Net Realized P&L Change (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.netPnl.delta.absolute[w.key].usd, name, color, unit: Unit.usd }), baseline({ series: tree.realized.netPnl.delta.absolute[w.key].usd, name, color, unit: Unit.usd }),
), ),
@@ -1300,7 +1235,7 @@ function groupedRealizedNetPnlDeltaTree(list, all, title) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Net Realized P&L Rate (${w.name})`), title: title(`Net Realized P&L Rate (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
percentRatio({ pattern: tree.realized.netPnl.delta.rate[w.key], name, color }), percentRatio({ pattern: tree.realized.netPnl.delta.rate[w.key], name, color }),
), ),
@@ -1399,7 +1334,7 @@ function groupedPnlChartsWithMarketCap(list, all, title) {
name: "USD", name: "USD",
title: title("Unrealized Profit"), title: title("Unrealized Profit"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.profit.base.usd, name, color, unit: Unit.usd }), line({ series: tree.unrealized.profit.usd, name, color, unit: Unit.usd }),
), ),
}, },
{ {
@@ -1418,7 +1353,7 @@ function groupedPnlChartsWithMarketCap(list, all, title) {
name: "USD", name: "USD",
title: title("Unrealized Loss"), title: title("Unrealized Loss"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.loss.base.usd, name, color, unit: Unit.usd }), line({ series: tree.unrealized.loss.usd, name, color, unit: Unit.usd }),
), ),
}, },
{ {
@@ -1453,14 +1388,14 @@ function groupedPnlChartsWithOwnMarketCap(list, all, title) {
name: "Profit", name: "Profit",
title: title("Unrealized Profit"), title: title("Unrealized Profit"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.profit.base.usd, name, color, unit: Unit.usd }), line({ series: tree.unrealized.profit.usd, name, color, unit: Unit.usd }),
), ),
}, },
{ {
name: "Loss", name: "Loss",
title: title("Unrealized Loss"), title: title("Unrealized Loss"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.loss.base.usd, name, color, unit: Unit.usd }), line({ series: tree.unrealized.loss.usd, name, color, unit: Unit.usd }),
), ),
}, },
{ {
@@ -1489,7 +1424,7 @@ function groupedPnlChartsLongTerm(list, all, title) {
name: "USD", name: "USD",
title: title("Unrealized Profit"), title: title("Unrealized Profit"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.profit.base.usd, name, color, unit: Unit.usd }), line({ series: tree.unrealized.profit.usd, name, color, unit: Unit.usd }),
), ),
}, },
{ {
@@ -1515,7 +1450,7 @@ function groupedPnlChartsLongTerm(list, all, title) {
name: "USD", name: "USD",
title: title("Unrealized Loss"), title: title("Unrealized Loss"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.loss.base.usd, name, color, unit: Unit.usd }), line({ series: tree.unrealized.loss.usd, name, color, unit: Unit.usd }),
), ),
}, },
{ {
@@ -1642,14 +1577,14 @@ export function createGroupedProfitabilitySectionWithProfitLoss({ list, all, tit
name: "Profit", name: "Profit",
title: title("Unrealized Profit"), title: title("Unrealized Profit"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.profit.base.usd, name, color, unit: Unit.usd }), line({ series: tree.unrealized.profit.usd, name, color, unit: Unit.usd }),
), ),
}, },
{ {
name: "Loss", name: "Loss",
title: title("Unrealized Loss"), title: title("Unrealized Loss"),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
line({ series: tree.unrealized.loss.base.usd, name, color, unit: Unit.usd }), line({ series: tree.unrealized.loss.usd, name, color, unit: Unit.usd }),
), ),
}, },
...groupedNuplCharts(list, all, title), ...groupedNuplCharts(list, all, title),

View File

@@ -50,9 +50,9 @@ export function createValuationSectionFull({ cohort, title }) {
bottom: createSingleRealizedCapSeries(cohort), bottom: createSingleRealizedCapSeries(cohort),
}, },
{ {
name: "% of Own Mcap", name: "% of Own Market Cap",
title: title("Realized Cap (% of Own Mcap)"), title: title("Realized Cap (% of Own Market Cap)"),
bottom: percentRatioBaseline({ pattern: tree.realized.cap.toOwnMcap, name: "Rel. to Own M.Cap", color }), bottom: percentRatioBaseline({ pattern: tree.realized.cap.toOwnMcap, name: "Rel. to Own Market Cap", color }),
}, },
], ],
}, },
@@ -140,7 +140,7 @@ export function createGroupedValuationSection({ list, all, title }) {
name: "Absolute", name: "Absolute",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Cap Change (${w.name})`), title: title(`Realized Cap Change (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.cap.delta.absolute[w.key].usd, name, color, unit: Unit.usd }), baseline({ series: tree.realized.cap.delta.absolute[w.key].usd, name, color, unit: Unit.usd }),
), ),
@@ -150,7 +150,7 @@ export function createGroupedValuationSection({ list, all, title }) {
name: "Rate", name: "Rate",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Cap Rate (${w.name})`), title: title(`Realized Cap Rate (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
percentRatio({ pattern: tree.realized.cap.delta.rate[w.key], name, color }), percentRatio({ pattern: tree.realized.cap.delta.rate[w.key], name, color }),
), ),
@@ -198,8 +198,8 @@ export function createGroupedValuationSectionWithOwnMarketCap({
), ),
}, },
{ {
name: "% of Own Mcap", name: "% of Own Market Cap",
title: title("Realized Cap (% of Own Mcap)"), title: title("Realized Cap (% of Own Market Cap)"),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
percentRatio({ pattern: tree.realized.cap.toOwnMcap, name, color }), percentRatio({ pattern: tree.realized.cap.toOwnMcap, name, color }),
), ),
@@ -213,7 +213,7 @@ export function createGroupedValuationSectionWithOwnMarketCap({
name: "Absolute", name: "Absolute",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Cap Change (${w.name})`), title: title(`Realized Cap Change (${w.title})`),
bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: mapCohortsWithAll(list, all, ({ name, color, tree }) =>
baseline({ series: tree.realized.cap.delta.absolute[w.key].usd, name, color, unit: Unit.usd }), baseline({ series: tree.realized.cap.delta.absolute[w.key].usd, name, color, unit: Unit.usd }),
), ),
@@ -223,7 +223,7 @@ export function createGroupedValuationSectionWithOwnMarketCap({
name: "Rate", name: "Rate",
tree: ROLLING_WINDOWS.map((w) => ({ tree: ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: title(`Realized Cap Rate (${w.name})`), title: title(`Realized Cap Rate (${w.title})`),
bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) => bottom: flatMapCohortsWithAll(list, all, ({ name, color, tree }) =>
percentRatio({ pattern: tree.realized.cap.delta.rate[w.key], name, color }), percentRatio({ pattern: tree.realized.cap.delta.rate[w.key], name, color }),
), ),

View File

@@ -292,26 +292,8 @@ export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
top: topPane(key), top: topPane(key),
}); });
/** @param {string} name @param {ShortPeriodKey} key */ /** @param {string} name @param {AllPeriodKey} key */
const shortReturnsChart = (name, key) => ({ const returnsChart = (name, key) => ({
name: "Returns",
title: `Returns: ${name} DCA vs Lump Sum`,
top: topPane(key),
bottom: [
...percentRatioBaseline({
pattern: dca.period.return[key],
name: "DCA",
}),
...percentRatioBaseline({
pattern: dca.period.lumpSumReturn[key],
name: "Lump Sum",
color: colors.bi.p2,
}),
],
});
/** @param {string} name @param {LongPeriodKey} key */
const longReturnsChart = (name, key) => ({
name: "Returns", name: "Returns",
title: `Returns: ${name} DCA vs Lump Sum`, title: `Returns: ${name} DCA vs Lump Sum`,
top: topPane(key), top: topPane(key),
@@ -372,7 +354,7 @@ export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
name, name,
tree: [ tree: [
costBasisChart(name, key), costBasisChart(name, key),
shortReturnsChart(name, key), returnsChart(name, key),
stackChart(name, key), stackChart(name, key),
], ],
}; };
@@ -385,7 +367,7 @@ export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
name, name,
tree: [ tree: [
costBasisChart(name, key), costBasisChart(name, key),
longReturnsChart(name, key), returnsChart(name, key),
longCagrChart(name, key), longCagrChart(name, key),
stackChart(name, key), stackChart(name, key),
], ],

View File

@@ -576,7 +576,7 @@ export function createMarketSection() {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: `Capitalization Growth Rate Spread ${w.name}`, title: `Capitalization Growth Rate Spread (${w.title})`,
bottom: [ bottom: [
baseline({ baseline({
series: supply.marketMinusRealizedCapGrowthRate[w.key], series: supply.marketMinusRealizedCapGrowthRate[w.key],
@@ -660,7 +660,7 @@ export function createMarketSection() {
const rsi = technical.rsi[w.key]; const rsi = technical.rsi[w.key];
return { return {
name: w.name, name: w.name,
title: `RSI (${w.name})`, title: `RSI (${w.title})`,
bottom: [ bottom: [
...indexRatio({ pattern: rsi.rsi, name: "RSI", color: colors.indicator.main }), ...indexRatio({ pattern: rsi.rsi, name: "RSI", color: colors.indicator.main }),
priceLine({ unit: Unit.index, number: 70 }), priceLine({ unit: Unit.index, number: 70 }),
@@ -675,7 +675,7 @@ export function createMarketSection() {
const rsi = technical.rsi[w.key]; const rsi = technical.rsi[w.key];
return { return {
name: w.name, name: w.name,
title: `Stochastic RSI (${w.name})`, title: `Stochastic RSI (${w.title})`,
bottom: [ bottom: [
...indexRatio({ pattern: rsi.stochRsiK, name: "K", color: colors.indicator.fast }), ...indexRatio({ pattern: rsi.stochRsiK, name: "K", color: colors.indicator.fast }),
...indexRatio({ pattern: rsi.stochRsiD, name: "D", color: colors.indicator.slow }), ...indexRatio({ pattern: rsi.stochRsiD, name: "D", color: colors.indicator.slow }),
@@ -698,7 +698,7 @@ export function createMarketSection() {
}, },
...ROLLING_WINDOWS_TO_1M.map((w) => ({ ...ROLLING_WINDOWS_TO_1M.map((w) => ({
name: w.name, name: w.name,
title: `MACD (${w.name})`, title: `MACD (${w.title})`,
bottom: [ bottom: [
line({ series: technical.macd[w.key].line, name: "MACD", color: colors.indicator.fast, unit: Unit.usd }), line({ series: technical.macd[w.key].line, name: "MACD", color: colors.indicator.fast, unit: Unit.usd }),
line({ series: technical.macd[w.key].signal, name: "Signal", color: colors.indicator.slow, unit: Unit.usd }), line({ series: technical.macd[w.key].signal, name: "Signal", color: colors.indicator.slow, unit: Unit.usd }),
@@ -726,7 +726,7 @@ export function createMarketSection() {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: `Volatility Index (${w.name})`, title: `Volatility Index (${w.title})`,
bottom: [line({ series: volatility[w.key], name: w.name, color: w.color, unit: Unit.percentage })], bottom: [line({ series: volatility[w.key], name: w.name, color: w.color, unit: Unit.percentage })],
})), })),
], ],

View File

@@ -59,27 +59,20 @@ export function createPartialOptions() {
} = buildCohortData(); } = buildCohortData();
return [ return [
// Charts section
{ {
name: "Charts", name: "Charts",
tree: [ tree: [
// Market section
createMarketSection(), createMarketSection(),
// Network section (on-chain activity)
createNetworkSection(), createNetworkSection(),
// Mining section (security & economics)
createMiningSection(), createMiningSection(),
// Cohorts section
{ {
name: "Distribution", name: "Distribution",
tree: [ tree: [
// Overview - All UTXOs
createCohortFolderAll({ ...cohortAll, name: "Overview" }), createCohortFolderAll({ ...cohortAll, name: "Overview" }),
// STH vs LTH - Direct comparison
createGroupedCohortFolderWithNupl({ createGroupedCohortFolderWithNupl({
name: "STH vs LTH", name: "STH vs LTH",
title: "STH vs LTH", title: "STH vs LTH",
@@ -87,17 +80,13 @@ export function createPartialOptions() {
all: cohortAll, all: cohortAll,
}), }),
// STH - Short term holder cohort
createCohortFolderFull(termShort), createCohortFolderFull(termShort),
// LTH - Long term holder cohort
createCohortFolderLongTerm(termLong), createCohortFolderLongTerm(termLong),
// Ages cohorts
{ {
name: "UTXO Age", name: "UTXO Age",
tree: [ tree: [
// Younger Than (< X old)
{ {
name: "Younger Than", name: "Younger Than",
tree: [ tree: [
@@ -110,7 +99,6 @@ export function createPartialOptions() {
...underAge.map(createCohortFolderWithAdjusted), ...underAge.map(createCohortFolderWithAdjusted),
], ],
}, },
// Older Than (≥ X old)
{ {
name: "Older Than", name: "Older Than",
tree: [ tree: [
@@ -123,7 +111,6 @@ export function createPartialOptions() {
...overAge.map(createCohortFolderWithAdjusted), ...overAge.map(createCohortFolderWithAdjusted),
], ],
}, },
// Range
{ {
name: "Range", name: "Range",
tree: [ tree: [
@@ -139,17 +126,15 @@ export function createPartialOptions() {
], ],
}, },
// Sizes cohorts (UTXO size)
{ {
name: "UTXO Size", name: "UTXO Size",
tree: [ tree: [
// Less Than (< X sats)
{ {
name: "Less Than", name: "Less Than",
tree: [ tree: [
createGroupedCohortFolderBasicWithMarketCap({ createGroupedCohortFolderBasicWithMarketCap({
name: "Compare", name: "Compare",
title: "Over Amount", title: "Under Amount",
list: utxosUnderAmount, list: utxosUnderAmount,
all: cohortAll, all: cohortAll,
}), }),
@@ -158,13 +143,12 @@ export function createPartialOptions() {
), ),
], ],
}, },
// More Than (≥ X sats)
{ {
name: "More Than", name: "More Than",
tree: [ tree: [
createGroupedCohortFolderBasicWithMarketCap({ createGroupedCohortFolderBasicWithMarketCap({
name: "Compare", name: "Compare",
title: "Under Amount", title: "Over Amount",
list: utxosOverAmount, list: utxosOverAmount,
all: cohortAll, all: cohortAll,
}), }),
@@ -173,7 +157,6 @@ export function createPartialOptions() {
), ),
], ],
}, },
// Range
{ {
name: "Range", name: "Range",
tree: [ tree: [
@@ -191,37 +174,39 @@ export function createPartialOptions() {
], ],
}, },
// Balances cohorts (Address balance) createUtxoProfitabilitySection({
range: profitabilityRange,
profit: profitabilityProfit,
loss: profitabilityLoss,
}),
{ {
name: "Address Balance", name: "Address Balance",
tree: [ tree: [
// Less Than (< X sats)
{ {
name: "Less Than", name: "Less Than",
tree: [ tree: [
createGroupedAddressCohortFolder({ createGroupedAddressCohortFolder({
name: "Compare", name: "Compare",
title: "Over Balance", title: "Under Balance",
list: addressesUnderAmount, list: addressesUnderAmount,
all: cohortAll, all: cohortAll,
}), }),
...addressesUnderAmount.map(createAddressCohortFolder), ...addressesUnderAmount.map(createAddressCohortFolder),
], ],
}, },
// More Than (≥ X sats)
{ {
name: "More Than", name: "More Than",
tree: [ tree: [
createGroupedAddressCohortFolder({ createGroupedAddressCohortFolder({
name: "Compare", name: "Compare",
title: "Under Balance", title: "Over Balance",
list: addressesOverAmount, list: addressesOverAmount,
all: cohortAll, all: cohortAll,
}), }),
...addressesOverAmount.map(createAddressCohortFolder), ...addressesOverAmount.map(createAddressCohortFolder),
], ],
}, },
// Range
{ {
name: "Range", name: "Range",
tree: [ tree: [
@@ -237,7 +222,6 @@ export function createPartialOptions() {
], ],
}, },
// Script Types - addressable types have addrCount, others don't
{ {
name: "Script Type", name: "Script Type",
tree: [ tree: [
@@ -252,7 +236,6 @@ export function createPartialOptions() {
], ],
}, },
// Epochs
{ {
name: "Epoch", name: "Epoch",
tree: [ tree: [
@@ -266,7 +249,6 @@ export function createPartialOptions() {
], ],
}, },
// Classes
{ {
name: "Class", name: "Class",
tree: [ tree: [
@@ -279,20 +261,11 @@ export function createPartialOptions() {
...class_.map(createCohortFolderWithAdjusted), ...class_.map(createCohortFolderWithAdjusted),
], ],
}, },
// UTXO Profitability bands
createUtxoProfitabilitySection({
range: profitabilityRange,
profit: profitabilityProfit,
loss: profitabilityLoss,
}),
], ],
}, },
// Investing section
createInvestingSection(), createInvestingSection(),
// Frameworks section
{ {
name: "Frameworks", name: "Frameworks",
tree: [createCointimeSection()], tree: [createCointimeSection()],
@@ -300,14 +273,12 @@ export function createPartialOptions() {
], ],
}, },
// API documentation
{ {
name: "API", name: "API",
url: () => "/api", url: () => "/api",
title: "API documentation", title: "API documentation",
}, },
// Project link
{ {
name: "Source", name: "Source",
url: () => "https://bitcoinresearchkit.org", url: () => "https://bitcoinresearchkit.org",

View File

@@ -17,11 +17,11 @@ export const ROLLING_WINDOWS = [
{ key: "_1y", name: "1y", title: "Yearly", color: colors.time._1y }, { key: "_1y", name: "1y", title: "Yearly", color: colors.time._1y },
]; ];
/** @type {ReadonlyArray<{key: '_24h' | '_1w' | '_1m', name: string, color: Color}>} */ /** @type {ReadonlyArray<{key: '_24h' | '_1w' | '_1m', name: string, title: string, color: Color}>} */
export const ROLLING_WINDOWS_TO_1M = [ export const ROLLING_WINDOWS_TO_1M = [
{ key: "_24h", name: "24h", color: colors.time._24h }, { key: "_24h", name: "24h", title: "Daily", color: colors.time._24h },
{ key: "_1w", name: "1w", color: colors.time._1w }, { key: "_1w", name: "1w", title: "Weekly", color: colors.time._1w },
{ key: "_1m", name: "1m", color: colors.time._1m }, { key: "_1m", name: "1m", title: "Monthly", color: colors.time._1m },
]; ];
/** /**
@@ -604,7 +604,7 @@ export function distributionWindowsTree({ pattern, base, title, unit }) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: `${title} Distribution (${w.name})`, title: `${title} Distribution (${w.title})`,
bottom: [ bottom: [
...(base ? [line({ series: base, name: "base", unit })] : []), ...(base ? [line({ series: base, name: "base", unit })] : []),
...fromStatsPattern({ ...fromStatsPattern({
@@ -755,15 +755,22 @@ export function percentRatioDots({ pattern, name, color, defaultActive }) {
* @param {boolean} [args.defaultActive] * @param {boolean} [args.defaultActive]
* @returns {AnyFetchedSeriesBlueprint[]} * @returns {AnyFetchedSeriesBlueprint[]}
*/ */
export function percentRatioBaseline({ pattern, name, defaultActive }) { export function percentRatioBaseline({ pattern, name, color, defaultActive }) {
return [ return [
baseline({ baseline({
series: pattern.percent, series: pattern.percent,
name, name,
color,
defaultActive, defaultActive,
unit: Unit.percentage, unit: Unit.percentage,
}), }),
baseline({ series: pattern.ratio, name, defaultActive, unit: Unit.ratio }), baseline({
series: pattern.ratio,
name,
color,
defaultActive,
unit: Unit.ratio,
}),
]; ];
} }
@@ -798,7 +805,7 @@ export function rollingPercentRatioTree({
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: `${title} ${w.name}`, title: `${title} (${w.title})`,
bottom: series({ pattern: windows[w.key], name: w.name }), bottom: series({ pattern: windows[w.key], name: w.name }),
})), })),
], ],
@@ -834,7 +841,7 @@ export function deltaTree({ delta, title, unit, extract }) {
}, },
...ROLLING_WINDOWS.map((w) => ({ ...ROLLING_WINDOWS.map((w) => ({
name: w.name, name: w.name,
title: `${title} Change ${w.name}`, title: `${title} Change (${w.title})`,
bottom: [ bottom: [
baseline({ baseline({
series: extract(delta.absolute[w.key]), series: extract(delta.absolute[w.key]),