mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-09 06:31:57 -07:00
computer: snapshot
This commit is contained in:
@@ -42,6 +42,7 @@ fn main() -> brk_client::Result<()> {
|
||||
.count
|
||||
.block_count
|
||||
.sum
|
||||
._24h
|
||||
.by
|
||||
.day1()
|
||||
.last(3)
|
||||
|
||||
@@ -2193,7 +2193,7 @@ impl GreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern {
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BlocksCoinbaseDaysDominanceFeeSubsidyPattern {
|
||||
pub blocks_mined: CumulativeHeightRollingPattern<StoredU32>,
|
||||
pub blocks_mined: CumulativeHeightSumPattern<StoredU32>,
|
||||
pub blocks_mined_1m_sum: MetricPattern1<StoredU32>,
|
||||
pub blocks_mined_1w_sum: MetricPattern1<StoredU32>,
|
||||
pub blocks_mined_1y_sum: MetricPattern1<StoredU32>,
|
||||
@@ -2214,7 +2214,7 @@ impl BlocksCoinbaseDaysDominanceFeeSubsidyPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
blocks_mined: CumulativeHeightRollingPattern::new(client.clone(), _m(&acc, "blocks_mined")),
|
||||
blocks_mined: CumulativeHeightSumPattern::new(client.clone(), _m(&acc, "blocks_mined")),
|
||||
blocks_mined_1m_sum: MetricPattern1::new(client.clone(), _m(&acc, "blocks_mined_1m_sum")),
|
||||
blocks_mined_1w_sum: MetricPattern1::new(client.clone(), _m(&acc, "blocks_mined_1w_sum")),
|
||||
blocks_mined_1y_sum: MetricPattern1::new(client.clone(), _m(&acc, "blocks_mined_1y_sum")),
|
||||
@@ -2817,8 +2817,8 @@ impl BalanceBothReactivatedReceivingSendingPattern {
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CoinblocksCoindaysSatblocksSatdaysSentPattern {
|
||||
pub coinblocks_destroyed: CumulativeHeightRollingPattern<StoredF64>,
|
||||
pub coindays_destroyed: CumulativeHeightRollingPattern<StoredF64>,
|
||||
pub coinblocks_destroyed: CumulativeHeightSumPattern<StoredF64>,
|
||||
pub coindays_destroyed: CumulativeHeightSumPattern<StoredF64>,
|
||||
pub satblocks_destroyed: MetricPattern20<Sats>,
|
||||
pub satdays_destroyed: MetricPattern20<Sats>,
|
||||
pub sent: BtcSatsUsdPattern2,
|
||||
@@ -2829,8 +2829,8 @@ impl CoinblocksCoindaysSatblocksSatdaysSentPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
coinblocks_destroyed: CumulativeHeightRollingPattern::new(client.clone(), _m(&acc, "coinblocks_destroyed")),
|
||||
coindays_destroyed: CumulativeHeightRollingPattern::new(client.clone(), _m(&acc, "coindays_destroyed")),
|
||||
coinblocks_destroyed: CumulativeHeightSumPattern::new(client.clone(), _m(&acc, "coinblocks_destroyed")),
|
||||
coindays_destroyed: CumulativeHeightSumPattern::new(client.clone(), _m(&acc, "coindays_destroyed")),
|
||||
satblocks_destroyed: MetricPattern20::new(client.clone(), _m(&acc, "satblocks_destroyed")),
|
||||
satdays_destroyed: MetricPattern20::new(client.clone(), _m(&acc, "satdays_destroyed")),
|
||||
sent: BtcSatsUsdPattern2::new(client.clone(), _m(&acc, "sent")),
|
||||
@@ -3002,13 +3002,13 @@ impl BtcSatsUsdPattern2 {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BtcSatsUsdPattern4 {
|
||||
pub struct BtcSatsUsdPattern3 {
|
||||
pub btc: MetricPattern1<Bitcoin>,
|
||||
pub sats: CumulativeHeightRollingPattern<Sats>,
|
||||
pub usd: CumulativeHeightRollingPattern<Dollars>,
|
||||
}
|
||||
|
||||
impl BtcSatsUsdPattern4 {
|
||||
impl BtcSatsUsdPattern3 {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
@@ -3020,19 +3020,19 @@ impl BtcSatsUsdPattern4 {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BtcSatsUsdPattern3 {
|
||||
pub struct BtcSatsUsdPattern4 {
|
||||
pub btc: MetricPattern1<Bitcoin>,
|
||||
pub sats: CumulativeHeightRollingPattern2<Sats>,
|
||||
pub usd: CumulativeHeightRollingPattern2<Dollars>,
|
||||
pub sats: CumulativeHeightSumPattern<Sats>,
|
||||
pub usd: CumulativeHeightSumPattern<Dollars>,
|
||||
}
|
||||
|
||||
impl BtcSatsUsdPattern3 {
|
||||
impl BtcSatsUsdPattern4 {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
btc: MetricPattern1::new(client.clone(), _m(&acc, "btc")),
|
||||
sats: CumulativeHeightRollingPattern2::new(client.clone(), acc.clone()),
|
||||
usd: CumulativeHeightRollingPattern2::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: CumulativeHeightSumPattern::new(client.clone(), acc.clone()),
|
||||
usd: CumulativeHeightSumPattern::new(client.clone(), _m(&acc, "usd")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3074,13 +3074,13 @@ impl HistogramLineSignalPattern {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CumulativeHeightRollingPattern2<T> {
|
||||
pub struct CumulativeHeightRollingPattern<T> {
|
||||
pub cumulative: MetricPattern1<T>,
|
||||
pub height: MetricPattern20<T>,
|
||||
pub rolling: AverageMaxMedianMinP10P25P75P90SumPattern,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> CumulativeHeightRollingPattern2<T> {
|
||||
impl<T: DeserializeOwned> CumulativeHeightRollingPattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
@@ -3092,19 +3092,19 @@ impl<T: DeserializeOwned> CumulativeHeightRollingPattern2<T> {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CumulativeHeightRollingPattern<T> {
|
||||
pub struct CumulativeHeightSumPattern<T> {
|
||||
pub cumulative: MetricPattern1<T>,
|
||||
pub height: MetricPattern20<T>,
|
||||
pub rolling: _1y24h30d7dPattern<T>,
|
||||
pub sum: _1y24h30d7dPattern<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> CumulativeHeightRollingPattern<T> {
|
||||
impl<T: DeserializeOwned> CumulativeHeightSumPattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")),
|
||||
height: MetricPattern20::new(client.clone(), acc.clone()),
|
||||
rolling: _1y24h30d7dPattern::new(client.clone(), acc.clone()),
|
||||
sum: _1y24h30d7dPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3290,7 +3290,7 @@ pub struct MetricsTree_Blocks {
|
||||
pub count: MetricsTree_Blocks_Count,
|
||||
pub interval: AverageHeightMaxMedianMinP10P25P75P90Pattern<Timestamp>,
|
||||
pub halving: MetricsTree_Blocks_Halving,
|
||||
pub vbytes: CumulativeHeightRollingPattern2<StoredU64>,
|
||||
pub vbytes: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub size: AverageCumulativeMaxMedianMinP10P25P75P90SumPattern,
|
||||
pub fullness: AverageHeightMaxMedianMinP10P25P75P90Pattern<StoredF32>,
|
||||
}
|
||||
@@ -3306,7 +3306,7 @@ impl MetricsTree_Blocks {
|
||||
count: MetricsTree_Blocks_Count::new(client.clone(), format!("{base_path}_count")),
|
||||
interval: AverageHeightMaxMedianMinP10P25P75P90Pattern::new(client.clone(), "block_interval".to_string()),
|
||||
halving: MetricsTree_Blocks_Halving::new(client.clone(), format!("{base_path}_halving")),
|
||||
vbytes: CumulativeHeightRollingPattern2::new(client.clone(), "block_vbytes".to_string()),
|
||||
vbytes: CumulativeHeightRollingPattern::new(client.clone(), "block_vbytes".to_string()),
|
||||
size: AverageCumulativeMaxMedianMinP10P25P75P90SumPattern::new(client.clone(), "block_size".to_string()),
|
||||
fullness: AverageHeightMaxMedianMinP10P25P75P90Pattern::new(client.clone(), "block_fullness".to_string()),
|
||||
}
|
||||
@@ -3436,7 +3436,7 @@ impl MetricsTree_Blocks_Weight {
|
||||
/// Metrics tree node.
|
||||
pub struct MetricsTree_Blocks_Count {
|
||||
pub block_count_target: MetricPattern1<StoredU64>,
|
||||
pub block_count: CumulativeHeightRollingPattern<StoredU32>,
|
||||
pub block_count: CumulativeHeightSumPattern<StoredU32>,
|
||||
pub block_count_sum: _1y24h30d7dPattern<StoredU32>,
|
||||
pub height_1h_ago: MetricPattern20<Height>,
|
||||
pub height_24h_ago: MetricPattern20<Height>,
|
||||
@@ -3475,7 +3475,7 @@ impl MetricsTree_Blocks_Count {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
block_count_target: MetricPattern1::new(client.clone(), "block_count_target".to_string()),
|
||||
block_count: CumulativeHeightRollingPattern::new(client.clone(), "block_count".to_string()),
|
||||
block_count: CumulativeHeightSumPattern::new(client.clone(), "block_count".to_string()),
|
||||
block_count_sum: _1y24h30d7dPattern::new(client.clone(), "block_count_sum".to_string()),
|
||||
height_1h_ago: MetricPattern20::new(client.clone(), "height_1h_ago".to_string()),
|
||||
height_24h_ago: MetricPattern20::new(client.clone(), "height_24h_ago".to_string()),
|
||||
@@ -3572,14 +3572,14 @@ impl MetricsTree_Transactions {
|
||||
|
||||
/// Metrics tree node.
|
||||
pub struct MetricsTree_Transactions_Count {
|
||||
pub tx_count: CumulativeHeightRollingPattern2<StoredU64>,
|
||||
pub tx_count: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub is_coinbase: MetricPattern21<StoredBool>,
|
||||
}
|
||||
|
||||
impl MetricsTree_Transactions_Count {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
tx_count: CumulativeHeightRollingPattern2::new(client.clone(), "tx_count".to_string()),
|
||||
tx_count: CumulativeHeightRollingPattern::new(client.clone(), "tx_count".to_string()),
|
||||
is_coinbase: MetricPattern21::new(client.clone(), "is_coinbase".to_string()),
|
||||
}
|
||||
}
|
||||
@@ -3621,17 +3621,17 @@ impl MetricsTree_Transactions_Fees {
|
||||
|
||||
/// Metrics tree node.
|
||||
pub struct MetricsTree_Transactions_Versions {
|
||||
pub v1: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub v2: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub v3: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub v1: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub v2: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub v3: CumulativeHeightSumPattern<StoredU64>,
|
||||
}
|
||||
|
||||
impl MetricsTree_Transactions_Versions {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
v1: CumulativeHeightRollingPattern::new(client.clone(), "tx_v1".to_string()),
|
||||
v2: CumulativeHeightRollingPattern::new(client.clone(), "tx_v2".to_string()),
|
||||
v3: CumulativeHeightRollingPattern::new(client.clone(), "tx_v3".to_string()),
|
||||
v1: CumulativeHeightSumPattern::new(client.clone(), "tx_v1".to_string()),
|
||||
v2: CumulativeHeightSumPattern::new(client.clone(), "tx_v2".to_string()),
|
||||
v3: CumulativeHeightSumPattern::new(client.clone(), "tx_v3".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3828,19 +3828,19 @@ impl MetricsTree_Scripts {
|
||||
|
||||
/// Metrics tree node.
|
||||
pub struct MetricsTree_Scripts_Count {
|
||||
pub p2a: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2ms: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2pk33: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2pk65: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2pkh: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2sh: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2tr: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2wpkh: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2wsh: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub opreturn: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub emptyoutput: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub unknownoutput: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub segwit: CumulativeHeightRollingPattern<StoredU64>,
|
||||
pub p2a: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub p2ms: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub p2pk33: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub p2pk65: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub p2pkh: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub p2sh: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub p2tr: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub p2wpkh: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub p2wsh: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub opreturn: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub emptyoutput: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub unknownoutput: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub segwit: CumulativeHeightSumPattern<StoredU64>,
|
||||
pub taproot_adoption: MetricPattern1<StoredF32>,
|
||||
pub segwit_adoption: MetricPattern1<StoredF32>,
|
||||
}
|
||||
@@ -3848,19 +3848,19 @@ pub struct MetricsTree_Scripts_Count {
|
||||
impl MetricsTree_Scripts_Count {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
p2a: CumulativeHeightRollingPattern::new(client.clone(), "p2a_count".to_string()),
|
||||
p2ms: CumulativeHeightRollingPattern::new(client.clone(), "p2ms_count".to_string()),
|
||||
p2pk33: CumulativeHeightRollingPattern::new(client.clone(), "p2pk33_count".to_string()),
|
||||
p2pk65: CumulativeHeightRollingPattern::new(client.clone(), "p2pk65_count".to_string()),
|
||||
p2pkh: CumulativeHeightRollingPattern::new(client.clone(), "p2pkh_count".to_string()),
|
||||
p2sh: CumulativeHeightRollingPattern::new(client.clone(), "p2sh_count".to_string()),
|
||||
p2tr: CumulativeHeightRollingPattern::new(client.clone(), "p2tr_count".to_string()),
|
||||
p2wpkh: CumulativeHeightRollingPattern::new(client.clone(), "p2wpkh_count".to_string()),
|
||||
p2wsh: CumulativeHeightRollingPattern::new(client.clone(), "p2wsh_count".to_string()),
|
||||
opreturn: CumulativeHeightRollingPattern::new(client.clone(), "opreturn_count".to_string()),
|
||||
emptyoutput: CumulativeHeightRollingPattern::new(client.clone(), "emptyoutput_count".to_string()),
|
||||
unknownoutput: CumulativeHeightRollingPattern::new(client.clone(), "unknownoutput_count".to_string()),
|
||||
segwit: CumulativeHeightRollingPattern::new(client.clone(), "segwit_count".to_string()),
|
||||
p2a: CumulativeHeightSumPattern::new(client.clone(), "p2a_count".to_string()),
|
||||
p2ms: CumulativeHeightSumPattern::new(client.clone(), "p2ms_count".to_string()),
|
||||
p2pk33: CumulativeHeightSumPattern::new(client.clone(), "p2pk33_count".to_string()),
|
||||
p2pk65: CumulativeHeightSumPattern::new(client.clone(), "p2pk65_count".to_string()),
|
||||
p2pkh: CumulativeHeightSumPattern::new(client.clone(), "p2pkh_count".to_string()),
|
||||
p2sh: CumulativeHeightSumPattern::new(client.clone(), "p2sh_count".to_string()),
|
||||
p2tr: CumulativeHeightSumPattern::new(client.clone(), "p2tr_count".to_string()),
|
||||
p2wpkh: CumulativeHeightSumPattern::new(client.clone(), "p2wpkh_count".to_string()),
|
||||
p2wsh: CumulativeHeightSumPattern::new(client.clone(), "p2wsh_count".to_string()),
|
||||
opreturn: CumulativeHeightSumPattern::new(client.clone(), "opreturn_count".to_string()),
|
||||
emptyoutput: CumulativeHeightSumPattern::new(client.clone(), "emptyoutput_count".to_string()),
|
||||
unknownoutput: CumulativeHeightSumPattern::new(client.clone(), "unknownoutput_count".to_string()),
|
||||
segwit: CumulativeHeightSumPattern::new(client.clone(), "segwit_count".to_string()),
|
||||
taproot_adoption: MetricPattern1::new(client.clone(), "taproot_adoption".to_string()),
|
||||
segwit_adoption: MetricPattern1::new(client.clone(), "segwit_adoption".to_string()),
|
||||
}
|
||||
@@ -4023,8 +4023,8 @@ impl MetricsTree_Cointime {
|
||||
|
||||
/// Metrics tree node.
|
||||
pub struct MetricsTree_Cointime_Activity {
|
||||
pub coinblocks_created: CumulativeHeightRollingPattern<StoredF64>,
|
||||
pub coinblocks_stored: CumulativeHeightRollingPattern<StoredF64>,
|
||||
pub coinblocks_created: CumulativeHeightSumPattern<StoredF64>,
|
||||
pub coinblocks_stored: CumulativeHeightSumPattern<StoredF64>,
|
||||
pub liveliness: MetricPattern1<StoredF64>,
|
||||
pub vaultedness: MetricPattern1<StoredF64>,
|
||||
pub activity_to_vaultedness_ratio: MetricPattern1<StoredF64>,
|
||||
@@ -4033,8 +4033,8 @@ pub struct MetricsTree_Cointime_Activity {
|
||||
impl MetricsTree_Cointime_Activity {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
coinblocks_created: CumulativeHeightRollingPattern::new(client.clone(), "coinblocks_created".to_string()),
|
||||
coinblocks_stored: CumulativeHeightRollingPattern::new(client.clone(), "coinblocks_stored".to_string()),
|
||||
coinblocks_created: CumulativeHeightSumPattern::new(client.clone(), "coinblocks_created".to_string()),
|
||||
coinblocks_stored: CumulativeHeightSumPattern::new(client.clone(), "coinblocks_stored".to_string()),
|
||||
liveliness: MetricPattern1::new(client.clone(), "liveliness".to_string()),
|
||||
vaultedness: MetricPattern1::new(client.clone(), "vaultedness".to_string()),
|
||||
activity_to_vaultedness_ratio: MetricPattern1::new(client.clone(), "activity_to_vaultedness_ratio".to_string()),
|
||||
@@ -4059,19 +4059,19 @@ impl MetricsTree_Cointime_Supply {
|
||||
|
||||
/// Metrics tree node.
|
||||
pub struct MetricsTree_Cointime_Value {
|
||||
pub cointime_value_destroyed: CumulativeHeightRollingPattern<StoredF64>,
|
||||
pub cointime_value_created: CumulativeHeightRollingPattern<StoredF64>,
|
||||
pub cointime_value_stored: CumulativeHeightRollingPattern<StoredF64>,
|
||||
pub vocdd: CumulativeHeightRollingPattern<StoredF64>,
|
||||
pub cointime_value_destroyed: CumulativeHeightSumPattern<StoredF64>,
|
||||
pub cointime_value_created: CumulativeHeightSumPattern<StoredF64>,
|
||||
pub cointime_value_stored: CumulativeHeightSumPattern<StoredF64>,
|
||||
pub vocdd: CumulativeHeightSumPattern<StoredF64>,
|
||||
}
|
||||
|
||||
impl MetricsTree_Cointime_Value {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
cointime_value_destroyed: CumulativeHeightRollingPattern::new(client.clone(), "cointime_value_destroyed".to_string()),
|
||||
cointime_value_created: CumulativeHeightRollingPattern::new(client.clone(), "cointime_value_created".to_string()),
|
||||
cointime_value_stored: CumulativeHeightRollingPattern::new(client.clone(), "cointime_value_stored".to_string()),
|
||||
vocdd: CumulativeHeightRollingPattern::new(client.clone(), "vocdd".to_string()),
|
||||
cointime_value_destroyed: CumulativeHeightSumPattern::new(client.clone(), "cointime_value_destroyed".to_string()),
|
||||
cointime_value_created: CumulativeHeightSumPattern::new(client.clone(), "cointime_value_created".to_string()),
|
||||
cointime_value_stored: CumulativeHeightSumPattern::new(client.clone(), "cointime_value_stored".to_string()),
|
||||
vocdd: CumulativeHeightSumPattern::new(client.clone(), "vocdd".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ impl Vecs {
|
||||
_30d: &self.height_1m_ago,
|
||||
_1y: &self.height_1y_ago,
|
||||
};
|
||||
self.block_count.rolling.compute_rolling_sum(
|
||||
self.block_count.sum.compute_rolling_sum(
|
||||
starting_indexes.height,
|
||||
&ws,
|
||||
&self.block_count.height,
|
||||
|
||||
@@ -128,7 +128,7 @@ pub(crate) fn process_blocks(
|
||||
debug!("txindex_to_height RangeMap built");
|
||||
|
||||
// Create reusable iterators for sequential txout/txin reads (16KB buffered)
|
||||
let txout_iters = TxOutReaders::new(indexer);
|
||||
let mut txout_iters = TxOutReaders::new(indexer);
|
||||
let mut txin_iters = TxInReaders::new(indexer, inputs, &mut txindex_to_height);
|
||||
|
||||
// Pre-collect first address indexes per type for the block range
|
||||
|
||||
@@ -21,32 +21,40 @@ pub struct TxOutData {
|
||||
pub typeindex: TypeIndex,
|
||||
}
|
||||
|
||||
/// Readers for txout vectors. Uses collect_range for bulk reads.
|
||||
/// Readers for txout vectors. Reuses internal buffers across blocks.
|
||||
pub struct TxOutReaders<'a> {
|
||||
indexer: &'a Indexer,
|
||||
values_buf: Vec<Sats>,
|
||||
outputtypes_buf: Vec<OutputType>,
|
||||
typeindexes_buf: Vec<TypeIndex>,
|
||||
}
|
||||
|
||||
impl<'a> TxOutReaders<'a> {
|
||||
pub(crate) fn new(indexer: &'a Indexer) -> Self {
|
||||
Self { indexer }
|
||||
Self {
|
||||
indexer,
|
||||
values_buf: Vec::new(),
|
||||
outputtypes_buf: Vec::new(),
|
||||
typeindexes_buf: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect output data for a block range using bulk reads.
|
||||
/// Collect output data for a block range using bulk reads with buffer reuse.
|
||||
pub(crate) fn collect_block_outputs(
|
||||
&self,
|
||||
&mut self,
|
||||
first_txoutindex: usize,
|
||||
output_count: usize,
|
||||
) -> Vec<TxOutData> {
|
||||
let end = first_txoutindex + output_count;
|
||||
let values: Vec<Sats> = self.indexer.vecs.outputs.value.collect_range_at(first_txoutindex, end);
|
||||
let outputtypes: Vec<OutputType> = self.indexer.vecs.outputs.outputtype.collect_range_at(first_txoutindex, end);
|
||||
let typeindexes: Vec<TypeIndex> = self.indexer.vecs.outputs.typeindex.collect_range_at(first_txoutindex, end);
|
||||
self.indexer.vecs.outputs.value.collect_range_into_at(first_txoutindex, end, &mut self.values_buf);
|
||||
self.indexer.vecs.outputs.outputtype.collect_range_into_at(first_txoutindex, end, &mut self.outputtypes_buf);
|
||||
self.indexer.vecs.outputs.typeindex.collect_range_into_at(first_txoutindex, end, &mut self.typeindexes_buf);
|
||||
|
||||
values
|
||||
.into_iter()
|
||||
.zip(outputtypes)
|
||||
.zip(typeindexes)
|
||||
.map(|((value, outputtype), typeindex)| TxOutData {
|
||||
self.values_buf
|
||||
.iter()
|
||||
.zip(&self.outputtypes_buf)
|
||||
.zip(&self.typeindexes_buf)
|
||||
.map(|((&value, &outputtype), &typeindex)| TxOutData {
|
||||
value,
|
||||
outputtype,
|
||||
typeindex,
|
||||
@@ -55,11 +63,12 @@ impl<'a> TxOutReaders<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Readers for txin vectors. Uses collect_range for bulk reads.
|
||||
/// Readers for txin vectors. Reuses outpoint buffer across blocks.
|
||||
pub struct TxInReaders<'a> {
|
||||
indexer: &'a Indexer,
|
||||
txins: &'a inputs::Vecs,
|
||||
txindex_to_height: &'a mut RangeMap<TxIndex, Height>,
|
||||
outpoints_buf: Vec<OutPoint>,
|
||||
}
|
||||
|
||||
impl<'a> TxInReaders<'a> {
|
||||
@@ -72,11 +81,12 @@ impl<'a> TxInReaders<'a> {
|
||||
indexer,
|
||||
txins,
|
||||
txindex_to_height,
|
||||
outpoints_buf: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect input data for a block range using bulk reads.
|
||||
/// Computes prev_height on-the-fly from outpoint using RangeMap lookup.
|
||||
/// Outpoint buffer is reused across blocks; returned vecs are fresh (caller-owned).
|
||||
pub(crate) fn collect_block_inputs(
|
||||
&mut self,
|
||||
first_txinindex: usize,
|
||||
@@ -85,11 +95,11 @@ impl<'a> TxInReaders<'a> {
|
||||
) -> (Vec<Sats>, Vec<Height>, Vec<OutputType>, Vec<TypeIndex>) {
|
||||
let end = first_txinindex + input_count;
|
||||
let values: Vec<Sats> = self.txins.spent.value.collect_range_at(first_txinindex, end);
|
||||
let outpoints: Vec<OutPoint> = self.indexer.vecs.inputs.outpoint.collect_range_at(first_txinindex, end);
|
||||
self.indexer.vecs.inputs.outpoint.collect_range_into_at(first_txinindex, end, &mut self.outpoints_buf);
|
||||
let outputtypes: Vec<OutputType> = self.indexer.vecs.inputs.outputtype.collect_range_at(first_txinindex, end);
|
||||
let typeindexes: Vec<TypeIndex> = self.indexer.vecs.inputs.typeindex.collect_range_at(first_txinindex, end);
|
||||
|
||||
let prev_heights: Vec<Height> = outpoints
|
||||
let prev_heights: Vec<Height> = self.outpoints_buf
|
||||
.iter()
|
||||
.map(|outpoint| {
|
||||
if outpoint.is_coinbase() {
|
||||
|
||||
@@ -11,8 +11,6 @@ use brk_types::{
|
||||
use rustc_hash::FxHashMap;
|
||||
use vecdb::Bytes;
|
||||
|
||||
use crate::utils::OptionExt;
|
||||
|
||||
use super::{CachedUnrealizedState, Percentiles, UnrealizedState};
|
||||
|
||||
/// Type alias for the price-to-sats map used in cost basis data.
|
||||
@@ -97,17 +95,17 @@ impl CostBasisData {
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = (CentsCompact, &Sats)> {
|
||||
self.assert_pending_empty();
|
||||
self.state.u().base.map.iter().map(|(&k, v)| (k, v))
|
||||
self.state.as_ref().unwrap().base.map.iter().map(|(&k, v)| (k, v))
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.pending.is_empty() && self.state.u().base.map.is_empty()
|
||||
self.pending.is_empty() && self.state.as_ref().unwrap().base.map.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn first_key_value(&self) -> Option<(CentsCompact, &Sats)> {
|
||||
self.assert_pending_empty();
|
||||
self.state
|
||||
.u()
|
||||
.as_ref().unwrap()
|
||||
.base
|
||||
.map
|
||||
.first_key_value()
|
||||
@@ -117,7 +115,7 @@ impl CostBasisData {
|
||||
pub(crate) fn last_key_value(&self) -> Option<(CentsCompact, &Sats)> {
|
||||
self.assert_pending_empty();
|
||||
self.state
|
||||
.u()
|
||||
.as_ref().unwrap()
|
||||
.base
|
||||
.map
|
||||
.last_key_value()
|
||||
@@ -127,13 +125,13 @@ impl CostBasisData {
|
||||
/// Get the exact cap_raw value (not recomputed from map).
|
||||
pub(crate) fn cap_raw(&self) -> CentsSats {
|
||||
self.assert_pending_empty();
|
||||
self.state.u().cap_raw
|
||||
self.state.as_ref().unwrap().cap_raw
|
||||
}
|
||||
|
||||
/// Get the exact investor_cap_raw value (not recomputed from map).
|
||||
pub(crate) fn investor_cap_raw(&self) -> CentsSquaredSats {
|
||||
self.assert_pending_empty();
|
||||
self.state.u().investor_cap_raw
|
||||
self.state.as_ref().unwrap().investor_cap_raw
|
||||
}
|
||||
|
||||
/// Increment with pre-computed typed values.
|
||||
@@ -181,7 +179,7 @@ impl CostBasisData {
|
||||
self.percentiles_dirty = true;
|
||||
}
|
||||
for (cents, (inc, dec)) in self.pending.drain() {
|
||||
let entry = self.state.um().base.map.entry(cents).or_default();
|
||||
let entry = self.state.as_mut().unwrap().base.map.entry(cents).or_default();
|
||||
*entry += inc;
|
||||
if *entry < dec {
|
||||
panic!(
|
||||
@@ -198,12 +196,12 @@ impl CostBasisData {
|
||||
}
|
||||
*entry -= dec;
|
||||
if *entry == Sats::ZERO {
|
||||
self.state.um().base.map.remove(¢s);
|
||||
self.state.as_mut().unwrap().base.map.remove(¢s);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply raw values
|
||||
let state = self.state.um();
|
||||
let state = self.state.as_mut().unwrap();
|
||||
state.cap_raw += self.pending_raw.cap_inc;
|
||||
|
||||
// Check for underflow before subtracting
|
||||
@@ -271,7 +269,7 @@ impl CostBasisData {
|
||||
);
|
||||
}
|
||||
|
||||
let map = &self.state.u().base.map;
|
||||
let map = &self.state.as_ref().unwrap().base.map;
|
||||
|
||||
let date_state =
|
||||
date_price.map(|p| CachedUnrealizedState::compute_full_standalone(p.into(), map));
|
||||
@@ -336,7 +334,7 @@ impl CostBasisData {
|
||||
}
|
||||
}
|
||||
|
||||
fs::write(self.path_state(height), self.state.u().serialize()?)?;
|
||||
fs::write(self.path_state(height), self.state.as_ref().unwrap().serialize()?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -48,19 +48,18 @@ impl Vecs {
|
||||
while batch_start < target {
|
||||
let batch_end = (batch_start + BATCH_SIZE).min(target);
|
||||
|
||||
let outpoints = indexer.vecs.inputs.outpoint.collect_range_at(batch_start, batch_end);
|
||||
|
||||
entries.clear();
|
||||
for (j, outpoint) in outpoints.into_iter().enumerate() {
|
||||
let txinindex = TxInIndex::from(batch_start + j);
|
||||
let mut j = 0usize;
|
||||
indexer.vecs.inputs.outpoint.for_each_range_at(batch_start, batch_end, |outpoint| {
|
||||
entries.push(Entry {
|
||||
txinindex,
|
||||
txinindex: TxInIndex::from(batch_start + j),
|
||||
txindex: outpoint.txindex(),
|
||||
vout: outpoint.vout(),
|
||||
txoutindex: TxOutIndex::COINBASE,
|
||||
value: Sats::MAX,
|
||||
});
|
||||
}
|
||||
j += 1;
|
||||
});
|
||||
|
||||
// Coinbase entries (txindex MAX) sorted to end
|
||||
entries.sort_unstable_by_key(|e| e.txindex);
|
||||
|
||||
@@ -11,7 +11,7 @@ use vecdb::{
|
||||
VecValue,
|
||||
};
|
||||
|
||||
use crate::utils::get_percentile;
|
||||
use brk_types::get_percentile;
|
||||
|
||||
use super::ComputedVecValue;
|
||||
|
||||
@@ -358,6 +358,7 @@ where
|
||||
let window_starts_batch: Vec<I> = window_starts.collect_range_at(start, fi_len);
|
||||
|
||||
let zero = T::from(0_usize);
|
||||
let mut values: Vec<T> = Vec::new();
|
||||
|
||||
first_indexes_batch
|
||||
.iter()
|
||||
@@ -389,8 +390,7 @@ where
|
||||
vec.truncate_push_at(idx, zero)?;
|
||||
}
|
||||
} else {
|
||||
let mut values: Vec<T> =
|
||||
source.collect_range_at(range_start_usize, range_end_usize);
|
||||
source.collect_range_into_at(range_start_usize, range_end_usize, &mut values);
|
||||
|
||||
// Compute sum before sorting
|
||||
let len = values.len();
|
||||
|
||||
@@ -15,3 +15,31 @@ pub struct DistributionStats<A, B = A, C = A, D = A, E = A, F = A, G = A, H = A>
|
||||
pub p75: G,
|
||||
pub p90: H,
|
||||
}
|
||||
|
||||
impl<A> DistributionStats<A> {
|
||||
/// Apply a fallible operation to each of the 8 fields.
|
||||
pub fn try_for_each_mut(&mut self, mut f: impl FnMut(&mut A) -> brk_error::Result<()>) -> brk_error::Result<()> {
|
||||
f(&mut self.average)?;
|
||||
f(&mut self.min)?;
|
||||
f(&mut self.max)?;
|
||||
f(&mut self.p10)?;
|
||||
f(&mut self.p25)?;
|
||||
f(&mut self.median)?;
|
||||
f(&mut self.p75)?;
|
||||
f(&mut self.p90)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get minimum value by applying a function to each field.
|
||||
pub fn min_by(&self, mut f: impl FnMut(&A) -> usize) -> usize {
|
||||
f(&self.average)
|
||||
.min(f(&self.min))
|
||||
.min(f(&self.max))
|
||||
.min(f(&self.p10))
|
||||
.min(f(&self.p25))
|
||||
.min(f(&self.median))
|
||||
.min(f(&self.p75))
|
||||
.min(f(&self.p90))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ mod indexes;
|
||||
mod lazy_eager_indexes;
|
||||
mod multi;
|
||||
mod single;
|
||||
pub(crate) mod sliding_window;
|
||||
mod traits;
|
||||
mod windows;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ where
|
||||
{
|
||||
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
|
||||
pub cumulative: ComputedFromHeightLast<T, M>,
|
||||
pub rolling: RollingWindows<T, M>,
|
||||
pub sum: RollingWindows<T, M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
@@ -49,7 +49,7 @@ where
|
||||
Ok(Self {
|
||||
height,
|
||||
cumulative,
|
||||
rolling,
|
||||
sum: rolling,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ where
|
||||
self.cumulative
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.height, exit)?;
|
||||
self.rolling
|
||||
self.sum
|
||||
.compute_rolling_sum(max_from, windows, &self.height, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec,
|
||||
use crate::{
|
||||
ComputeIndexes, blocks, indexes,
|
||||
internal::{ComputedFromHeightStdDevExtended, Price},
|
||||
utils::get_percentile,
|
||||
};
|
||||
use brk_types::get_percentile;
|
||||
|
||||
use super::super::ComputedFromHeightLast;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use brk_types::{
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{LazyAggVec, ReadableBoxedVec, ReadableCloneableVec};
|
||||
use vecdb::{LazyAggVec, ReadOnlyClone, ReadableBoxedVec, ReadableCloneableVec};
|
||||
|
||||
use crate::{
|
||||
indexes, indexes_from,
|
||||
@@ -41,6 +41,17 @@ pub struct ComputedHeightDerivedLast<T>(
|
||||
where
|
||||
T: ComputedVecValue + PartialOrd + JsonSchema;
|
||||
|
||||
/// Already read-only (no StorageMode); cloning is sufficient.
|
||||
impl<T> ReadOnlyClone for ComputedHeightDerivedLast<T>
|
||||
where
|
||||
T: ComputedVecValue + PartialOrd + JsonSchema,
|
||||
{
|
||||
type ReadOnly = Self;
|
||||
fn read_only_clone(&self) -> Self {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> ComputedHeightDerivedLast<T>
|
||||
|
||||
@@ -9,7 +9,9 @@ use brk_types::{
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{LazyVecFrom1, ReadableBoxedVec, ReadableCloneableVec, UnaryTransform, VecIndex, VecValue};
|
||||
use vecdb::{
|
||||
LazyVecFrom1, ReadableBoxedVec, ReadableCloneableVec, UnaryTransform, VecIndex, VecValue,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
indexes, indexes_from,
|
||||
@@ -108,7 +110,8 @@ where
|
||||
where
|
||||
S1T: NumericValue,
|
||||
{
|
||||
let derived = ComputedHeightDerivedLast::forced_import(name, height_source, version, indexes);
|
||||
let derived =
|
||||
ComputedHeightDerivedLast::forced_import(name, height_source, version, indexes);
|
||||
Self::from_derived_computed::<F>(name, version, &derived)
|
||||
}
|
||||
|
||||
|
||||
@@ -66,62 +66,33 @@ where
|
||||
T: Copy + Ord + From<f64> + Default,
|
||||
f64: From<T>,
|
||||
{
|
||||
// Single pass per window: all 8 stats extracted from one sorted vec
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from,
|
||||
windows._24h,
|
||||
source,
|
||||
&mut self.0.average._24h.height,
|
||||
&mut self.0.min._24h.height,
|
||||
&mut self.0.max._24h.height,
|
||||
&mut self.0.p10._24h.height,
|
||||
&mut self.0.p25._24h.height,
|
||||
&mut self.0.median._24h.height,
|
||||
&mut self.0.p75._24h.height,
|
||||
&mut self.0.p90._24h.height,
|
||||
exit,
|
||||
max_from, windows._24h, source,
|
||||
&mut self.0.average._24h.height, &mut self.0.min._24h.height,
|
||||
&mut self.0.max._24h.height, &mut self.0.p10._24h.height,
|
||||
&mut self.0.p25._24h.height, &mut self.0.median._24h.height,
|
||||
&mut self.0.p75._24h.height, &mut self.0.p90._24h.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from,
|
||||
windows._7d,
|
||||
source,
|
||||
&mut self.0.average._7d.height,
|
||||
&mut self.0.min._7d.height,
|
||||
&mut self.0.max._7d.height,
|
||||
&mut self.0.p10._7d.height,
|
||||
&mut self.0.p25._7d.height,
|
||||
&mut self.0.median._7d.height,
|
||||
&mut self.0.p75._7d.height,
|
||||
&mut self.0.p90._7d.height,
|
||||
exit,
|
||||
max_from, windows._7d, source,
|
||||
&mut self.0.average._7d.height, &mut self.0.min._7d.height,
|
||||
&mut self.0.max._7d.height, &mut self.0.p10._7d.height,
|
||||
&mut self.0.p25._7d.height, &mut self.0.median._7d.height,
|
||||
&mut self.0.p75._7d.height, &mut self.0.p90._7d.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from,
|
||||
windows._30d,
|
||||
source,
|
||||
&mut self.0.average._30d.height,
|
||||
&mut self.0.min._30d.height,
|
||||
&mut self.0.max._30d.height,
|
||||
&mut self.0.p10._30d.height,
|
||||
&mut self.0.p25._30d.height,
|
||||
&mut self.0.median._30d.height,
|
||||
&mut self.0.p75._30d.height,
|
||||
&mut self.0.p90._30d.height,
|
||||
exit,
|
||||
max_from, windows._30d, source,
|
||||
&mut self.0.average._30d.height, &mut self.0.min._30d.height,
|
||||
&mut self.0.max._30d.height, &mut self.0.p10._30d.height,
|
||||
&mut self.0.p25._30d.height, &mut self.0.median._30d.height,
|
||||
&mut self.0.p75._30d.height, &mut self.0.p90._30d.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from,
|
||||
windows._1y,
|
||||
source,
|
||||
&mut self.0.average._1y.height,
|
||||
&mut self.0.min._1y.height,
|
||||
&mut self.0.max._1y.height,
|
||||
&mut self.0.p10._1y.height,
|
||||
&mut self.0.p25._1y.height,
|
||||
&mut self.0.median._1y.height,
|
||||
&mut self.0.p75._1y.height,
|
||||
&mut self.0.p90._1y.height,
|
||||
exit,
|
||||
max_from, windows._1y, source,
|
||||
&mut self.0.average._1y.height, &mut self.0.min._1y.height,
|
||||
&mut self.0.max._1y.height, &mut self.0.p10._1y.height,
|
||||
&mut self.0.p25._1y.height, &mut self.0.median._1y.height,
|
||||
&mut self.0.p75._1y.height, &mut self.0.p90._1y.height, exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -72,18 +72,9 @@ impl StoredValueRollingWindows {
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.0
|
||||
._24h
|
||||
.compute_rolling_sum(max_from, windows._24h, sats_source, usd_source, exit)?;
|
||||
self.0
|
||||
._7d
|
||||
.compute_rolling_sum(max_from, windows._7d, sats_source, usd_source, exit)?;
|
||||
self.0
|
||||
._30d
|
||||
.compute_rolling_sum(max_from, windows._30d, sats_source, usd_source, exit)?;
|
||||
self.0
|
||||
._1y
|
||||
.compute_rolling_sum(max_from, windows._1y, sats_source, usd_source, exit)?;
|
||||
for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
w.compute_rolling_sum(max_from, starts, sats_source, usd_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ pub struct WindowStarts<'a> {
|
||||
pub _1y: &'a EagerVec<PcoVec<Height, Height>>,
|
||||
}
|
||||
|
||||
impl<'a> WindowStarts<'a> {
|
||||
pub fn as_array(&self) -> [&'a EagerVec<PcoVec<Height, Height>>; 4] {
|
||||
[self._24h, self._7d, self._30d, self._1y]
|
||||
}
|
||||
}
|
||||
|
||||
/// 4 rolling window vecs (24h, 7d, 30d, 1y), each with height data + all 17 index views.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
@@ -64,22 +70,9 @@ where
|
||||
where
|
||||
T: Default + SubAssign,
|
||||
{
|
||||
self.0
|
||||
._24h
|
||||
.height
|
||||
.compute_rolling_sum(max_from, windows._24h, source, exit)?;
|
||||
self.0
|
||||
._7d
|
||||
.height
|
||||
.compute_rolling_sum(max_from, windows._7d, source, exit)?;
|
||||
self.0
|
||||
._30d
|
||||
.height
|
||||
.compute_rolling_sum(max_from, windows._30d, source, exit)?;
|
||||
self.0
|
||||
._1y
|
||||
.height
|
||||
.compute_rolling_sum(max_from, windows._1y, source, exit)?;
|
||||
for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
w.height.compute_rolling_sum(max_from, starts, source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
mod block_count_target;
|
||||
mod cents_to_dollars;
|
||||
mod cents_to_sats;
|
||||
mod ohlc_cents_to_dollars;
|
||||
mod ohlc_cents_to_sats;
|
||||
|
||||
mod dollar_halve;
|
||||
mod dollar_identity;
|
||||
@@ -35,6 +37,8 @@ mod volatility_sqrt7;
|
||||
pub use block_count_target::*;
|
||||
pub use cents_to_dollars::*;
|
||||
pub use cents_to_sats::*;
|
||||
pub use ohlc_cents_to_dollars::*;
|
||||
pub use ohlc_cents_to_sats::*;
|
||||
|
||||
pub use dollar_halve::*;
|
||||
pub use dollar_identity::*;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
use brk_types::{OHLCCents, OHLCDollars};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct OhlcCentsToDollars;
|
||||
|
||||
impl UnaryTransform<OHLCCents, OHLCDollars> for OhlcCentsToDollars {
|
||||
#[inline(always)]
|
||||
fn apply(cents: OHLCCents) -> OHLCDollars {
|
||||
OHLCDollars::from(cents)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use brk_types::{Close, High, Low, OHLCCents, OHLCSats, Open};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
use super::CentsUnsignedToSats;
|
||||
|
||||
/// OHLCCents -> OHLCSats with high/low swapped (inverse price relationship).
|
||||
pub struct OhlcCentsToSats;
|
||||
|
||||
impl UnaryTransform<OHLCCents, OHLCSats> for OhlcCentsToSats {
|
||||
#[inline(always)]
|
||||
fn apply(cents: OHLCCents) -> OHLCSats {
|
||||
OHLCSats {
|
||||
open: Open::new(CentsUnsignedToSats::apply(*cents.open)),
|
||||
high: High::new(CentsUnsignedToSats::apply(*cents.low)),
|
||||
low: Low::new(CentsUnsignedToSats::apply(*cents.high)),
|
||||
close: Close::new(CentsUnsignedToSats::apply(*cents.close)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/// Sqrt-decomposed sorted structure for O(sqrt(n)) insert/remove/kth.
|
||||
///
|
||||
/// Maintains `blocks` sorted sub-arrays where each block is sorted and
|
||||
/// the blocks are ordered (max of block[i] <= min of block[i+1]).
|
||||
/// Total element count is tracked via `total_len`.
|
||||
struct SortedBlocks {
|
||||
blocks: Vec<Vec<f64>>,
|
||||
total_len: usize,
|
||||
block_size: usize,
|
||||
}
|
||||
|
||||
impl SortedBlocks {
|
||||
fn new(capacity: usize) -> Self {
|
||||
let block_size = ((capacity as f64).sqrt() as usize).max(64);
|
||||
Self {
|
||||
blocks: Vec::new(),
|
||||
total_len: 0,
|
||||
block_size,
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.total_len
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.total_len == 0
|
||||
}
|
||||
|
||||
/// Insert a value in sorted order. O(sqrt(n)).
|
||||
fn insert(&mut self, value: f64) {
|
||||
self.total_len += 1;
|
||||
|
||||
if self.blocks.is_empty() {
|
||||
self.blocks.push(vec![value]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the block where value belongs: first block whose max >= value
|
||||
let block_idx = self.blocks.iter().position(|b| {
|
||||
*b.last().unwrap() >= value
|
||||
}).unwrap_or(self.blocks.len() - 1);
|
||||
|
||||
let block = &mut self.blocks[block_idx];
|
||||
let pos = block.partition_point(|a| *a < value);
|
||||
block.insert(pos, value);
|
||||
|
||||
// Split if block too large
|
||||
if block.len() > 2 * self.block_size {
|
||||
let mid = block.len() / 2;
|
||||
let right = block[mid..].to_vec();
|
||||
block.truncate(mid);
|
||||
self.blocks.insert(block_idx + 1, right);
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove one occurrence of value. O(sqrt(n)).
|
||||
fn remove(&mut self, value: f64) -> bool {
|
||||
for (bi, block) in self.blocks.iter_mut().enumerate() {
|
||||
if block.is_empty() {
|
||||
continue;
|
||||
}
|
||||
// If value > block max, it's not in this block
|
||||
if *block.last().unwrap() < value {
|
||||
continue;
|
||||
}
|
||||
let pos = block.partition_point(|a| *a < value);
|
||||
if pos < block.len() && block[pos] == value {
|
||||
block.remove(pos);
|
||||
self.total_len -= 1;
|
||||
if block.is_empty() {
|
||||
self.blocks.remove(bi);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Value not found (would be in this block range but isn't)
|
||||
return false;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Get the k-th smallest element (0-indexed). O(sqrt(n)).
|
||||
fn kth(&self, mut k: usize) -> f64 {
|
||||
for block in &self.blocks {
|
||||
if k < block.len() {
|
||||
return block[k];
|
||||
}
|
||||
k -= block.len();
|
||||
}
|
||||
unreachable!("kth out of bounds")
|
||||
}
|
||||
|
||||
fn first(&self) -> f64 {
|
||||
self.blocks.first().unwrap().first().copied().unwrap()
|
||||
}
|
||||
|
||||
fn last(&self) -> f64 {
|
||||
self.blocks.last().unwrap().last().copied().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Sorted sliding window for rolling distribution/median computations.
|
||||
///
|
||||
/// Uses sqrt-decomposition for O(sqrt(n)) insert/remove/kth instead of
|
||||
/// O(n) memmoves with a flat sorted Vec.
|
||||
pub(crate) struct SlidingWindowSorted {
|
||||
sorted: SortedBlocks,
|
||||
running_sum: f64,
|
||||
prev_start: usize,
|
||||
}
|
||||
|
||||
impl SlidingWindowSorted {
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
Self {
|
||||
sorted: SortedBlocks::new(cap),
|
||||
running_sum: 0.0,
|
||||
prev_start: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reconstruct state from historical data (the elements in [range_start..skip]).
|
||||
pub fn reconstruct(&mut self, partial_values: &[f64], range_start: usize, skip: usize) {
|
||||
self.prev_start = range_start;
|
||||
for idx in range_start..skip {
|
||||
let v = partial_values[idx - range_start];
|
||||
self.running_sum += v;
|
||||
self.sorted.insert(v);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a new value and remove all expired values up to `new_start`.
|
||||
pub fn advance(&mut self, value: f64, new_start: usize, partial_values: &[f64], range_start: usize) {
|
||||
self.running_sum += value;
|
||||
self.sorted.insert(value);
|
||||
|
||||
while self.prev_start < new_start {
|
||||
let old = partial_values[self.prev_start - range_start];
|
||||
self.running_sum -= old;
|
||||
self.sorted.remove(old);
|
||||
self.prev_start += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.sorted.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn average(&self) -> f64 {
|
||||
if self.sorted.is_empty() {
|
||||
0.0
|
||||
} else {
|
||||
self.running_sum / self.sorted.len() as f64
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn min(&self) -> f64 {
|
||||
if self.sorted.is_empty() { 0.0 } else { self.sorted.first() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max(&self) -> f64 {
|
||||
if self.sorted.is_empty() { 0.0 } else { self.sorted.last() }
|
||||
}
|
||||
|
||||
/// Extract a percentile (0.0-1.0) using linear interpolation.
|
||||
#[inline]
|
||||
pub fn percentile(&self, p: f64) -> f64 {
|
||||
let len = self.sorted.len();
|
||||
if len == 0 {
|
||||
return 0.0;
|
||||
}
|
||||
if len == 1 {
|
||||
return self.sorted.kth(0);
|
||||
}
|
||||
let rank = p * (len - 1) as f64;
|
||||
let lo = rank.floor() as usize;
|
||||
let hi = rank.ceil() as usize;
|
||||
if lo == hi {
|
||||
self.sorted.kth(lo)
|
||||
} else {
|
||||
let frac = rank - lo as f64;
|
||||
self.sorted.kth(lo) * (1.0 - frac) + self.sorted.kth(hi) * frac
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,3 +15,9 @@ pub struct Windows<A, B = A, C = A, D = A> {
|
||||
#[traversable(rename = "1y")]
|
||||
pub _1y: D,
|
||||
}
|
||||
|
||||
impl<A> Windows<A> {
|
||||
pub fn as_mut_array(&mut self) -> [&mut A; 4] {
|
||||
[&mut self._24h, &mut self._7d, &mut self._30d, &mut self._1y]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ mod scripts;
|
||||
mod supply;
|
||||
mod traits;
|
||||
mod transactions;
|
||||
mod utils;
|
||||
|
||||
use indexes::ComputeIndexes;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ impl Vecs {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let h2d = &indexes.height.day1;
|
||||
let close = &prices.usd.close.day1;
|
||||
let close = &prices.usd.split.close.day1;
|
||||
|
||||
let first_price_di = Day1::try_from(Date::new(2010, 7, 12))
|
||||
.unwrap()
|
||||
|
||||
@@ -16,10 +16,10 @@ pub(super) fn collect_returns(tf: &str, returns: &ReturnsVecs) -> Vec<f32> {
|
||||
|
||||
pub(super) fn collect_closes(tf: &str, prices: &prices::Vecs) -> Vec<Dollars> {
|
||||
match tf {
|
||||
"1d" => prices.usd.close.day1.collect_or_default(),
|
||||
"1w" => prices.usd.close.week1.collect_or_default(),
|
||||
"1m" => prices.usd.close.month1.collect_or_default(),
|
||||
"1y" => prices.usd.close.year1.collect_or_default(),
|
||||
"1d" => prices.usd.split.close.day1.collect_or_default(),
|
||||
"1w" => prices.usd.split.close.week1.collect_or_default(),
|
||||
"1m" => prices.usd.split.close.month1.collect_or_default(),
|
||||
"1y" => prices.usd.split.close.year1.collect_or_default(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ impl Vecs {
|
||||
}
|
||||
|
||||
let h2d = &indexes.height.day1;
|
||||
let closes: Vec<Dollars> = prices.usd.close.day1.collect_or_default();
|
||||
let closes: Vec<Dollars> = prices.usd.split.close.day1.collect_or_default();
|
||||
|
||||
for (ema, period) in [
|
||||
(&mut self.price_1w_ema, 7),
|
||||
|
||||
@@ -98,18 +98,15 @@ impl Vecs {
|
||||
first_txinindex_data[batch_end_height.to_usize() + 1 - offset].to_usize()
|
||||
};
|
||||
|
||||
// Collect and process txins
|
||||
// Stream txins directly into pairs — avoids intermediate Vec allocation
|
||||
pairs.clear();
|
||||
let txoutindexes: Vec<TxOutIndex> = txinindex_to_txoutindex.collect_range_at(txin_start, txin_end);
|
||||
for (j, txoutindex) in txoutindexes.into_iter().enumerate() {
|
||||
let txinindex = TxInIndex::from(txin_start + j);
|
||||
|
||||
if txoutindex.is_coinbase() {
|
||||
continue;
|
||||
let mut j = txin_start;
|
||||
txinindex_to_txoutindex.for_each_range_at(txin_start, txin_end, |txoutindex: TxOutIndex| {
|
||||
if !txoutindex.is_coinbase() {
|
||||
pairs.push((txoutindex, TxInIndex::from(j)));
|
||||
}
|
||||
|
||||
pairs.push((txoutindex, txinindex));
|
||||
}
|
||||
j += 1;
|
||||
});
|
||||
|
||||
pairs.sort_unstable_by_key(|(txoutindex, _)| *txoutindex);
|
||||
|
||||
|
||||
@@ -19,12 +19,24 @@ impl Vecs {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.compute_prices(indexer, starting_indexes, exit)?;
|
||||
self.open
|
||||
self.split
|
||||
.open
|
||||
.compute_first(starting_indexes, &self.price, indexes, exit)?;
|
||||
self.high
|
||||
self.split
|
||||
.high
|
||||
.compute_max(starting_indexes, &self.price, indexes, exit)?;
|
||||
self.low
|
||||
self.split
|
||||
.low
|
||||
.compute_min(starting_indexes, &self.price, indexes, exit)?;
|
||||
self.ohlc.compute_from_split(
|
||||
starting_indexes,
|
||||
&self.split.open,
|
||||
&self.split.high,
|
||||
&self.split.low,
|
||||
&self.split.close,
|
||||
indexes,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -132,6 +144,10 @@ impl Vecs {
|
||||
// across blocks, so the cursor only advances forward.
|
||||
let mut txout_cursor = indexer.vecs.transactions.first_txoutindex.cursor();
|
||||
|
||||
// Reusable buffers — avoid per-block allocation
|
||||
let mut values: Vec<Sats> = Vec::new();
|
||||
let mut output_types: Vec<OutputType> = Vec::new();
|
||||
|
||||
for (idx, _h) in range.enumerate() {
|
||||
let first_txindex = first_txindexes[idx];
|
||||
let next_first_txindex = first_txindexes
|
||||
@@ -156,16 +172,8 @@ impl Vecs {
|
||||
.unwrap_or(TxOutIndex::from(total_outputs))
|
||||
.to_usize();
|
||||
|
||||
let values: Vec<Sats> = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.value
|
||||
.collect_range_at(out_start, out_end);
|
||||
let output_types: Vec<OutputType> = indexer
|
||||
.vecs
|
||||
.outputs
|
||||
.outputtype
|
||||
.collect_range_at(out_start, out_end);
|
||||
indexer.vecs.outputs.value.collect_range_into_at(out_start, out_end, &mut values);
|
||||
indexer.vecs.outputs.outputtype.collect_range_into_at(out_start, out_end, &mut output_types);
|
||||
|
||||
let mut hist = [0u32; NUM_BINS];
|
||||
for i in 0..values.len() {
|
||||
|
||||
@@ -5,6 +5,7 @@ use vecdb::{Database, ImportableVec, PcoVec, ReadableCloneableVec};
|
||||
use super::Vecs;
|
||||
use crate::indexes;
|
||||
use crate::internal::{ComputedHeightDerivedLast, EagerIndexes};
|
||||
use crate::prices::{ohlcs::OhlcVecs, split::SplitOhlc};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(
|
||||
@@ -16,23 +17,26 @@ impl Vecs {
|
||||
|
||||
let price = PcoVec::forced_import(db, "price_cents", version)?;
|
||||
|
||||
let open = EagerIndexes::forced_import(db, "price_cents_open", version)?;
|
||||
let high = EagerIndexes::forced_import(db, "price_cents_high", version)?;
|
||||
let low = EagerIndexes::forced_import(db, "price_cents_low", version)?;
|
||||
let open = EagerIndexes::forced_import(db, "price_open_cents", version)?;
|
||||
let high = EagerIndexes::forced_import(db, "price_high_cents", version)?;
|
||||
let low = EagerIndexes::forced_import(db, "price_low_cents", version)?;
|
||||
|
||||
let close = ComputedHeightDerivedLast::forced_import(
|
||||
"price_cents_close",
|
||||
"price_close_cents",
|
||||
price.read_only_boxed_clone(),
|
||||
version,
|
||||
indexes,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
price,
|
||||
let split = SplitOhlc {
|
||||
open,
|
||||
high,
|
||||
low,
|
||||
close,
|
||||
})
|
||||
};
|
||||
|
||||
let ohlc = OhlcVecs::forced_import(db, "price_ohlc_cents", version)?;
|
||||
|
||||
Ok(Self { split, ohlc, price })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, Height};
|
||||
use brk_types::{Cents, Height, OHLCCents};
|
||||
use vecdb::{PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedHeightDerivedLast, EagerIndexes};
|
||||
use crate::prices::{ohlcs::OhlcVecs, split::SplitOhlc};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub split: SplitOhlc<
|
||||
EagerIndexes<Cents, M>,
|
||||
EagerIndexes<Cents, M>,
|
||||
EagerIndexes<Cents, M>,
|
||||
ComputedHeightDerivedLast<Cents>,
|
||||
>,
|
||||
pub ohlc: OhlcVecs<OHLCCents, M>,
|
||||
pub price: M::Stored<PcoVec<Height, Cents>>,
|
||||
pub open: EagerIndexes<Cents, M>,
|
||||
pub high: EagerIndexes<Cents, M>,
|
||||
pub low: EagerIndexes<Cents, M>,
|
||||
pub close: ComputedHeightDerivedLast<Cents>,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
mod compute;
|
||||
pub(crate) mod ohlcs;
|
||||
pub(crate) mod split;
|
||||
|
||||
pub mod cents;
|
||||
pub mod sats;
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
Cents, Close, Day1, Day3, DifficultyEpoch, HalvingEpoch, High, Hour1, Hour4, Hour12, Low,
|
||||
Minute1, Minute5, Minute10, Minute30, Month1, Month3, Month6, OHLCCents, Open, Version, Week1,
|
||||
Year1, Year10,
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use vecdb::{
|
||||
BytesVec, BytesVecValue, Database, EagerVec, Exit, Formattable, ImportableVec, LazyVecFrom1,
|
||||
ReadableCloneableVec, ReadableVec, Rw, StorageMode, UnaryTransform,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ComputeIndexes, indexes, indexes_from,
|
||||
internal::{ComputedHeightDerivedLast, EagerIndexes, Indexes},
|
||||
};
|
||||
|
||||
// ── EagerOhlcIndexes ─────────────────────────────────────────────────
|
||||
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct OhlcVecs<T, M: StorageMode = Rw>(
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub Indexes<
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute1, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute5, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute10, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute30, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Hour1, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Hour4, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Hour12, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Day1, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Day3, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Week1, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Month1, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Month3, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Month6, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Year1, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<Year10, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<HalvingEpoch, T>>>,
|
||||
<M as StorageMode>::Stored<EagerVec<BytesVec<DifficultyEpoch, T>>>,
|
||||
>,
|
||||
)
|
||||
where
|
||||
T: BytesVecValue + Formattable + Serialize + JsonSchema;
|
||||
|
||||
const EAGER_VERSION: Version = Version::ZERO;
|
||||
|
||||
impl<T> OhlcVecs<T>
|
||||
where
|
||||
T: BytesVecValue + Formattable + Serialize + JsonSchema,
|
||||
{
|
||||
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
|
||||
let v = version + EAGER_VERSION;
|
||||
|
||||
macro_rules! period {
|
||||
($idx:ident) => {
|
||||
ImportableVec::forced_import(db, &format!("{name}_{}", stringify!($idx)), v)?
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Self(indexes_from!(period)))
|
||||
}
|
||||
}
|
||||
|
||||
impl OhlcVecs<OHLCCents> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn compute_from_split(
|
||||
&mut self,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
open: &EagerIndexes<Cents>,
|
||||
high: &EagerIndexes<Cents>,
|
||||
low: &EagerIndexes<Cents>,
|
||||
close: &ComputedHeightDerivedLast<Cents>,
|
||||
indexes: &indexes::Vecs,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
macro_rules! period {
|
||||
($field:ident) => {
|
||||
self.0.$field.compute_transform(
|
||||
starting_indexes.$field,
|
||||
&indexes.$field.first_height,
|
||||
|(idx, _first_h, _)| {
|
||||
let o = open.$field.collect_one(idx).unwrap_or_default();
|
||||
let h = high.$field.collect_one(idx).unwrap_or_default();
|
||||
let l = low.$field.collect_one(idx).unwrap_or_default();
|
||||
let c = close.$field.collect_one(idx).flatten().unwrap_or_default();
|
||||
(
|
||||
idx,
|
||||
OHLCCents {
|
||||
open: Open::new(o),
|
||||
high: High::new(h),
|
||||
low: Low::new(l),
|
||||
close: Close::new(c),
|
||||
},
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! epoch {
|
||||
($field:ident) => {
|
||||
self.0.$field.compute_transform(
|
||||
starting_indexes.$field,
|
||||
&indexes.$field.first_height,
|
||||
|(idx, _first_h, _)| {
|
||||
let o = open.$field.collect_one(idx).unwrap_or_default();
|
||||
let h = high.$field.collect_one(idx).unwrap_or_default();
|
||||
let l = low.$field.collect_one(idx).unwrap_or_default();
|
||||
let c = close.$field.collect_one(idx).unwrap_or_default();
|
||||
(
|
||||
idx,
|
||||
OHLCCents {
|
||||
open: Open::new(o),
|
||||
high: High::new(h),
|
||||
low: Low::new(l),
|
||||
close: Close::new(c),
|
||||
},
|
||||
)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
};
|
||||
}
|
||||
|
||||
period!(minute1);
|
||||
period!(minute5);
|
||||
period!(minute10);
|
||||
period!(minute30);
|
||||
period!(hour1);
|
||||
period!(hour4);
|
||||
period!(hour12);
|
||||
period!(day1);
|
||||
period!(day3);
|
||||
period!(week1);
|
||||
period!(month1);
|
||||
period!(month3);
|
||||
period!(month6);
|
||||
period!(year1);
|
||||
period!(year10);
|
||||
epoch!(halvingepoch);
|
||||
epoch!(difficultyepoch);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ── LazyOhlcIndexes ──────────────────────────────────────────────────
|
||||
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct LazyOhlcVecs<T, S>(
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub Indexes<
|
||||
LazyVecFrom1<Minute1, T, Minute1, S>,
|
||||
LazyVecFrom1<Minute5, T, Minute5, S>,
|
||||
LazyVecFrom1<Minute10, T, Minute10, S>,
|
||||
LazyVecFrom1<Minute30, T, Minute30, S>,
|
||||
LazyVecFrom1<Hour1, T, Hour1, S>,
|
||||
LazyVecFrom1<Hour4, T, Hour4, S>,
|
||||
LazyVecFrom1<Hour12, T, Hour12, S>,
|
||||
LazyVecFrom1<Day1, T, Day1, S>,
|
||||
LazyVecFrom1<Day3, T, Day3, S>,
|
||||
LazyVecFrom1<Week1, T, Week1, S>,
|
||||
LazyVecFrom1<Month1, T, Month1, S>,
|
||||
LazyVecFrom1<Month3, T, Month3, S>,
|
||||
LazyVecFrom1<Month6, T, Month6, S>,
|
||||
LazyVecFrom1<Year1, T, Year1, S>,
|
||||
LazyVecFrom1<Year10, T, Year10, S>,
|
||||
LazyVecFrom1<HalvingEpoch, T, HalvingEpoch, S>,
|
||||
LazyVecFrom1<DifficultyEpoch, T, DifficultyEpoch, S>,
|
||||
>,
|
||||
)
|
||||
where
|
||||
T: BytesVecValue + Formattable + Serialize + JsonSchema,
|
||||
S: BytesVecValue;
|
||||
|
||||
impl<T, S> LazyOhlcVecs<T, S>
|
||||
where
|
||||
T: BytesVecValue + Formattable + Serialize + JsonSchema,
|
||||
S: BytesVecValue + Formattable + Serialize + JsonSchema,
|
||||
{
|
||||
pub(crate) fn from_eager_ohlc_indexes<Transform: UnaryTransform<S, T>>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
source: &OhlcVecs<S>,
|
||||
) -> Self {
|
||||
macro_rules! period {
|
||||
($idx:ident) => {
|
||||
LazyVecFrom1::transformed::<Transform>(
|
||||
&format!("{name}_{}", stringify!($idx)),
|
||||
version,
|
||||
source.$idx.read_only_boxed_clone(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
Self(indexes_from!(period))
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,10 @@ use vecdb::{LazyVecFrom1, ReadableCloneableVec};
|
||||
|
||||
use super::super::cents;
|
||||
use super::Vecs;
|
||||
use crate::prices::{ohlcs::LazyOhlcVecs, split::SplitOhlc};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{CentsUnsignedToSats, ComputedHeightDerivedLast, LazyEagerIndexes},
|
||||
internal::{CentsUnsignedToSats, ComputedHeightDerivedLast, LazyEagerIndexes, OhlcCentsToSats},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -21,26 +22,43 @@ impl Vecs {
|
||||
);
|
||||
|
||||
// Sats are inversely related to cents (sats = 10B/cents), so high↔low are swapped
|
||||
let open =
|
||||
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>("price_sats_open", version, ¢s.open);
|
||||
let high =
|
||||
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>("price_sats_high", version, ¢s.low);
|
||||
let low =
|
||||
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>("price_sats_low", version, ¢s.high);
|
||||
let open = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>(
|
||||
"price_open_sats",
|
||||
version,
|
||||
¢s.split.open,
|
||||
);
|
||||
let high = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>(
|
||||
"price_high_sats",
|
||||
version,
|
||||
¢s.split.low,
|
||||
);
|
||||
let low = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToSats>(
|
||||
"price_low_sats",
|
||||
version,
|
||||
¢s.split.high,
|
||||
);
|
||||
|
||||
let close = ComputedHeightDerivedLast::forced_import(
|
||||
"price_sats_close",
|
||||
"price_close_sats",
|
||||
price.read_only_boxed_clone(),
|
||||
version,
|
||||
indexes,
|
||||
);
|
||||
|
||||
Self {
|
||||
price,
|
||||
let split = SplitOhlc {
|
||||
open,
|
||||
high,
|
||||
low,
|
||||
close,
|
||||
}
|
||||
};
|
||||
|
||||
// OhlcCentsToSats handles the high↔low swap internally
|
||||
let ohlc = LazyOhlcVecs::from_eager_ohlc_indexes::<OhlcCentsToSats>(
|
||||
"price_ohlc_sats",
|
||||
version,
|
||||
¢s.ohlc,
|
||||
);
|
||||
|
||||
Self { split, ohlc, price }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, Height, Sats};
|
||||
use brk_types::{Cents, Height, OHLCCents, OHLCSats, Sats};
|
||||
use vecdb::LazyVecFrom1;
|
||||
|
||||
use crate::internal::{ComputedHeightDerivedLast, LazyEagerIndexes};
|
||||
use crate::prices::{ohlcs::LazyOhlcVecs, split::SplitOhlc};
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Vecs {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub split: SplitOhlc<
|
||||
LazyEagerIndexes<Sats, Cents>,
|
||||
LazyEagerIndexes<Sats, Cents>,
|
||||
LazyEagerIndexes<Sats, Cents>,
|
||||
ComputedHeightDerivedLast<Sats>,
|
||||
>,
|
||||
pub ohlc: LazyOhlcVecs<OHLCSats, OHLCCents>,
|
||||
pub price: LazyVecFrom1<Height, Sats, Height, Cents>,
|
||||
pub open: LazyEagerIndexes<Sats, Cents>,
|
||||
pub high: LazyEagerIndexes<Sats, Cents>,
|
||||
pub low: LazyEagerIndexes<Sats, Cents>,
|
||||
pub close: ComputedHeightDerivedLast<Sats>,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
use brk_traversable::Traversable;
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct SplitOhlc<O, H, L, C> {
|
||||
pub open: O,
|
||||
pub high: H,
|
||||
pub low: L,
|
||||
pub close: C,
|
||||
}
|
||||
@@ -3,9 +3,12 @@ use vecdb::{LazyVecFrom1, ReadableCloneableVec};
|
||||
|
||||
use super::super::cents;
|
||||
use super::Vecs;
|
||||
use crate::prices::{ohlcs::LazyOhlcVecs, split::SplitOhlc};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{CentsUnsignedToDollars, ComputedHeightDerivedLast, LazyEagerIndexes},
|
||||
internal::{
|
||||
CentsUnsignedToDollars, ComputedHeightDerivedLast, LazyEagerIndexes, OhlcCentsToDollars,
|
||||
},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -15,32 +18,48 @@ impl Vecs {
|
||||
cents: ¢s::Vecs,
|
||||
) -> Self {
|
||||
let price = LazyVecFrom1::transformed::<CentsUnsignedToDollars>(
|
||||
"price_usd",
|
||||
"price",
|
||||
version,
|
||||
cents.price.read_only_boxed_clone(),
|
||||
);
|
||||
|
||||
// Dollars are monotonically increasing from cents, so open→open, high→high, low→low
|
||||
let open =
|
||||
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>("price_usd_open", version, ¢s.open);
|
||||
let high =
|
||||
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>("price_usd_high", version, ¢s.high);
|
||||
let low =
|
||||
LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>("price_usd_low", version, ¢s.low);
|
||||
let open = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>(
|
||||
"price_open",
|
||||
version,
|
||||
¢s.split.open,
|
||||
);
|
||||
let high = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>(
|
||||
"price_high",
|
||||
version,
|
||||
¢s.split.high,
|
||||
);
|
||||
let low = LazyEagerIndexes::from_eager_indexes::<CentsUnsignedToDollars>(
|
||||
"price_low",
|
||||
version,
|
||||
¢s.split.low,
|
||||
);
|
||||
|
||||
let close = ComputedHeightDerivedLast::forced_import(
|
||||
"price_usd_close",
|
||||
"price_close",
|
||||
price.read_only_boxed_clone(),
|
||||
version,
|
||||
indexes,
|
||||
);
|
||||
|
||||
Self {
|
||||
price,
|
||||
let split = SplitOhlc {
|
||||
open,
|
||||
high,
|
||||
low,
|
||||
close,
|
||||
}
|
||||
};
|
||||
|
||||
let ohlc = LazyOhlcVecs::from_eager_ohlc_indexes::<OhlcCentsToDollars>(
|
||||
"price_ohlc",
|
||||
version,
|
||||
¢s.ohlc,
|
||||
);
|
||||
|
||||
Self { split, ohlc, price }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, Dollars, Height};
|
||||
use brk_types::{Cents, Dollars, Height, OHLCCents, OHLCDollars};
|
||||
use vecdb::LazyVecFrom1;
|
||||
|
||||
use crate::internal::{ComputedHeightDerivedLast, LazyEagerIndexes};
|
||||
use crate::prices::{ohlcs::LazyOhlcVecs, split::SplitOhlc};
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Vecs {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub split: SplitOhlc<
|
||||
LazyEagerIndexes<Dollars, Cents>,
|
||||
LazyEagerIndexes<Dollars, Cents>,
|
||||
LazyEagerIndexes<Dollars, Cents>,
|
||||
ComputedHeightDerivedLast<Dollars>,
|
||||
>,
|
||||
pub ohlc: LazyOhlcVecs<OHLCDollars, OHLCCents>,
|
||||
pub price: LazyVecFrom1<Height, Dollars, Height, Cents>,
|
||||
pub open: LazyEagerIndexes<Dollars, Cents>,
|
||||
pub high: LazyEagerIndexes<Dollars, Cents>,
|
||||
pub low: LazyEagerIndexes<Dollars, Cents>,
|
||||
pub close: ComputedHeightDerivedLast<Dollars>,
|
||||
}
|
||||
|
||||
@@ -62,16 +62,17 @@ impl Vecs {
|
||||
let out_start = first_txoutindex.to_usize();
|
||||
let out_end = next_first_txoutindex.to_usize();
|
||||
|
||||
// Sum opreturn values — batch read both ranges for the block
|
||||
let values = indexer.vecs.outputs.value.collect_range_at(out_start, out_end);
|
||||
// Sum opreturn values — fold over both vecs without allocation
|
||||
let opreturn_value = indexer.vecs.outputs.outputtype.fold_range_at(
|
||||
out_start, out_end,
|
||||
(Sats::ZERO, 0_usize),
|
||||
|(mut sum, idx), ot| {
|
||||
if ot == OutputType::OpReturn {
|
||||
sum += values[idx];
|
||||
}
|
||||
(sum, idx + 1)
|
||||
(Sats::ZERO, out_start),
|
||||
|(sum, vi), ot| {
|
||||
let new_sum = if ot == OutputType::OpReturn {
|
||||
sum + indexer.vecs.outputs.value.collect_one_at(vi).unwrap()
|
||||
} else {
|
||||
sum
|
||||
};
|
||||
(new_sum, vi + 1)
|
||||
},
|
||||
).0;
|
||||
|
||||
|
||||
@@ -5,6 +5,77 @@ use vecdb::{
|
||||
WritableVec,
|
||||
};
|
||||
|
||||
use crate::internal::sliding_window::SlidingWindowSorted;
|
||||
|
||||
/// Unified rolling extremum (min or max) from window starts.
|
||||
///
|
||||
/// `should_replace` determines whether to evict the deque back:
|
||||
/// - For min: `|back, new| *back >= *new`
|
||||
/// - For max: `|back, new| *back <= *new`
|
||||
pub fn compute_rolling_extremum_from_starts<I, T, A>(
|
||||
out: &mut EagerVec<PcoVec<I, T>>,
|
||||
max_from: I,
|
||||
window_starts: &impl ReadableVec<I, I>,
|
||||
values: &impl ReadableVec<I, A>,
|
||||
should_replace: fn(&A, &A) -> bool,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
I: VecIndex,
|
||||
T: PcoVecValue + From<A>,
|
||||
A: VecValue + Ord,
|
||||
{
|
||||
out.validate_and_truncate(window_starts.version() + values.version(), max_from)?;
|
||||
|
||||
out.repeat_until_complete(exit, |this| {
|
||||
let skip = this.len();
|
||||
let mut deque: std::collections::VecDeque<(usize, A)> =
|
||||
std::collections::VecDeque::new();
|
||||
|
||||
let start_offset = if skip > 0 {
|
||||
window_starts.collect_one_at(skip - 1).unwrap().to_usize()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let end = window_starts.len().min(values.len());
|
||||
let starts_batch = window_starts.collect_range_at(start_offset, end);
|
||||
let values_batch = values.collect_range_at(start_offset, end);
|
||||
|
||||
for (j, (start, value)) in starts_batch.into_iter().zip(values_batch).enumerate() {
|
||||
let i = start_offset + j;
|
||||
let start_usize = start.to_usize();
|
||||
while let Some(&(idx, _)) = deque.front() {
|
||||
if idx < start_usize {
|
||||
deque.pop_front();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while let Some((_, back)) = deque.back() {
|
||||
if should_replace(back, &value) {
|
||||
deque.pop_back();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
deque.push_back((i, value));
|
||||
|
||||
if i >= skip {
|
||||
let extremum = deque.front().unwrap().1.clone();
|
||||
this.checked_push_at(i, T::from(extremum))?;
|
||||
if this.batch_limit_reached() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub trait ComputeRollingMinFromStarts<I: VecIndex, T> {
|
||||
fn compute_rolling_min_from_starts<A>(
|
||||
&mut self,
|
||||
@@ -34,56 +105,14 @@ where
|
||||
A: VecValue + Ord,
|
||||
T: From<A>,
|
||||
{
|
||||
self.validate_computed_version_or_reset(window_starts.version() + values.version())?;
|
||||
self.truncate_if_needed(max_from)?;
|
||||
|
||||
self.repeat_until_complete(exit, |this| {
|
||||
let skip = this.len();
|
||||
let mut deque: std::collections::VecDeque<(usize, A)> =
|
||||
std::collections::VecDeque::new();
|
||||
|
||||
let start_offset = if skip > 0 {
|
||||
window_starts.collect_one_at(skip - 1).unwrap().to_usize()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let end = window_starts.len().min(values.len());
|
||||
let starts_batch = window_starts.collect_range_at(start_offset, end);
|
||||
let values_batch = values.collect_range_at(start_offset, end);
|
||||
|
||||
for (j, (start, value)) in starts_batch.into_iter().zip(values_batch).enumerate() {
|
||||
let i = start_offset + j;
|
||||
let start_usize = start.to_usize();
|
||||
while let Some(&(idx, _)) = deque.front() {
|
||||
if idx < start_usize {
|
||||
deque.pop_front();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while let Some((_, back)) = deque.back() {
|
||||
if *back >= value {
|
||||
deque.pop_back();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
deque.push_back((i, value));
|
||||
|
||||
if i >= skip {
|
||||
let min_val = deque.front().unwrap().1.clone();
|
||||
this.checked_push_at(i, T::from(min_val))?;
|
||||
if this.batch_limit_reached() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
compute_rolling_extremum_from_starts(
|
||||
self,
|
||||
max_from,
|
||||
window_starts,
|
||||
values,
|
||||
|back, new| *back >= *new,
|
||||
exit,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,56 +145,14 @@ where
|
||||
A: VecValue + Ord,
|
||||
T: From<A>,
|
||||
{
|
||||
self.validate_computed_version_or_reset(window_starts.version() + values.version())?;
|
||||
self.truncate_if_needed(max_from)?;
|
||||
|
||||
self.repeat_until_complete(exit, |this| {
|
||||
let skip = this.len();
|
||||
let mut deque: std::collections::VecDeque<(usize, A)> =
|
||||
std::collections::VecDeque::new();
|
||||
|
||||
let start_offset = if skip > 0 {
|
||||
window_starts.collect_one_at(skip - 1).unwrap().to_usize()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let end = window_starts.len().min(values.len());
|
||||
let starts_batch = window_starts.collect_range_at(start_offset, end);
|
||||
let values_batch = values.collect_range_at(start_offset, end);
|
||||
|
||||
for (j, (start, value)) in starts_batch.into_iter().zip(values_batch).enumerate() {
|
||||
let i = start_offset + j;
|
||||
let start_usize = start.to_usize();
|
||||
while let Some(&(idx, _)) = deque.front() {
|
||||
if idx < start_usize {
|
||||
deque.pop_front();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while let Some((_, back)) = deque.back() {
|
||||
if *back <= value {
|
||||
deque.pop_back();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
deque.push_back((i, value));
|
||||
|
||||
if i >= skip {
|
||||
let max_val = deque.front().unwrap().1.clone();
|
||||
this.checked_push_at(i, T::from(max_val))?;
|
||||
if this.batch_limit_reached() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
compute_rolling_extremum_from_starts(
|
||||
self,
|
||||
max_from,
|
||||
window_starts,
|
||||
values,
|
||||
|back, new| *back <= *new,
|
||||
exit,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,70 +185,47 @@ where
|
||||
A: VecValue + Copy,
|
||||
f64: From<A>,
|
||||
{
|
||||
self.validate_computed_version_or_reset(window_starts.version() + values.version())?;
|
||||
|
||||
self.truncate_if_needed(max_from)?;
|
||||
self.validate_and_truncate(window_starts.version() + values.version(), max_from)?;
|
||||
|
||||
self.repeat_until_complete(exit, |this| {
|
||||
let skip = this.len();
|
||||
let end = window_starts.len().min(values.len());
|
||||
|
||||
// Only collect the range needed: from window start of previous
|
||||
// element to end. For incremental (1 block) this is ~window_size
|
||||
// instead of the full history.
|
||||
let range_start = if skip > 0 {
|
||||
window_starts.collect_one_at(skip - 1).unwrap().to_usize()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let partial_values: Vec<A> = values.collect_range_at(range_start, end);
|
||||
let partial_values: Vec<f64> = values
|
||||
.collect_range_at(range_start, end)
|
||||
.into_iter()
|
||||
.map(|a| f64::from(a))
|
||||
.collect();
|
||||
|
||||
let mut sorted: Vec<f64> = Vec::new();
|
||||
let mut prev_start_usize: usize = range_start;
|
||||
let capacity = if skip > 0 && skip < end {
|
||||
let first_start = window_starts.collect_one_at(skip).unwrap().to_usize();
|
||||
(skip + 1).saturating_sub(first_start)
|
||||
} else if !partial_values.is_empty() {
|
||||
partial_values.len().min(1024)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let mut window = SlidingWindowSorted::with_capacity(capacity);
|
||||
|
||||
// Reconstruct state from historical data
|
||||
if skip > 0 {
|
||||
(range_start..skip).for_each(|idx| {
|
||||
let v = f64::from(partial_values[idx - range_start]);
|
||||
let pos = sorted
|
||||
.binary_search_by(|a| {
|
||||
a.partial_cmp(&v).unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.unwrap_or_else(|x| x);
|
||||
sorted.insert(pos, v);
|
||||
});
|
||||
window.reconstruct(&partial_values, range_start, skip);
|
||||
}
|
||||
|
||||
let starts_batch = window_starts.collect_range_at(skip, end);
|
||||
|
||||
for (j, start) in starts_batch.into_iter().enumerate() {
|
||||
let i = skip + j;
|
||||
let v = f64::from(partial_values[i - range_start]);
|
||||
let pos = sorted
|
||||
.binary_search_by(|a| a.partial_cmp(&v).unwrap_or(std::cmp::Ordering::Equal))
|
||||
.unwrap_or_else(|x| x);
|
||||
sorted.insert(pos, v);
|
||||
|
||||
let v = partial_values[i - range_start];
|
||||
let start_usize = start.to_usize();
|
||||
while prev_start_usize < start_usize {
|
||||
let old = f64::from(partial_values[prev_start_usize - range_start]);
|
||||
if let Ok(pos) = sorted.binary_search_by(|a| {
|
||||
a.partial_cmp(&old).unwrap_or(std::cmp::Ordering::Equal)
|
||||
}) {
|
||||
sorted.remove(pos);
|
||||
}
|
||||
prev_start_usize += 1;
|
||||
}
|
||||
|
||||
let median = if sorted.is_empty() {
|
||||
0.0
|
||||
} else if sorted.len().is_multiple_of(2) {
|
||||
let mid = sorted.len() / 2;
|
||||
(sorted[mid - 1] + sorted[mid]) / 2.0
|
||||
} else {
|
||||
sorted[sorted.len() / 2]
|
||||
};
|
||||
window.advance(v, start_usize, &partial_values, range_start);
|
||||
|
||||
let median = window.percentile(0.50);
|
||||
this.checked_push_at(i, T::from(median))?;
|
||||
|
||||
if this.batch_limit_reached() {
|
||||
@@ -278,11 +242,6 @@ where
|
||||
|
||||
/// Compute all 8 rolling distribution stats (avg, min, max, p10, p25, median, p75, p90)
|
||||
/// in a single sorted-vec pass per window.
|
||||
///
|
||||
/// Since the percentile pass already sorts data, min = sorted[0], max = sorted[last],
|
||||
/// and average = running_sum / count — all extracted at negligible extra cost.
|
||||
/// This replaces 3 separate passes (avg, min, max) + 1 percentile pass = 4 passes
|
||||
/// with a single unified pass.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn compute_rolling_distribution_from_starts<I, T, A>(
|
||||
max_from: I,
|
||||
@@ -306,34 +265,12 @@ where
|
||||
{
|
||||
let version = window_starts.version() + values.version();
|
||||
|
||||
average_out.validate_computed_version_or_reset(version)?;
|
||||
min_out.validate_computed_version_or_reset(version)?;
|
||||
max_out.validate_computed_version_or_reset(version)?;
|
||||
p10_out.validate_computed_version_or_reset(version)?;
|
||||
p25_out.validate_computed_version_or_reset(version)?;
|
||||
median_out.validate_computed_version_or_reset(version)?;
|
||||
p75_out.validate_computed_version_or_reset(version)?;
|
||||
p90_out.validate_computed_version_or_reset(version)?;
|
||||
for v in [&mut *average_out, &mut *min_out, &mut *max_out, &mut *p10_out, &mut *p25_out, &mut *median_out, &mut *p75_out, &mut *p90_out] {
|
||||
v.validate_and_truncate(version, max_from)?;
|
||||
}
|
||||
|
||||
average_out.truncate_if_needed(max_from)?;
|
||||
min_out.truncate_if_needed(max_from)?;
|
||||
max_out.truncate_if_needed(max_from)?;
|
||||
p10_out.truncate_if_needed(max_from)?;
|
||||
p25_out.truncate_if_needed(max_from)?;
|
||||
median_out.truncate_if_needed(max_from)?;
|
||||
p75_out.truncate_if_needed(max_from)?;
|
||||
p90_out.truncate_if_needed(max_from)?;
|
||||
|
||||
// All 8 vecs should be at the same length; use min to be safe
|
||||
let skip = average_out
|
||||
.len()
|
||||
.min(min_out.len())
|
||||
.min(max_out.len())
|
||||
.min(p10_out.len())
|
||||
.min(p25_out.len())
|
||||
.min(median_out.len())
|
||||
.min(p75_out.len())
|
||||
.min(p90_out.len());
|
||||
let skip = [average_out.len(), min_out.len(), max_out.len(), p10_out.len(), p25_out.len(), median_out.len(), p75_out.len(), p90_out.len()]
|
||||
.into_iter().min().unwrap();
|
||||
|
||||
let end = window_starts.len().min(values.len());
|
||||
if skip >= end {
|
||||
@@ -345,113 +282,68 @@ where
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let partial_values: Vec<A> = values.collect_range_at(range_start, end);
|
||||
let partial_values: Vec<f64> = values
|
||||
.collect_range_at(range_start, end)
|
||||
.into_iter()
|
||||
.map(|a| f64::from(a))
|
||||
.collect();
|
||||
|
||||
let mut sorted: Vec<f64> = Vec::new();
|
||||
let mut running_sum: f64 = 0.0;
|
||||
let mut prev_start_usize: usize = range_start;
|
||||
let capacity = if skip > 0 && skip < end {
|
||||
let first_start = window_starts.collect_one_at(skip).unwrap().to_usize();
|
||||
(skip + 1).saturating_sub(first_start)
|
||||
} else if !partial_values.is_empty() {
|
||||
partial_values.len().min(1024)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let mut window = SlidingWindowSorted::with_capacity(capacity);
|
||||
|
||||
// Reconstruct sorted state + running sum from historical data
|
||||
if skip > 0 {
|
||||
for idx in range_start..skip {
|
||||
let v = f64::from(partial_values[idx - range_start]);
|
||||
running_sum += v;
|
||||
let pos = sorted
|
||||
.binary_search_by(|a| a.partial_cmp(&v).unwrap_or(std::cmp::Ordering::Equal))
|
||||
.unwrap_or_else(|x| x);
|
||||
sorted.insert(pos, v);
|
||||
}
|
||||
window.reconstruct(&partial_values, range_start, skip);
|
||||
}
|
||||
|
||||
let starts_batch = window_starts.collect_range_at(skip, end);
|
||||
|
||||
for (j, start) in starts_batch.into_iter().enumerate() {
|
||||
let i = skip + j;
|
||||
let v = f64::from(partial_values[i - range_start]);
|
||||
running_sum += v;
|
||||
let pos = sorted
|
||||
.binary_search_by(|a| a.partial_cmp(&v).unwrap_or(std::cmp::Ordering::Equal))
|
||||
.unwrap_or_else(|x| x);
|
||||
sorted.insert(pos, v);
|
||||
|
||||
let v = partial_values[i - range_start];
|
||||
let start_usize = start.to_usize();
|
||||
while prev_start_usize < start_usize {
|
||||
let old = f64::from(partial_values[prev_start_usize - range_start]);
|
||||
running_sum -= old;
|
||||
if let Ok(pos) = sorted
|
||||
.binary_search_by(|a| a.partial_cmp(&old).unwrap_or(std::cmp::Ordering::Equal))
|
||||
{
|
||||
sorted.remove(pos);
|
||||
}
|
||||
prev_start_usize += 1;
|
||||
}
|
||||
window.advance(v, start_usize, &partial_values, range_start);
|
||||
|
||||
let len = sorted.len();
|
||||
if len == 0 {
|
||||
if window.is_empty() {
|
||||
let zero = T::from(0.0);
|
||||
average_out.checked_push_at(i, zero)?;
|
||||
min_out.checked_push_at(i, zero)?;
|
||||
max_out.checked_push_at(i, zero)?;
|
||||
p10_out.checked_push_at(i, zero)?;
|
||||
p25_out.checked_push_at(i, zero)?;
|
||||
median_out.checked_push_at(i, zero)?;
|
||||
p75_out.checked_push_at(i, zero)?;
|
||||
p90_out.checked_push_at(i, zero)?;
|
||||
for v in [&mut *average_out, &mut *min_out, &mut *max_out, &mut *p10_out, &mut *p25_out, &mut *median_out, &mut *p75_out, &mut *p90_out] {
|
||||
v.checked_push_at(i, zero)?;
|
||||
}
|
||||
} else {
|
||||
average_out.checked_push_at(i, T::from(running_sum / len as f64))?;
|
||||
min_out.checked_push_at(i, T::from(sorted[0]))?;
|
||||
max_out.checked_push_at(i, T::from(sorted[len - 1]))?;
|
||||
p10_out.checked_push_at(i, T::from(percentile_of_sorted(&sorted, 0.10)))?;
|
||||
p25_out.checked_push_at(i, T::from(percentile_of_sorted(&sorted, 0.25)))?;
|
||||
median_out.checked_push_at(i, T::from(percentile_of_sorted(&sorted, 0.50)))?;
|
||||
p75_out.checked_push_at(i, T::from(percentile_of_sorted(&sorted, 0.75)))?;
|
||||
p90_out.checked_push_at(i, T::from(percentile_of_sorted(&sorted, 0.90)))?;
|
||||
average_out.checked_push_at(i, T::from(window.average()))?;
|
||||
min_out.checked_push_at(i, T::from(window.min()))?;
|
||||
max_out.checked_push_at(i, T::from(window.max()))?;
|
||||
p10_out.checked_push_at(i, T::from(window.percentile(0.10)))?;
|
||||
p25_out.checked_push_at(i, T::from(window.percentile(0.25)))?;
|
||||
median_out.checked_push_at(i, T::from(window.percentile(0.50)))?;
|
||||
p75_out.checked_push_at(i, T::from(window.percentile(0.75)))?;
|
||||
p90_out.checked_push_at(i, T::from(window.percentile(0.90)))?;
|
||||
}
|
||||
|
||||
if average_out.batch_limit_reached() {
|
||||
let _lock = exit.lock();
|
||||
average_out.write()?;
|
||||
min_out.write()?;
|
||||
max_out.write()?;
|
||||
p10_out.write()?;
|
||||
p25_out.write()?;
|
||||
median_out.write()?;
|
||||
p75_out.write()?;
|
||||
p90_out.write()?;
|
||||
for v in [&mut *average_out, &mut *min_out, &mut *max_out, &mut *p10_out, &mut *p25_out, &mut *median_out, &mut *p75_out, &mut *p90_out] {
|
||||
v.write()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Final flush
|
||||
let _lock = exit.lock();
|
||||
average_out.write()?;
|
||||
min_out.write()?;
|
||||
max_out.write()?;
|
||||
p10_out.write()?;
|
||||
p25_out.write()?;
|
||||
median_out.write()?;
|
||||
p75_out.write()?;
|
||||
p90_out.write()?;
|
||||
for v in [average_out, min_out, max_out, p10_out, p25_out, median_out, p75_out, p90_out] {
|
||||
v.write()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Extract a percentile (0.0-1.0) from a sorted slice using linear interpolation.
|
||||
fn percentile_of_sorted(sorted: &[f64], p: f64) -> f64 {
|
||||
let len = sorted.len();
|
||||
if len == 1 {
|
||||
return sorted[0];
|
||||
}
|
||||
let rank = p * (len - 1) as f64;
|
||||
let lo = rank.floor() as usize;
|
||||
let hi = rank.ceil() as usize;
|
||||
if lo == hi {
|
||||
sorted[lo]
|
||||
} else {
|
||||
let frac = rank - lo as f64;
|
||||
sorted[lo] * (1.0 - frac) + sorted[hi] * frac
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ComputeDrawdown<I: VecIndex> {
|
||||
fn compute_drawdown<C, A>(
|
||||
&mut self,
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
use std::ops::{Add, Div};
|
||||
|
||||
/// Extension trait for Option to provide shorter unwrap methods
|
||||
pub trait OptionExt<T> {
|
||||
/// Shorthand for `.as_ref().unwrap()`
|
||||
fn u(&self) -> &T;
|
||||
/// Shorthand for `.as_mut().unwrap()`
|
||||
fn um(&mut self) -> &mut T;
|
||||
}
|
||||
|
||||
impl<T> OptionExt<T> for Option<T> {
|
||||
#[inline]
|
||||
fn u(&self) -> &T {
|
||||
self.as_ref().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn um(&mut self) -> &mut T {
|
||||
self.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_percentile<T>(sorted: &[T], percentile: f64) -> T
|
||||
where
|
||||
T: Clone + Div<usize, Output = T> + Add<T, Output = T>,
|
||||
{
|
||||
let len = sorted.len();
|
||||
|
||||
if len == 0 {
|
||||
panic!();
|
||||
} else if len == 1 {
|
||||
sorted[0].clone()
|
||||
} else {
|
||||
let index = (len - 1) as f64 * percentile;
|
||||
|
||||
let fract = index.fract();
|
||||
|
||||
if fract != 0.0 {
|
||||
let left = sorted.get(index as usize).unwrap().clone();
|
||||
let right = sorted.get(index.ceil() as usize).unwrap().clone();
|
||||
left / 2 + right / 2
|
||||
} else {
|
||||
// dbg!(sorted.len(), index);
|
||||
sorted.get(index as usize).unwrap().clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ impl Query {
|
||||
let price = &self.computer().prices;
|
||||
let spot = price
|
||||
.cents
|
||||
.split
|
||||
.close
|
||||
.day1
|
||||
.collect_one_flat(day1)
|
||||
|
||||
+105
-105
@@ -2763,7 +2763,7 @@ function createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(clien
|
||||
|
||||
/**
|
||||
* @typedef {Object} BlocksCoinbaseDaysDominanceFeeSubsidyPattern
|
||||
* @property {CumulativeHeightRollingPattern<StoredU32>} blocksMined
|
||||
* @property {CumulativeHeightSumPattern<StoredU32>} blocksMined
|
||||
* @property {MetricPattern1<StoredU32>} blocksMined1mSum
|
||||
* @property {MetricPattern1<StoredU32>} blocksMined1wSum
|
||||
* @property {MetricPattern1<StoredU32>} blocksMined1ySum
|
||||
@@ -2788,7 +2788,7 @@ function createGreedInvestedInvestorNegNetPainSupplyTotalUnrealizedPattern(clien
|
||||
*/
|
||||
function createBlocksCoinbaseDaysDominanceFeeSubsidyPattern(client, acc) {
|
||||
return {
|
||||
blocksMined: createCumulativeHeightRollingPattern(client, _m(acc, 'blocks_mined')),
|
||||
blocksMined: createCumulativeHeightSumPattern(client, _m(acc, 'blocks_mined')),
|
||||
blocksMined1mSum: createMetricPattern1(client, _m(acc, 'blocks_mined_1m_sum')),
|
||||
blocksMined1wSum: createMetricPattern1(client, _m(acc, 'blocks_mined_1w_sum')),
|
||||
blocksMined1ySum: createMetricPattern1(client, _m(acc, 'blocks_mined_1y_sum')),
|
||||
@@ -3455,8 +3455,8 @@ function createBalanceBothReactivatedReceivingSendingPattern(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} CoinblocksCoindaysSatblocksSatdaysSentPattern
|
||||
* @property {CumulativeHeightRollingPattern<StoredF64>} coinblocksDestroyed
|
||||
* @property {CumulativeHeightRollingPattern<StoredF64>} coindaysDestroyed
|
||||
* @property {CumulativeHeightSumPattern<StoredF64>} coinblocksDestroyed
|
||||
* @property {CumulativeHeightSumPattern<StoredF64>} coindaysDestroyed
|
||||
* @property {MetricPattern20<Sats>} satblocksDestroyed
|
||||
* @property {MetricPattern20<Sats>} satdaysDestroyed
|
||||
* @property {BtcSatsUsdPattern2} sent
|
||||
@@ -3471,8 +3471,8 @@ function createBalanceBothReactivatedReceivingSendingPattern(client, acc) {
|
||||
*/
|
||||
function createCoinblocksCoindaysSatblocksSatdaysSentPattern(client, acc) {
|
||||
return {
|
||||
coinblocksDestroyed: createCumulativeHeightRollingPattern(client, _m(acc, 'coinblocks_destroyed')),
|
||||
coindaysDestroyed: createCumulativeHeightRollingPattern(client, _m(acc, 'coindays_destroyed')),
|
||||
coinblocksDestroyed: createCumulativeHeightSumPattern(client, _m(acc, 'coinblocks_destroyed')),
|
||||
coindaysDestroyed: createCumulativeHeightSumPattern(client, _m(acc, 'coindays_destroyed')),
|
||||
satblocksDestroyed: createMetricPattern20(client, _m(acc, 'satblocks_destroyed')),
|
||||
satdaysDestroyed: createMetricPattern20(client, _m(acc, 'satdays_destroyed')),
|
||||
sent: createBtcSatsUsdPattern2(client, _m(acc, 'sent')),
|
||||
@@ -3673,33 +3673,12 @@ function createBtcSatsUsdPattern2(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BtcSatsUsdPattern4
|
||||
* @typedef {Object} BtcSatsUsdPattern3
|
||||
* @property {MetricPattern1<Bitcoin>} btc
|
||||
* @property {CumulativeHeightRollingPattern<Sats>} sats
|
||||
* @property {CumulativeHeightRollingPattern<Dollars>} usd
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a BtcSatsUsdPattern4 pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {BtcSatsUsdPattern4}
|
||||
*/
|
||||
function createBtcSatsUsdPattern4(client, acc) {
|
||||
return {
|
||||
btc: createMetricPattern1(client, _m(acc, 'btc')),
|
||||
sats: createCumulativeHeightRollingPattern(client, acc),
|
||||
usd: createCumulativeHeightRollingPattern(client, _m(acc, 'usd')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BtcSatsUsdPattern3
|
||||
* @property {MetricPattern1<Bitcoin>} btc
|
||||
* @property {CumulativeHeightRollingPattern2<Sats>} sats
|
||||
* @property {CumulativeHeightRollingPattern2<Dollars>} usd
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a BtcSatsUsdPattern3 pattern node
|
||||
* @param {BrkClientBase} client
|
||||
@@ -3709,8 +3688,29 @@ function createBtcSatsUsdPattern4(client, acc) {
|
||||
function createBtcSatsUsdPattern3(client, acc) {
|
||||
return {
|
||||
btc: createMetricPattern1(client, _m(acc, 'btc')),
|
||||
sats: createCumulativeHeightRollingPattern2(client, acc),
|
||||
usd: createCumulativeHeightRollingPattern2(client, _m(acc, 'usd')),
|
||||
sats: createCumulativeHeightRollingPattern(client, acc),
|
||||
usd: createCumulativeHeightRollingPattern(client, _m(acc, 'usd')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BtcSatsUsdPattern4
|
||||
* @property {MetricPattern1<Bitcoin>} btc
|
||||
* @property {CumulativeHeightSumPattern<Sats>} sats
|
||||
* @property {CumulativeHeightSumPattern<Dollars>} usd
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a BtcSatsUsdPattern4 pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {BtcSatsUsdPattern4}
|
||||
*/
|
||||
function createBtcSatsUsdPattern4(client, acc) {
|
||||
return {
|
||||
btc: createMetricPattern1(client, _m(acc, 'btc')),
|
||||
sats: createCumulativeHeightSumPattern(client, acc),
|
||||
usd: createCumulativeHeightSumPattern(client, _m(acc, 'usd')),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3756,35 +3756,12 @@ function createHistogramLineSignalPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} CumulativeHeightRollingPattern2
|
||||
* @property {MetricPattern1<T>} cumulative
|
||||
* @property {MetricPattern20<T>} height
|
||||
* @property {AverageMaxMedianMinP10P25P75P90SumPattern} rolling
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CumulativeHeightRollingPattern2 pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CumulativeHeightRollingPattern2<T>}
|
||||
*/
|
||||
function createCumulativeHeightRollingPattern2(client, acc) {
|
||||
return {
|
||||
cumulative: createMetricPattern1(client, _m(acc, 'cumulative')),
|
||||
height: createMetricPattern20(client, acc),
|
||||
rolling: createAverageMaxMedianMinP10P25P75P90SumPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} CumulativeHeightRollingPattern
|
||||
* @property {MetricPattern1<T>} cumulative
|
||||
* @property {MetricPattern20<T>} height
|
||||
* @property {_1y24h30d7dPattern<T>} rolling
|
||||
* @property {AverageMaxMedianMinP10P25P75P90SumPattern} rolling
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -3798,7 +3775,30 @@ function createCumulativeHeightRollingPattern(client, acc) {
|
||||
return {
|
||||
cumulative: createMetricPattern1(client, _m(acc, 'cumulative')),
|
||||
height: createMetricPattern20(client, acc),
|
||||
rolling: create_1y24h30d7dPattern(client, acc),
|
||||
rolling: createAverageMaxMedianMinP10P25P75P90SumPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} CumulativeHeightSumPattern
|
||||
* @property {MetricPattern1<T>} cumulative
|
||||
* @property {MetricPattern20<T>} height
|
||||
* @property {_1y24h30d7dPattern<T>} sum
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CumulativeHeightSumPattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CumulativeHeightSumPattern<T>}
|
||||
*/
|
||||
function createCumulativeHeightSumPattern(client, acc) {
|
||||
return {
|
||||
cumulative: createMetricPattern1(client, _m(acc, 'cumulative')),
|
||||
height: createMetricPattern20(client, acc),
|
||||
sum: create_1y24h30d7dPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3986,7 +3986,7 @@ function createRatioPattern2(client, acc) {
|
||||
* @property {MetricsTree_Blocks_Count} count
|
||||
* @property {AverageHeightMaxMedianMinP10P25P75P90Pattern<Timestamp>} interval
|
||||
* @property {MetricsTree_Blocks_Halving} halving
|
||||
* @property {CumulativeHeightRollingPattern2<StoredU64>} vbytes
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} vbytes
|
||||
* @property {AverageCumulativeMaxMedianMinP10P25P75P90SumPattern} size
|
||||
* @property {AverageHeightMaxMedianMinP10P25P75P90Pattern<StoredF32>} fullness
|
||||
*/
|
||||
@@ -4048,7 +4048,7 @@ function createRatioPattern2(client, acc) {
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Blocks_Count
|
||||
* @property {MetricPattern1<StoredU64>} blockCountTarget
|
||||
* @property {CumulativeHeightRollingPattern<StoredU32>} blockCount
|
||||
* @property {CumulativeHeightSumPattern<StoredU32>} blockCount
|
||||
* @property {_1y24h30d7dPattern<StoredU32>} blockCountSum
|
||||
* @property {MetricPattern20<Height>} height1hAgo
|
||||
* @property {MetricPattern20<Height>} height24hAgo
|
||||
@@ -4111,7 +4111,7 @@ function createRatioPattern2(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Transactions_Count
|
||||
* @property {CumulativeHeightRollingPattern2<StoredU64>} txCount
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} txCount
|
||||
* @property {MetricPattern21<StoredBool>} isCoinbase
|
||||
*/
|
||||
|
||||
@@ -4131,9 +4131,9 @@ function createRatioPattern2(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Transactions_Versions
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} v1
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} v2
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} v3
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} v1
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} v2
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} v3
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -4221,19 +4221,19 @@ function createRatioPattern2(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Scripts_Count
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2a
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2ms
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2pk33
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2pk65
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2pkh
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2sh
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2tr
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2wpkh
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} p2wsh
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} opreturn
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} emptyoutput
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} unknownoutput
|
||||
* @property {CumulativeHeightRollingPattern<StoredU64>} segwit
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2a
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2ms
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2pk33
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2pk65
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2pkh
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2sh
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2tr
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2wpkh
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} p2wsh
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} opreturn
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} emptyoutput
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} unknownoutput
|
||||
* @property {CumulativeHeightSumPattern<StoredU64>} segwit
|
||||
* @property {MetricPattern1<StoredF32>} taprootAdoption
|
||||
* @property {MetricPattern1<StoredF32>} segwitAdoption
|
||||
*/
|
||||
@@ -4308,8 +4308,8 @@ function createRatioPattern2(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Cointime_Activity
|
||||
* @property {CumulativeHeightRollingPattern<StoredF64>} coinblocksCreated
|
||||
* @property {CumulativeHeightRollingPattern<StoredF64>} coinblocksStored
|
||||
* @property {CumulativeHeightSumPattern<StoredF64>} coinblocksCreated
|
||||
* @property {CumulativeHeightSumPattern<StoredF64>} coinblocksStored
|
||||
* @property {MetricPattern1<StoredF64>} liveliness
|
||||
* @property {MetricPattern1<StoredF64>} vaultedness
|
||||
* @property {MetricPattern1<StoredF64>} activityToVaultednessRatio
|
||||
@@ -4323,10 +4323,10 @@ function createRatioPattern2(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Cointime_Value
|
||||
* @property {CumulativeHeightRollingPattern<StoredF64>} cointimeValueDestroyed
|
||||
* @property {CumulativeHeightRollingPattern<StoredF64>} cointimeValueCreated
|
||||
* @property {CumulativeHeightRollingPattern<StoredF64>} cointimeValueStored
|
||||
* @property {CumulativeHeightRollingPattern<StoredF64>} vocdd
|
||||
* @property {CumulativeHeightSumPattern<StoredF64>} cointimeValueDestroyed
|
||||
* @property {CumulativeHeightSumPattern<StoredF64>} cointimeValueCreated
|
||||
* @property {CumulativeHeightSumPattern<StoredF64>} cointimeValueStored
|
||||
* @property {CumulativeHeightSumPattern<StoredF64>} vocdd
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -6576,7 +6576,7 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
count: {
|
||||
blockCountTarget: createMetricPattern1(this, 'block_count_target'),
|
||||
blockCount: createCumulativeHeightRollingPattern(this, 'block_count'),
|
||||
blockCount: createCumulativeHeightSumPattern(this, 'block_count'),
|
||||
blockCountSum: create_1y24h30d7dPattern(this, 'block_count_sum'),
|
||||
height1hAgo: createMetricPattern20(this, 'height_1h_ago'),
|
||||
height24hAgo: createMetricPattern20(this, 'height_24h_ago'),
|
||||
@@ -6616,7 +6616,7 @@ class BrkClient extends BrkClientBase {
|
||||
blocksBeforeNextHalving: createMetricPattern1(this, 'blocks_before_next_halving'),
|
||||
daysBeforeNextHalving: createMetricPattern1(this, 'days_before_next_halving'),
|
||||
},
|
||||
vbytes: createCumulativeHeightRollingPattern2(this, 'block_vbytes'),
|
||||
vbytes: createCumulativeHeightRollingPattern(this, 'block_vbytes'),
|
||||
size: createAverageCumulativeMaxMedianMinP10P25P75P90SumPattern(this, 'block_size'),
|
||||
fullness: createAverageHeightMaxMedianMinP10P25P75P90Pattern(this, 'block_fullness'),
|
||||
},
|
||||
@@ -6632,7 +6632,7 @@ class BrkClient extends BrkClientBase {
|
||||
firstTxinindex: createMetricPattern21(this, 'first_txinindex'),
|
||||
firstTxoutindex: createMetricPattern21(this, 'first_txoutindex'),
|
||||
count: {
|
||||
txCount: createCumulativeHeightRollingPattern2(this, 'tx_count'),
|
||||
txCount: createCumulativeHeightRollingPattern(this, 'tx_count'),
|
||||
isCoinbase: createMetricPattern21(this, 'is_coinbase'),
|
||||
},
|
||||
size: {
|
||||
@@ -6646,9 +6646,9 @@ class BrkClient extends BrkClientBase {
|
||||
feeRate: create_1h24hBlockTxindexPattern(this, 'fee_rate'),
|
||||
},
|
||||
versions: {
|
||||
v1: createCumulativeHeightRollingPattern(this, 'tx_v1'),
|
||||
v2: createCumulativeHeightRollingPattern(this, 'tx_v2'),
|
||||
v3: createCumulativeHeightRollingPattern(this, 'tx_v3'),
|
||||
v1: createCumulativeHeightSumPattern(this, 'tx_v1'),
|
||||
v2: createCumulativeHeightSumPattern(this, 'tx_v2'),
|
||||
v3: createCumulativeHeightSumPattern(this, 'tx_v3'),
|
||||
},
|
||||
volume: {
|
||||
sentSum: createBtcRollingSatsUsdPattern(this, 'sent_sum'),
|
||||
@@ -6713,19 +6713,19 @@ class BrkClient extends BrkClientBase {
|
||||
p2msToTxindex: createMetricPattern27(this, 'txindex'),
|
||||
unknownToTxindex: createMetricPattern35(this, 'txindex'),
|
||||
count: {
|
||||
p2a: createCumulativeHeightRollingPattern(this, 'p2a_count'),
|
||||
p2ms: createCumulativeHeightRollingPattern(this, 'p2ms_count'),
|
||||
p2pk33: createCumulativeHeightRollingPattern(this, 'p2pk33_count'),
|
||||
p2pk65: createCumulativeHeightRollingPattern(this, 'p2pk65_count'),
|
||||
p2pkh: createCumulativeHeightRollingPattern(this, 'p2pkh_count'),
|
||||
p2sh: createCumulativeHeightRollingPattern(this, 'p2sh_count'),
|
||||
p2tr: createCumulativeHeightRollingPattern(this, 'p2tr_count'),
|
||||
p2wpkh: createCumulativeHeightRollingPattern(this, 'p2wpkh_count'),
|
||||
p2wsh: createCumulativeHeightRollingPattern(this, 'p2wsh_count'),
|
||||
opreturn: createCumulativeHeightRollingPattern(this, 'opreturn_count'),
|
||||
emptyoutput: createCumulativeHeightRollingPattern(this, 'emptyoutput_count'),
|
||||
unknownoutput: createCumulativeHeightRollingPattern(this, 'unknownoutput_count'),
|
||||
segwit: createCumulativeHeightRollingPattern(this, 'segwit_count'),
|
||||
p2a: createCumulativeHeightSumPattern(this, 'p2a_count'),
|
||||
p2ms: createCumulativeHeightSumPattern(this, 'p2ms_count'),
|
||||
p2pk33: createCumulativeHeightSumPattern(this, 'p2pk33_count'),
|
||||
p2pk65: createCumulativeHeightSumPattern(this, 'p2pk65_count'),
|
||||
p2pkh: createCumulativeHeightSumPattern(this, 'p2pkh_count'),
|
||||
p2sh: createCumulativeHeightSumPattern(this, 'p2sh_count'),
|
||||
p2tr: createCumulativeHeightSumPattern(this, 'p2tr_count'),
|
||||
p2wpkh: createCumulativeHeightSumPattern(this, 'p2wpkh_count'),
|
||||
p2wsh: createCumulativeHeightSumPattern(this, 'p2wsh_count'),
|
||||
opreturn: createCumulativeHeightSumPattern(this, 'opreturn_count'),
|
||||
emptyoutput: createCumulativeHeightSumPattern(this, 'emptyoutput_count'),
|
||||
unknownoutput: createCumulativeHeightSumPattern(this, 'unknownoutput_count'),
|
||||
segwit: createCumulativeHeightSumPattern(this, 'segwit_count'),
|
||||
taprootAdoption: createMetricPattern1(this, 'taproot_adoption'),
|
||||
segwitAdoption: createMetricPattern1(this, 'segwit_adoption'),
|
||||
},
|
||||
@@ -6777,8 +6777,8 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
cointime: {
|
||||
activity: {
|
||||
coinblocksCreated: createCumulativeHeightRollingPattern(this, 'coinblocks_created'),
|
||||
coinblocksStored: createCumulativeHeightRollingPattern(this, 'coinblocks_stored'),
|
||||
coinblocksCreated: createCumulativeHeightSumPattern(this, 'coinblocks_created'),
|
||||
coinblocksStored: createCumulativeHeightSumPattern(this, 'coinblocks_stored'),
|
||||
liveliness: createMetricPattern1(this, 'liveliness'),
|
||||
vaultedness: createMetricPattern1(this, 'vaultedness'),
|
||||
activityToVaultednessRatio: createMetricPattern1(this, 'activity_to_vaultedness_ratio'),
|
||||
@@ -6788,10 +6788,10 @@ class BrkClient extends BrkClientBase {
|
||||
activeSupply: createBtcSatsUsdPattern(this, 'active_supply'),
|
||||
},
|
||||
value: {
|
||||
cointimeValueDestroyed: createCumulativeHeightRollingPattern(this, 'cointime_value_destroyed'),
|
||||
cointimeValueCreated: createCumulativeHeightRollingPattern(this, 'cointime_value_created'),
|
||||
cointimeValueStored: createCumulativeHeightRollingPattern(this, 'cointime_value_stored'),
|
||||
vocdd: createCumulativeHeightRollingPattern(this, 'vocdd'),
|
||||
cointimeValueDestroyed: createCumulativeHeightSumPattern(this, 'cointime_value_destroyed'),
|
||||
cointimeValueCreated: createCumulativeHeightSumPattern(this, 'cointime_value_created'),
|
||||
cointimeValueStored: createCumulativeHeightSumPattern(this, 'cointime_value_stored'),
|
||||
vocdd: createCumulativeHeightSumPattern(this, 'vocdd'),
|
||||
},
|
||||
cap: {
|
||||
thermoCap: createMetricPattern1(this, 'thermo_cap'),
|
||||
|
||||
@@ -2660,7 +2660,7 @@ class BlocksCoinbaseDaysDominanceFeeSubsidyPattern:
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.blocks_mined: CumulativeHeightRollingPattern[StoredU32] = CumulativeHeightRollingPattern(client, _m(acc, 'blocks_mined'))
|
||||
self.blocks_mined: CumulativeHeightSumPattern[StoredU32] = CumulativeHeightSumPattern(client, _m(acc, 'blocks_mined'))
|
||||
self.blocks_mined_1m_sum: MetricPattern1[StoredU32] = MetricPattern1(client, _m(acc, 'blocks_mined_1m_sum'))
|
||||
self.blocks_mined_1w_sum: MetricPattern1[StoredU32] = MetricPattern1(client, _m(acc, 'blocks_mined_1w_sum'))
|
||||
self.blocks_mined_1y_sum: MetricPattern1[StoredU32] = MetricPattern1(client, _m(acc, 'blocks_mined_1y_sum'))
|
||||
@@ -2972,8 +2972,8 @@ class CoinblocksCoindaysSatblocksSatdaysSentPattern:
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.coinblocks_destroyed: CumulativeHeightRollingPattern[StoredF64] = CumulativeHeightRollingPattern(client, _m(acc, 'coinblocks_destroyed'))
|
||||
self.coindays_destroyed: CumulativeHeightRollingPattern[StoredF64] = CumulativeHeightRollingPattern(client, _m(acc, 'coindays_destroyed'))
|
||||
self.coinblocks_destroyed: CumulativeHeightSumPattern[StoredF64] = CumulativeHeightSumPattern(client, _m(acc, 'coinblocks_destroyed'))
|
||||
self.coindays_destroyed: CumulativeHeightSumPattern[StoredF64] = CumulativeHeightSumPattern(client, _m(acc, 'coindays_destroyed'))
|
||||
self.satblocks_destroyed: MetricPattern20[Sats] = MetricPattern20(client, _m(acc, 'satblocks_destroyed'))
|
||||
self.satdays_destroyed: MetricPattern20[Sats] = MetricPattern20(client, _m(acc, 'satdays_destroyed'))
|
||||
self.sent: BtcSatsUsdPattern2 = BtcSatsUsdPattern2(client, _m(acc, 'sent'))
|
||||
@@ -3060,7 +3060,7 @@ class BtcSatsUsdPattern2:
|
||||
self.sats: CumulativeHeightPattern[Sats] = CumulativeHeightPattern(client, acc)
|
||||
self.usd: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'usd'))
|
||||
|
||||
class BtcSatsUsdPattern4:
|
||||
class BtcSatsUsdPattern3:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
@@ -3069,14 +3069,14 @@ class BtcSatsUsdPattern4:
|
||||
self.sats: CumulativeHeightRollingPattern[Sats] = CumulativeHeightRollingPattern(client, acc)
|
||||
self.usd: CumulativeHeightRollingPattern[Dollars] = CumulativeHeightRollingPattern(client, _m(acc, 'usd'))
|
||||
|
||||
class BtcSatsUsdPattern3:
|
||||
class BtcSatsUsdPattern4:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.btc: MetricPattern1[Bitcoin] = MetricPattern1(client, _m(acc, 'btc'))
|
||||
self.sats: CumulativeHeightRollingPattern2[Sats] = CumulativeHeightRollingPattern2(client, acc)
|
||||
self.usd: CumulativeHeightRollingPattern2[Dollars] = CumulativeHeightRollingPattern2(client, _m(acc, 'usd'))
|
||||
self.sats: CumulativeHeightSumPattern[Sats] = CumulativeHeightSumPattern(client, acc)
|
||||
self.usd: CumulativeHeightSumPattern[Dollars] = CumulativeHeightSumPattern(client, _m(acc, 'usd'))
|
||||
|
||||
class BtcSatsUsdPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -3096,7 +3096,7 @@ class HistogramLineSignalPattern:
|
||||
self.line: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'line_1y'))
|
||||
self.signal: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'signal_1y'))
|
||||
|
||||
class CumulativeHeightRollingPattern2(Generic[T]):
|
||||
class CumulativeHeightRollingPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
@@ -3105,14 +3105,14 @@ class CumulativeHeightRollingPattern2(Generic[T]):
|
||||
self.height: MetricPattern20[T] = MetricPattern20(client, acc)
|
||||
self.rolling: AverageMaxMedianMinP10P25P75P90SumPattern = AverageMaxMedianMinP10P25P75P90SumPattern(client, acc)
|
||||
|
||||
class CumulativeHeightRollingPattern(Generic[T]):
|
||||
class CumulativeHeightSumPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative'))
|
||||
self.height: MetricPattern20[T] = MetricPattern20(client, acc)
|
||||
self.rolling: _1y24h30d7dPattern[T] = _1y24h30d7dPattern(client, acc)
|
||||
self.sum: _1y24h30d7dPattern[T] = _1y24h30d7dPattern(client, acc)
|
||||
|
||||
class _30dCountPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -3242,7 +3242,7 @@ class MetricsTree_Blocks_Count:
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.block_count_target: MetricPattern1[StoredU64] = MetricPattern1(client, 'block_count_target')
|
||||
self.block_count: CumulativeHeightRollingPattern[StoredU32] = CumulativeHeightRollingPattern(client, 'block_count')
|
||||
self.block_count: CumulativeHeightSumPattern[StoredU32] = CumulativeHeightSumPattern(client, 'block_count')
|
||||
self.block_count_sum: _1y24h30d7dPattern[StoredU32] = _1y24h30d7dPattern(client, 'block_count_sum')
|
||||
self.height_1h_ago: MetricPattern20[Height] = MetricPattern20(client, 'height_1h_ago')
|
||||
self.height_24h_ago: MetricPattern20[Height] = MetricPattern20(client, 'height_24h_ago')
|
||||
@@ -3296,7 +3296,7 @@ class MetricsTree_Blocks:
|
||||
self.count: MetricsTree_Blocks_Count = MetricsTree_Blocks_Count(client)
|
||||
self.interval: AverageHeightMaxMedianMinP10P25P75P90Pattern[Timestamp] = AverageHeightMaxMedianMinP10P25P75P90Pattern(client, 'block_interval')
|
||||
self.halving: MetricsTree_Blocks_Halving = MetricsTree_Blocks_Halving(client)
|
||||
self.vbytes: CumulativeHeightRollingPattern2[StoredU64] = CumulativeHeightRollingPattern2(client, 'block_vbytes')
|
||||
self.vbytes: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'block_vbytes')
|
||||
self.size: AverageCumulativeMaxMedianMinP10P25P75P90SumPattern = AverageCumulativeMaxMedianMinP10P25P75P90SumPattern(client, 'block_size')
|
||||
self.fullness: AverageHeightMaxMedianMinP10P25P75P90Pattern[StoredF32] = AverageHeightMaxMedianMinP10P25P75P90Pattern(client, 'block_fullness')
|
||||
|
||||
@@ -3304,7 +3304,7 @@ class MetricsTree_Transactions_Count:
|
||||
"""Metrics tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.tx_count: CumulativeHeightRollingPattern2[StoredU64] = CumulativeHeightRollingPattern2(client, 'tx_count')
|
||||
self.tx_count: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'tx_count')
|
||||
self.is_coinbase: MetricPattern21[StoredBool] = MetricPattern21(client, 'is_coinbase')
|
||||
|
||||
class MetricsTree_Transactions_Size:
|
||||
@@ -3327,9 +3327,9 @@ class MetricsTree_Transactions_Versions:
|
||||
"""Metrics tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.v1: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'tx_v1')
|
||||
self.v2: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'tx_v2')
|
||||
self.v3: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'tx_v3')
|
||||
self.v1: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'tx_v1')
|
||||
self.v2: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'tx_v2')
|
||||
self.v3: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'tx_v3')
|
||||
|
||||
class MetricsTree_Transactions_Volume:
|
||||
"""Metrics tree node."""
|
||||
@@ -3431,19 +3431,19 @@ class MetricsTree_Scripts_Count:
|
||||
"""Metrics tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.p2a: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2a_count')
|
||||
self.p2ms: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2ms_count')
|
||||
self.p2pk33: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2pk33_count')
|
||||
self.p2pk65: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2pk65_count')
|
||||
self.p2pkh: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2pkh_count')
|
||||
self.p2sh: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2sh_count')
|
||||
self.p2tr: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2tr_count')
|
||||
self.p2wpkh: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2wpkh_count')
|
||||
self.p2wsh: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'p2wsh_count')
|
||||
self.opreturn: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'opreturn_count')
|
||||
self.emptyoutput: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'emptyoutput_count')
|
||||
self.unknownoutput: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'unknownoutput_count')
|
||||
self.segwit: CumulativeHeightRollingPattern[StoredU64] = CumulativeHeightRollingPattern(client, 'segwit_count')
|
||||
self.p2a: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2a_count')
|
||||
self.p2ms: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2ms_count')
|
||||
self.p2pk33: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2pk33_count')
|
||||
self.p2pk65: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2pk65_count')
|
||||
self.p2pkh: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2pkh_count')
|
||||
self.p2sh: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2sh_count')
|
||||
self.p2tr: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2tr_count')
|
||||
self.p2wpkh: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2wpkh_count')
|
||||
self.p2wsh: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'p2wsh_count')
|
||||
self.opreturn: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'opreturn_count')
|
||||
self.emptyoutput: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'emptyoutput_count')
|
||||
self.unknownoutput: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'unknownoutput_count')
|
||||
self.segwit: CumulativeHeightSumPattern[StoredU64] = CumulativeHeightSumPattern(client, 'segwit_count')
|
||||
self.taproot_adoption: MetricPattern1[StoredF32] = MetricPattern1(client, 'taproot_adoption')
|
||||
self.segwit_adoption: MetricPattern1[StoredF32] = MetricPattern1(client, 'segwit_adoption')
|
||||
|
||||
@@ -3528,8 +3528,8 @@ class MetricsTree_Cointime_Activity:
|
||||
"""Metrics tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.coinblocks_created: CumulativeHeightRollingPattern[StoredF64] = CumulativeHeightRollingPattern(client, 'coinblocks_created')
|
||||
self.coinblocks_stored: CumulativeHeightRollingPattern[StoredF64] = CumulativeHeightRollingPattern(client, 'coinblocks_stored')
|
||||
self.coinblocks_created: CumulativeHeightSumPattern[StoredF64] = CumulativeHeightSumPattern(client, 'coinblocks_created')
|
||||
self.coinblocks_stored: CumulativeHeightSumPattern[StoredF64] = CumulativeHeightSumPattern(client, 'coinblocks_stored')
|
||||
self.liveliness: MetricPattern1[StoredF64] = MetricPattern1(client, 'liveliness')
|
||||
self.vaultedness: MetricPattern1[StoredF64] = MetricPattern1(client, 'vaultedness')
|
||||
self.activity_to_vaultedness_ratio: MetricPattern1[StoredF64] = MetricPattern1(client, 'activity_to_vaultedness_ratio')
|
||||
@@ -3545,10 +3545,10 @@ class MetricsTree_Cointime_Value:
|
||||
"""Metrics tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.cointime_value_destroyed: CumulativeHeightRollingPattern[StoredF64] = CumulativeHeightRollingPattern(client, 'cointime_value_destroyed')
|
||||
self.cointime_value_created: CumulativeHeightRollingPattern[StoredF64] = CumulativeHeightRollingPattern(client, 'cointime_value_created')
|
||||
self.cointime_value_stored: CumulativeHeightRollingPattern[StoredF64] = CumulativeHeightRollingPattern(client, 'cointime_value_stored')
|
||||
self.vocdd: CumulativeHeightRollingPattern[StoredF64] = CumulativeHeightRollingPattern(client, 'vocdd')
|
||||
self.cointime_value_destroyed: CumulativeHeightSumPattern[StoredF64] = CumulativeHeightSumPattern(client, 'cointime_value_destroyed')
|
||||
self.cointime_value_created: CumulativeHeightSumPattern[StoredF64] = CumulativeHeightSumPattern(client, 'cointime_value_created')
|
||||
self.cointime_value_stored: CumulativeHeightSumPattern[StoredF64] = CumulativeHeightSumPattern(client, 'cointime_value_stored')
|
||||
self.vocdd: CumulativeHeightSumPattern[StoredF64] = CumulativeHeightSumPattern(client, 'vocdd')
|
||||
|
||||
class MetricsTree_Cointime_Cap:
|
||||
"""Metrics tree node."""
|
||||
|
||||
@@ -55,7 +55,7 @@ export function buildCohortData() {
|
||||
name: shortNames.short,
|
||||
title: shortNames.long,
|
||||
color: colors.term.short,
|
||||
tree: utxoCohorts.term.short,
|
||||
tree: utxoCohorts.sth,
|
||||
};
|
||||
|
||||
const longNames = TERM_NAMES.long;
|
||||
@@ -63,7 +63,7 @@ export function buildCohortData() {
|
||||
name: longNames.short,
|
||||
title: longNames.long,
|
||||
color: colors.term.long,
|
||||
tree: utxoCohorts.term.long,
|
||||
tree: utxoCohorts.lth,
|
||||
};
|
||||
|
||||
// Max age cohorts (up to X time)
|
||||
|
||||
Reference in New Issue
Block a user