mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-16 17:59:45 -07:00
global: add cohorts by entry
This commit is contained in:
Generated
+49
-50
@@ -213,7 +213,7 @@ version = "0.72.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"bitflags 2.13.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
@@ -277,9 +277,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.12.1"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a"
|
||||
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
||||
|
||||
[[package]]
|
||||
name = "blk"
|
||||
@@ -757,9 +757,9 @@ checksum = "1c53ba0f290bfc610084c05582d9c5d421662128fc69f4bf236707af6fd321b9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.63"
|
||||
version = "1.2.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
|
||||
checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
@@ -1240,9 +1240,9 @@ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "fjall"
|
||||
version = "3.1.4"
|
||||
version = "3.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b62b25b4d815ae178d7d9e4aa32ee59f072efd5431c736abede1e6ee13c8c453"
|
||||
checksum = "038acd422d607e0eca09e093f299f9eccf9bd097554343d93746afff81a45113"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"byteview",
|
||||
@@ -1292,7 +1292,7 @@ version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c7e611d49285d4c4b2e1727b72cf05353558885cc5252f93707b845dfcaf3d3"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"bitflags 2.13.0",
|
||||
"byteorder",
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
@@ -1522,9 +1522,9 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.4.1"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0"
|
||||
checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"itoa",
|
||||
@@ -1879,13 +1879,12 @@ checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.99"
|
||||
version = "0.3.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
|
||||
checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -1999,9 +1998,9 @@ checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
||||
|
||||
[[package]]
|
||||
name = "lsm-tree"
|
||||
version = "3.1.4"
|
||||
version = "3.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e447ac67ff6aef4ec07fc19e507b219336cbba90a697c0dbeb1bf51b91536b67"
|
||||
checksum = "8ef86c3c797c10eefcc73407c43ae48c19d4df686131a8334b2895a513e91df4"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"byteview",
|
||||
@@ -2036,9 +2035,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.1"
|
||||
version = "2.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
|
||||
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
@@ -2360,9 +2359,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quick_cache"
|
||||
version = "0.6.22"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1c821816e9b928e20e92ed59bb3ac4aab321d16ca2316871c9fe7ca739cd477"
|
||||
checksum = "3a3db184a8b66cfe87f0263a1de147a6b554c864d1767c6f7fa4eb0e5497b565"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.16.1",
|
||||
@@ -2463,7 +2462,7 @@ version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"bitflags 2.13.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2499,9 +2498,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.3"
|
||||
version = "1.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
||||
checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -2522,9 +2521,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.10"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
@@ -2576,7 +2575,7 @@ version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"bitflags 2.13.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@@ -2859,9 +2858,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
version = "1.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
@@ -3144,7 +3143,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"bitflags 2.12.1",
|
||||
"bitflags 2.13.0",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
@@ -3336,9 +3335,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "varint-rs"
|
||||
version = "2.2.0"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23"
|
||||
checksum = "bfa6c38708f6257f1ec2ca7e5a11f9bbf58a27d7060078b6b333624968183d96"
|
||||
|
||||
[[package]]
|
||||
name = "vecdb"
|
||||
@@ -3397,9 +3396,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.3+wasi-0.2.9"
|
||||
version = "1.0.4+wasi-0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
||||
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
||||
dependencies = [
|
||||
"wit-bindgen 0.57.1",
|
||||
]
|
||||
@@ -3415,9 +3414,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.122"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
|
||||
checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
@@ -3428,9 +3427,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.122"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
|
||||
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -3438,9 +3437,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.122"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
|
||||
checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
@@ -3451,9 +3450,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.122"
|
||||
version = "0.2.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
|
||||
checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -3486,7 +3485,7 @@ version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||
dependencies = [
|
||||
"bitflags 2.12.1",
|
||||
"bitflags 2.13.0",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"semver",
|
||||
@@ -3494,9 +3493,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.99"
|
||||
version = "0.3.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
|
||||
checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -3768,7 +3767,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.12.1",
|
||||
"bitflags 2.13.0",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
@@ -3846,18 +3845,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.50"
|
||||
version = "0.8.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1"
|
||||
checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.50"
|
||||
version = "0.8.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639"
|
||||
checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3887,9 +3886,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.2"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ color-eyre = "0.6.5"
|
||||
corepc-jsonrpc = { package = "jsonrpc", version = "0.19.0", features = ["simple_http"], default-features = false }
|
||||
corepc-types = { version = "0.14.0", features = ["std"], default-features = false }
|
||||
derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
|
||||
fjall = "3.1.4"
|
||||
fjall = "3.1.5"
|
||||
indexmap = { version = "2.14.0", features = ["serde"] }
|
||||
jiff = { version = "0.2.28", features = ["perf-inline", "tz-system"], default-features = false }
|
||||
owo-colors = "4.3.0"
|
||||
@@ -77,7 +77,7 @@ serde = "1.0.228"
|
||||
serde_bytes = "0.11.19"
|
||||
serde_derive = "1.0.228"
|
||||
serde_json = { version = "1.0.150", features = ["float_roundtrip", "preserve_order"] }
|
||||
smallvec = "1.15.1"
|
||||
smallvec = "1.15.2"
|
||||
tokio = { version = "1.52.3", features = ["rt-multi-thread"] }
|
||||
tower-http = { version = "0.6.11", features = ["catch-panic", "compression-br", "compression-gzip", "compression-zstd", "cors", "normalize-path", "timeout", "trace"] }
|
||||
tower-layer = "0.3"
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use brk_cohort::{
|
||||
AGE_RANGE_NAMES, AMOUNT_RANGE_NAMES, CLASS_NAMES, EPOCH_NAMES, LOSS_NAMES, OVER_AGE_NAMES,
|
||||
OVER_AMOUNT_NAMES, PROFIT_NAMES, PROFITABILITY_RANGE_NAMES, SPENDABLE_TYPE_NAMES, TERM_NAMES,
|
||||
UNDER_AGE_NAMES, UNDER_AMOUNT_NAMES,
|
||||
AGE_RANGE_NAMES, AMOUNT_RANGE_NAMES, CLASS_NAMES, ENTRY_NAMES, EPOCH_NAMES, LOSS_NAMES,
|
||||
OVER_AGE_NAMES, OVER_AMOUNT_NAMES, PROFIT_NAMES, PROFITABILITY_RANGE_NAMES,
|
||||
SPENDABLE_TYPE_NAMES, TERM_NAMES, UNDER_AGE_NAMES, UNDER_AMOUNT_NAMES,
|
||||
};
|
||||
use brk_types::{Index, pools};
|
||||
use serde::Serialize;
|
||||
@@ -59,6 +59,7 @@ impl CohortConstants {
|
||||
("TERM_NAMES", to_value(&TERM_NAMES)),
|
||||
("EPOCH_NAMES", to_value(&EPOCH_NAMES)),
|
||||
("CLASS_NAMES", to_value(&CLASS_NAMES)),
|
||||
("ENTRY_NAMES", to_value(&ENTRY_NAMES)),
|
||||
("SPENDABLE_TYPE_NAMES", to_value(&SPENDABLE_TYPE_NAMES)),
|
||||
("AGE_RANGE_NAMES", to_value(&AGE_RANGE_NAMES)),
|
||||
("UNDER_AGE_NAMES", to_value(&UNDER_AGE_NAMES)),
|
||||
|
||||
+603
-18
@@ -1191,6 +1191,22 @@ pub struct CapCapitalizedGrossLossMvrvNetPeakPriceProfitSellSoprPattern {
|
||||
pub sopr: AdjustedRatioValuePattern,
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CapCapitalizedGrossLossMvrvNetPeakPriceProfitSellSoprPattern2 {
|
||||
pub cap: CentsDeltaToUsdPattern,
|
||||
pub capitalized: PricePattern,
|
||||
pub gross_pnl: BlockCumulativeSumPattern,
|
||||
pub loss: BlockCumulativeNegativeSumPattern,
|
||||
pub mvrv: SeriesPattern1<StoredF32>,
|
||||
pub net_pnl: BlockChangeCumulativeDeltaSumPattern,
|
||||
pub peak_regret: BlockCumulativeSumPattern,
|
||||
pub price: BpsCentsPercentilesRatioSatsSmaStdUsdPattern,
|
||||
pub profit: BlockCumulativeSumPattern,
|
||||
pub profit_to_loss_ratio: _1m1w1y24hPattern<StoredF64>,
|
||||
pub sell_side_risk_ratio: _1m1w1y24hPattern8,
|
||||
pub sopr: RatioValuePattern2,
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct EmptyOpP2aP2msP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshUnknownPattern2 {
|
||||
pub empty: _1m1w1y24hBpsPercentRatioPattern,
|
||||
@@ -1658,6 +1674,17 @@ pub struct ActiveInputOutputSpendablePattern {
|
||||
pub spendable_output_to_reused_addr_share: _1m1w1y24hBpsPercentRatioPattern,
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct ActivityCostInvestedOutputsRealizedSupplyUnrealizedPattern2 {
|
||||
pub activity: CoindaysCoinyearsDormancyTransferPattern,
|
||||
pub cost_basis: InMaxMinPerSupplyPattern,
|
||||
pub invested_capital: InPattern,
|
||||
pub outputs: SpendingSpentUnspentPattern,
|
||||
pub realized: CapCapitalizedGrossLossMvrvNetPeakPriceProfitSellSoprPattern2,
|
||||
pub supply: DeltaDominanceHalfInTotalPattern2,
|
||||
pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2,
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CapLossMvrvNetPriceProfitSoprPattern {
|
||||
pub cap: CentsDeltaUsdPattern,
|
||||
@@ -3408,6 +3435,22 @@ impl PriceRatioPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct RatioValuePattern2 {
|
||||
pub ratio: _1m1w1y24hPattern<StoredF64>,
|
||||
pub value_destroyed: AverageBlockCumulativeSumPattern<Cents>,
|
||||
}
|
||||
|
||||
impl RatioValuePattern2 {
|
||||
/// Create a new pattern node with accumulated series name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
ratio: _1m1w1y24hPattern::new(client.clone(), _m(&acc, "sopr")),
|
||||
value_destroyed: AverageBlockCumulativeSumPattern::new(client.clone(), _m(&acc, "value_destroyed")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct RatioValuePattern {
|
||||
pub ratio: _24hPattern,
|
||||
@@ -7199,6 +7242,7 @@ pub struct SeriesTree_Cohorts_Utxo {
|
||||
pub over_age: SeriesTree_Cohorts_Utxo_OverAge,
|
||||
pub epoch: SeriesTree_Cohorts_Utxo_Epoch,
|
||||
pub class: SeriesTree_Cohorts_Utxo_Class,
|
||||
pub entry: SeriesTree_Cohorts_Utxo_Entry,
|
||||
pub over_amount: SeriesTree_Cohorts_Utxo_OverAmount,
|
||||
pub amount_range: SeriesTree_Cohorts_Utxo_AmountRange,
|
||||
pub under_amount: SeriesTree_Cohorts_Utxo_UnderAmount,
|
||||
@@ -7218,6 +7262,7 @@ impl SeriesTree_Cohorts_Utxo {
|
||||
over_age: SeriesTree_Cohorts_Utxo_OverAge::new(client.clone(), format!("{base_path}_over_age")),
|
||||
epoch: SeriesTree_Cohorts_Utxo_Epoch::new(client.clone(), format!("{base_path}_epoch")),
|
||||
class: SeriesTree_Cohorts_Utxo_Class::new(client.clone(), format!("{base_path}_class")),
|
||||
entry: SeriesTree_Cohorts_Utxo_Entry::new(client.clone(), format!("{base_path}_entry")),
|
||||
over_amount: SeriesTree_Cohorts_Utxo_OverAmount::new(client.clone(), format!("{base_path}_over_amount")),
|
||||
amount_range: SeriesTree_Cohorts_Utxo_AmountRange::new(client.clone(), format!("{base_path}_amount_range")),
|
||||
under_amount: SeriesTree_Cohorts_Utxo_UnderAmount::new(client.clone(), format!("{base_path}_under_amount")),
|
||||
@@ -7999,7 +8044,7 @@ pub struct SeriesTree_Cohorts_Utxo_Lth_Realized {
|
||||
pub price: SeriesTree_Cohorts_Utxo_Lth_Realized_Price,
|
||||
pub mvrv: SeriesPattern1<StoredF32>,
|
||||
pub net_pnl: BlockChangeCumulativeDeltaSumPattern,
|
||||
pub sopr: SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr,
|
||||
pub sopr: RatioValuePattern2,
|
||||
pub gross_pnl: BlockCumulativeSumPattern,
|
||||
pub sell_side_risk_ratio: _1m1w1y24hPattern8,
|
||||
pub peak_regret: BlockCumulativeSumPattern,
|
||||
@@ -8016,7 +8061,7 @@ impl SeriesTree_Cohorts_Utxo_Lth_Realized {
|
||||
price: SeriesTree_Cohorts_Utxo_Lth_Realized_Price::new(client.clone(), format!("{base_path}_price")),
|
||||
mvrv: SeriesPattern1::new(client.clone(), "lth_mvrv".to_string()),
|
||||
net_pnl: BlockChangeCumulativeDeltaSumPattern::new(client.clone(), "lth_net".to_string()),
|
||||
sopr: SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr::new(client.clone(), format!("{base_path}_sopr")),
|
||||
sopr: RatioValuePattern2::new(client.clone(), "lth".to_string()),
|
||||
gross_pnl: BlockCumulativeSumPattern::new(client.clone(), "lth_realized_gross_pnl".to_string()),
|
||||
sell_side_risk_ratio: _1m1w1y24hPattern8::new(client.clone(), "lth_sell_side_risk_ratio".to_string()),
|
||||
peak_regret: BlockCumulativeSumPattern::new(client.clone(), "lth_realized_peak_regret".to_string()),
|
||||
@@ -8236,21 +8281,6 @@ impl SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev_1y {
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr {
|
||||
pub value_destroyed: AverageBlockCumulativeSumPattern<Cents>,
|
||||
pub ratio: _1m1w1y24hPattern<StoredF64>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
value_destroyed: AverageBlockCumulativeSumPattern::new(client.clone(), "lth_value_destroyed".to_string()),
|
||||
ratio: _1m1w1y24hPattern::new(client.clone(), "lth_sopr".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_AgeRange {
|
||||
pub under_1h: ActivityOutputsRealizedSupplyUnrealizedPattern,
|
||||
@@ -8466,6 +8496,561 @@ impl SeriesTree_Cohorts_Utxo_Class {
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry {
|
||||
pub discount: SeriesTree_Cohorts_Utxo_Entry_Discount,
|
||||
pub premium: SeriesTree_Cohorts_Utxo_Entry_Premium,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
discount: SeriesTree_Cohorts_Utxo_Entry_Discount::new(client.clone(), format!("{base_path}_discount")),
|
||||
premium: SeriesTree_Cohorts_Utxo_Entry_Premium::new(client.clone(), format!("{base_path}_premium")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Discount {
|
||||
pub supply: DeltaDominanceHalfInTotalPattern2,
|
||||
pub outputs: SpendingSpentUnspentPattern,
|
||||
pub activity: CoindaysCoinyearsDormancyTransferPattern,
|
||||
pub realized: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized,
|
||||
pub cost_basis: InMaxMinPerSupplyPattern,
|
||||
pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2,
|
||||
pub invested_capital: InPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Discount {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
supply: DeltaDominanceHalfInTotalPattern2::new(client.clone(), "veteran_supply".to_string()),
|
||||
outputs: SpendingSpentUnspentPattern::new(client.clone(), "veteran".to_string()),
|
||||
activity: CoindaysCoinyearsDormancyTransferPattern::new(client.clone(), "veteran".to_string()),
|
||||
realized: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized::new(client.clone(), format!("{base_path}_realized")),
|
||||
cost_basis: InMaxMinPerSupplyPattern::new(client.clone(), "veteran".to_string()),
|
||||
unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2::new(client.clone(), "veteran".to_string()),
|
||||
invested_capital: InPattern::new(client.clone(), "veteran_invested_capital_in".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Discount_Realized {
|
||||
pub cap: CentsDeltaToUsdPattern,
|
||||
pub profit: BlockCumulativeSumPattern,
|
||||
pub loss: BlockCumulativeNegativeSumPattern,
|
||||
pub price: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price,
|
||||
pub mvrv: SeriesPattern1<StoredF32>,
|
||||
pub net_pnl: BlockChangeCumulativeDeltaSumPattern,
|
||||
pub sopr: RatioValuePattern2,
|
||||
pub gross_pnl: BlockCumulativeSumPattern,
|
||||
pub sell_side_risk_ratio: _1m1w1y24hPattern8,
|
||||
pub peak_regret: BlockCumulativeSumPattern,
|
||||
pub capitalized: PricePattern,
|
||||
pub profit_to_loss_ratio: _1m1w1y24hPattern<StoredF64>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Discount_Realized {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
cap: CentsDeltaToUsdPattern::new(client.clone(), "veteran_realized_cap".to_string()),
|
||||
profit: BlockCumulativeSumPattern::new(client.clone(), "veteran_realized_profit".to_string()),
|
||||
loss: BlockCumulativeNegativeSumPattern::new(client.clone(), "veteran_realized_loss".to_string()),
|
||||
price: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price::new(client.clone(), format!("{base_path}_price")),
|
||||
mvrv: SeriesPattern1::new(client.clone(), "veteran_mvrv".to_string()),
|
||||
net_pnl: BlockChangeCumulativeDeltaSumPattern::new(client.clone(), "veteran_net".to_string()),
|
||||
sopr: RatioValuePattern2::new(client.clone(), "veteran".to_string()),
|
||||
gross_pnl: BlockCumulativeSumPattern::new(client.clone(), "veteran_realized_gross_pnl".to_string()),
|
||||
sell_side_risk_ratio: _1m1w1y24hPattern8::new(client.clone(), "veteran_sell_side_risk_ratio".to_string()),
|
||||
peak_regret: BlockCumulativeSumPattern::new(client.clone(), "veteran_realized_peak_regret".to_string()),
|
||||
capitalized: PricePattern::new(client.clone(), "veteran_capitalized_price".to_string()),
|
||||
profit_to_loss_ratio: _1m1w1y24hPattern::new(client.clone(), "veteran_realized_profit_to_loss_ratio".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price {
|
||||
pub usd: SeriesPattern1<Dollars>,
|
||||
pub cents: SeriesPattern1<Cents>,
|
||||
pub sats: SeriesPattern1<SatsFract>,
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
pub ratio: SeriesPattern1<StoredF32>,
|
||||
pub percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub sma: _1m1w1y2y4yAllPattern,
|
||||
pub std_dev: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
usd: SeriesPattern1::new(client.clone(), "veteran_realized_price".to_string()),
|
||||
cents: SeriesPattern1::new(client.clone(), "veteran_realized_price_cents".to_string()),
|
||||
sats: SeriesPattern1::new(client.clone(), "veteran_realized_price_sats".to_string()),
|
||||
bps: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_bps".to_string()),
|
||||
ratio: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio".to_string()),
|
||||
percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), "veteran_realized_price".to_string()),
|
||||
sma: _1m1w1y2y4yAllPattern::new(client.clone(), "veteran_realized_price_ratio_sma".to_string()),
|
||||
std_dev: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev::new(client.clone(), format!("{base_path}_std_dev")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev {
|
||||
pub all: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All,
|
||||
pub _4y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y,
|
||||
pub _2y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y,
|
||||
pub _1y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
all: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All::new(client.clone(), format!("{base_path}_all")),
|
||||
_4y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y::new(client.clone(), format!("{base_path}_4y")),
|
||||
_2y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y::new(client.clone(), format!("{base_path}_2y")),
|
||||
_1y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y::new(client.clone(), format!("{base_path}_1y")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All {
|
||||
pub sd: SeriesPattern1<StoredF32>,
|
||||
pub zscore: SeriesPattern1<StoredF32>,
|
||||
pub _0sd: CentsSatsUsdPattern,
|
||||
pub p0_5sd: PriceRatioPattern,
|
||||
pub p1sd: PriceRatioPattern,
|
||||
pub p1_5sd: PriceRatioPattern,
|
||||
pub p2sd: PriceRatioPattern,
|
||||
pub p2_5sd: PriceRatioPattern,
|
||||
pub p3sd: PriceRatioPattern,
|
||||
pub m0_5sd: PriceRatioPattern,
|
||||
pub m1sd: PriceRatioPattern,
|
||||
pub m1_5sd: PriceRatioPattern,
|
||||
pub m2sd: PriceRatioPattern,
|
||||
pub m2_5sd: PriceRatioPattern,
|
||||
pub m3sd: PriceRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sd: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_sd".to_string()),
|
||||
zscore: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_zscore".to_string()),
|
||||
_0sd: CentsSatsUsdPattern::new(client.clone(), "veteran_realized_price_0sd".to_string()),
|
||||
p0_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p0_5sd".to_string()),
|
||||
p1sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p1sd".to_string()),
|
||||
p1_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p1_5sd".to_string()),
|
||||
p2sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p2sd".to_string()),
|
||||
p2_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p2_5sd".to_string()),
|
||||
p3sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p3sd".to_string()),
|
||||
m0_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m0_5sd".to_string()),
|
||||
m1sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m1sd".to_string()),
|
||||
m1_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m1_5sd".to_string()),
|
||||
m2sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m2sd".to_string()),
|
||||
m2_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m2_5sd".to_string()),
|
||||
m3sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m3sd".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y {
|
||||
pub sd: SeriesPattern1<StoredF32>,
|
||||
pub zscore: SeriesPattern1<StoredF32>,
|
||||
pub _0sd: CentsSatsUsdPattern,
|
||||
pub p0_5sd: PriceRatioPattern,
|
||||
pub p1sd: PriceRatioPattern,
|
||||
pub p1_5sd: PriceRatioPattern,
|
||||
pub p2sd: PriceRatioPattern,
|
||||
pub p2_5sd: PriceRatioPattern,
|
||||
pub p3sd: PriceRatioPattern,
|
||||
pub m0_5sd: PriceRatioPattern,
|
||||
pub m1sd: PriceRatioPattern,
|
||||
pub m1_5sd: PriceRatioPattern,
|
||||
pub m2sd: PriceRatioPattern,
|
||||
pub m2_5sd: PriceRatioPattern,
|
||||
pub m3sd: PriceRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sd: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_sd_4y".to_string()),
|
||||
zscore: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_zscore_4y".to_string()),
|
||||
_0sd: CentsSatsUsdPattern::new(client.clone(), "veteran_realized_price_0sd_4y".to_string()),
|
||||
p0_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p0_5sd_4y".to_string()),
|
||||
p1sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p1sd_4y".to_string()),
|
||||
p1_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p1_5sd_4y".to_string()),
|
||||
p2sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p2sd_4y".to_string()),
|
||||
p2_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p2_5sd_4y".to_string()),
|
||||
p3sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p3sd_4y".to_string()),
|
||||
m0_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m0_5sd_4y".to_string()),
|
||||
m1sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m1sd_4y".to_string()),
|
||||
m1_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m1_5sd_4y".to_string()),
|
||||
m2sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m2sd_4y".to_string()),
|
||||
m2_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m2_5sd_4y".to_string()),
|
||||
m3sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m3sd_4y".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y {
|
||||
pub sd: SeriesPattern1<StoredF32>,
|
||||
pub zscore: SeriesPattern1<StoredF32>,
|
||||
pub _0sd: CentsSatsUsdPattern,
|
||||
pub p0_5sd: PriceRatioPattern,
|
||||
pub p1sd: PriceRatioPattern,
|
||||
pub p1_5sd: PriceRatioPattern,
|
||||
pub p2sd: PriceRatioPattern,
|
||||
pub p2_5sd: PriceRatioPattern,
|
||||
pub p3sd: PriceRatioPattern,
|
||||
pub m0_5sd: PriceRatioPattern,
|
||||
pub m1sd: PriceRatioPattern,
|
||||
pub m1_5sd: PriceRatioPattern,
|
||||
pub m2sd: PriceRatioPattern,
|
||||
pub m2_5sd: PriceRatioPattern,
|
||||
pub m3sd: PriceRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sd: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_sd_2y".to_string()),
|
||||
zscore: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_zscore_2y".to_string()),
|
||||
_0sd: CentsSatsUsdPattern::new(client.clone(), "veteran_realized_price_0sd_2y".to_string()),
|
||||
p0_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p0_5sd_2y".to_string()),
|
||||
p1sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p1sd_2y".to_string()),
|
||||
p1_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p1_5sd_2y".to_string()),
|
||||
p2sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p2sd_2y".to_string()),
|
||||
p2_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p2_5sd_2y".to_string()),
|
||||
p3sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p3sd_2y".to_string()),
|
||||
m0_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m0_5sd_2y".to_string()),
|
||||
m1sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m1sd_2y".to_string()),
|
||||
m1_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m1_5sd_2y".to_string()),
|
||||
m2sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m2sd_2y".to_string()),
|
||||
m2_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m2_5sd_2y".to_string()),
|
||||
m3sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m3sd_2y".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y {
|
||||
pub sd: SeriesPattern1<StoredF32>,
|
||||
pub zscore: SeriesPattern1<StoredF32>,
|
||||
pub _0sd: CentsSatsUsdPattern,
|
||||
pub p0_5sd: PriceRatioPattern,
|
||||
pub p1sd: PriceRatioPattern,
|
||||
pub p1_5sd: PriceRatioPattern,
|
||||
pub p2sd: PriceRatioPattern,
|
||||
pub p2_5sd: PriceRatioPattern,
|
||||
pub p3sd: PriceRatioPattern,
|
||||
pub m0_5sd: PriceRatioPattern,
|
||||
pub m1sd: PriceRatioPattern,
|
||||
pub m1_5sd: PriceRatioPattern,
|
||||
pub m2sd: PriceRatioPattern,
|
||||
pub m2_5sd: PriceRatioPattern,
|
||||
pub m3sd: PriceRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sd: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_sd_1y".to_string()),
|
||||
zscore: SeriesPattern1::new(client.clone(), "veteran_realized_price_ratio_zscore_1y".to_string()),
|
||||
_0sd: CentsSatsUsdPattern::new(client.clone(), "veteran_realized_price_0sd_1y".to_string()),
|
||||
p0_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p0_5sd_1y".to_string()),
|
||||
p1sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p1sd_1y".to_string()),
|
||||
p1_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p1_5sd_1y".to_string()),
|
||||
p2sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p2sd_1y".to_string()),
|
||||
p2_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p2_5sd_1y".to_string()),
|
||||
p3sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "p3sd_1y".to_string()),
|
||||
m0_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m0_5sd_1y".to_string()),
|
||||
m1sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m1sd_1y".to_string()),
|
||||
m1_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m1_5sd_1y".to_string()),
|
||||
m2sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m2sd_1y".to_string()),
|
||||
m2_5sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m2_5sd_1y".to_string()),
|
||||
m3sd: PriceRatioPattern::new(client.clone(), "veteran_realized_price".to_string(), "m3sd_1y".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Premium {
|
||||
pub supply: DeltaDominanceHalfInTotalPattern2,
|
||||
pub outputs: SpendingSpentUnspentPattern,
|
||||
pub activity: CoindaysCoinyearsDormancyTransferPattern,
|
||||
pub realized: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized,
|
||||
pub cost_basis: InMaxMinPerSupplyPattern,
|
||||
pub unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2,
|
||||
pub invested_capital: InPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Premium {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
supply: DeltaDominanceHalfInTotalPattern2::new(client.clone(), "rookie_supply".to_string()),
|
||||
outputs: SpendingSpentUnspentPattern::new(client.clone(), "rookie".to_string()),
|
||||
activity: CoindaysCoinyearsDormancyTransferPattern::new(client.clone(), "rookie".to_string()),
|
||||
realized: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized::new(client.clone(), format!("{base_path}_realized")),
|
||||
cost_basis: InMaxMinPerSupplyPattern::new(client.clone(), "rookie".to_string()),
|
||||
unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2::new(client.clone(), "rookie".to_string()),
|
||||
invested_capital: InPattern::new(client.clone(), "rookie_invested_capital_in".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Premium_Realized {
|
||||
pub cap: CentsDeltaToUsdPattern,
|
||||
pub profit: BlockCumulativeSumPattern,
|
||||
pub loss: BlockCumulativeNegativeSumPattern,
|
||||
pub price: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price,
|
||||
pub mvrv: SeriesPattern1<StoredF32>,
|
||||
pub net_pnl: BlockChangeCumulativeDeltaSumPattern,
|
||||
pub sopr: RatioValuePattern2,
|
||||
pub gross_pnl: BlockCumulativeSumPattern,
|
||||
pub sell_side_risk_ratio: _1m1w1y24hPattern8,
|
||||
pub peak_regret: BlockCumulativeSumPattern,
|
||||
pub capitalized: PricePattern,
|
||||
pub profit_to_loss_ratio: _1m1w1y24hPattern<StoredF64>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Premium_Realized {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
cap: CentsDeltaToUsdPattern::new(client.clone(), "rookie_realized_cap".to_string()),
|
||||
profit: BlockCumulativeSumPattern::new(client.clone(), "rookie_realized_profit".to_string()),
|
||||
loss: BlockCumulativeNegativeSumPattern::new(client.clone(), "rookie_realized_loss".to_string()),
|
||||
price: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price::new(client.clone(), format!("{base_path}_price")),
|
||||
mvrv: SeriesPattern1::new(client.clone(), "rookie_mvrv".to_string()),
|
||||
net_pnl: BlockChangeCumulativeDeltaSumPattern::new(client.clone(), "rookie_net".to_string()),
|
||||
sopr: RatioValuePattern2::new(client.clone(), "rookie".to_string()),
|
||||
gross_pnl: BlockCumulativeSumPattern::new(client.clone(), "rookie_realized_gross_pnl".to_string()),
|
||||
sell_side_risk_ratio: _1m1w1y24hPattern8::new(client.clone(), "rookie_sell_side_risk_ratio".to_string()),
|
||||
peak_regret: BlockCumulativeSumPattern::new(client.clone(), "rookie_realized_peak_regret".to_string()),
|
||||
capitalized: PricePattern::new(client.clone(), "rookie_capitalized_price".to_string()),
|
||||
profit_to_loss_ratio: _1m1w1y24hPattern::new(client.clone(), "rookie_realized_profit_to_loss_ratio".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price {
|
||||
pub usd: SeriesPattern1<Dollars>,
|
||||
pub cents: SeriesPattern1<Cents>,
|
||||
pub sats: SeriesPattern1<SatsFract>,
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
pub ratio: SeriesPattern1<StoredF32>,
|
||||
pub percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub sma: _1m1w1y2y4yAllPattern,
|
||||
pub std_dev: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
usd: SeriesPattern1::new(client.clone(), "rookie_realized_price".to_string()),
|
||||
cents: SeriesPattern1::new(client.clone(), "rookie_realized_price_cents".to_string()),
|
||||
sats: SeriesPattern1::new(client.clone(), "rookie_realized_price_sats".to_string()),
|
||||
bps: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_bps".to_string()),
|
||||
ratio: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio".to_string()),
|
||||
percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), "rookie_realized_price".to_string()),
|
||||
sma: _1m1w1y2y4yAllPattern::new(client.clone(), "rookie_realized_price_ratio_sma".to_string()),
|
||||
std_dev: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev::new(client.clone(), format!("{base_path}_std_dev")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev {
|
||||
pub all: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All,
|
||||
pub _4y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y,
|
||||
pub _2y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y,
|
||||
pub _1y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
all: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All::new(client.clone(), format!("{base_path}_all")),
|
||||
_4y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y::new(client.clone(), format!("{base_path}_4y")),
|
||||
_2y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y::new(client.clone(), format!("{base_path}_2y")),
|
||||
_1y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y::new(client.clone(), format!("{base_path}_1y")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All {
|
||||
pub sd: SeriesPattern1<StoredF32>,
|
||||
pub zscore: SeriesPattern1<StoredF32>,
|
||||
pub _0sd: CentsSatsUsdPattern,
|
||||
pub p0_5sd: PriceRatioPattern,
|
||||
pub p1sd: PriceRatioPattern,
|
||||
pub p1_5sd: PriceRatioPattern,
|
||||
pub p2sd: PriceRatioPattern,
|
||||
pub p2_5sd: PriceRatioPattern,
|
||||
pub p3sd: PriceRatioPattern,
|
||||
pub m0_5sd: PriceRatioPattern,
|
||||
pub m1sd: PriceRatioPattern,
|
||||
pub m1_5sd: PriceRatioPattern,
|
||||
pub m2sd: PriceRatioPattern,
|
||||
pub m2_5sd: PriceRatioPattern,
|
||||
pub m3sd: PriceRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sd: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_sd".to_string()),
|
||||
zscore: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_zscore".to_string()),
|
||||
_0sd: CentsSatsUsdPattern::new(client.clone(), "rookie_realized_price_0sd".to_string()),
|
||||
p0_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p0_5sd".to_string()),
|
||||
p1sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p1sd".to_string()),
|
||||
p1_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p1_5sd".to_string()),
|
||||
p2sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p2sd".to_string()),
|
||||
p2_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p2_5sd".to_string()),
|
||||
p3sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p3sd".to_string()),
|
||||
m0_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m0_5sd".to_string()),
|
||||
m1sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m1sd".to_string()),
|
||||
m1_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m1_5sd".to_string()),
|
||||
m2sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m2sd".to_string()),
|
||||
m2_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m2_5sd".to_string()),
|
||||
m3sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m3sd".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y {
|
||||
pub sd: SeriesPattern1<StoredF32>,
|
||||
pub zscore: SeriesPattern1<StoredF32>,
|
||||
pub _0sd: CentsSatsUsdPattern,
|
||||
pub p0_5sd: PriceRatioPattern,
|
||||
pub p1sd: PriceRatioPattern,
|
||||
pub p1_5sd: PriceRatioPattern,
|
||||
pub p2sd: PriceRatioPattern,
|
||||
pub p2_5sd: PriceRatioPattern,
|
||||
pub p3sd: PriceRatioPattern,
|
||||
pub m0_5sd: PriceRatioPattern,
|
||||
pub m1sd: PriceRatioPattern,
|
||||
pub m1_5sd: PriceRatioPattern,
|
||||
pub m2sd: PriceRatioPattern,
|
||||
pub m2_5sd: PriceRatioPattern,
|
||||
pub m3sd: PriceRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sd: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_sd_4y".to_string()),
|
||||
zscore: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_zscore_4y".to_string()),
|
||||
_0sd: CentsSatsUsdPattern::new(client.clone(), "rookie_realized_price_0sd_4y".to_string()),
|
||||
p0_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p0_5sd_4y".to_string()),
|
||||
p1sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p1sd_4y".to_string()),
|
||||
p1_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p1_5sd_4y".to_string()),
|
||||
p2sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p2sd_4y".to_string()),
|
||||
p2_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p2_5sd_4y".to_string()),
|
||||
p3sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p3sd_4y".to_string()),
|
||||
m0_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m0_5sd_4y".to_string()),
|
||||
m1sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m1sd_4y".to_string()),
|
||||
m1_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m1_5sd_4y".to_string()),
|
||||
m2sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m2sd_4y".to_string()),
|
||||
m2_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m2_5sd_4y".to_string()),
|
||||
m3sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m3sd_4y".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y {
|
||||
pub sd: SeriesPattern1<StoredF32>,
|
||||
pub zscore: SeriesPattern1<StoredF32>,
|
||||
pub _0sd: CentsSatsUsdPattern,
|
||||
pub p0_5sd: PriceRatioPattern,
|
||||
pub p1sd: PriceRatioPattern,
|
||||
pub p1_5sd: PriceRatioPattern,
|
||||
pub p2sd: PriceRatioPattern,
|
||||
pub p2_5sd: PriceRatioPattern,
|
||||
pub p3sd: PriceRatioPattern,
|
||||
pub m0_5sd: PriceRatioPattern,
|
||||
pub m1sd: PriceRatioPattern,
|
||||
pub m1_5sd: PriceRatioPattern,
|
||||
pub m2sd: PriceRatioPattern,
|
||||
pub m2_5sd: PriceRatioPattern,
|
||||
pub m3sd: PriceRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sd: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_sd_2y".to_string()),
|
||||
zscore: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_zscore_2y".to_string()),
|
||||
_0sd: CentsSatsUsdPattern::new(client.clone(), "rookie_realized_price_0sd_2y".to_string()),
|
||||
p0_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p0_5sd_2y".to_string()),
|
||||
p1sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p1sd_2y".to_string()),
|
||||
p1_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p1_5sd_2y".to_string()),
|
||||
p2sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p2sd_2y".to_string()),
|
||||
p2_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p2_5sd_2y".to_string()),
|
||||
p3sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p3sd_2y".to_string()),
|
||||
m0_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m0_5sd_2y".to_string()),
|
||||
m1sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m1sd_2y".to_string()),
|
||||
m1_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m1_5sd_2y".to_string()),
|
||||
m2sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m2sd_2y".to_string()),
|
||||
m2_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m2_5sd_2y".to_string()),
|
||||
m3sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m3sd_2y".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y {
|
||||
pub sd: SeriesPattern1<StoredF32>,
|
||||
pub zscore: SeriesPattern1<StoredF32>,
|
||||
pub _0sd: CentsSatsUsdPattern,
|
||||
pub p0_5sd: PriceRatioPattern,
|
||||
pub p1sd: PriceRatioPattern,
|
||||
pub p1_5sd: PriceRatioPattern,
|
||||
pub p2sd: PriceRatioPattern,
|
||||
pub p2_5sd: PriceRatioPattern,
|
||||
pub p3sd: PriceRatioPattern,
|
||||
pub m0_5sd: PriceRatioPattern,
|
||||
pub m1sd: PriceRatioPattern,
|
||||
pub m1_5sd: PriceRatioPattern,
|
||||
pub m2sd: PriceRatioPattern,
|
||||
pub m2_5sd: PriceRatioPattern,
|
||||
pub m3sd: PriceRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sd: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_sd_1y".to_string()),
|
||||
zscore: SeriesPattern1::new(client.clone(), "rookie_realized_price_ratio_zscore_1y".to_string()),
|
||||
_0sd: CentsSatsUsdPattern::new(client.clone(), "rookie_realized_price_0sd_1y".to_string()),
|
||||
p0_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p0_5sd_1y".to_string()),
|
||||
p1sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p1sd_1y".to_string()),
|
||||
p1_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p1_5sd_1y".to_string()),
|
||||
p2sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p2sd_1y".to_string()),
|
||||
p2_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p2_5sd_1y".to_string()),
|
||||
p3sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "p3sd_1y".to_string()),
|
||||
m0_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m0_5sd_1y".to_string()),
|
||||
m1sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m1sd_1y".to_string()),
|
||||
m1_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m1_5sd_1y".to_string()),
|
||||
m2sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m2sd_1y".to_string()),
|
||||
m2_5sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m2_5sd_1y".to_string()),
|
||||
m3sd: PriceRatioPattern::new(client.clone(), "rookie_realized_price".to_string(), "m3sd_1y".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Cohorts_Utxo_OverAmount {
|
||||
pub _1sat: ActivityOutputsRealizedSupplyUnrealizedPattern2,
|
||||
@@ -8953,7 +9538,7 @@ pub struct BrkClient {
|
||||
|
||||
impl BrkClient {
|
||||
/// Client version.
|
||||
pub const VERSION: &'static str = "v0.3.2";
|
||||
pub const VERSION: &'static str = "v0.3.3";
|
||||
|
||||
/// Create a new client with the given base URL.
|
||||
pub fn new(base_url: impl Into<String>) -> Self {
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
use brk_traversable::Traversable;
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
use serde::Serialize;
|
||||
|
||||
use super::{CohortName, Filter};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EntryPrice {
|
||||
Discount,
|
||||
Premium,
|
||||
}
|
||||
|
||||
impl EntryPrice {
|
||||
#[inline]
|
||||
pub const fn from_is_discount(is_discount: bool) -> Self {
|
||||
if is_discount {
|
||||
Self::Discount
|
||||
} else {
|
||||
Self::Premium
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn is_discount(self) -> bool {
|
||||
matches!(self, Self::Discount)
|
||||
}
|
||||
}
|
||||
|
||||
pub const ENTRY_FILTERS: ByEntry<Filter> = ByEntry {
|
||||
discount: Filter::Entry(EntryPrice::Discount),
|
||||
premium: Filter::Entry(EntryPrice::Premium),
|
||||
};
|
||||
|
||||
pub const ENTRY_NAMES: ByEntry<CohortName> = ByEntry {
|
||||
discount: CohortName::new("veteran", "Veteran", "Veteran Coins"),
|
||||
premium: CohortName::new("rookie", "Rookie", "Rookie Coins"),
|
||||
};
|
||||
|
||||
#[derive(Default, Clone, Traversable, Serialize)]
|
||||
pub struct ByEntry<T> {
|
||||
pub discount: T,
|
||||
pub premium: T,
|
||||
}
|
||||
|
||||
impl ByEntry<CohortName> {
|
||||
pub const fn names() -> &'static Self {
|
||||
&ENTRY_NAMES
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByEntry<T> {
|
||||
pub fn new<F>(mut create: F) -> Self
|
||||
where
|
||||
F: FnMut(Filter, &'static str) -> T,
|
||||
{
|
||||
let f = ENTRY_FILTERS;
|
||||
let n = ENTRY_NAMES;
|
||||
Self {
|
||||
discount: create(f.discount, n.discount.id),
|
||||
premium: create(f.premium, n.premium.id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_new<F, E>(mut create: F) -> Result<Self, E>
|
||||
where
|
||||
F: FnMut(Filter, &'static str) -> Result<T, E>,
|
||||
{
|
||||
let f = ENTRY_FILTERS;
|
||||
let n = ENTRY_NAMES;
|
||||
Ok(Self {
|
||||
discount: create(f.discount, n.discount.id)?,
|
||||
premium: create(f.premium, n.premium.id)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get(&self, entry: EntryPrice) -> &T {
|
||||
match entry {
|
||||
EntryPrice::Discount => &self.discount,
|
||||
EntryPrice::Premium => &self.premium,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, entry: EntryPrice) -> &mut T {
|
||||
match entry {
|
||||
EntryPrice::Discount => &mut self.discount,
|
||||
EntryPrice::Premium => &mut self.premium,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
[&self.discount, &self.premium].into_iter()
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
|
||||
[&mut self.discount, &mut self.premium].into_iter()
|
||||
}
|
||||
|
||||
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
{
|
||||
[&mut self.discount, &mut self.premium].into_par_iter()
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ impl CohortContext {
|
||||
/// Build full name for a filter, adding prefix only for Time/Amount filters.
|
||||
///
|
||||
/// Prefix rules:
|
||||
/// - No prefix: `All`, `Term`, `Epoch`, `Class`, `Type`
|
||||
/// - No prefix: `All`, `Term`, `Epoch`, `Class`, `Entry`, `Type`
|
||||
/// - Context prefix: `Time`, `Amount`
|
||||
pub fn full_name(&self, filter: &Filter, name: &str) -> String {
|
||||
match filter {
|
||||
@@ -32,6 +32,7 @@ impl CohortContext {
|
||||
| Filter::Term(_)
|
||||
| Filter::Epoch(_)
|
||||
| Filter::Class(_)
|
||||
| Filter::Entry(_)
|
||||
| Filter::Type(_) => name.to_string(),
|
||||
Filter::Time(_) | Filter::Amount(_) => self.prefixed(name),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_types::{Halving, OutputType, Sats, Year};
|
||||
|
||||
use super::{AmountFilter, CohortContext, Term, TimeFilter};
|
||||
use super::{AmountFilter, CohortContext, EntryPrice, Term, TimeFilter};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Filter {
|
||||
@@ -10,6 +10,7 @@ pub enum Filter {
|
||||
Amount(AmountFilter),
|
||||
Epoch(Halving),
|
||||
Class(Year),
|
||||
Entry(EntryPrice),
|
||||
Type(OutputType),
|
||||
}
|
||||
|
||||
@@ -68,7 +69,8 @@ impl Filter {
|
||||
}
|
||||
|
||||
/// Whether to compute extended metrics (realized cap ratios, profit/loss ratios, percentiles)
|
||||
/// For UTXO context: true only for age range cohorts (Range) and aggregate cohorts (All, Term)
|
||||
/// For UTXO context: true for age range cohorts (Range), aggregate cohorts (All, Term),
|
||||
/// and immutable entry valuation cohorts.
|
||||
/// For address context: always false
|
||||
pub fn is_extended(&self, context: CohortContext) -> bool {
|
||||
match context {
|
||||
@@ -76,7 +78,10 @@ impl Filter {
|
||||
CohortContext::Utxo => {
|
||||
matches!(
|
||||
self,
|
||||
Filter::All | Filter::Term(_) | Filter::Time(TimeFilter::Range(_))
|
||||
Filter::All
|
||||
| Filter::Term(_)
|
||||
| Filter::Time(TimeFilter::Range(_))
|
||||
| Filter::Entry(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ mod amount_range;
|
||||
mod by_addr_type;
|
||||
mod by_any_addr;
|
||||
mod by_epoch;
|
||||
mod by_entry;
|
||||
mod by_term;
|
||||
mod by_type;
|
||||
mod class;
|
||||
@@ -36,6 +37,7 @@ pub use amount_range::*;
|
||||
pub use by_addr_type::*;
|
||||
pub use by_any_addr::*;
|
||||
pub use by_epoch::*;
|
||||
pub use by_entry::*;
|
||||
pub use by_term::*;
|
||||
pub use by_type::*;
|
||||
pub use class::*;
|
||||
|
||||
@@ -2,8 +2,8 @@ use brk_traversable::Traversable;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::{
|
||||
AgeRange, AmountRange, ByEpoch, ByTerm, Class, Filter, OverAge, OverAmount, SpendableType,
|
||||
UnderAge, UnderAmount,
|
||||
AgeRange, AmountRange, ByEntry, ByEpoch, ByTerm, Class, Filter, OverAge, OverAmount,
|
||||
SpendableType, UnderAge, UnderAmount,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone, Traversable)]
|
||||
@@ -12,6 +12,7 @@ pub struct UTXOGroups<T> {
|
||||
pub age_range: AgeRange<T>,
|
||||
pub epoch: ByEpoch<T>,
|
||||
pub class: Class<T>,
|
||||
pub entry: ByEntry<T>,
|
||||
pub over_age: OverAge<T>,
|
||||
pub over_amount: OverAmount<T>,
|
||||
pub amount_range: AmountRange<T>,
|
||||
@@ -31,6 +32,7 @@ impl<T> UTXOGroups<T> {
|
||||
age_range: AgeRange::new(&mut create),
|
||||
epoch: ByEpoch::new(&mut create),
|
||||
class: Class::new(&mut create),
|
||||
entry: ByEntry::new(&mut create),
|
||||
over_age: OverAge::new(&mut create),
|
||||
over_amount: OverAmount::new(&mut create),
|
||||
amount_range: AmountRange::new(&mut create),
|
||||
@@ -51,6 +53,7 @@ impl<T> UTXOGroups<T> {
|
||||
.chain(self.age_range.iter())
|
||||
.chain(self.epoch.iter())
|
||||
.chain(self.class.iter())
|
||||
.chain(self.entry.iter())
|
||||
.chain(self.amount_range.iter())
|
||||
.chain(self.under_amount.iter())
|
||||
.chain(self.type_.iter())
|
||||
@@ -66,6 +69,7 @@ impl<T> UTXOGroups<T> {
|
||||
.chain(self.age_range.iter_mut())
|
||||
.chain(self.epoch.iter_mut())
|
||||
.chain(self.class.iter_mut())
|
||||
.chain(self.entry.iter_mut())
|
||||
.chain(self.amount_range.iter_mut())
|
||||
.chain(self.under_amount.iter_mut())
|
||||
.chain(self.type_.iter_mut())
|
||||
@@ -84,6 +88,7 @@ impl<T> UTXOGroups<T> {
|
||||
.chain(self.age_range.par_iter_mut())
|
||||
.chain(self.epoch.par_iter_mut())
|
||||
.chain(self.class.par_iter_mut())
|
||||
.chain(self.entry.par_iter_mut())
|
||||
.chain(self.amount_range.par_iter_mut())
|
||||
.chain(self.under_amount.par_iter_mut())
|
||||
.chain(self.type_.par_iter_mut())
|
||||
@@ -94,6 +99,7 @@ impl<T> UTXOGroups<T> {
|
||||
.iter()
|
||||
.chain(self.epoch.iter())
|
||||
.chain(self.class.iter())
|
||||
.chain(self.entry.iter())
|
||||
.chain(self.amount_range.iter())
|
||||
.chain(self.type_.iter())
|
||||
}
|
||||
@@ -103,6 +109,7 @@ impl<T> UTXOGroups<T> {
|
||||
.iter_mut()
|
||||
.chain(self.epoch.iter_mut())
|
||||
.chain(self.class.iter_mut())
|
||||
.chain(self.entry.iter_mut())
|
||||
.chain(self.amount_range.iter_mut())
|
||||
.chain(self.type_.iter_mut())
|
||||
}
|
||||
@@ -115,6 +122,7 @@ impl<T> UTXOGroups<T> {
|
||||
.par_iter_mut()
|
||||
.chain(self.epoch.par_iter_mut())
|
||||
.chain(self.class.par_iter_mut())
|
||||
.chain(self.entry.par_iter_mut())
|
||||
.chain(self.amount_range.par_iter_mut())
|
||||
.chain(self.type_.par_iter_mut())
|
||||
}
|
||||
|
||||
@@ -30,18 +30,34 @@ const TREE_SIZE: usize = TIER0_COUNT + TIER1_COUNT + OVERFLOW; // 190,001
|
||||
pub(super) struct CostBasisNode {
|
||||
all_sats: i64,
|
||||
sth_sats: i64,
|
||||
discount_sats: i64,
|
||||
all_usd: i128,
|
||||
sth_usd: i128,
|
||||
discount_usd: i128,
|
||||
}
|
||||
|
||||
impl CostBasisNode {
|
||||
#[inline(always)]
|
||||
fn new(sats: i64, usd: i128, is_sth: bool) -> Self {
|
||||
fn new_supply(sats: i64, usd: i128, is_sth: bool) -> Self {
|
||||
Self {
|
||||
all_sats: sats,
|
||||
sth_sats: if is_sth { sats } else { 0 },
|
||||
discount_sats: 0,
|
||||
all_usd: usd,
|
||||
sth_usd: if is_sth { usd } else { 0 },
|
||||
discount_usd: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn new_discount(sats: i64, usd: i128) -> Self {
|
||||
Self {
|
||||
all_sats: 0,
|
||||
sth_sats: 0,
|
||||
discount_sats: sats,
|
||||
all_usd: 0,
|
||||
sth_usd: 0,
|
||||
discount_usd: usd,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,8 +67,10 @@ impl FenwickNode for CostBasisNode {
|
||||
fn add_assign(&mut self, other: &Self) {
|
||||
self.all_sats += other.all_sats;
|
||||
self.sth_sats += other.sth_sats;
|
||||
self.discount_sats += other.discount_sats;
|
||||
self.all_usd += other.all_usd;
|
||||
self.sth_usd += other.sth_usd;
|
||||
self.discount_usd += other.discount_usd;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,16 +169,34 @@ impl CostBasisFenwick {
|
||||
}
|
||||
let bucket = price_to_bucket(price);
|
||||
let delta =
|
||||
CostBasisNode::new(net_sats, price.as_u128() as i128 * net_sats as i128, is_sth);
|
||||
CostBasisNode::new_supply(net_sats, price.as_u128() as i128 * net_sats as i128, is_sth);
|
||||
self.tree.add(bucket, &delta);
|
||||
self.totals.add_assign(&delta);
|
||||
}
|
||||
|
||||
/// Bulk-initialize from BTreeMaps (one per age-range cohort).
|
||||
/// Call after state import when all pending maps have been drained.
|
||||
pub(super) fn bulk_init<'a>(
|
||||
/// Apply a net delta from the discount-entry cohort.
|
||||
///
|
||||
/// Supply totals are maintained from the age-range cohorts; this updates
|
||||
/// only the discount-entry partition so premium can be derived as all - discount.
|
||||
pub(super) fn apply_discount_delta(&mut self, price: CentsCompact, pending: &PendingDelta) {
|
||||
let net_sats = u64::from(pending.inc) as i64 - u64::from(pending.dec) as i64;
|
||||
if net_sats == 0 {
|
||||
return;
|
||||
}
|
||||
let bucket = price_to_bucket(price);
|
||||
let delta =
|
||||
CostBasisNode::new_discount(net_sats, price.as_u128() as i128 * net_sats as i128);
|
||||
self.tree.add(bucket, &delta);
|
||||
self.totals.add_assign(&delta);
|
||||
}
|
||||
|
||||
/// Bulk-initialize from age-range maps plus the discount-entry map.
|
||||
/// Age-range maps maintain all/STH/LTH totals; the discount-entry map
|
||||
/// maintains only the discount partition used to derive premium.
|
||||
pub(super) fn bulk_init_with_discount<'a>(
|
||||
&mut self,
|
||||
maps: impl Iterator<Item = (&'a std::collections::BTreeMap<CentsCompact, Sats>, bool)>,
|
||||
discount_maps: impl Iterator<Item = &'a std::collections::BTreeMap<CentsCompact, Sats>>,
|
||||
) {
|
||||
self.tree.reset();
|
||||
self.totals = CostBasisNode::default();
|
||||
@@ -169,7 +205,18 @@ impl CostBasisFenwick {
|
||||
for (&price, &sats) in map.iter() {
|
||||
let bucket = price_to_bucket(price);
|
||||
let s = u64::from(sats) as i64;
|
||||
let node = CostBasisNode::new(s, price.as_u128() as i128 * s as i128, is_sth);
|
||||
let node =
|
||||
CostBasisNode::new_supply(s, price.as_u128() as i128 * s as i128, is_sth);
|
||||
self.tree.add_raw(bucket, &node);
|
||||
self.totals.add_assign(&node);
|
||||
}
|
||||
}
|
||||
|
||||
for map in discount_maps {
|
||||
for (&price, &sats) in map.iter() {
|
||||
let bucket = price_to_bucket(price);
|
||||
let s = u64::from(sats) as i64;
|
||||
let node = CostBasisNode::new_discount(s, price.as_u128() as i128 * s as i128);
|
||||
self.tree.add_raw(bucket, &node);
|
||||
self.totals.add_assign(&node);
|
||||
}
|
||||
@@ -212,6 +259,26 @@ impl CostBasisFenwick {
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute percentile prices for discount-entry cohort.
|
||||
pub(super) fn percentiles_discount_entry(&self) -> PercentileResult {
|
||||
self.compute_percentiles(
|
||||
self.totals.discount_sats,
|
||||
self.totals.discount_usd,
|
||||
|n| n.discount_sats,
|
||||
|n| n.discount_usd,
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute percentile prices for premium-entry cohort (all - discount).
|
||||
pub(super) fn percentiles_premium_entry(&self) -> PercentileResult {
|
||||
self.compute_percentiles(
|
||||
self.totals.all_sats - self.totals.discount_sats,
|
||||
self.totals.all_usd - self.totals.discount_usd,
|
||||
|n| n.all_sats - n.discount_sats,
|
||||
|n| n.all_usd - n.discount_usd,
|
||||
)
|
||||
}
|
||||
|
||||
fn compute_percentiles(
|
||||
&self,
|
||||
total_sats: i64,
|
||||
@@ -271,6 +338,37 @@ impl CostBasisFenwick {
|
||||
return (0, 0, 0);
|
||||
}
|
||||
|
||||
let range = self.density_range(spot_price);
|
||||
let all_range = range.all_sats.max(0);
|
||||
let sth_range = range.sth_sats.max(0);
|
||||
let lth_range = all_range - sth_range;
|
||||
|
||||
let lth_total = self.totals.all_sats - self.totals.sth_sats;
|
||||
(
|
||||
Self::to_bps(all_range, self.totals.all_sats),
|
||||
Self::to_bps(sth_range, self.totals.sth_sats),
|
||||
Self::to_bps(lth_range, lth_total),
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute supply density for entry cohorts: (discount_bps, premium_bps).
|
||||
pub(super) fn entry_density(&self, spot_price: Cents) -> (u16, u16) {
|
||||
if self.totals.all_sats <= 0 {
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
let range = self.density_range(spot_price);
|
||||
let discount_range = range.discount_sats.max(0);
|
||||
let premium_range = range.all_sats.max(0) - discount_range;
|
||||
let premium_total = self.totals.all_sats - self.totals.discount_sats;
|
||||
|
||||
(
|
||||
Self::to_bps(discount_range, self.totals.discount_sats),
|
||||
Self::to_bps(premium_range, premium_total),
|
||||
)
|
||||
}
|
||||
|
||||
fn density_range(&self, spot_price: Cents) -> CostBasisNode {
|
||||
let spot_f64 = u64::from(spot_price) as f64;
|
||||
let low = Cents::from((spot_f64 * 0.95) as u64);
|
||||
let high = Cents::from((spot_f64 * 1.05) as u64);
|
||||
@@ -285,24 +383,23 @@ impl CostBasisFenwick {
|
||||
CostBasisNode::default()
|
||||
};
|
||||
|
||||
let all_range = (cum_high.all_sats - cum_low.all_sats).max(0);
|
||||
let sth_range = (cum_high.sth_sats - cum_low.sth_sats).max(0);
|
||||
let lth_range = all_range - sth_range;
|
||||
CostBasisNode {
|
||||
all_sats: cum_high.all_sats - cum_low.all_sats,
|
||||
sth_sats: cum_high.sth_sats - cum_low.sth_sats,
|
||||
discount_sats: cum_high.discount_sats - cum_low.discount_sats,
|
||||
all_usd: cum_high.all_usd - cum_low.all_usd,
|
||||
sth_usd: cum_high.sth_usd - cum_low.sth_usd,
|
||||
discount_usd: cum_high.discount_usd - cum_low.discount_usd,
|
||||
}
|
||||
}
|
||||
|
||||
let to_bps = |range: i64, total: i64| -> u16 {
|
||||
if total <= 0 {
|
||||
0
|
||||
} else {
|
||||
(range as f64 / total as f64 * 10000.0).round() as u16
|
||||
}
|
||||
};
|
||||
|
||||
let lth_total = self.totals.all_sats - self.totals.sth_sats;
|
||||
(
|
||||
to_bps(all_range, self.totals.all_sats),
|
||||
to_bps(sth_range, self.totals.sth_sats),
|
||||
to_bps(lth_range, lth_total),
|
||||
)
|
||||
#[inline(always)]
|
||||
fn to_bps(range: i64, total: i64) -> u16 {
|
||||
if total <= 0 {
|
||||
0
|
||||
} else {
|
||||
(range as f64 / total as f64 * 10000.0).round() as u16
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_cohort::{
|
||||
AgeRange, AmountRange, ByEpoch, Class, CohortContext, Filter, Filtered, OverAge, OverAmount,
|
||||
SpendableType, Term, UnderAge, UnderAmount,
|
||||
AgeRange, AmountRange, ByEntry, ByEpoch, Class, CohortContext, Filter, Filtered, OverAge,
|
||||
OverAmount, SpendableType, Term, UnderAge, UnderAmount,
|
||||
};
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
@@ -16,7 +16,6 @@ use vecdb::{
|
||||
use crate::{
|
||||
blocks,
|
||||
distribution::{
|
||||
DynCohortVecs,
|
||||
metrics::{
|
||||
AllCohortMetrics, BasicCohortMetrics, CohortMetricsBase, CoreCohortMetrics,
|
||||
ExtendedAdjustedCohortMetrics, ExtendedCohortMetrics, ImportConfig,
|
||||
@@ -24,6 +23,7 @@ use crate::{
|
||||
TypeCohortMetrics,
|
||||
},
|
||||
state::UTXOCohortState,
|
||||
DynCohortVecs,
|
||||
},
|
||||
indexes,
|
||||
internal::{ValuePerBlockCumulativeRolling, WindowStartVec, Windows},
|
||||
@@ -45,6 +45,7 @@ pub struct UTXOCohorts<M: StorageMode = Rw> {
|
||||
pub over_age: OverAge<UTXOCohortVecs<CoreCohortMetrics<M>>>,
|
||||
pub epoch: ByEpoch<UTXOCohortVecs<CoreCohortMetrics<M>>>,
|
||||
pub class: Class<UTXOCohortVecs<CoreCohortMetrics<M>>>,
|
||||
pub entry: ByEntry<UTXOCohortVecs<ExtendedCohortMetrics<M>>>,
|
||||
pub over_amount: OverAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
|
||||
pub amount_range: AmountRange<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
|
||||
pub under_amount: UnderAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
|
||||
@@ -67,8 +68,10 @@ pub(crate) struct UTXOCohortsTransientState {
|
||||
}
|
||||
|
||||
impl UTXOCohorts<Rw> {
|
||||
/// ~71 separate cohorts (21 age + 5 epoch + 18 class + 15 amount + 12 type)
|
||||
const SEPARATE_COHORT_CAPACITY: usize = 80;
|
||||
/// Separate cohorts currently total 72:
|
||||
/// 21 age + 5 epoch + 18 class + 2 entry + 15 amount + 11 spendable type.
|
||||
/// Keep small headroom because this is only Vec allocation capacity.
|
||||
const SEPARATE_COHORT_CAPACITY: usize = 82;
|
||||
|
||||
/// Import all UTXO cohorts from database.
|
||||
pub(crate) fn forced_import(
|
||||
@@ -136,6 +139,26 @@ impl UTXOCohorts<Rw> {
|
||||
let epoch = ByEpoch::try_new(&core_separate)?;
|
||||
let class = Class::try_new(&core_separate)?;
|
||||
|
||||
let extended_separate =
|
||||
|f: Filter, name: &'static str| -> Result<UTXOCohortVecs<ExtendedCohortMetrics>> {
|
||||
let full_name = CohortContext::Utxo.full_name(&f, name);
|
||||
let cfg = ImportConfig {
|
||||
db,
|
||||
filter: &f,
|
||||
full_name: &full_name,
|
||||
version: v,
|
||||
indexes,
|
||||
cached_starts,
|
||||
};
|
||||
let state = Some(Box::new(UTXOCohortState::new(states_path, &full_name)));
|
||||
Ok(UTXOCohortVecs::new(
|
||||
state,
|
||||
ExtendedCohortMetrics::forced_import(&cfg)?,
|
||||
))
|
||||
};
|
||||
|
||||
let entry = ByEntry::try_new(&extended_separate)?;
|
||||
|
||||
// Helper for separate cohorts with MinimalCohortMetrics + MinimalRealizedState
|
||||
let minimal_separate =
|
||||
|f: Filter, name: &'static str| -> Result<UTXOCohortVecs<MinimalCohortMetrics>> {
|
||||
@@ -281,6 +304,7 @@ impl UTXOCohorts<Rw> {
|
||||
lth,
|
||||
epoch,
|
||||
class,
|
||||
entry,
|
||||
type_,
|
||||
under_age,
|
||||
over_age,
|
||||
@@ -309,6 +333,7 @@ impl UTXOCohorts<Rw> {
|
||||
sth,
|
||||
caches,
|
||||
age_range,
|
||||
entry,
|
||||
..
|
||||
} = self;
|
||||
caches
|
||||
@@ -327,7 +352,15 @@ impl UTXOCohorts<Rw> {
|
||||
Some((map, caches.fenwick.is_sth_at(i)))
|
||||
})
|
||||
.collect();
|
||||
caches.fenwick.bulk_init(maps.into_iter());
|
||||
let discount_maps = entry
|
||||
.discount
|
||||
.state
|
||||
.as_ref()
|
||||
.map(|state| state.cost_basis_map())
|
||||
.into_iter();
|
||||
caches
|
||||
.fenwick
|
||||
.bulk_init_with_discount(maps.into_iter(), discount_maps);
|
||||
}
|
||||
|
||||
/// Apply pending deltas from all age-range cohorts to the Fenwick tree.
|
||||
@@ -338,7 +371,10 @@ impl UTXOCohorts<Rw> {
|
||||
}
|
||||
// Destructure to get separate borrows on caches and age_range
|
||||
let Self {
|
||||
caches, age_range, ..
|
||||
caches,
|
||||
age_range,
|
||||
entry,
|
||||
..
|
||||
} = self;
|
||||
for (i, sub) in age_range.iter().enumerate() {
|
||||
if let Some(state) = sub.state.as_ref() {
|
||||
@@ -348,6 +384,11 @@ impl UTXOCohorts<Rw> {
|
||||
});
|
||||
}
|
||||
}
|
||||
if let Some(state) = entry.discount.state.as_ref() {
|
||||
state.for_each_cost_basis_pending(|&price, delta| {
|
||||
caches.fenwick.apply_discount_delta(price, delta);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Push maturation sats to the matured vecs for the given height.
|
||||
@@ -365,6 +406,7 @@ impl UTXOCohorts<Rw> {
|
||||
age_range,
|
||||
epoch,
|
||||
class,
|
||||
entry,
|
||||
amount_range,
|
||||
type_,
|
||||
..
|
||||
@@ -374,6 +416,7 @@ impl UTXOCohorts<Rw> {
|
||||
.map(|x| x as &mut dyn DynCohortVecs)
|
||||
.chain(epoch.par_iter_mut().map(|x| x as &mut dyn DynCohortVecs))
|
||||
.chain(class.par_iter_mut().map(|x| x as &mut dyn DynCohortVecs))
|
||||
.chain(entry.par_iter_mut().map(|x| x as &mut dyn DynCohortVecs))
|
||||
.chain(
|
||||
amount_range
|
||||
.par_iter_mut()
|
||||
@@ -389,6 +432,7 @@ impl UTXOCohorts<Rw> {
|
||||
age_range,
|
||||
epoch,
|
||||
class,
|
||||
entry,
|
||||
amount_range,
|
||||
type_,
|
||||
..
|
||||
@@ -398,6 +442,7 @@ impl UTXOCohorts<Rw> {
|
||||
.map(|x| x as &mut dyn DynCohortVecs)
|
||||
.chain(epoch.iter_mut().map(|x| x as &mut dyn DynCohortVecs))
|
||||
.chain(class.iter_mut().map(|x| x as &mut dyn DynCohortVecs))
|
||||
.chain(entry.iter_mut().map(|x| x as &mut dyn DynCohortVecs))
|
||||
.chain(amount_range.iter_mut().map(|x| x as &mut dyn DynCohortVecs))
|
||||
.chain(type_.iter_mut().map(|x| x as &mut dyn DynCohortVecs))
|
||||
}
|
||||
@@ -409,6 +454,7 @@ impl UTXOCohorts<Rw> {
|
||||
.map(|x| x as &dyn DynCohortVecs)
|
||||
.chain(self.epoch.iter().map(|x| x as &dyn DynCohortVecs))
|
||||
.chain(self.class.iter().map(|x| x as &dyn DynCohortVecs))
|
||||
.chain(self.entry.iter().map(|x| x as &dyn DynCohortVecs))
|
||||
.chain(self.amount_range.iter().map(|x| x as &dyn DynCohortVecs))
|
||||
.chain(self.type_.iter().map(|x| x as &dyn DynCohortVecs))
|
||||
}
|
||||
@@ -516,6 +562,7 @@ impl UTXOCohorts<Rw> {
|
||||
);
|
||||
all.extend(self.epoch.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
|
||||
all.extend(self.class.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
|
||||
all.extend(self.entry.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
|
||||
all.extend(
|
||||
self.amount_range
|
||||
.iter_mut()
|
||||
@@ -604,6 +651,7 @@ impl UTXOCohorts<Rw> {
|
||||
under_amount,
|
||||
epoch,
|
||||
class,
|
||||
entry,
|
||||
type_,
|
||||
..
|
||||
} = self;
|
||||
@@ -676,6 +724,19 @@ impl UTXOCohorts<Rw> {
|
||||
.compute_rest_part2(prices, starting_lengths, ss, au, exit)
|
||||
})
|
||||
}),
|
||||
Box::new(|| {
|
||||
entry.par_iter_mut().try_for_each(|v| {
|
||||
v.metrics.compute_rest_part2(
|
||||
blocks,
|
||||
prices,
|
||||
starting_lengths,
|
||||
height_to_market_cap,
|
||||
ss,
|
||||
au,
|
||||
exit,
|
||||
)
|
||||
})
|
||||
}),
|
||||
Box::new(|| {
|
||||
amount_range.par_iter_mut().try_for_each(|v| {
|
||||
v.metrics
|
||||
@@ -730,6 +791,9 @@ impl UTXOCohorts<Rw> {
|
||||
for v in self.class.iter_mut() {
|
||||
vecs.extend(v.metrics.collect_all_vecs_mut());
|
||||
}
|
||||
for v in self.entry.iter_mut() {
|
||||
vecs.extend(v.metrics.collect_all_vecs_mut());
|
||||
}
|
||||
for v in self.amount_range.iter_mut() {
|
||||
vecs.extend(v.metrics.collect_all_vecs_mut());
|
||||
}
|
||||
@@ -813,7 +877,7 @@ impl UTXOCohorts<Rw> {
|
||||
|
||||
/// Aggregate RealizedFull fields from age_range states and push to all/sth/lth.
|
||||
/// Called during the block loop after separate cohorts' push_state but before reset.
|
||||
pub(crate) fn push_overlapping(&mut self, height_price: Cents) {
|
||||
pub(crate) fn push_overlapping(&mut self, height_price: Cents) -> Cents {
|
||||
let Self {
|
||||
all,
|
||||
sth,
|
||||
@@ -852,7 +916,7 @@ impl UTXOCohorts<Rw> {
|
||||
}
|
||||
}
|
||||
|
||||
all.metrics.realized.push_accum(&all_acc);
|
||||
let all_capitalized_price = all.metrics.realized.push_accum(&all_acc);
|
||||
sth.metrics.realized.push_accum(&sth_acc);
|
||||
lth.metrics.realized.push_accum(<h_acc);
|
||||
|
||||
@@ -880,6 +944,8 @@ impl UTXOCohorts<Rw> {
|
||||
.unrealized
|
||||
.capitalized_cap_in_loss_raw
|
||||
.push(CentsSquaredSats::new(lth_ccap.1));
|
||||
|
||||
all_capitalized_price
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,22 @@ impl UTXOCohorts {
|
||||
let lth = self.caches.fenwick.percentiles_lth();
|
||||
push_cost_basis(<h, lth_d, &mut self.lth.metrics.cost_basis);
|
||||
|
||||
let (discount_d, premium_d) = self.caches.fenwick.entry_density(spot_price);
|
||||
|
||||
let discount = self.caches.fenwick.percentiles_discount_entry();
|
||||
push_cost_basis(
|
||||
&discount,
|
||||
discount_d,
|
||||
&mut self.entry.discount.metrics.cost_basis,
|
||||
);
|
||||
|
||||
let premium = self.caches.fenwick.percentiles_premium_entry();
|
||||
push_cost_basis(
|
||||
&premium,
|
||||
premium_d,
|
||||
&mut self.entry.premium.metrics.cost_basis,
|
||||
);
|
||||
|
||||
let prof = self.caches.fenwick.profitability(spot_price);
|
||||
push_profitability(&prof, &mut self.profitability);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use brk_cohort::EntryPrice;
|
||||
use brk_types::{Cents, CostBasisSnapshot, Height, Timestamp};
|
||||
use vecdb::Rw;
|
||||
|
||||
@@ -12,6 +13,7 @@ impl UTXOCohorts<Rw> {
|
||||
/// - The "under_1h" age cohort (all new UTXOs start at 0 hours old)
|
||||
/// - The appropriate epoch cohort based on block height
|
||||
/// - The appropriate class cohort based on block timestamp
|
||||
/// - The immutable entry valuation cohort based on creation price versus anchor
|
||||
/// - The appropriate output type cohort (P2PKH, P2SH, etc.)
|
||||
/// - The appropriate amount range cohort based on value
|
||||
pub(crate) fn receive(
|
||||
@@ -20,13 +22,14 @@ impl UTXOCohorts<Rw> {
|
||||
height: Height,
|
||||
timestamp: Timestamp,
|
||||
price: Cents,
|
||||
entry: EntryPrice,
|
||||
) {
|
||||
let supply_state = received.spendable_supply;
|
||||
|
||||
// Pre-compute snapshot once for the 3 cohorts sharing the same supply_state
|
||||
// Pre-compute snapshot once for cohorts sharing the block-level supply_state
|
||||
let snapshot = CostBasisSnapshot::from_utxo(price, &supply_state);
|
||||
|
||||
// New UTXOs go into under_1h, current epoch, and current class
|
||||
// New UTXOs go into under_1h plus immutable creation cohorts
|
||||
self.age_range
|
||||
.under_1h
|
||||
.state
|
||||
@@ -45,6 +48,12 @@ impl UTXOCohorts<Rw> {
|
||||
.unwrap()
|
||||
.receive_utxo_snapshot(&supply_state, &snapshot);
|
||||
}
|
||||
self.entry
|
||||
.get_mut(entry)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.receive_utxo_snapshot(&supply_state, &snapshot);
|
||||
|
||||
// Update output type cohorts (skip types with no outputs this block)
|
||||
self.type_.iter_typed_mut().for_each(|(output_type, vecs)| {
|
||||
|
||||
@@ -49,7 +49,7 @@ impl UTXOCohorts<Rw> {
|
||||
// This is the max price between receive and send heights
|
||||
let peak_price = price_range_max.max_between(receive_height, send_height);
|
||||
|
||||
// Pre-compute once for age_range, epoch, year (all share sent.spendable_supply)
|
||||
// Pre-compute once for cohorts sharing the sent supply.
|
||||
if let Some(pre) = SendPrecomputed::new(
|
||||
&sent.spendable_supply,
|
||||
current_price,
|
||||
@@ -75,6 +75,12 @@ impl UTXOCohorts<Rw> {
|
||||
.unwrap()
|
||||
.send_utxo_precomputed(&sent.spendable_supply, &pre);
|
||||
}
|
||||
self.entry
|
||||
.get_mut(block_state.entry)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send_utxo_precomputed(&sent.spendable_supply, &pre);
|
||||
} else if sent.spendable_supply.utxo_count > 0 {
|
||||
// Zero-value UTXOs: just subtract supply
|
||||
self.age_range.get_mut(age).state.as_mut().unwrap().supply -=
|
||||
@@ -85,6 +91,12 @@ impl UTXOCohorts<Rw> {
|
||||
if let Some(v) = self.class.mut_vec_from_timestamp(block_state.timestamp) {
|
||||
v.state.as_mut().unwrap().supply -= &sent.spendable_supply;
|
||||
}
|
||||
self.entry
|
||||
.get_mut(block_state.entry)
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.supply -= &sent.spendable_supply;
|
||||
}
|
||||
|
||||
// Update output type cohorts (skip zero-supply entries)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use brk_cohort::ByAddrType;
|
||||
use brk_cohort::{ByAddrType, EntryPrice};
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{
|
||||
@@ -46,6 +46,7 @@ pub(crate) fn process_blocks(
|
||||
last_height: Height,
|
||||
chain_state: &mut Vec<BlockState>,
|
||||
tx_index_to_height: &mut RangeMap<TxIndex, Height>,
|
||||
mut entry_anchor: Cents,
|
||||
cached_prices: &[Cents],
|
||||
cached_timestamps: &[Timestamp],
|
||||
cached_price_range_max: &PriceRangeMax,
|
||||
@@ -370,9 +371,14 @@ pub(crate) fn process_blocks(
|
||||
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
|
||||
}
|
||||
|
||||
let entry = EntryPrice::from_is_discount(
|
||||
entry_anchor == Cents::ZERO || block_price <= entry_anchor,
|
||||
);
|
||||
|
||||
// Push current block state before processing cohort updates
|
||||
chain_state.push(BlockState {
|
||||
supply: transacted.spendable_supply,
|
||||
entry,
|
||||
price: block_price,
|
||||
timestamp,
|
||||
});
|
||||
@@ -411,7 +417,7 @@ pub(crate) fn process_blocks(
|
||||
|| {
|
||||
// UTXO cohorts receive/send
|
||||
vecs.utxo_cohorts
|
||||
.receive(transacted, height, timestamp, block_price);
|
||||
.receive(transacted, height, timestamp, block_price, entry);
|
||||
if let Some(min_h) =
|
||||
vecs.utxo_cohorts
|
||||
.send(height_to_sent, chain_state, ctx.price_range_max)
|
||||
@@ -460,7 +466,7 @@ pub(crate) fn process_blocks(
|
||||
let is_last_of_day = is_last_of_day[offset];
|
||||
let date_opt = is_last_of_day.then(|| Date::from(timestamp));
|
||||
|
||||
push_cohort_states(
|
||||
entry_anchor = push_cohort_states(
|
||||
&mut vecs.utxo_cohorts,
|
||||
&mut vecs.addr_cohorts,
|
||||
height,
|
||||
@@ -527,7 +533,7 @@ fn push_cohort_states(
|
||||
addr_cohorts: &mut AddrCohorts,
|
||||
height: Height,
|
||||
height_price: Cents,
|
||||
) {
|
||||
) -> Cents {
|
||||
// Phase 1: push + unrealized (no reset yet, states still needed for aggregation)
|
||||
rayon::join(
|
||||
|| {
|
||||
@@ -545,7 +551,7 @@ fn push_cohort_states(
|
||||
);
|
||||
|
||||
// Phase 2: aggregate age_range states → push to overlapping cohorts
|
||||
utxo_cohorts.push_overlapping(height_price);
|
||||
let all_capitalized_price = utxo_cohorts.push_overlapping(height_price);
|
||||
|
||||
// Phase 3: reset per-block values
|
||||
utxo_cohorts
|
||||
@@ -554,4 +560,6 @@ fn push_cohort_states(
|
||||
addr_cohorts
|
||||
.iter_separate_mut()
|
||||
.for_each(|v| v.reset_single_iteration_values());
|
||||
|
||||
all_capitalized_price
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ impl RealizedFull {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn push_accum(&mut self, accum: &RealizedFullAccum) {
|
||||
pub(crate) fn push_accum(&mut self, accum: &RealizedFullAccum) -> Cents {
|
||||
self.cap_raw.push(accum.cap_raw);
|
||||
self.capitalized.cap_raw.push(accum.capitalized_cap_raw);
|
||||
|
||||
@@ -221,6 +221,8 @@ impl RealizedFull {
|
||||
self.capitalized.price.cents.height.push(capitalized_price);
|
||||
|
||||
self.peak_regret.value.block.cents.push(accum.peak_regret());
|
||||
|
||||
capitalized_price
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rest_part1(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::ops::{Add, AddAssign, SubAssign};
|
||||
|
||||
use brk_cohort::EntryPrice;
|
||||
use brk_types::{Cents, SupplyState, Timestamp};
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -8,6 +9,8 @@ pub struct BlockState {
|
||||
#[serde(flatten)]
|
||||
pub supply: SupplyState,
|
||||
#[serde(skip)]
|
||||
pub entry: EntryPrice,
|
||||
#[serde(skip)]
|
||||
pub price: Cents,
|
||||
#[serde(skip)]
|
||||
pub timestamp: Timestamp,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use brk_cohort::{ByAddrType, Filter};
|
||||
use brk_cohort::{ByAddrType, EntryPrice, Filter};
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_traversable::Traversable;
|
||||
@@ -436,13 +436,34 @@ impl Vecs {
|
||||
let end = usize::from(recovered_height);
|
||||
debug!("building supply_state vec for {} heights", recovered_height);
|
||||
let supply_state_data: Vec<_> = self.supply_state.collect_range_at(0, end);
|
||||
let capitalized_price_data: Vec<_> = self
|
||||
.utxo_cohorts
|
||||
.all
|
||||
.metrics
|
||||
.realized
|
||||
.capitalized
|
||||
.price
|
||||
.cents
|
||||
.height
|
||||
.collect_range_at(0, end);
|
||||
|
||||
let mut entry_anchor = Cents::ZERO;
|
||||
chain_state = supply_state_data
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(h, supply)| BlockState {
|
||||
supply,
|
||||
price: self.caches.prices[h],
|
||||
timestamp: self.caches.timestamps[h],
|
||||
.map(|(h, supply)| {
|
||||
let price = self.caches.prices[h];
|
||||
let entry = EntryPrice::from_is_discount(
|
||||
entry_anchor == Cents::ZERO || price <= entry_anchor,
|
||||
);
|
||||
entry_anchor = capitalized_price_data[h];
|
||||
|
||||
BlockState {
|
||||
supply,
|
||||
entry,
|
||||
price,
|
||||
timestamp: self.caches.timestamps[h],
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
debug!("chain_state rebuilt");
|
||||
@@ -474,6 +495,20 @@ impl Vecs {
|
||||
let prices = std::mem::take(&mut self.caches.prices);
|
||||
let timestamps = std::mem::take(&mut self.caches.timestamps);
|
||||
let price_range_max = std::mem::take(&mut self.caches.price_range_max);
|
||||
let entry_anchor = starting_height
|
||||
.decremented()
|
||||
.and_then(|height| {
|
||||
self.utxo_cohorts
|
||||
.all
|
||||
.metrics
|
||||
.realized
|
||||
.capitalized
|
||||
.price
|
||||
.cents
|
||||
.height
|
||||
.collect_one(height)
|
||||
})
|
||||
.unwrap_or(Cents::ZERO);
|
||||
|
||||
process_blocks(
|
||||
self,
|
||||
@@ -486,6 +521,7 @@ impl Vecs {
|
||||
last_height,
|
||||
&mut chain_state,
|
||||
&mut tx_index_to_height,
|
||||
entry_anchor,
|
||||
&prices,
|
||||
×tamps,
|
||||
&price_range_max,
|
||||
|
||||
+516
-11
@@ -2506,6 +2506,22 @@ function create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(client, acc) {
|
||||
* @property {AdjustedRatioValuePattern} sopr
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CapCapitalizedGrossLossMvrvNetPeakPriceProfitSellSoprPattern2
|
||||
* @property {CentsDeltaToUsdPattern} cap
|
||||
* @property {PricePattern} capitalized
|
||||
* @property {BlockCumulativeSumPattern} grossPnl
|
||||
* @property {BlockCumulativeNegativeSumPattern} loss
|
||||
* @property {SeriesPattern1<StoredF32>} mvrv
|
||||
* @property {BlockChangeCumulativeDeltaSumPattern} netPnl
|
||||
* @property {BlockCumulativeSumPattern} peakRegret
|
||||
* @property {BpsCentsPercentilesRatioSatsSmaStdUsdPattern} price
|
||||
* @property {BlockCumulativeSumPattern} profit
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} profitToLossRatio
|
||||
* @property {_1m1w1y24hPattern8} sellSideRiskRatio
|
||||
* @property {RatioValuePattern2} sopr
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} EmptyOpP2aP2msP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshUnknownPattern2
|
||||
* @property {_1m1w1y24hBpsPercentRatioPattern} empty
|
||||
@@ -3017,6 +3033,17 @@ function create_1m1w1y24hBpsPercentRatioPattern(client, acc) {
|
||||
* @property {_1m1w1y24hBpsPercentRatioPattern} spendableOutputToReusedAddrShare
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ActivityCostInvestedOutputsRealizedSupplyUnrealizedPattern2
|
||||
* @property {CoindaysCoinyearsDormancyTransferPattern} activity
|
||||
* @property {InMaxMinPerSupplyPattern} costBasis
|
||||
* @property {InPattern} investedCapital
|
||||
* @property {SpendingSpentUnspentPattern} outputs
|
||||
* @property {CapCapitalizedGrossLossMvrvNetPeakPriceProfitSellSoprPattern2} realized
|
||||
* @property {DeltaDominanceHalfInTotalPattern2} supply
|
||||
* @property {CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CapLossMvrvNetPriceProfitSoprPattern
|
||||
* @property {CentsDeltaUsdPattern} cap
|
||||
@@ -5046,6 +5073,25 @@ function createPriceRatioPattern(client, acc, disc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} RatioValuePattern2
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} ratio
|
||||
* @property {AverageBlockCumulativeSumPattern<Cents>} valueDestroyed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a RatioValuePattern2 pattern node
|
||||
* @param {BrkClient} client
|
||||
* @param {string} acc - Accumulated series name
|
||||
* @returns {RatioValuePattern2}
|
||||
*/
|
||||
function createRatioValuePattern2(client, acc) {
|
||||
return {
|
||||
ratio: create_1m1w1y24hPattern(client, _m(acc, 'sopr')),
|
||||
valueDestroyed: createAverageBlockCumulativeSumPattern(client, _m(acc, 'value_destroyed')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} RatioValuePattern
|
||||
* @property {_24hPattern} ratio
|
||||
@@ -6787,6 +6833,7 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesTree_Cohorts_Utxo_OverAge} overAge
|
||||
* @property {SeriesTree_Cohorts_Utxo_Epoch} epoch
|
||||
* @property {SeriesTree_Cohorts_Utxo_Class} class
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry} entry
|
||||
* @property {SeriesTree_Cohorts_Utxo_OverAmount} overAmount
|
||||
* @property {SeriesTree_Cohorts_Utxo_AmountRange} amountRange
|
||||
* @property {SeriesTree_Cohorts_Utxo_UnderAmount} underAmount
|
||||
@@ -7144,7 +7191,7 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesTree_Cohorts_Utxo_Lth_Realized_Price} price
|
||||
* @property {SeriesPattern1<StoredF32>} mvrv
|
||||
* @property {BlockChangeCumulativeDeltaSumPattern} netPnl
|
||||
* @property {SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr} sopr
|
||||
* @property {RatioValuePattern2} sopr
|
||||
* @property {BlockCumulativeSumPattern} grossPnl
|
||||
* @property {_1m1w1y24hPattern8} sellSideRiskRatio
|
||||
* @property {BlockCumulativeSumPattern} peakRegret
|
||||
@@ -7248,12 +7295,6 @@ function createTransferPattern(client, acc) {
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr
|
||||
* @property {AverageBlockCumulativeSumPattern<Cents>} valueDestroyed
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} ratio
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_AgeRange
|
||||
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern} under1h
|
||||
@@ -7354,6 +7395,258 @@ function createTransferPattern(client, acc) {
|
||||
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern} _2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Discount} discount
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Premium} premium
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Discount
|
||||
* @property {DeltaDominanceHalfInTotalPattern2} supply
|
||||
* @property {SpendingSpentUnspentPattern} outputs
|
||||
* @property {CoindaysCoinyearsDormancyTransferPattern} activity
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Discount_Realized} realized
|
||||
* @property {InMaxMinPerSupplyPattern} costBasis
|
||||
* @property {CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2} unrealized
|
||||
* @property {InPattern} investedCapital
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Discount_Realized
|
||||
* @property {CentsDeltaToUsdPattern} cap
|
||||
* @property {BlockCumulativeSumPattern} profit
|
||||
* @property {BlockCumulativeNegativeSumPattern} loss
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price} price
|
||||
* @property {SeriesPattern1<StoredF32>} mvrv
|
||||
* @property {BlockChangeCumulativeDeltaSumPattern} netPnl
|
||||
* @property {RatioValuePattern2} sopr
|
||||
* @property {BlockCumulativeSumPattern} grossPnl
|
||||
* @property {_1m1w1y24hPattern8} sellSideRiskRatio
|
||||
* @property {BlockCumulativeSumPattern} peakRegret
|
||||
* @property {PricePattern} capitalized
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} profitToLossRatio
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price
|
||||
* @property {SeriesPattern1<Dollars>} usd
|
||||
* @property {SeriesPattern1<Cents>} cents
|
||||
* @property {SeriesPattern1<SatsFract>} sats
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
* @property {SeriesPattern1<StoredF32>} ratio
|
||||
* @property {Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {_1m1w1y2y4yAllPattern} sma
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev} stdDev
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All} all
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y} _4y
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y} _2y
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y} _1y
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All
|
||||
* @property {SeriesPattern1<StoredF32>} sd
|
||||
* @property {SeriesPattern1<StoredF32>} zscore
|
||||
* @property {CentsSatsUsdPattern} _0sd
|
||||
* @property {PriceRatioPattern} p05sd
|
||||
* @property {PriceRatioPattern} p1sd
|
||||
* @property {PriceRatioPattern} p15sd
|
||||
* @property {PriceRatioPattern} p2sd
|
||||
* @property {PriceRatioPattern} p25sd
|
||||
* @property {PriceRatioPattern} p3sd
|
||||
* @property {PriceRatioPattern} m05sd
|
||||
* @property {PriceRatioPattern} m1sd
|
||||
* @property {PriceRatioPattern} m15sd
|
||||
* @property {PriceRatioPattern} m2sd
|
||||
* @property {PriceRatioPattern} m25sd
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y
|
||||
* @property {SeriesPattern1<StoredF32>} sd
|
||||
* @property {SeriesPattern1<StoredF32>} zscore
|
||||
* @property {CentsSatsUsdPattern} _0sd
|
||||
* @property {PriceRatioPattern} p05sd
|
||||
* @property {PriceRatioPattern} p1sd
|
||||
* @property {PriceRatioPattern} p15sd
|
||||
* @property {PriceRatioPattern} p2sd
|
||||
* @property {PriceRatioPattern} p25sd
|
||||
* @property {PriceRatioPattern} p3sd
|
||||
* @property {PriceRatioPattern} m05sd
|
||||
* @property {PriceRatioPattern} m1sd
|
||||
* @property {PriceRatioPattern} m15sd
|
||||
* @property {PriceRatioPattern} m2sd
|
||||
* @property {PriceRatioPattern} m25sd
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y
|
||||
* @property {SeriesPattern1<StoredF32>} sd
|
||||
* @property {SeriesPattern1<StoredF32>} zscore
|
||||
* @property {CentsSatsUsdPattern} _0sd
|
||||
* @property {PriceRatioPattern} p05sd
|
||||
* @property {PriceRatioPattern} p1sd
|
||||
* @property {PriceRatioPattern} p15sd
|
||||
* @property {PriceRatioPattern} p2sd
|
||||
* @property {PriceRatioPattern} p25sd
|
||||
* @property {PriceRatioPattern} p3sd
|
||||
* @property {PriceRatioPattern} m05sd
|
||||
* @property {PriceRatioPattern} m1sd
|
||||
* @property {PriceRatioPattern} m15sd
|
||||
* @property {PriceRatioPattern} m2sd
|
||||
* @property {PriceRatioPattern} m25sd
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y
|
||||
* @property {SeriesPattern1<StoredF32>} sd
|
||||
* @property {SeriesPattern1<StoredF32>} zscore
|
||||
* @property {CentsSatsUsdPattern} _0sd
|
||||
* @property {PriceRatioPattern} p05sd
|
||||
* @property {PriceRatioPattern} p1sd
|
||||
* @property {PriceRatioPattern} p15sd
|
||||
* @property {PriceRatioPattern} p2sd
|
||||
* @property {PriceRatioPattern} p25sd
|
||||
* @property {PriceRatioPattern} p3sd
|
||||
* @property {PriceRatioPattern} m05sd
|
||||
* @property {PriceRatioPattern} m1sd
|
||||
* @property {PriceRatioPattern} m15sd
|
||||
* @property {PriceRatioPattern} m2sd
|
||||
* @property {PriceRatioPattern} m25sd
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Premium
|
||||
* @property {DeltaDominanceHalfInTotalPattern2} supply
|
||||
* @property {SpendingSpentUnspentPattern} outputs
|
||||
* @property {CoindaysCoinyearsDormancyTransferPattern} activity
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Premium_Realized} realized
|
||||
* @property {InMaxMinPerSupplyPattern} costBasis
|
||||
* @property {CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2} unrealized
|
||||
* @property {InPattern} investedCapital
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Premium_Realized
|
||||
* @property {CentsDeltaToUsdPattern} cap
|
||||
* @property {BlockCumulativeSumPattern} profit
|
||||
* @property {BlockCumulativeNegativeSumPattern} loss
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price} price
|
||||
* @property {SeriesPattern1<StoredF32>} mvrv
|
||||
* @property {BlockChangeCumulativeDeltaSumPattern} netPnl
|
||||
* @property {RatioValuePattern2} sopr
|
||||
* @property {BlockCumulativeSumPattern} grossPnl
|
||||
* @property {_1m1w1y24hPattern8} sellSideRiskRatio
|
||||
* @property {BlockCumulativeSumPattern} peakRegret
|
||||
* @property {PricePattern} capitalized
|
||||
* @property {_1m1w1y24hPattern<StoredF64>} profitToLossRatio
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price
|
||||
* @property {SeriesPattern1<Dollars>} usd
|
||||
* @property {SeriesPattern1<Cents>} cents
|
||||
* @property {SeriesPattern1<SatsFract>} sats
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
* @property {SeriesPattern1<StoredF32>} ratio
|
||||
* @property {Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {_1m1w1y2y4yAllPattern} sma
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev} stdDev
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All} all
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y} _4y
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y} _2y
|
||||
* @property {SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y} _1y
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All
|
||||
* @property {SeriesPattern1<StoredF32>} sd
|
||||
* @property {SeriesPattern1<StoredF32>} zscore
|
||||
* @property {CentsSatsUsdPattern} _0sd
|
||||
* @property {PriceRatioPattern} p05sd
|
||||
* @property {PriceRatioPattern} p1sd
|
||||
* @property {PriceRatioPattern} p15sd
|
||||
* @property {PriceRatioPattern} p2sd
|
||||
* @property {PriceRatioPattern} p25sd
|
||||
* @property {PriceRatioPattern} p3sd
|
||||
* @property {PriceRatioPattern} m05sd
|
||||
* @property {PriceRatioPattern} m1sd
|
||||
* @property {PriceRatioPattern} m15sd
|
||||
* @property {PriceRatioPattern} m2sd
|
||||
* @property {PriceRatioPattern} m25sd
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y
|
||||
* @property {SeriesPattern1<StoredF32>} sd
|
||||
* @property {SeriesPattern1<StoredF32>} zscore
|
||||
* @property {CentsSatsUsdPattern} _0sd
|
||||
* @property {PriceRatioPattern} p05sd
|
||||
* @property {PriceRatioPattern} p1sd
|
||||
* @property {PriceRatioPattern} p15sd
|
||||
* @property {PriceRatioPattern} p2sd
|
||||
* @property {PriceRatioPattern} p25sd
|
||||
* @property {PriceRatioPattern} p3sd
|
||||
* @property {PriceRatioPattern} m05sd
|
||||
* @property {PriceRatioPattern} m1sd
|
||||
* @property {PriceRatioPattern} m15sd
|
||||
* @property {PriceRatioPattern} m2sd
|
||||
* @property {PriceRatioPattern} m25sd
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y
|
||||
* @property {SeriesPattern1<StoredF32>} sd
|
||||
* @property {SeriesPattern1<StoredF32>} zscore
|
||||
* @property {CentsSatsUsdPattern} _0sd
|
||||
* @property {PriceRatioPattern} p05sd
|
||||
* @property {PriceRatioPattern} p1sd
|
||||
* @property {PriceRatioPattern} p15sd
|
||||
* @property {PriceRatioPattern} p2sd
|
||||
* @property {PriceRatioPattern} p25sd
|
||||
* @property {PriceRatioPattern} p3sd
|
||||
* @property {PriceRatioPattern} m05sd
|
||||
* @property {PriceRatioPattern} m1sd
|
||||
* @property {PriceRatioPattern} m15sd
|
||||
* @property {PriceRatioPattern} m2sd
|
||||
* @property {PriceRatioPattern} m25sd
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y
|
||||
* @property {SeriesPattern1<StoredF32>} sd
|
||||
* @property {SeriesPattern1<StoredF32>} zscore
|
||||
* @property {CentsSatsUsdPattern} _0sd
|
||||
* @property {PriceRatioPattern} p05sd
|
||||
* @property {PriceRatioPattern} p1sd
|
||||
* @property {PriceRatioPattern} p15sd
|
||||
* @property {PriceRatioPattern} p2sd
|
||||
* @property {PriceRatioPattern} p25sd
|
||||
* @property {PriceRatioPattern} p3sd
|
||||
* @property {PriceRatioPattern} m05sd
|
||||
* @property {PriceRatioPattern} m1sd
|
||||
* @property {PriceRatioPattern} m15sd
|
||||
* @property {PriceRatioPattern} m2sd
|
||||
* @property {PriceRatioPattern} m25sd
|
||||
* @property {PriceRatioPattern} m3sd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Cohorts_Utxo_OverAmount
|
||||
* @property {ActivityOutputsRealizedSupplyUnrealizedPattern2} _1sat
|
||||
@@ -7919,6 +8212,19 @@ class BrkClient extends BrkClientBase {
|
||||
}
|
||||
});
|
||||
|
||||
ENTRY_NAMES = /** @type {const} */ ({
|
||||
"discount": {
|
||||
"id": "veteran",
|
||||
"short": "Veteran",
|
||||
"long": "Veteran Coins"
|
||||
},
|
||||
"premium": {
|
||||
"id": "rookie",
|
||||
"short": "Rookie",
|
||||
"long": "Rookie Coins"
|
||||
}
|
||||
});
|
||||
|
||||
SPENDABLE_TYPE_NAMES = /** @type {const} */ ({
|
||||
"p2pk65": {
|
||||
"id": "p2pk65",
|
||||
@@ -10239,10 +10545,7 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
mvrv: createSeriesPattern1(this, 'lth_mvrv'),
|
||||
netPnl: createBlockChangeCumulativeDeltaSumPattern(this, 'lth_net'),
|
||||
sopr: {
|
||||
valueDestroyed: createAverageBlockCumulativeSumPattern(this, 'lth_value_destroyed'),
|
||||
ratio: create_1m1w1y24hPattern(this, 'lth_sopr'),
|
||||
},
|
||||
sopr: createRatioValuePattern2(this, 'lth'),
|
||||
grossPnl: createBlockCumulativeSumPattern(this, 'lth_realized_gross_pnl'),
|
||||
sellSideRiskRatio: create_1m1w1y24hPattern8(this, 'lth_sell_side_risk_ratio'),
|
||||
peakRegret: createBlockCumulativeSumPattern(this, 'lth_realized_peak_regret'),
|
||||
@@ -10343,6 +10646,208 @@ class BrkClient extends BrkClientBase {
|
||||
_2025: createActivityOutputsRealizedSupplyUnrealizedPattern(this, 'class_2025'),
|
||||
_2026: createActivityOutputsRealizedSupplyUnrealizedPattern(this, 'class_2026'),
|
||||
},
|
||||
entry: {
|
||||
discount: {
|
||||
supply: createDeltaDominanceHalfInTotalPattern2(this, 'veteran_supply'),
|
||||
outputs: createSpendingSpentUnspentPattern(this, 'veteran'),
|
||||
activity: createCoindaysCoinyearsDormancyTransferPattern(this, 'veteran'),
|
||||
realized: {
|
||||
cap: createCentsDeltaToUsdPattern(this, 'veteran_realized_cap'),
|
||||
profit: createBlockCumulativeSumPattern(this, 'veteran_realized_profit'),
|
||||
loss: createBlockCumulativeNegativeSumPattern(this, 'veteran_realized_loss'),
|
||||
price: {
|
||||
usd: createSeriesPattern1(this, 'veteran_realized_price'),
|
||||
cents: createSeriesPattern1(this, 'veteran_realized_price_cents'),
|
||||
sats: createSeriesPattern1(this, 'veteran_realized_price_sats'),
|
||||
bps: createSeriesPattern1(this, 'veteran_realized_price_ratio_bps'),
|
||||
ratio: createSeriesPattern1(this, 'veteran_realized_price_ratio'),
|
||||
percentiles: createPct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(this, 'veteran_realized_price'),
|
||||
sma: create_1m1w1y2y4yAllPattern(this, 'veteran_realized_price_ratio_sma'),
|
||||
stdDev: {
|
||||
all: {
|
||||
sd: createSeriesPattern1(this, 'veteran_realized_price_ratio_sd'),
|
||||
zscore: createSeriesPattern1(this, 'veteran_realized_price_ratio_zscore'),
|
||||
_0sd: createCentsSatsUsdPattern(this, 'veteran_realized_price_0sd'),
|
||||
p05sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p0_5sd'),
|
||||
p1sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p1sd'),
|
||||
p15sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p1_5sd'),
|
||||
p2sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p2sd'),
|
||||
p25sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p2_5sd'),
|
||||
p3sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p3sd'),
|
||||
m05sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm0_5sd'),
|
||||
m1sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm1sd'),
|
||||
m15sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm1_5sd'),
|
||||
m2sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm2sd'),
|
||||
m25sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm2_5sd'),
|
||||
m3sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm3sd'),
|
||||
},
|
||||
_4y: {
|
||||
sd: createSeriesPattern1(this, 'veteran_realized_price_ratio_sd_4y'),
|
||||
zscore: createSeriesPattern1(this, 'veteran_realized_price_ratio_zscore_4y'),
|
||||
_0sd: createCentsSatsUsdPattern(this, 'veteran_realized_price_0sd_4y'),
|
||||
p05sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p0_5sd_4y'),
|
||||
p1sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p1sd_4y'),
|
||||
p15sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p1_5sd_4y'),
|
||||
p2sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p2sd_4y'),
|
||||
p25sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p2_5sd_4y'),
|
||||
p3sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p3sd_4y'),
|
||||
m05sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm0_5sd_4y'),
|
||||
m1sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm1sd_4y'),
|
||||
m15sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm1_5sd_4y'),
|
||||
m2sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm2sd_4y'),
|
||||
m25sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm2_5sd_4y'),
|
||||
m3sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm3sd_4y'),
|
||||
},
|
||||
_2y: {
|
||||
sd: createSeriesPattern1(this, 'veteran_realized_price_ratio_sd_2y'),
|
||||
zscore: createSeriesPattern1(this, 'veteran_realized_price_ratio_zscore_2y'),
|
||||
_0sd: createCentsSatsUsdPattern(this, 'veteran_realized_price_0sd_2y'),
|
||||
p05sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p0_5sd_2y'),
|
||||
p1sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p1sd_2y'),
|
||||
p15sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p1_5sd_2y'),
|
||||
p2sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p2sd_2y'),
|
||||
p25sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p2_5sd_2y'),
|
||||
p3sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p3sd_2y'),
|
||||
m05sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm0_5sd_2y'),
|
||||
m1sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm1sd_2y'),
|
||||
m15sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm1_5sd_2y'),
|
||||
m2sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm2sd_2y'),
|
||||
m25sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm2_5sd_2y'),
|
||||
m3sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm3sd_2y'),
|
||||
},
|
||||
_1y: {
|
||||
sd: createSeriesPattern1(this, 'veteran_realized_price_ratio_sd_1y'),
|
||||
zscore: createSeriesPattern1(this, 'veteran_realized_price_ratio_zscore_1y'),
|
||||
_0sd: createCentsSatsUsdPattern(this, 'veteran_realized_price_0sd_1y'),
|
||||
p05sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p0_5sd_1y'),
|
||||
p1sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p1sd_1y'),
|
||||
p15sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p1_5sd_1y'),
|
||||
p2sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p2sd_1y'),
|
||||
p25sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p2_5sd_1y'),
|
||||
p3sd: createPriceRatioPattern(this, 'veteran_realized_price', 'p3sd_1y'),
|
||||
m05sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm0_5sd_1y'),
|
||||
m1sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm1sd_1y'),
|
||||
m15sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm1_5sd_1y'),
|
||||
m2sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm2sd_1y'),
|
||||
m25sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm2_5sd_1y'),
|
||||
m3sd: createPriceRatioPattern(this, 'veteran_realized_price', 'm3sd_1y'),
|
||||
},
|
||||
},
|
||||
},
|
||||
mvrv: createSeriesPattern1(this, 'veteran_mvrv'),
|
||||
netPnl: createBlockChangeCumulativeDeltaSumPattern(this, 'veteran_net'),
|
||||
sopr: createRatioValuePattern2(this, 'veteran'),
|
||||
grossPnl: createBlockCumulativeSumPattern(this, 'veteran_realized_gross_pnl'),
|
||||
sellSideRiskRatio: create_1m1w1y24hPattern8(this, 'veteran_sell_side_risk_ratio'),
|
||||
peakRegret: createBlockCumulativeSumPattern(this, 'veteran_realized_peak_regret'),
|
||||
capitalized: createPricePattern(this, 'veteran_capitalized_price'),
|
||||
profitToLossRatio: create_1m1w1y24hPattern(this, 'veteran_realized_profit_to_loss_ratio'),
|
||||
},
|
||||
costBasis: createInMaxMinPerSupplyPattern(this, 'veteran'),
|
||||
unrealized: createCapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(this, 'veteran'),
|
||||
investedCapital: createInPattern(this, 'veteran_invested_capital_in'),
|
||||
},
|
||||
premium: {
|
||||
supply: createDeltaDominanceHalfInTotalPattern2(this, 'rookie_supply'),
|
||||
outputs: createSpendingSpentUnspentPattern(this, 'rookie'),
|
||||
activity: createCoindaysCoinyearsDormancyTransferPattern(this, 'rookie'),
|
||||
realized: {
|
||||
cap: createCentsDeltaToUsdPattern(this, 'rookie_realized_cap'),
|
||||
profit: createBlockCumulativeSumPattern(this, 'rookie_realized_profit'),
|
||||
loss: createBlockCumulativeNegativeSumPattern(this, 'rookie_realized_loss'),
|
||||
price: {
|
||||
usd: createSeriesPattern1(this, 'rookie_realized_price'),
|
||||
cents: createSeriesPattern1(this, 'rookie_realized_price_cents'),
|
||||
sats: createSeriesPattern1(this, 'rookie_realized_price_sats'),
|
||||
bps: createSeriesPattern1(this, 'rookie_realized_price_ratio_bps'),
|
||||
ratio: createSeriesPattern1(this, 'rookie_realized_price_ratio'),
|
||||
percentiles: createPct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(this, 'rookie_realized_price'),
|
||||
sma: create_1m1w1y2y4yAllPattern(this, 'rookie_realized_price_ratio_sma'),
|
||||
stdDev: {
|
||||
all: {
|
||||
sd: createSeriesPattern1(this, 'rookie_realized_price_ratio_sd'),
|
||||
zscore: createSeriesPattern1(this, 'rookie_realized_price_ratio_zscore'),
|
||||
_0sd: createCentsSatsUsdPattern(this, 'rookie_realized_price_0sd'),
|
||||
p05sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p0_5sd'),
|
||||
p1sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p1sd'),
|
||||
p15sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p1_5sd'),
|
||||
p2sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p2sd'),
|
||||
p25sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p2_5sd'),
|
||||
p3sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p3sd'),
|
||||
m05sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm0_5sd'),
|
||||
m1sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm1sd'),
|
||||
m15sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm1_5sd'),
|
||||
m2sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm2sd'),
|
||||
m25sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm2_5sd'),
|
||||
m3sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm3sd'),
|
||||
},
|
||||
_4y: {
|
||||
sd: createSeriesPattern1(this, 'rookie_realized_price_ratio_sd_4y'),
|
||||
zscore: createSeriesPattern1(this, 'rookie_realized_price_ratio_zscore_4y'),
|
||||
_0sd: createCentsSatsUsdPattern(this, 'rookie_realized_price_0sd_4y'),
|
||||
p05sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p0_5sd_4y'),
|
||||
p1sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p1sd_4y'),
|
||||
p15sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p1_5sd_4y'),
|
||||
p2sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p2sd_4y'),
|
||||
p25sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p2_5sd_4y'),
|
||||
p3sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p3sd_4y'),
|
||||
m05sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm0_5sd_4y'),
|
||||
m1sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm1sd_4y'),
|
||||
m15sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm1_5sd_4y'),
|
||||
m2sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm2sd_4y'),
|
||||
m25sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm2_5sd_4y'),
|
||||
m3sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm3sd_4y'),
|
||||
},
|
||||
_2y: {
|
||||
sd: createSeriesPattern1(this, 'rookie_realized_price_ratio_sd_2y'),
|
||||
zscore: createSeriesPattern1(this, 'rookie_realized_price_ratio_zscore_2y'),
|
||||
_0sd: createCentsSatsUsdPattern(this, 'rookie_realized_price_0sd_2y'),
|
||||
p05sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p0_5sd_2y'),
|
||||
p1sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p1sd_2y'),
|
||||
p15sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p1_5sd_2y'),
|
||||
p2sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p2sd_2y'),
|
||||
p25sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p2_5sd_2y'),
|
||||
p3sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p3sd_2y'),
|
||||
m05sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm0_5sd_2y'),
|
||||
m1sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm1sd_2y'),
|
||||
m15sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm1_5sd_2y'),
|
||||
m2sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm2sd_2y'),
|
||||
m25sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm2_5sd_2y'),
|
||||
m3sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm3sd_2y'),
|
||||
},
|
||||
_1y: {
|
||||
sd: createSeriesPattern1(this, 'rookie_realized_price_ratio_sd_1y'),
|
||||
zscore: createSeriesPattern1(this, 'rookie_realized_price_ratio_zscore_1y'),
|
||||
_0sd: createCentsSatsUsdPattern(this, 'rookie_realized_price_0sd_1y'),
|
||||
p05sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p0_5sd_1y'),
|
||||
p1sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p1sd_1y'),
|
||||
p15sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p1_5sd_1y'),
|
||||
p2sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p2sd_1y'),
|
||||
p25sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p2_5sd_1y'),
|
||||
p3sd: createPriceRatioPattern(this, 'rookie_realized_price', 'p3sd_1y'),
|
||||
m05sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm0_5sd_1y'),
|
||||
m1sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm1sd_1y'),
|
||||
m15sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm1_5sd_1y'),
|
||||
m2sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm2sd_1y'),
|
||||
m25sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm2_5sd_1y'),
|
||||
m3sd: createPriceRatioPattern(this, 'rookie_realized_price', 'm3sd_1y'),
|
||||
},
|
||||
},
|
||||
},
|
||||
mvrv: createSeriesPattern1(this, 'rookie_mvrv'),
|
||||
netPnl: createBlockChangeCumulativeDeltaSumPattern(this, 'rookie_net'),
|
||||
sopr: createRatioValuePattern2(this, 'rookie'),
|
||||
grossPnl: createBlockCumulativeSumPattern(this, 'rookie_realized_gross_pnl'),
|
||||
sellSideRiskRatio: create_1m1w1y24hPattern8(this, 'rookie_sell_side_risk_ratio'),
|
||||
peakRegret: createBlockCumulativeSumPattern(this, 'rookie_realized_peak_regret'),
|
||||
capitalized: createPricePattern(this, 'rookie_capitalized_price'),
|
||||
profitToLossRatio: create_1m1w1y24hPattern(this, 'rookie_realized_profit_to_loss_ratio'),
|
||||
},
|
||||
costBasis: createInMaxMinPerSupplyPattern(this, 'rookie'),
|
||||
unrealized: createCapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(this, 'rookie'),
|
||||
investedCapital: createInPattern(this, 'rookie_invested_capital_in'),
|
||||
},
|
||||
},
|
||||
overAmount: {
|
||||
_1sat: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_over_1sat'),
|
||||
_10sats: createActivityOutputsRealizedSupplyUnrealizedPattern2(this, 'utxos_over_10sats'),
|
||||
|
||||
@@ -2954,6 +2954,10 @@ class CapCapitalizedGrossLossMvrvNetPeakPriceProfitSellSoprPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class CapCapitalizedGrossLossMvrvNetPeakPriceProfitSellSoprPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class EmptyOpP2aP2msP2pk33P2pk65P2pkhP2shP2trP2wpkhP2wshUnknownPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -3181,6 +3185,10 @@ class ActiveInputOutputSpendablePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class ActivityCostInvestedOutputsRealizedSupplyUnrealizedPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class CapLossMvrvNetPriceProfitSoprPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -4056,6 +4064,14 @@ class PriceRatioPattern:
|
||||
self.price: CentsSatsUsdPattern = CentsSatsUsdPattern(client, _m(acc, disc))
|
||||
self.ratio: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, f'ratio_{disc}'))
|
||||
|
||||
class RatioValuePattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClient, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, _m(acc, 'sopr'))
|
||||
self.value_destroyed: AverageBlockCumulativeSumPattern[Cents] = AverageBlockCumulativeSumPattern(client, _m(acc, 'value_destroyed'))
|
||||
|
||||
class RatioValuePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -6299,13 +6315,6 @@ class SeriesTree_Cohorts_Utxo_Lth_Realized_Price:
|
||||
self.sma: _1m1w1y2y4yAllPattern = _1m1w1y2y4yAllPattern(client, 'lth_realized_price_ratio_sma')
|
||||
self.std_dev: SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev = SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.value_destroyed: AverageBlockCumulativeSumPattern[Cents] = AverageBlockCumulativeSumPattern(client, 'lth_value_destroyed')
|
||||
self.ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'lth_sopr')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Lth_Realized:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -6316,7 +6325,7 @@ class SeriesTree_Cohorts_Utxo_Lth_Realized:
|
||||
self.price: SeriesTree_Cohorts_Utxo_Lth_Realized_Price = SeriesTree_Cohorts_Utxo_Lth_Realized_Price(client)
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'lth_mvrv')
|
||||
self.net_pnl: BlockChangeCumulativeDeltaSumPattern = BlockChangeCumulativeDeltaSumPattern(client, 'lth_net')
|
||||
self.sopr: SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr = SeriesTree_Cohorts_Utxo_Lth_Realized_Sopr(client)
|
||||
self.sopr: RatioValuePattern2 = RatioValuePattern2(client, 'lth')
|
||||
self.gross_pnl: BlockCumulativeSumPattern = BlockCumulativeSumPattern(client, 'lth_realized_gross_pnl')
|
||||
self.sell_side_risk_ratio: _1m1w1y24hPattern8 = _1m1w1y24hPattern8(client, 'lth_sell_side_risk_ratio')
|
||||
self.peak_regret: BlockCumulativeSumPattern = BlockCumulativeSumPattern(client, 'lth_realized_peak_regret')
|
||||
@@ -6440,6 +6449,275 @@ class SeriesTree_Cohorts_Utxo_Class:
|
||||
self._2025: ActivityOutputsRealizedSupplyUnrealizedPattern = ActivityOutputsRealizedSupplyUnrealizedPattern(client, 'class_2025')
|
||||
self._2026: ActivityOutputsRealizedSupplyUnrealizedPattern = ActivityOutputsRealizedSupplyUnrealizedPattern(client, 'class_2026')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.sd: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio_sd')
|
||||
self.zscore: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio_zscore')
|
||||
self._0sd: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'veteran_realized_price_0sd')
|
||||
self.p0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p0_5sd')
|
||||
self.p1sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p1sd')
|
||||
self.p1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p1_5sd')
|
||||
self.p2sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p2sd')
|
||||
self.p2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p2_5sd')
|
||||
self.p3sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p3sd')
|
||||
self.m0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm0_5sd')
|
||||
self.m1sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm1sd')
|
||||
self.m1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm1_5sd')
|
||||
self.m2sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm2sd')
|
||||
self.m2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm2_5sd')
|
||||
self.m3sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm3sd')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.sd: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio_sd_4y')
|
||||
self.zscore: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio_zscore_4y')
|
||||
self._0sd: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'veteran_realized_price_0sd_4y')
|
||||
self.p0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p0_5sd_4y')
|
||||
self.p1sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p1sd_4y')
|
||||
self.p1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p1_5sd_4y')
|
||||
self.p2sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p2sd_4y')
|
||||
self.p2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p2_5sd_4y')
|
||||
self.p3sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p3sd_4y')
|
||||
self.m0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm0_5sd_4y')
|
||||
self.m1sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm1sd_4y')
|
||||
self.m1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm1_5sd_4y')
|
||||
self.m2sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm2sd_4y')
|
||||
self.m2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm2_5sd_4y')
|
||||
self.m3sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm3sd_4y')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.sd: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio_sd_2y')
|
||||
self.zscore: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio_zscore_2y')
|
||||
self._0sd: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'veteran_realized_price_0sd_2y')
|
||||
self.p0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p0_5sd_2y')
|
||||
self.p1sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p1sd_2y')
|
||||
self.p1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p1_5sd_2y')
|
||||
self.p2sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p2sd_2y')
|
||||
self.p2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p2_5sd_2y')
|
||||
self.p3sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p3sd_2y')
|
||||
self.m0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm0_5sd_2y')
|
||||
self.m1sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm1sd_2y')
|
||||
self.m1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm1_5sd_2y')
|
||||
self.m2sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm2sd_2y')
|
||||
self.m2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm2_5sd_2y')
|
||||
self.m3sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm3sd_2y')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.sd: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio_sd_1y')
|
||||
self.zscore: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio_zscore_1y')
|
||||
self._0sd: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'veteran_realized_price_0sd_1y')
|
||||
self.p0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p0_5sd_1y')
|
||||
self.p1sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p1sd_1y')
|
||||
self.p1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p1_5sd_1y')
|
||||
self.p2sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p2sd_1y')
|
||||
self.p2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p2_5sd_1y')
|
||||
self.p3sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'p3sd_1y')
|
||||
self.m0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm0_5sd_1y')
|
||||
self.m1sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm1sd_1y')
|
||||
self.m1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm1_5sd_1y')
|
||||
self.m2sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm2sd_1y')
|
||||
self.m2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm2_5sd_1y')
|
||||
self.m3sd: PriceRatioPattern = PriceRatioPattern(client, 'veteran_realized_price', 'm3sd_1y')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.all: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All = SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_All(client)
|
||||
self._4y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y = SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_4y(client)
|
||||
self._2y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y = SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_2y(client)
|
||||
self._1y: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y = SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev_1y(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, 'veteran_realized_price')
|
||||
self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, 'veteran_realized_price_cents')
|
||||
self.sats: SeriesPattern1[SatsFract] = SeriesPattern1(client, 'veteran_realized_price_sats')
|
||||
self.bps: SeriesPattern1[BasisPoints32] = SeriesPattern1(client, 'veteran_realized_price_ratio_bps')
|
||||
self.ratio: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_realized_price_ratio')
|
||||
self.percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, 'veteran_realized_price')
|
||||
self.sma: _1m1w1y2y4yAllPattern = _1m1w1y2y4yAllPattern(client, 'veteran_realized_price_ratio_sma')
|
||||
self.std_dev: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev = SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price_StdDev(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Discount_Realized:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.cap: CentsDeltaToUsdPattern = CentsDeltaToUsdPattern(client, 'veteran_realized_cap')
|
||||
self.profit: BlockCumulativeSumPattern = BlockCumulativeSumPattern(client, 'veteran_realized_profit')
|
||||
self.loss: BlockCumulativeNegativeSumPattern = BlockCumulativeNegativeSumPattern(client, 'veteran_realized_loss')
|
||||
self.price: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price = SeriesTree_Cohorts_Utxo_Entry_Discount_Realized_Price(client)
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'veteran_mvrv')
|
||||
self.net_pnl: BlockChangeCumulativeDeltaSumPattern = BlockChangeCumulativeDeltaSumPattern(client, 'veteran_net')
|
||||
self.sopr: RatioValuePattern2 = RatioValuePattern2(client, 'veteran')
|
||||
self.gross_pnl: BlockCumulativeSumPattern = BlockCumulativeSumPattern(client, 'veteran_realized_gross_pnl')
|
||||
self.sell_side_risk_ratio: _1m1w1y24hPattern8 = _1m1w1y24hPattern8(client, 'veteran_sell_side_risk_ratio')
|
||||
self.peak_regret: BlockCumulativeSumPattern = BlockCumulativeSumPattern(client, 'veteran_realized_peak_regret')
|
||||
self.capitalized: PricePattern = PricePattern(client, 'veteran_capitalized_price')
|
||||
self.profit_to_loss_ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'veteran_realized_profit_to_loss_ratio')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Discount:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.supply: DeltaDominanceHalfInTotalPattern2 = DeltaDominanceHalfInTotalPattern2(client, 'veteran_supply')
|
||||
self.outputs: SpendingSpentUnspentPattern = SpendingSpentUnspentPattern(client, 'veteran')
|
||||
self.activity: CoindaysCoinyearsDormancyTransferPattern = CoindaysCoinyearsDormancyTransferPattern(client, 'veteran')
|
||||
self.realized: SeriesTree_Cohorts_Utxo_Entry_Discount_Realized = SeriesTree_Cohorts_Utxo_Entry_Discount_Realized(client)
|
||||
self.cost_basis: InMaxMinPerSupplyPattern = InMaxMinPerSupplyPattern(client, 'veteran')
|
||||
self.unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 = CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(client, 'veteran')
|
||||
self.invested_capital: InPattern = InPattern(client, 'veteran_invested_capital_in')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.sd: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio_sd')
|
||||
self.zscore: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio_zscore')
|
||||
self._0sd: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'rookie_realized_price_0sd')
|
||||
self.p0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p0_5sd')
|
||||
self.p1sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p1sd')
|
||||
self.p1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p1_5sd')
|
||||
self.p2sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p2sd')
|
||||
self.p2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p2_5sd')
|
||||
self.p3sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p3sd')
|
||||
self.m0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm0_5sd')
|
||||
self.m1sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm1sd')
|
||||
self.m1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm1_5sd')
|
||||
self.m2sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm2sd')
|
||||
self.m2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm2_5sd')
|
||||
self.m3sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm3sd')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.sd: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio_sd_4y')
|
||||
self.zscore: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio_zscore_4y')
|
||||
self._0sd: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'rookie_realized_price_0sd_4y')
|
||||
self.p0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p0_5sd_4y')
|
||||
self.p1sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p1sd_4y')
|
||||
self.p1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p1_5sd_4y')
|
||||
self.p2sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p2sd_4y')
|
||||
self.p2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p2_5sd_4y')
|
||||
self.p3sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p3sd_4y')
|
||||
self.m0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm0_5sd_4y')
|
||||
self.m1sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm1sd_4y')
|
||||
self.m1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm1_5sd_4y')
|
||||
self.m2sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm2sd_4y')
|
||||
self.m2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm2_5sd_4y')
|
||||
self.m3sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm3sd_4y')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.sd: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio_sd_2y')
|
||||
self.zscore: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio_zscore_2y')
|
||||
self._0sd: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'rookie_realized_price_0sd_2y')
|
||||
self.p0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p0_5sd_2y')
|
||||
self.p1sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p1sd_2y')
|
||||
self.p1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p1_5sd_2y')
|
||||
self.p2sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p2sd_2y')
|
||||
self.p2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p2_5sd_2y')
|
||||
self.p3sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p3sd_2y')
|
||||
self.m0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm0_5sd_2y')
|
||||
self.m1sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm1sd_2y')
|
||||
self.m1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm1_5sd_2y')
|
||||
self.m2sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm2sd_2y')
|
||||
self.m2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm2_5sd_2y')
|
||||
self.m3sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm3sd_2y')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.sd: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio_sd_1y')
|
||||
self.zscore: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio_zscore_1y')
|
||||
self._0sd: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'rookie_realized_price_0sd_1y')
|
||||
self.p0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p0_5sd_1y')
|
||||
self.p1sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p1sd_1y')
|
||||
self.p1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p1_5sd_1y')
|
||||
self.p2sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p2sd_1y')
|
||||
self.p2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p2_5sd_1y')
|
||||
self.p3sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'p3sd_1y')
|
||||
self.m0_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm0_5sd_1y')
|
||||
self.m1sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm1sd_1y')
|
||||
self.m1_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm1_5sd_1y')
|
||||
self.m2sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm2sd_1y')
|
||||
self.m2_5sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm2_5sd_1y')
|
||||
self.m3sd: PriceRatioPattern = PriceRatioPattern(client, 'rookie_realized_price', 'm3sd_1y')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.all: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All = SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_All(client)
|
||||
self._4y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y = SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_4y(client)
|
||||
self._2y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y = SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_2y(client)
|
||||
self._1y: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y = SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev_1y(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, 'rookie_realized_price')
|
||||
self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, 'rookie_realized_price_cents')
|
||||
self.sats: SeriesPattern1[SatsFract] = SeriesPattern1(client, 'rookie_realized_price_sats')
|
||||
self.bps: SeriesPattern1[BasisPoints32] = SeriesPattern1(client, 'rookie_realized_price_ratio_bps')
|
||||
self.ratio: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_realized_price_ratio')
|
||||
self.percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, 'rookie_realized_price')
|
||||
self.sma: _1m1w1y2y4yAllPattern = _1m1w1y2y4yAllPattern(client, 'rookie_realized_price_ratio_sma')
|
||||
self.std_dev: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev = SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price_StdDev(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Premium_Realized:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.cap: CentsDeltaToUsdPattern = CentsDeltaToUsdPattern(client, 'rookie_realized_cap')
|
||||
self.profit: BlockCumulativeSumPattern = BlockCumulativeSumPattern(client, 'rookie_realized_profit')
|
||||
self.loss: BlockCumulativeNegativeSumPattern = BlockCumulativeNegativeSumPattern(client, 'rookie_realized_loss')
|
||||
self.price: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price = SeriesTree_Cohorts_Utxo_Entry_Premium_Realized_Price(client)
|
||||
self.mvrv: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'rookie_mvrv')
|
||||
self.net_pnl: BlockChangeCumulativeDeltaSumPattern = BlockChangeCumulativeDeltaSumPattern(client, 'rookie_net')
|
||||
self.sopr: RatioValuePattern2 = RatioValuePattern2(client, 'rookie')
|
||||
self.gross_pnl: BlockCumulativeSumPattern = BlockCumulativeSumPattern(client, 'rookie_realized_gross_pnl')
|
||||
self.sell_side_risk_ratio: _1m1w1y24hPattern8 = _1m1w1y24hPattern8(client, 'rookie_sell_side_risk_ratio')
|
||||
self.peak_regret: BlockCumulativeSumPattern = BlockCumulativeSumPattern(client, 'rookie_realized_peak_regret')
|
||||
self.capitalized: PricePattern = PricePattern(client, 'rookie_capitalized_price')
|
||||
self.profit_to_loss_ratio: _1m1w1y24hPattern[StoredF64] = _1m1w1y24hPattern(client, 'rookie_realized_profit_to_loss_ratio')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry_Premium:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.supply: DeltaDominanceHalfInTotalPattern2 = DeltaDominanceHalfInTotalPattern2(client, 'rookie_supply')
|
||||
self.outputs: SpendingSpentUnspentPattern = SpendingSpentUnspentPattern(client, 'rookie')
|
||||
self.activity: CoindaysCoinyearsDormancyTransferPattern = CoindaysCoinyearsDormancyTransferPattern(client, 'rookie')
|
||||
self.realized: SeriesTree_Cohorts_Utxo_Entry_Premium_Realized = SeriesTree_Cohorts_Utxo_Entry_Premium_Realized(client)
|
||||
self.cost_basis: InMaxMinPerSupplyPattern = InMaxMinPerSupplyPattern(client, 'rookie')
|
||||
self.unrealized: CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2 = CapitalizedGrossInvestedLossNetNuplProfitSentimentPattern2(client, 'rookie')
|
||||
self.invested_capital: InPattern = InPattern(client, 'rookie_invested_capital_in')
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_Entry:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClient, base_path: str = ''):
|
||||
self.discount: SeriesTree_Cohorts_Utxo_Entry_Discount = SeriesTree_Cohorts_Utxo_Entry_Discount(client)
|
||||
self.premium: SeriesTree_Cohorts_Utxo_Entry_Premium = SeriesTree_Cohorts_Utxo_Entry_Premium(client)
|
||||
|
||||
class SeriesTree_Cohorts_Utxo_OverAmount:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -6621,6 +6899,7 @@ class SeriesTree_Cohorts_Utxo:
|
||||
self.over_age: SeriesTree_Cohorts_Utxo_OverAge = SeriesTree_Cohorts_Utxo_OverAge(client)
|
||||
self.epoch: SeriesTree_Cohorts_Utxo_Epoch = SeriesTree_Cohorts_Utxo_Epoch(client)
|
||||
self.class_: SeriesTree_Cohorts_Utxo_Class = SeriesTree_Cohorts_Utxo_Class(client)
|
||||
self.entry: SeriesTree_Cohorts_Utxo_Entry = SeriesTree_Cohorts_Utxo_Entry(client)
|
||||
self.over_amount: SeriesTree_Cohorts_Utxo_OverAmount = SeriesTree_Cohorts_Utxo_OverAmount(client)
|
||||
self.amount_range: SeriesTree_Cohorts_Utxo_AmountRange = SeriesTree_Cohorts_Utxo_AmountRange(client)
|
||||
self.under_amount: SeriesTree_Cohorts_Utxo_UnderAmount = SeriesTree_Cohorts_Utxo_UnderAmount(client)
|
||||
@@ -7064,6 +7343,19 @@ class BrkClient(BrkClientBase):
|
||||
}
|
||||
}
|
||||
|
||||
ENTRY_NAMES = {
|
||||
"discount": {
|
||||
"id": "veteran",
|
||||
"short": "Veteran",
|
||||
"long": "Veteran Coins"
|
||||
},
|
||||
"premium": {
|
||||
"id": "rookie",
|
||||
"short": "Rookie",
|
||||
"long": "Rookie Coins"
|
||||
}
|
||||
}
|
||||
|
||||
SPENDABLE_TYPE_NAMES = {
|
||||
"p2pk65": {
|
||||
"id": "p2pk65",
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../modules
|
||||
@@ -1,14 +0,0 @@
|
||||
LICENSE
|
||||
**/*.*.*/*.json
|
||||
*webcomponent*
|
||||
cli*
|
||||
extras/
|
||||
*.cjs
|
||||
dev.js
|
||||
*.development*
|
||||
*.iife.*
|
||||
nano.*
|
||||
worker.*
|
||||
*.mts
|
||||
*.cts
|
||||
*.rs
|
||||
@@ -1 +0,0 @@
|
||||
generated
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"checkJs": true,
|
||||
"strict": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"bugs": {
|
||||
"url": "https://github.com/bitcoinresearchkit/brk/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node tests/basic.js && node tests/tree.js",
|
||||
"test:basic": "node tests/basic.js",
|
||||
"test:tree": "node tests/tree.js"
|
||||
},
|
||||
"description": "Bitcoin on-chain analytics client — thousands of metrics, block explorer, and address index",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"exports": {
|
||||
".": "./index.js"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"generated"
|
||||
],
|
||||
"homepage": "https://github.com/bitcoinresearchkit/brk/tree/main/modules/brk-client",
|
||||
"keywords": [
|
||||
"brk",
|
||||
"bitcoin",
|
||||
"blockchain",
|
||||
"research",
|
||||
"on-chain",
|
||||
"analytics",
|
||||
"metrics",
|
||||
"api",
|
||||
"data",
|
||||
"cryptocurrency"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"name": "brk-client",
|
||||
"repository": {
|
||||
"directory": "modules/brk-client",
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/bitcoinresearchkit/brk.git"
|
||||
},
|
||||
"type": "module",
|
||||
"version": "0.3.1"
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import { BrkClient } from "../index.js";
|
||||
|
||||
const client = new BrkClient("http://localhost:3110");
|
||||
|
||||
console.log("Testing idiomatic API...\n");
|
||||
|
||||
// Test getter access (property)
|
||||
console.log("1. Getter access (.by.dateindex):");
|
||||
const all = await client.series.prices.split.close.usd.by.day1;
|
||||
console.log(` Got: ${all.data.length} items\n`);
|
||||
|
||||
// Test dynamic access (bracket notation)
|
||||
console.log("2. Dynamic access (.by['dateindex']):");
|
||||
const allDynamic = await client.series.prices.split.close.usd.by.day1;
|
||||
console.log(` Got: ${allDynamic.data.length} items\n`);
|
||||
|
||||
// Test fetch all (explicit .fetch())
|
||||
console.log("3. Explicit .fetch():");
|
||||
const allExplicit = await client.series.prices.split.close.usd.by.day1.fetch();
|
||||
console.log(` Got: ${allExplicit.data.length} items\n`);
|
||||
|
||||
// Test first(n)
|
||||
console.log("4. First 5 items (.first(5)):");
|
||||
const first5 = await client.series.prices.split.close.usd.by.day1.first(5);
|
||||
console.log(
|
||||
` Start: ${first5.start}, End: ${first5.end}, Got: ${first5.data.length} items\n`,
|
||||
);
|
||||
|
||||
// Test last(n)
|
||||
console.log("5. Last 5 items (.last(5)):");
|
||||
const last5 = await client.series.prices.split.close.usd.by.day1.last(5);
|
||||
console.log(
|
||||
` Start: ${last5.start}, End: ${last5.end}, Got: ${last5.data.length} items\n`,
|
||||
);
|
||||
|
||||
// Test slice(start, end)
|
||||
console.log("6. Slice 10-20 (.slice(10, 20)):");
|
||||
const sliced = await client.series.prices.split.close.usd.by.day1.slice(10, 20);
|
||||
console.log(
|
||||
` Start: ${sliced.start}, End: ${sliced.end}, Got: ${sliced.data.length} items\n`,
|
||||
);
|
||||
|
||||
// Test get(index) - single item
|
||||
console.log("7. Single item (.get(100)):");
|
||||
const single = await client.series.prices.split.close.usd.by.day1.get(100);
|
||||
console.log(
|
||||
` Start: ${single.start}, End: ${single.end}, Got: ${single.data.length} item(s)\n`,
|
||||
);
|
||||
|
||||
// Test skip(n).take(m) chaining
|
||||
console.log("8. Skip and take (.skip(100).take(10)):");
|
||||
const skipTake = await client.series.prices.split.close.usd.by.day1
|
||||
.skip(100)
|
||||
.take(10);
|
||||
console.log(
|
||||
` Start: ${skipTake.start}, End: ${skipTake.end}, Got: ${skipTake.data.length} items\n`,
|
||||
);
|
||||
|
||||
// Test fetchCsv
|
||||
console.log("9. Fetch as CSV (.last(3).fetchCsv()):");
|
||||
const csv = await client.series.prices.split.close.usd.by.day1
|
||||
.last(3)
|
||||
.fetchCsv();
|
||||
console.log(` CSV preview: ${csv.substring(0, 100)}...\n`);
|
||||
|
||||
console.log("All tests passed!");
|
||||
@@ -1,132 +0,0 @@
|
||||
/**
|
||||
* Consistency test: verifies that all series sharing the same index have the same length.
|
||||
* Useful for catching stale/inconsistent state after a reorg rollback.
|
||||
*/
|
||||
|
||||
import { BrkClient } from "../index.js";
|
||||
|
||||
/**
|
||||
* @typedef {import('../index.js').AnySeriesPattern} AnyMetricPattern
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {any} obj
|
||||
* @returns {obj is AnyMetricPattern}
|
||||
*/
|
||||
function isMetricPattern(obj) {
|
||||
return (
|
||||
obj &&
|
||||
typeof obj === "object" &&
|
||||
typeof obj.indexes === "function" &&
|
||||
obj.by &&
|
||||
typeof obj.by === "object"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively collect all metric patterns from the tree.
|
||||
* @param {Record<string, any>} obj
|
||||
* @param {string} path
|
||||
* @returns {Array<{path: string, metric: AnyMetricPattern}>}
|
||||
*/
|
||||
function getAllMetrics(obj, path = "") {
|
||||
/** @type {Array<{path: string, metric: AnyMetricPattern}>} */
|
||||
const metrics = [];
|
||||
|
||||
for (const key of Object.keys(obj)) {
|
||||
const attr = obj[key];
|
||||
if (!attr || typeof attr !== "object") continue;
|
||||
|
||||
const currentPath = path ? `${path}.${key}` : key;
|
||||
|
||||
if (isMetricPattern(attr)) {
|
||||
metrics.push({ path: currentPath, metric: attr });
|
||||
}
|
||||
|
||||
if (typeof attr === "object" && !Array.isArray(attr)) {
|
||||
metrics.push(...getAllMetrics(attr, currentPath));
|
||||
}
|
||||
}
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
async function testConsistency() {
|
||||
const client = new BrkClient({
|
||||
baseUrl: "http://localhost:3110",
|
||||
timeout: 15000,
|
||||
});
|
||||
|
||||
const metrics = getAllMetrics(client.series);
|
||||
console.log(`\nFound ${metrics.length} metrics`);
|
||||
|
||||
/** @type {Map<string, Array<{path: string, total: number}>>} */
|
||||
const byIndex = new Map();
|
||||
|
||||
for (const { path, metric } of metrics) {
|
||||
const indexes = metric.indexes();
|
||||
|
||||
for (const idxName of indexes) {
|
||||
const fullPath = `${path}.by.${idxName}`;
|
||||
const endpoint = metric.by[idxName];
|
||||
|
||||
if (!endpoint) {
|
||||
console.log(`SKIP: ${fullPath} (undefined endpoint)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await endpoint.last(0);
|
||||
const total = result.end;
|
||||
|
||||
if (!byIndex.has(idxName)) {
|
||||
byIndex.set(idxName, []);
|
||||
}
|
||||
/** @type {Array<{path: string, total: number}>} */ (byIndex.get(idxName)).push({ path: fullPath, total });
|
||||
} catch (e) {
|
||||
console.log(
|
||||
`FAIL: ${fullPath} -> ${e instanceof Error ? e.message : e}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let failed = false;
|
||||
|
||||
for (const [index, entries] of byIndex) {
|
||||
const totals = new Set(entries.map((e) => e.total));
|
||||
|
||||
if (totals.size === 1) {
|
||||
const [total] = totals;
|
||||
console.log(`OK: ${index} — ${entries.length} series, all length ${total}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
failed = true;
|
||||
console.log(`\nMISMATCH: ${index} — ${entries.length} series with ${totals.size} different lengths:`);
|
||||
|
||||
/** @type {Map<number, string[]>} */
|
||||
const grouped = new Map();
|
||||
for (const { path, total } of entries) {
|
||||
if (!grouped.has(total)) grouped.set(total, []);
|
||||
/** @type {string[]} */ (grouped.get(total)).push(path);
|
||||
}
|
||||
|
||||
for (const [total, paths] of [...grouped].sort((a, b) => b[0] - a[0])) {
|
||||
console.log(` length ${total}: (${paths.length} series)`);
|
||||
for (const p of paths) {
|
||||
console.log(` ${p}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
console.log("\nFAILED: length mismatches detected");
|
||||
throw new Error("length mismatches detected");
|
||||
} else {
|
||||
console.log("\nPASSED: all indexes consistent");
|
||||
}
|
||||
}
|
||||
|
||||
testConsistency();
|
||||
@@ -1,248 +0,0 @@
|
||||
/**
|
||||
* Tests for MetricData helper methods and date conversion functions.
|
||||
* Run: node tests/metric_data.js
|
||||
*/
|
||||
|
||||
import { BrkClient } from "../index.js";
|
||||
|
||||
const client = new BrkClient("http://localhost:3110");
|
||||
|
||||
console.log("Testing MetricData helpers...\n");
|
||||
|
||||
// Fetch a date-based metric
|
||||
console.log("1. Fetching price data (day1):");
|
||||
const price = await client.series.prices.split.close.usd.by.day1.first(5);
|
||||
console.log(` Start: ${price.start}, End: ${price.end}`);
|
||||
|
||||
// Test isDateBased
|
||||
console.log("\n2. isDateBased:");
|
||||
if (!price.isDateBased) throw new Error("day1 should be date-based");
|
||||
console.log(` day1: ${price.isDateBased}`);
|
||||
|
||||
// Test indexes() - always returns numbers
|
||||
console.log("\n3. indexes():");
|
||||
const indexes = price.indexes();
|
||||
console.log(` ${JSON.stringify(indexes)}`);
|
||||
if (indexes.length !== 5) throw new Error("Expected 5 indexes");
|
||||
if (indexes[0] !== price.start)
|
||||
throw new Error("First index should equal start");
|
||||
|
||||
// Test dates() - DateMetricData method
|
||||
console.log("\n4. dates():");
|
||||
const dates = price.dates();
|
||||
console.log(
|
||||
` First: ${dates[0].toISOString()}, Last: ${dates[dates.length - 1].toISOString()}`,
|
||||
);
|
||||
if (dates.length !== 5) throw new Error("Expected 5 dates");
|
||||
// DateIndex 0 = Jan 3, 2009 (genesis)
|
||||
if (
|
||||
dates[0].getFullYear() !== 2009 ||
|
||||
dates[0].getMonth() !== 0 ||
|
||||
dates[0].getDate() !== 3
|
||||
) {
|
||||
throw new Error(
|
||||
`Expected genesis date (2009-01-03), got ${dates[0].toISOString()}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Test keys() - always returns numbers (alias for indexes)
|
||||
console.log("\n5. keys():");
|
||||
const keys = price.keys();
|
||||
if (keys.length !== 5) throw new Error("Expected 5 keys");
|
||||
if (typeof keys[0] !== "number") throw new Error("Expected number keys");
|
||||
console.log(` Length: ${keys.length}, First: ${keys[0]}`);
|
||||
|
||||
// Test entries() - returns [number, value] pairs
|
||||
console.log("\n6. entries():");
|
||||
const entries = price.entries();
|
||||
if (typeof entries[0][0] !== "number")
|
||||
throw new Error("Expected number entry key");
|
||||
console.log(` First: [${entries[0][0]}, ${entries[0][1]}]`);
|
||||
if (entries[0][1] !== price.data[0])
|
||||
throw new Error("First entry value mismatch");
|
||||
|
||||
// Test dateEntries() - DateMetricData method, returns [Date, value] pairs
|
||||
console.log("\n7. dateEntries():");
|
||||
const dateEntries = price.dateEntries();
|
||||
if (!(dateEntries[0][0] instanceof Date))
|
||||
throw new Error("Expected Date entry key");
|
||||
console.log(
|
||||
` First: [${dateEntries[0][0].toISOString()}, ${dateEntries[0][1]}]`,
|
||||
);
|
||||
|
||||
// Test toMap() - returns Map<number, value>
|
||||
console.log("\n8. toMap():");
|
||||
const map = price.toMap();
|
||||
console.log(` Size: ${map.size}`);
|
||||
if (map.size !== 5) throw new Error("Expected map size 5");
|
||||
|
||||
// Test toDateMap() - DateMetricData method
|
||||
console.log("\n9. toDateMap():");
|
||||
const dateMap = price.toDateMap();
|
||||
console.log(` Size: ${dateMap.size}`);
|
||||
if (dateMap.size !== 5) throw new Error("Expected date map size 5");
|
||||
|
||||
// Test Symbol.iterator (for...of) - yields [number, value]
|
||||
console.log("\n10. for...of iteration:");
|
||||
let count = 0;
|
||||
for (const [key, _val] of price) {
|
||||
if (count === 0 && typeof key !== "number")
|
||||
throw new Error("Expected number keys in iteration");
|
||||
count++;
|
||||
}
|
||||
console.log(` Iterated ${count} items`);
|
||||
if (count !== 5) throw new Error("Expected 5 iterations");
|
||||
|
||||
// Test with non-date-based index (height)
|
||||
console.log("\n11. Testing height-based metric:");
|
||||
const heightMetric = await client.series.prices.spot.usd.by.height.last(3);
|
||||
console.log(` Start: ${heightMetric.start}, End: ${heightMetric.end}`);
|
||||
if (heightMetric.isDateBased)
|
||||
throw new Error("height should not be date-based");
|
||||
|
||||
// Test keys() - always numbers
|
||||
const heightKeys = heightMetric.keys();
|
||||
console.log(` keys(): ${JSON.stringify(heightKeys)}`);
|
||||
if (typeof heightKeys[0] !== "number")
|
||||
throw new Error("Expected number keys for height");
|
||||
|
||||
// Test entries() - [number, value]
|
||||
const heightEntries = heightMetric.entries();
|
||||
console.log(
|
||||
` entries()[0]: [${heightEntries[0][0]}, ${heightEntries[0][1]}]`,
|
||||
);
|
||||
if (heightEntries[0][0] !== heightMetric.start)
|
||||
throw new Error("First entry index mismatch");
|
||||
|
||||
// Test toMap() - Map<number, value>
|
||||
const heightMap = heightMetric.toMap();
|
||||
if (heightMap.size !== 3) throw new Error("Expected map size 3");
|
||||
if (heightMap.get(heightMetric.start) !== heightMetric.data[0])
|
||||
throw new Error("First value mismatch");
|
||||
|
||||
// Test for...of on non-date metric
|
||||
console.log("\n12. for...of iteration (height):");
|
||||
let heightCount = 0;
|
||||
for (const [key, _val] of heightMetric) {
|
||||
if (heightCount === 0 && typeof key !== "number")
|
||||
throw new Error("Expected number keys for height iteration");
|
||||
heightCount++;
|
||||
}
|
||||
console.log(` Iterated ${heightCount} items`);
|
||||
|
||||
// Test different date indexes
|
||||
console.log("\n13. Testing month1:");
|
||||
const monthMetric =
|
||||
await client.series.prices.split.close.usd.by.month1.first(3);
|
||||
const monthDates = monthMetric.dates();
|
||||
console.log(` First month: ${monthDates[0].toISOString()}`);
|
||||
// MonthIndex 0 = Jan 1, 2009
|
||||
if (
|
||||
monthDates[0].getFullYear() !== 2009 ||
|
||||
monthDates[0].getMonth() !== 0 ||
|
||||
monthDates[0].getDate() !== 1
|
||||
) {
|
||||
throw new Error(`Expected 2009-01-01, got ${monthDates[0].toISOString()}`);
|
||||
}
|
||||
|
||||
// Test indexToDate directly
|
||||
console.log("\n14. Testing indexToDate():");
|
||||
const genesis = client.indexToDate("day1", 0);
|
||||
if (
|
||||
genesis.getFullYear() !== 2009 ||
|
||||
genesis.getMonth() !== 0 ||
|
||||
genesis.getDate() !== 3
|
||||
) {
|
||||
throw new Error(`Expected genesis 2009-01-03, got ${genesis.toISOString()}`);
|
||||
}
|
||||
const dayOne = client.indexToDate("day1", 1);
|
||||
if (
|
||||
dayOne.getFullYear() !== 2009 ||
|
||||
dayOne.getMonth() !== 0 ||
|
||||
dayOne.getDate() !== 9
|
||||
) {
|
||||
throw new Error(`Expected day one 2009-01-09, got ${dayOne.toISOString()}`);
|
||||
}
|
||||
console.log(` day1 0: ${genesis.toISOString()}`);
|
||||
console.log(` day1 1: ${dayOne.toISOString()}`);
|
||||
|
||||
// Test week1
|
||||
const week0 = client.indexToDate("week1", 0);
|
||||
const week1 = client.indexToDate("week1", 1);
|
||||
if (week0.getTime() !== genesis.getTime())
|
||||
throw new Error("week1 0 should equal genesis");
|
||||
console.log(` week1 0: ${week0.toISOString()}`);
|
||||
console.log(` week1 1: ${week1.toISOString()}`);
|
||||
|
||||
// Test year1
|
||||
const year0 = client.indexToDate("year1", 0);
|
||||
const year1 = client.indexToDate("year1", 1);
|
||||
if (
|
||||
year0.getFullYear() !== 2009 ||
|
||||
year0.getMonth() !== 0 ||
|
||||
year0.getDate() !== 1
|
||||
) {
|
||||
throw new Error(`Expected 2009-01-01, got ${year0.toISOString()}`);
|
||||
}
|
||||
if (year1.getFullYear() !== 2010) throw new Error("year1 1 should be 2010");
|
||||
console.log(` year1 0: ${year0.toISOString()}`);
|
||||
console.log(` year1 1: ${year1.toISOString()}`);
|
||||
|
||||
// Test month3
|
||||
const q0 = client.indexToDate("month3", 0);
|
||||
const q1 = client.indexToDate("month3", 1);
|
||||
if (q0.getMonth() !== 0) throw new Error("month3 0 should be January");
|
||||
if (q1.getMonth() !== 3) throw new Error("month3 1 should be April");
|
||||
console.log(` month3 0: ${q0.toISOString()}`);
|
||||
console.log(` month3 1: ${q1.toISOString()}`);
|
||||
|
||||
// Test month6
|
||||
const s0 = client.indexToDate("month6", 0);
|
||||
const s1 = client.indexToDate("month6", 1);
|
||||
if (s0.getMonth() !== 0) throw new Error("month6 0 should be January");
|
||||
if (s1.getMonth() !== 6) throw new Error("month6 1 should be July");
|
||||
console.log(` month6 0: ${s0.toISOString()}`);
|
||||
console.log(` month6 1: ${s1.toISOString()}`);
|
||||
|
||||
// Test year10
|
||||
const d0 = client.indexToDate("year10", 0);
|
||||
const d1 = client.indexToDate("year10", 1);
|
||||
if (d0.getFullYear() !== 2009) throw new Error("year10 0 should be 2009");
|
||||
if (d1.getFullYear() !== 2019) throw new Error("year10 1 should be 2019");
|
||||
console.log(` year10 0: ${d0.toISOString()}`);
|
||||
console.log(` year10 1: ${d1.toISOString()}`);
|
||||
|
||||
// Test dateToIndex
|
||||
console.log("\n15. Testing dateToIndex():");
|
||||
const idx = client.dateToIndex("day1", new Date(Date.UTC(2009, 0, 9)));
|
||||
if (idx !== 1) throw new Error(`Expected day1 index 1, got ${idx}`);
|
||||
console.log(` day1 2009-01-09: ${idx}`);
|
||||
|
||||
const monthIdx = client.dateToIndex("month1", new Date(Date.UTC(2010, 0, 1)));
|
||||
if (monthIdx !== 12)
|
||||
throw new Error(`Expected month1 index 12, got ${monthIdx}`);
|
||||
console.log(` month1 2010-01-01: ${monthIdx}`);
|
||||
|
||||
const yearIdx = client.dateToIndex("year1", new Date(Date.UTC(2019, 0, 1)));
|
||||
if (yearIdx !== 10) throw new Error(`Expected year1 index 10, got ${yearIdx}`);
|
||||
console.log(` year1 2019-01-01: ${yearIdx}`);
|
||||
|
||||
// Test roundtrip: indexToDate -> dateToIndex
|
||||
const testDate = client.indexToDate("day1", 100);
|
||||
const roundtrip = client.dateToIndex("day1", testDate);
|
||||
if (roundtrip !== 100)
|
||||
throw new Error(`Roundtrip failed: expected 100, got ${roundtrip}`);
|
||||
console.log(` Roundtrip day1 100: ${testDate.toISOString()} -> ${roundtrip}`);
|
||||
|
||||
// Test slice with Date
|
||||
console.log("\n16. Testing slice with Date:");
|
||||
const dateSlice = await client.series.prices.split.close.usd.by.day1
|
||||
.slice(new Date(Date.UTC(2020, 0, 1)), new Date(Date.UTC(2020, 0, 4)))
|
||||
.fetch();
|
||||
console.log(
|
||||
` Slice start: ${dateSlice.start}, end: ${dateSlice.end}, items: ${dateSlice.data.length}`,
|
||||
);
|
||||
if (dateSlice.data.length !== dateSlice.end - dateSlice.start)
|
||||
throw new Error("Slice data length mismatch");
|
||||
|
||||
console.log("\nAll MetricData tests passed!");
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* Comprehensive test that fetches all endpoints in the tree.
|
||||
*/
|
||||
|
||||
import { BrkClient } from "../index.js";
|
||||
|
||||
/**
|
||||
* @typedef {import('../index.js').AnySeriesPattern} AnyMetricPattern
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check if an object is a metric pattern (has indexes() method and by object).
|
||||
* @param {any} obj
|
||||
* @returns {obj is AnyMetricPattern}
|
||||
*/
|
||||
function isMetricPattern(obj) {
|
||||
return (
|
||||
obj &&
|
||||
typeof obj === "object" &&
|
||||
typeof obj.indexes === "function" &&
|
||||
obj.by &&
|
||||
typeof obj.by === "object"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively collect all metric patterns from the tree.
|
||||
* @param {Record<string, any>} obj
|
||||
* @param {string} path
|
||||
* @returns {Array<{path: string, metric: AnyMetricPattern}>}
|
||||
*/
|
||||
function getAllMetrics(obj, path = "") {
|
||||
/** @type {Array<{path: string, metric: AnyMetricPattern}>} */
|
||||
const metrics = [];
|
||||
|
||||
for (const key of Object.keys(obj)) {
|
||||
const attr = obj[key];
|
||||
if (!attr || typeof attr !== "object") continue;
|
||||
|
||||
const currentPath = path ? `${path}.${key}` : key;
|
||||
|
||||
// Check if this is a metric pattern using the indexes() method
|
||||
if (isMetricPattern(attr)) {
|
||||
metrics.push({ path: currentPath, metric: attr });
|
||||
}
|
||||
|
||||
// Recurse into nested tree nodes
|
||||
if (typeof attr === "object" && !Array.isArray(attr)) {
|
||||
metrics.push(...getAllMetrics(attr, currentPath));
|
||||
}
|
||||
}
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
async function testAllEndpoints() {
|
||||
const client = new BrkClient({
|
||||
baseUrl: "http://localhost:3110",
|
||||
timeout: 15000,
|
||||
});
|
||||
|
||||
const metrics = getAllMetrics(client.series);
|
||||
console.log(`\nFound ${metrics.length} metrics`);
|
||||
|
||||
let success = 0;
|
||||
|
||||
for (const { path, metric } of metrics) {
|
||||
// Use the indexes() method to get all available indexes
|
||||
const indexes = metric.indexes();
|
||||
|
||||
for (const idxName of indexes) {
|
||||
const fullPath = `${path}.by.${idxName}`;
|
||||
|
||||
try {
|
||||
// Verify both access methods work: .by[index] and .get(index)
|
||||
const endpointByProperty = metric.by[idxName];
|
||||
const endpointByGet = metric.get(idxName);
|
||||
|
||||
if (!endpointByProperty) {
|
||||
throw new Error(`metric.by.${idxName} is undefined`);
|
||||
}
|
||||
if (!endpointByGet) {
|
||||
throw new Error(`metric.get('${idxName}') returned undefined`);
|
||||
}
|
||||
|
||||
await endpointByProperty.last(0);
|
||||
success++;
|
||||
console.log(`OK: ${fullPath}`);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
`FAIL: ${fullPath} -> ${e instanceof Error ? e.message : e}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n=== Results ===`);
|
||||
console.log(`Success: ${success}`);
|
||||
}
|
||||
|
||||
testAllEndpoints();
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"strict": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"outDir": "/tmp/brk",
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"exclude": ["dist", "tests"]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
*.js
|
||||
-653
@@ -1,653 +0,0 @@
|
||||
declare module 'lean-qr' {
|
||||
interface ImageDataLike {
|
||||
readonly data: Uint8ClampedArray;
|
||||
}
|
||||
|
||||
interface Context2DLike<DataT extends ImageDataLike> {
|
||||
createImageData(width: number, height: number): DataT;
|
||||
putImageData(data: DataT, x: number, y: number): void;
|
||||
}
|
||||
|
||||
interface CanvasLike<DataT extends ImageDataLike> {
|
||||
width: number;
|
||||
height: number;
|
||||
getContext(type: '2d'): Context2DLike<DataT> | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A colour in `[red, green, blue, alpha]` format (all values from 0 to 255).
|
||||
* If alpha is omitted, it is assumed to be 255 (opaque).
|
||||
*/
|
||||
export type RGBA = readonly [number, number, number, number?];
|
||||
|
||||
export interface Bitmap1D {
|
||||
/**
|
||||
* Appends a sequence of bits.
|
||||
*
|
||||
* @param value an integer containing the bits to append (big endian).
|
||||
* @param bits the number of bits to read from `value`. Must be between 1 and 24.
|
||||
*/
|
||||
push(value: number, bits: number): void;
|
||||
}
|
||||
|
||||
export interface StringOptions {
|
||||
/** the text to use for modules which are 'on' (typically black) */
|
||||
on?: string;
|
||||
|
||||
/** the text to use for modules which are 'off' (typically white) */
|
||||
off?: string;
|
||||
|
||||
/** the text to use for linefeeds between rows */
|
||||
lf?: string;
|
||||
|
||||
/** the padding to apply around the output (populated with 'off' modules) */
|
||||
pad?: number;
|
||||
|
||||
/**
|
||||
* the padding to apply on the left and right of the output (populated with 'off' modules)
|
||||
* @deprecated use `pad` instead
|
||||
*/
|
||||
padX?: number;
|
||||
|
||||
/**
|
||||
* the padding to apply on the top and bottom of the output (populated with 'off' modules)
|
||||
* @deprecated use `pad` instead
|
||||
*/
|
||||
padY?: number;
|
||||
}
|
||||
|
||||
export interface ImageDataOptions {
|
||||
/** the colour to use for modules which are 'on' (typically black) */
|
||||
on?: RGBA;
|
||||
|
||||
/** the colour to use for modules which are 'off' (typically white) */
|
||||
off?: RGBA;
|
||||
|
||||
/** the padding to apply around the output (filled with 'off') */
|
||||
pad?: number;
|
||||
|
||||
/**
|
||||
* the padding to apply on the left and right of the output (filled with 'off')
|
||||
* @deprecated use `pad` instead
|
||||
*/
|
||||
padX?: number;
|
||||
|
||||
/**
|
||||
* the padding to apply on the top and bottom of the output (filled with 'off')
|
||||
* @deprecated use `pad` instead
|
||||
*/
|
||||
padY?: number;
|
||||
}
|
||||
|
||||
export interface Bitmap2D {
|
||||
/** the width / height of the QR code in modules (excluding any padding) */
|
||||
readonly size: number;
|
||||
|
||||
/**
|
||||
* Read the state of a module from the QR code.
|
||||
*
|
||||
* @param x the x coordinate to read. Can be negative / out of bounds.
|
||||
* @param y the y coordinate to read. Can be negative / out of bounds.
|
||||
* @returns true if the requested module is set (i.e. typically black)
|
||||
*/
|
||||
get(x: number, y: number): boolean;
|
||||
|
||||
/**
|
||||
* Generate a string containing the QR code, suitable for displaying in a
|
||||
* terminal environment. Generally, you should customise on and off to use
|
||||
* the ANSI escapes of your target terminal for better rendering.
|
||||
*
|
||||
* @param options optional configuration for the display.
|
||||
*/
|
||||
toString(options?: Readonly<StringOptions>): string;
|
||||
|
||||
/**
|
||||
* Generate image data containing the QR code, at a scale of 1 pixel per
|
||||
* module. Use this if you need more control than toCanvas allows.
|
||||
*
|
||||
* @param context a context to use for creating the image data.
|
||||
* @param options optional configuration for the display.
|
||||
*/
|
||||
toImageData<DataT extends ImageDataLike>(
|
||||
context: Context2DLike<DataT>,
|
||||
options?: Readonly<ImageDataOptions>,
|
||||
): DataT;
|
||||
|
||||
/**
|
||||
* Generate a `data:image/*` URL for the QR code.
|
||||
*
|
||||
* @param options optional configuration for the output.
|
||||
* @returns a string suitable for use as the `src` of an `img` tag.
|
||||
*/
|
||||
toDataURL(
|
||||
options?: Readonly<
|
||||
ImageDataOptions & {
|
||||
type?: `image/${string}`;
|
||||
scale?: number;
|
||||
}
|
||||
>,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Populate a given canvas with the QR code, at a scale of 1 pixel per
|
||||
* module. Set image-rendering: pixelated and scale the canvas using CSS
|
||||
* for a large image. Automatically resizes the canvas to fit the QR code
|
||||
* if necessary.
|
||||
*
|
||||
* @param canvas the canvas to populate.
|
||||
* @param options optional configuration for the display.
|
||||
*/
|
||||
toCanvas(
|
||||
canvas: CanvasLike<ImageDataLike>,
|
||||
options?: Readonly<ImageDataOptions>,
|
||||
): void;
|
||||
}
|
||||
|
||||
export type Mask = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
||||
export type Mode = (data: Bitmap1D, version: number) => void;
|
||||
export interface ModeFactory {
|
||||
(value: string): Mode;
|
||||
/** a function which returns true when given a character which the current mode can represent */
|
||||
test(string: string): boolean;
|
||||
/** a function which returns an estimate of the number of bits required to encode a given value */
|
||||
est(value: string, version: number): number;
|
||||
/** an optional ECI which must be active for this mode to be interpreted correctly by a reader */
|
||||
eci?: number;
|
||||
}
|
||||
|
||||
interface ModeAutoOptions {
|
||||
/** a list of modes which can be considered when encoding a message */
|
||||
modes?: ReadonlyArray<ModeFactory>;
|
||||
}
|
||||
|
||||
export const mode: Readonly<{
|
||||
/** automatically picks the most optimal combination of modes for the requested message */
|
||||
auto(value: string, options?: Readonly<ModeAutoOptions>): Mode;
|
||||
/** concatenates multiple modes together */
|
||||
multi(...modes: ReadonlyArray<Mode>): Mode;
|
||||
/** sets the Extended Channel Interpretation for the message from this point onwards */
|
||||
eci(id: number): Mode;
|
||||
/** supports `0-9` and stores 3 characters per 10 bits */
|
||||
numeric: ModeFactory;
|
||||
/** supports `0-9A-Z $%*+-./:` and stores 2 characters per 11 bits */
|
||||
alphaNumeric: ModeFactory;
|
||||
/** arbitrary byte data, typically combined with `eci` */
|
||||
bytes(data: Uint8Array | ReadonlyArray<number>): Mode;
|
||||
/** supports 7-bit ASCII and stores 1 character per 8 bits with no ECI */
|
||||
ascii: ModeFactory;
|
||||
/** supports 8-bit ISO-8859-1 and stores 1 character per 8 bits with ECI 3 */
|
||||
iso8859_1: ModeFactory;
|
||||
/** supports double-byte Shift-JIS characters stores 1 character per 13 bits */
|
||||
shift_jis: ModeFactory;
|
||||
/** supports variable length UTF-8 with ECI 26 */
|
||||
utf8: ModeFactory;
|
||||
}>;
|
||||
|
||||
export type Correction = number & { readonly _: unique symbol };
|
||||
export const correction: Readonly<{
|
||||
/**
|
||||
* minimum possible correction level (same as L)
|
||||
* @deprecated use correction.L
|
||||
*/
|
||||
min: Correction;
|
||||
/** ~7.5% error tolerance, ~25% data overhead */
|
||||
L: Correction;
|
||||
/** ~15% error tolerance, ~60% data overhead */
|
||||
M: Correction;
|
||||
/** ~22.5% error tolerance, ~120% data overhead */
|
||||
Q: Correction;
|
||||
/** ~30% error tolerance, ~190% data overhead */
|
||||
H: Correction;
|
||||
/**
|
||||
* maximum possible correction level (same as H)
|
||||
* @deprecated use correction.H
|
||||
*/
|
||||
max: Correction;
|
||||
}>;
|
||||
|
||||
export interface GenerateOptions extends ModeAutoOptions {
|
||||
/** the minimum correction level to use (higher levels may still be used if the chosen version has space) */
|
||||
minCorrectionLevel?: Correction;
|
||||
/** the maximum correction level to use */
|
||||
maxCorrectionLevel?: Correction;
|
||||
/** the minimum version (size) of code to generate (must be between 1 and 40) */
|
||||
minVersion?: number;
|
||||
/** the maximum version (size) of code to generate (must be between 1 and 40) */
|
||||
maxVersion?: number;
|
||||
/** a mask to use on the QR code (should be left as `null` for ISO compliance but may be changed for artistic effect) */
|
||||
mask?: null | Mask;
|
||||
/** padding bits to use for extra space in the QR code (should be left as the default for ISO compliance but may be changed for artistic effect) */
|
||||
trailer?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a QR code.
|
||||
*
|
||||
* @param data either a string, or a pre-encoded mode.
|
||||
* @param options optional configuration for the QR code.
|
||||
* @returns the requested QR code.
|
||||
*/
|
||||
export type GenerateFn = (
|
||||
data: Mode | string,
|
||||
options?: Readonly<GenerateOptions>,
|
||||
) => Bitmap2D;
|
||||
interface Generate extends GenerateFn {
|
||||
/**
|
||||
* Creates a scoped `generate` function which considers additional modes
|
||||
* when using auto encoding.
|
||||
*
|
||||
* @param modes the modes to add.
|
||||
* @returns a `generate` function which will additionally consider the
|
||||
* given modes when using auto encoding.
|
||||
*
|
||||
* @deprecated this will be removed in version 3. Prefer passing an explicit list of modes when calling `generate`.
|
||||
*/
|
||||
with(...modes: ReadonlyArray<ModeFactory>): GenerateFn;
|
||||
}
|
||||
export const generate: Generate;
|
||||
}
|
||||
|
||||
declare module 'lean-qr/nano' {
|
||||
import type {
|
||||
Correction,
|
||||
Bitmap2D as FullBitmap2D,
|
||||
GenerateOptions as FullGenerateOptions,
|
||||
} from 'lean-qr';
|
||||
import { correction as fullCorrection } from 'lean-qr';
|
||||
|
||||
export type { Correction };
|
||||
|
||||
export const correction: Pick<typeof fullCorrection, 'L' | 'M' | 'Q' | 'H'>;
|
||||
|
||||
export type Bitmap2D = Pick<FullBitmap2D, 'size' | 'get' | 'toCanvas'>;
|
||||
|
||||
export type GenerateOptions = Pick<
|
||||
FullGenerateOptions,
|
||||
'minCorrectionLevel' | 'minVersion'
|
||||
>;
|
||||
|
||||
/**
|
||||
* Generate a QR code.
|
||||
*
|
||||
* @param data either a string, or a pre-encoded mode.
|
||||
* @param options optional configuration for the QR code.
|
||||
* @returns the requested QR code.
|
||||
*/
|
||||
export function generate(
|
||||
data: string,
|
||||
options?: Readonly<GenerateOptions>,
|
||||
): Bitmap2D;
|
||||
}
|
||||
|
||||
declare module 'lean-qr/extras/svg' {
|
||||
import type { Bitmap2D as FullBitmap2D } from 'lean-qr';
|
||||
|
||||
type Bitmap2D = Pick<FullBitmap2D, 'size' | 'get'>;
|
||||
|
||||
export interface SVGOptions {
|
||||
/** the colour to use for modules which are 'on' (typically black) */
|
||||
on?: string;
|
||||
/** the colour to use for modules which are 'off' (typically white) */
|
||||
off?: string;
|
||||
/** the padding to apply around the output (filled with 'off') */
|
||||
pad?: number;
|
||||
/**
|
||||
* the padding to apply on the left and right of the output (filled with 'off')
|
||||
* @deprecated use `pad` instead
|
||||
*/
|
||||
padX?: number;
|
||||
/**
|
||||
* the padding to apply on the top and bottom of the output (filled with 'off')
|
||||
* @deprecated use `pad` instead
|
||||
*/
|
||||
padY?: number;
|
||||
/** a width to apply to the resulting image (overrides `scale`) */
|
||||
width?: number | null;
|
||||
/** a height to apply to the resulting image (overrides `scale`) */
|
||||
height?: number | null;
|
||||
/** a scale to apply to the resulting image (`scale` pixels = 1 module) */
|
||||
scale?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the raw outline of the QR code for use in an existing SVG.
|
||||
*
|
||||
* @param code the QR code to convert.
|
||||
* @returns a string suitable for passing to the `d` attribute of a `path`.
|
||||
*/
|
||||
export function toSvgPath(code: Bitmap2D): string;
|
||||
|
||||
/**
|
||||
* Generate an SVG element which can be added to the DOM.
|
||||
*
|
||||
* @param code the QR code to convert.
|
||||
* @param options optional configuration for the display.
|
||||
* @returns an SVG element.
|
||||
*/
|
||||
export function toSvg(
|
||||
code: Bitmap2D,
|
||||
target: Document | SVGElement,
|
||||
options?: Readonly<SVGOptions>,
|
||||
): SVGElement;
|
||||
|
||||
/**
|
||||
* Generate an SVG document which can be exported to a file or served from a
|
||||
* web server.
|
||||
*
|
||||
* @param code the QR code to convert.
|
||||
* @param options optional configuration for the display.
|
||||
* @returns an SVG document.
|
||||
*/
|
||||
export function toSvgSource(
|
||||
code: Bitmap2D,
|
||||
options?: Readonly<
|
||||
SVGOptions & {
|
||||
/** `true` to include an XML declaration at the start of the source (for standalone documents which will not be embedded inside another document) */
|
||||
xmlDeclaration?: boolean;
|
||||
}
|
||||
>,
|
||||
): string;
|
||||
|
||||
/**
|
||||
* Generate a `data:image/svg+xml` URL.
|
||||
*
|
||||
* @param code the QR code to convert.
|
||||
* @param options optional configuration for the display.
|
||||
* @returns a string suitable for use as the `src` of an `img` tag.
|
||||
*/
|
||||
export function toSvgDataURL(
|
||||
code: Bitmap2D,
|
||||
options?: Readonly<SVGOptions>,
|
||||
): string;
|
||||
}
|
||||
|
||||
declare module 'lean-qr/extras/node_export' {
|
||||
import type { RGBA, Bitmap2D as FullBitmap2D } from 'lean-qr';
|
||||
|
||||
type Bitmap2D = Pick<FullBitmap2D, 'size' | 'get'>;
|
||||
|
||||
export interface PNGOptions {
|
||||
/** the colour to use for modules which are 'on' (typically black) */
|
||||
on?: RGBA;
|
||||
/** the colour to use for modules which are 'off' (typically white) */
|
||||
off?: RGBA;
|
||||
/** the padding to apply around the output (filled with 'off') */
|
||||
pad?: number;
|
||||
/**
|
||||
* the padding to apply on the left and right of the output (filled with 'off')
|
||||
* @deprecated use `pad` instead
|
||||
*/
|
||||
padX?: number;
|
||||
/**
|
||||
* the padding to apply on the top and bottom of the output (filled with 'off')
|
||||
* @deprecated use `pad` instead
|
||||
*/
|
||||
padY?: number;
|
||||
/** a scale to apply to the resulting image (`scale` pixels = 1 module) */
|
||||
scale?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a PNG document which can be exported to a file or served from a
|
||||
* web server.
|
||||
*
|
||||
* @param code the QR code to convert.
|
||||
* @param options optional configuration for the display.
|
||||
* @returns a PNG document.
|
||||
*/
|
||||
export function toPngBuffer(
|
||||
code: Bitmap2D,
|
||||
options?: Readonly<PNGOptions>,
|
||||
): Uint8Array;
|
||||
|
||||
/**
|
||||
* Generate a `data:image/png` URL.
|
||||
*
|
||||
* @param code the QR code to convert.
|
||||
* @param options optional configuration for the display.
|
||||
* @returns a string suitable for use as the `src` of an `img` tag.
|
||||
*/
|
||||
export function toPngDataURL(
|
||||
code: Bitmap2D,
|
||||
options?: Readonly<PNGOptions>,
|
||||
): string;
|
||||
}
|
||||
|
||||
declare module 'lean-qr/extras/react' {
|
||||
import type {
|
||||
Bitmap2D as FullBitmap2D,
|
||||
GenerateOptions,
|
||||
ImageDataOptions,
|
||||
} from 'lean-qr';
|
||||
import type {
|
||||
SVGOptions,
|
||||
toSvgDataURL as toSvgDataURLFn,
|
||||
} from 'lean-qr/extras/svg';
|
||||
|
||||
export interface AsyncFramework<T> {
|
||||
createElement: (
|
||||
type: 'canvas',
|
||||
props: {
|
||||
ref: any;
|
||||
style: { imageRendering: 'pixelated' };
|
||||
className: string;
|
||||
},
|
||||
) => T;
|
||||
useRef<T>(initialValue: T | null): { readonly current: T | null };
|
||||
useEffect(fn: () => void | (() => void), deps: unknown[]): void;
|
||||
}
|
||||
|
||||
interface QRComponentProps {
|
||||
content: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface AsyncQRComponentProps
|
||||
extends ImageDataOptions,
|
||||
GenerateOptions,
|
||||
QRComponentProps {}
|
||||
|
||||
export type AsyncQRComponent<T> = (
|
||||
props: Readonly<AsyncQRComponentProps>,
|
||||
) => T;
|
||||
|
||||
/**
|
||||
* Generate an asynchronous QR component (rendering to a `canvas`).
|
||||
* You should call this just once, in the global scope.
|
||||
*
|
||||
* ```js
|
||||
* import * as React from 'react';
|
||||
* import { generate } from 'lean-qr';
|
||||
* import { makeAsyncComponent } from 'lean-qr/extras/react';
|
||||
* const QR = makeAsyncComponent(React, generate);
|
||||
* ```
|
||||
*
|
||||
* This is not suitable for server-side rendering (use `makeSyncComponent`
|
||||
* instead).
|
||||
*
|
||||
* @param framework the framework to use (e.g. `React`).
|
||||
* @param generate the `generate` function to use
|
||||
* (from `lean-qr` or `lean-qr/nano`).
|
||||
* @param defaultProps optional default properties to apply when the
|
||||
* component is used (overridden by properties set on use).
|
||||
* @returns a component which can be rendered elsewhere.
|
||||
*/
|
||||
export function makeAsyncComponent<T>(
|
||||
framework: Readonly<AsyncFramework<T>>,
|
||||
generate: (
|
||||
data: string,
|
||||
options?: Readonly<GenerateOptions>,
|
||||
) => Pick<FullBitmap2D, 'toCanvas'>,
|
||||
defaultProps?: Readonly<Partial<AsyncQRComponentProps>>,
|
||||
): AsyncQRComponent<T>;
|
||||
|
||||
export interface SyncFramework<T> {
|
||||
createElement: (
|
||||
type: 'img',
|
||||
props: {
|
||||
src: string;
|
||||
style: { imageRendering: 'pixelated' };
|
||||
className: string;
|
||||
},
|
||||
) => T;
|
||||
useMemo<T>(fn: () => T, deps: unknown[]): T;
|
||||
}
|
||||
|
||||
export interface SyncQRComponentProps
|
||||
extends SVGOptions,
|
||||
GenerateOptions,
|
||||
QRComponentProps {}
|
||||
|
||||
export type SyncQRComponent<T> = (props: Readonly<SyncQRComponentProps>) => T;
|
||||
|
||||
/**
|
||||
* Generate a synchronous QR component (rendering to an SVG).
|
||||
* You should call this just once, in the global scope.
|
||||
*
|
||||
* ```js
|
||||
* import * as React from 'react';
|
||||
* import { generate } from 'lean-qr';
|
||||
* import { toSvgDataURL } from 'lean-qr/extras/svg';
|
||||
* import { makeSyncComponent } from 'lean-qr/extras/react';
|
||||
* const QR = makeSyncComponent(React, generate, toSvgDataURL);
|
||||
* ```
|
||||
*
|
||||
* This is best suited for server-side rendering (prefer
|
||||
* `makeAsyncComponent` if you only need client-side rendering).
|
||||
*
|
||||
* @param framework the framework to use (e.g. `React`).
|
||||
* @param generate the `generate` function to use
|
||||
* (from `lean-qr` or `lean-qr/nano`).
|
||||
* @param toSvgDataURL the `toSvgDataURL` function to use
|
||||
* (from `lean-qr/extras/svg`).
|
||||
* @param defaultProps optional default properties to apply when the
|
||||
* component is used (overridden by properties set on use).
|
||||
* @returns a component which can be rendered elsewhere.
|
||||
*/
|
||||
export function makeSyncComponent<T>(
|
||||
framework: Readonly<SyncFramework<T>>,
|
||||
generate: (
|
||||
data: string,
|
||||
options?: Readonly<GenerateOptions>,
|
||||
) => Pick<FullBitmap2D, 'size' | 'get'>,
|
||||
toSvgDataURL: typeof toSvgDataURLFn,
|
||||
defaultProps?: Readonly<Partial<SyncQRComponentProps>>,
|
||||
): SyncQRComponent<T>;
|
||||
}
|
||||
|
||||
declare module 'lean-qr/extras/vue' {
|
||||
import type {
|
||||
Bitmap2D as FullBitmap2D,
|
||||
GenerateOptions,
|
||||
ImageDataOptions,
|
||||
} from 'lean-qr';
|
||||
import type {
|
||||
SVGOptions,
|
||||
toSvgDataURL as toSvgDataURLFn,
|
||||
} from 'lean-qr/extras/svg';
|
||||
|
||||
export interface Framework {
|
||||
h:
|
||||
| ((type: 'canvas', props: { ref: string; style: string }) => unknown)
|
||||
| ((type: 'img', props: { src: string; style: string }) => unknown);
|
||||
}
|
||||
|
||||
interface QRComponentProps {
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface VueCanvasComponentProps
|
||||
extends ImageDataOptions,
|
||||
GenerateOptions,
|
||||
QRComponentProps {}
|
||||
|
||||
type VueComponentDefinition<Props> = {
|
||||
props: {
|
||||
[k in keyof Props]-?: {
|
||||
type: { (): Required<Props>[k] };
|
||||
required: undefined extends Props[k] ? false : true;
|
||||
};
|
||||
};
|
||||
} & ThisType<unknown>;
|
||||
|
||||
/**
|
||||
* Generate a QR component which renders to a `canvas`.
|
||||
* You should call this just once, in the global scope.
|
||||
*
|
||||
* ```js
|
||||
* import { h, defineComponent } from 'vue';
|
||||
* import { generate } from 'lean-qr';
|
||||
* import { makeVueCanvasComponent } from 'lean-qr/extras/vue';
|
||||
* export const QR = defineComponent(makeVueCanvasComponent({ h }, generate));
|
||||
* ```
|
||||
*
|
||||
* This is not suitable for server-side rendering (use `makeSyncComponent`
|
||||
* instead).
|
||||
*
|
||||
* @param framework the framework to use (e.g. `{ h }`).
|
||||
* @param generate the `generate` function to use
|
||||
* (from `lean-qr` or `lean-qr/nano`).
|
||||
* @param defaultProps optional default properties to apply when the
|
||||
* component is used (overridden by properties set on use).
|
||||
* @returns a component which can be rendered elsewhere.
|
||||
*/
|
||||
export function makeVueCanvasComponent(
|
||||
framework: Readonly<Framework>,
|
||||
generate: (
|
||||
data: string,
|
||||
options?: Readonly<GenerateOptions>,
|
||||
) => Pick<FullBitmap2D, 'toCanvas'>,
|
||||
defaultProps?: Readonly<Partial<VueCanvasComponentProps>>,
|
||||
): VueComponentDefinition<VueCanvasComponentProps>;
|
||||
|
||||
export interface VueSVGComponentProps
|
||||
extends SVGOptions,
|
||||
GenerateOptions,
|
||||
QRComponentProps {}
|
||||
|
||||
/**
|
||||
* Generate a QR component which renders to an SVG.
|
||||
* You should call this just once, in the global scope:
|
||||
*
|
||||
* ```js
|
||||
* import { h, defineComponent } from 'vue';
|
||||
* import { generate } from 'lean-qr';
|
||||
* import { toSvgDataURL } from 'lean-qr/extras/svg';
|
||||
* import { makeVueSvgComponent } from 'lean-qr/extras/vue';
|
||||
* export const QR = defineComponent(makeVueSvgComponent({ h }, generate, toSvgDataURL));
|
||||
* ```
|
||||
*
|
||||
* This is best suited for server-side rendering (prefer
|
||||
* `makeAsyncComponent` if you only need client-side rendering).
|
||||
*
|
||||
* @param framework the framework to use (e.g. `{ h }`).
|
||||
* @param generate the `generate` function to use
|
||||
* (from `lean-qr` or `lean-qr/nano`).
|
||||
* @param toSvgDataURL the `toSvgDataURL` function to use
|
||||
* (from `lean-qr/extras/svg`).
|
||||
* @param defaultProps optional default properties to apply when the
|
||||
* component is used (overridden by properties set on use).
|
||||
* @returns a component which can be rendered elsewhere.
|
||||
*/
|
||||
export function makeVueSvgComponent(
|
||||
framework: Readonly<Framework>,
|
||||
generate: (
|
||||
data: string,
|
||||
options?: Readonly<GenerateOptions>,
|
||||
) => Pick<FullBitmap2D, 'size' | 'get'>,
|
||||
toSvgDataURL: typeof toSvgDataURLFn,
|
||||
defaultProps?: Readonly<Partial<VueSVGComponentProps>>,
|
||||
): VueComponentDefinition<VueSVGComponentProps>;
|
||||
}
|
||||
|
||||
declare module 'lean-qr/extras/errors' {
|
||||
/**
|
||||
* Convert an error into a human-readable message. This is intended for use
|
||||
* with Lean QR errors, but will return somewhat meaningful messages for
|
||||
* other errors too.
|
||||
*
|
||||
* @param error the error to convert.
|
||||
* @returns a human-readable message explaining the error.
|
||||
*/
|
||||
export function readError(error: unknown): string;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
||||
*charts.pro*
|
||||
light*.js
|
||||
Vendored
-8
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,433 +0,0 @@
|
||||
const DEFAULT_SEPARATORS = "_- :/";
|
||||
const DEFAULT_TRIGRAM_BUDGET = 6;
|
||||
const DEFAULT_LIMIT = 100;
|
||||
const DEFAULT_MIN_SCORE = 2;
|
||||
|
||||
/**
|
||||
* Search configuration.
|
||||
*
|
||||
* Defaults work well for most use cases.
|
||||
* Tweak `trigramBudget` to trade speed for typo tolerance.
|
||||
*/
|
||||
export class QuickMatchConfig {
|
||||
/** Characters that separate words in items (e.g. "hash_rate" → ["hash", "rate"]).
|
||||
* @type {string} */
|
||||
separators = DEFAULT_SEPARATORS;
|
||||
|
||||
/** Max results returned per query.
|
||||
* @type {number} */
|
||||
limit = DEFAULT_LIMIT;
|
||||
|
||||
/** How hard to try matching typos (0 = off, 3–6 = fast, 9–15 = thorough, max 20).
|
||||
* @type {number} */
|
||||
trigramBudget = DEFAULT_TRIGRAM_BUDGET;
|
||||
|
||||
/** Min overlap required for a typo match. Higher = fewer false positives.
|
||||
* @type {number} */
|
||||
minScore = DEFAULT_MIN_SCORE;
|
||||
|
||||
/** @param {number} n - Max results (default: 100, min: 1) */
|
||||
withLimit(n) {
|
||||
this.limit = Math.max(1, n);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @param {number} n - Trigram budget (0-20, default: 6) */
|
||||
withTrigramBudget(n) {
|
||||
this.trigramBudget = Math.max(0, Math.min(20, n));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @param {string} s - Separator characters (default: '_- :/') */
|
||||
withSeparators(s) {
|
||||
this.separators = s;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @param {number} n - Min trigram score (default: 2, min: 1) */
|
||||
withMinScore(n) {
|
||||
this.minScore = Math.max(1, n);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instant search over a list of strings.
|
||||
*
|
||||
* Supports exact words, prefixes ("dom" → "dominance"), joined words
|
||||
* ("hashrate" → "hash_rate"), and typo tolerance ("suply" → "supply").
|
||||
* Results are ranked: exact matches first, then by specificity.
|
||||
*/
|
||||
export class QuickMatch {
|
||||
/** @param {string[]} items - Searchable items (lowercase) @param {QuickMatchConfig} [config] */
|
||||
constructor(items, config = new QuickMatchConfig()) {
|
||||
this.config = config;
|
||||
this.items = items;
|
||||
/** @type {Map<string, number[]>} */
|
||||
this.wordIndex = new Map();
|
||||
/** @type {Map<string, number[]>} */
|
||||
this.trigramIndex = new Map();
|
||||
this._sepLookup = sepLookup(config.separators);
|
||||
this._scores = new Uint32Array(items.length);
|
||||
/** @type {number[]} */
|
||||
this._dirty = [];
|
||||
|
||||
let maxWordLen = 0;
|
||||
let maxQueryLen = 0;
|
||||
let maxWords = 0;
|
||||
const sep = this._sepLookup;
|
||||
|
||||
for (let idx = 0; idx < items.length; idx++) {
|
||||
const item = items[idx];
|
||||
if (item.length > maxQueryLen) maxQueryLen = item.length;
|
||||
|
||||
const words = [];
|
||||
let start = 0;
|
||||
|
||||
for (let i = 0; i <= item.length; i++) {
|
||||
if (i < item.length && !sep[item.charCodeAt(i)]) continue;
|
||||
if (i > start) {
|
||||
const word = item.slice(start, i);
|
||||
words.push(word);
|
||||
if (word.length > maxWordLen) maxWordLen = word.length;
|
||||
for (let len = 1; len <= word.length; len++) {
|
||||
addToIndex(this.wordIndex, word.slice(0, len), idx);
|
||||
}
|
||||
for (let k = 0; k <= word.length - 3; k++) {
|
||||
addToIndex(this.trigramIndex, word[k] + word[k + 1] + word[k + 2], idx);
|
||||
}
|
||||
}
|
||||
start = i + 1;
|
||||
}
|
||||
|
||||
for (let i = 0; i < words.length - 1; i++) {
|
||||
const compound = words[i] + words[i + 1];
|
||||
// A joined-word query ("hashrate") can be longer than any single
|
||||
// word. Capping at the longest index key keeps the DDoS guard
|
||||
// data-bounded while still letting it match.
|
||||
if (compound.length > maxWordLen) maxWordLen = compound.length;
|
||||
const from = words[i].length + 1;
|
||||
for (let len = from; len <= compound.length; len++) {
|
||||
addToIndex(this.wordIndex, compound.slice(0, len), idx);
|
||||
}
|
||||
}
|
||||
|
||||
if (words.length > maxWords) maxWords = words.length;
|
||||
}
|
||||
|
||||
this.maxWordLen = maxWordLen + 4;
|
||||
this.maxQueryLen = maxQueryLen + 6;
|
||||
this.maxWords = maxWords + 2;
|
||||
}
|
||||
|
||||
/** @param {string} query */
|
||||
matches(query) {
|
||||
return this.matchesWith(query, this.config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} query
|
||||
* @param {QuickMatchConfig} config
|
||||
*/
|
||||
matchesWith(query, config) {
|
||||
const { limit, trigramBudget } = config;
|
||||
const sep =
|
||||
config.separators === this.config.separators
|
||||
? this._sepLookup
|
||||
: sepLookup(config.separators);
|
||||
|
||||
const q = normalize(query);
|
||||
if (!q || q.length > this.maxQueryLen) return [];
|
||||
|
||||
const qwords = splitWords(q, sep, this.maxWordLen);
|
||||
if (!qwords.length || qwords.length > this.maxWords) return [];
|
||||
|
||||
const known = [];
|
||||
const unknown = [];
|
||||
|
||||
for (const w of qwords) {
|
||||
const hits = this.wordIndex.get(w);
|
||||
if (hits) {
|
||||
known.push(hits);
|
||||
} else if (w.length >= 3 && unknown.length < trigramBudget) {
|
||||
unknown.push(w);
|
||||
}
|
||||
}
|
||||
|
||||
const pool = intersect(known);
|
||||
|
||||
// Try typo matching for unknown words
|
||||
if (unknown.length && trigramBudget) {
|
||||
const { _scores: scores, _dirty: dirty } = this;
|
||||
|
||||
if (pool) {
|
||||
for (const i of pool) {
|
||||
scores[i] = 1;
|
||||
dirty.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
const hitCount = this._scoreTrigrams(
|
||||
unknown,
|
||||
trigramBudget,
|
||||
pool !== null,
|
||||
Math.max(0, q.length - 3),
|
||||
);
|
||||
const minScore = Math.max(config.minScore, Math.ceil(hitCount / 2));
|
||||
const result = this._rank(dirty, minScore, qwords, sep, limit);
|
||||
|
||||
for (const i of dirty) scores[i] = 0;
|
||||
dirty.length = 0;
|
||||
|
||||
if (result.length > 0) return result;
|
||||
}
|
||||
|
||||
// Rank known candidates (intersection, or union as fallback)
|
||||
const candidates = pool || union(known);
|
||||
return candidates.length > 0
|
||||
? this._rank(candidates, null, qwords, sep, limit)
|
||||
: [];
|
||||
}
|
||||
|
||||
/** @private @param {string[]} unknown @param {number} budget @param {boolean} poolOnly @param {number} minLen */
|
||||
_scoreTrigrams(unknown, budget, poolOnly, minLen) {
|
||||
const { _scores: scores, _dirty: dirty, items } = this;
|
||||
const visited = new Set();
|
||||
const maxRounds = budget;
|
||||
let hits = 0;
|
||||
|
||||
outer: for (let round = 0; round < maxRounds; round++) {
|
||||
for (const word of unknown) {
|
||||
if (budget <= 0) break outer;
|
||||
|
||||
const pos = trigramPosition(word.length, round);
|
||||
if (pos < 0) continue;
|
||||
|
||||
const tri = word[pos] + word[pos + 1] + word[pos + 2];
|
||||
if (visited.has(tri)) continue;
|
||||
visited.add(tri);
|
||||
budget--;
|
||||
|
||||
const matched = this.trigramIndex.get(tri);
|
||||
if (!matched) continue;
|
||||
hits++;
|
||||
|
||||
if (poolOnly) {
|
||||
for (let j = 0; j < matched.length; j++) {
|
||||
const i = matched[j];
|
||||
if (scores[i] > 0) scores[i]++;
|
||||
}
|
||||
} else {
|
||||
for (let j = 0; j < matched.length; j++) {
|
||||
const i = matched[j];
|
||||
if (items[i].length >= minLen) {
|
||||
if (scores[i] === 0) dirty.push(i);
|
||||
scores[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {number[]} indices
|
||||
* @param {number|null} minScore
|
||||
* @param {string[]} qwords
|
||||
* @param {Uint8Array} sep
|
||||
* @param {number} limit
|
||||
*/
|
||||
_rank(indices, minScore, qwords, sep, limit) {
|
||||
const { items, _scores: scores } = this;
|
||||
/** @type {[number, number][][]} */
|
||||
const buckets = Array.from({ length: qwords.length + 1 }, () => []);
|
||||
|
||||
for (let i = 0; i < indices.length; i++) {
|
||||
const idx = indices[i];
|
||||
if (minScore !== null && scores[idx] < minScore) continue;
|
||||
const [matched, position] = wordMatch(items[idx], qwords, sep);
|
||||
buckets[matched].push([idx, position]);
|
||||
}
|
||||
|
||||
const results = [];
|
||||
for (let ps = buckets.length - 1; ps >= 0 && results.length < limit; ps--) {
|
||||
const bucket = buckets[ps];
|
||||
if (!bucket.length) continue;
|
||||
bucket.sort(
|
||||
([a, pa], [b, pb]) =>
|
||||
scores[b] - scores[a] ||
|
||||
pa - pb ||
|
||||
items[a].length - items[b].length ||
|
||||
(items[a] < items[b] ? -1 : 1), // item text, asc (total order)
|
||||
);
|
||||
const take = Math.min(bucket.length, limit - results.length);
|
||||
for (let i = 0; i < take; i++) results.push(items[bucket[i][0]]);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
/** @param {string} query */
|
||||
function normalize(query) {
|
||||
let out = "";
|
||||
let start = 0;
|
||||
let end = query.length;
|
||||
while (start < end && query.charCodeAt(start) <= 32) start++;
|
||||
while (end > start && query.charCodeAt(end - 1) <= 32) end--;
|
||||
for (let i = start; i < end; i++) {
|
||||
const c = query.charCodeAt(i);
|
||||
if (c >= 128) continue;
|
||||
out += c >= 65 && c <= 90 ? String.fromCharCode(c + 32) : query[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** @param {string} separators */
|
||||
function sepLookup(separators) {
|
||||
const t = new Uint8Array(128);
|
||||
for (let i = 0; i < separators.length; i++) {
|
||||
const c = separators.charCodeAt(i);
|
||||
if (c < 128) t[c] = 1;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {Uint8Array} sep
|
||||
* @param {number} maxLen
|
||||
*/
|
||||
function splitWords(text, sep, maxLen) {
|
||||
/** @type {string[]} */
|
||||
const words = [];
|
||||
let start = 0;
|
||||
for (let i = 0; i <= text.length; i++) {
|
||||
if (i < text.length && !sep[text.charCodeAt(i)]) continue;
|
||||
if (i > start) {
|
||||
const w = text.slice(start, i);
|
||||
if (w.length <= maxLen && !words.includes(w)) words.push(w);
|
||||
}
|
||||
start = i + 1;
|
||||
}
|
||||
return words;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Map<string, number[]>} index
|
||||
* @param {string} key
|
||||
* @param {number} value
|
||||
*/
|
||||
function addToIndex(index, key, value) {
|
||||
const arr = index.get(key);
|
||||
if (arr) {
|
||||
if (arr[arr.length - 1] !== value) arr.push(value);
|
||||
} else {
|
||||
index.set(key, [value]);
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {number[][]} arrays */
|
||||
function union(arrays) {
|
||||
if (arrays.length <= 1) return arrays[0] || [];
|
||||
const seen = new Set();
|
||||
const result = [];
|
||||
for (const arr of arrays) {
|
||||
for (const idx of arr) {
|
||||
if (!seen.has(idx)) {
|
||||
seen.add(idx);
|
||||
result.push(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @param {number[][]} arrays @returns {number[]|null} */
|
||||
function intersect(arrays) {
|
||||
if (arrays.length <= 1) return arrays[0] || null;
|
||||
|
||||
let si = 0;
|
||||
for (let i = 1; i < arrays.length; i++) {
|
||||
if (arrays[i].length < arrays[si].length) si = i;
|
||||
}
|
||||
|
||||
const result = arrays[si].slice();
|
||||
for (let i = 0; i < arrays.length; i++) {
|
||||
if (i === si) continue;
|
||||
let w = 0;
|
||||
for (let j = 0; j < result.length; j++) {
|
||||
if (bsearch(arrays[i], result[j])) result[w++] = result[j];
|
||||
}
|
||||
result.length = w;
|
||||
if (!w) return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number[]} arr
|
||||
* @param {number} val
|
||||
*/
|
||||
function bsearch(arr, val) {
|
||||
let lo = 0,
|
||||
hi = arr.length - 1;
|
||||
while (lo <= hi) {
|
||||
const mid = (lo + hi) >> 1;
|
||||
if (arr[mid] === val) return true;
|
||||
if (arr[mid] < val) lo = mid + 1;
|
||||
else hi = mid - 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aligns query words against the item's words, in order.
|
||||
* @param {string} item @param {string[]} qwords @param {Uint8Array} sep
|
||||
* @returns {[number, number]} `[matched, position]` - query words matched as
|
||||
* an in-order subsequence, and the item-word index where that run starts
|
||||
* (or the item's word count when nothing matched).
|
||||
*/
|
||||
function wordMatch(item, qwords, sep) {
|
||||
const len = item.length;
|
||||
let matched = 0;
|
||||
let position = 0;
|
||||
let pos = 0;
|
||||
|
||||
while (pos < len) {
|
||||
while (pos < len && sep[item.charCodeAt(pos)]) pos++;
|
||||
if (pos >= len) break;
|
||||
|
||||
const ws = pos;
|
||||
while (pos < len && !sep[item.charCodeAt(pos)]) pos++;
|
||||
|
||||
const qw = qwords[matched];
|
||||
if (qw !== undefined && pos - ws >= qw.length && item.startsWith(qw, ws)) {
|
||||
matched++;
|
||||
} else if (matched === 0) {
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
return [matched, position];
|
||||
}
|
||||
|
||||
/** @param {number} len @param {number} round */
|
||||
function trigramPosition(len, round) {
|
||||
const max = len - 3;
|
||||
if (max < 0) return -1;
|
||||
if (round === 0) return 0;
|
||||
if (round === 1 && max > 0) return max;
|
||||
if (round === 2 && max > 1) return max >> 1;
|
||||
if (max <= 2) return -1;
|
||||
|
||||
const mid = max >> 1;
|
||||
const off = (round - 2) >> 1;
|
||||
const pos = round & 1 ? Math.max(0, mid - off) : mid + off;
|
||||
return pos === 0 || pos >= max || pos === mid ? -1 : pos;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"outDir": "/tmp/brk",
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
|
||||
"skipLibCheck": true,
|
||||
},
|
||||
"exclude": ["assets", "./scripts/modules"],
|
||||
}
|
||||
@@ -1,410 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
print_debug() {
|
||||
if [[ "${DEBUG:-}" == "1" ]]; then
|
||||
echo -e "${YELLOW}[DEBUG]${NC} $1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if required tools are installed
|
||||
check_dependencies() {
|
||||
local missing_deps=()
|
||||
|
||||
if ! command -v curl &> /dev/null; then
|
||||
missing_deps+=("curl")
|
||||
fi
|
||||
|
||||
if ! command -v grep &> /dev/null; then
|
||||
missing_deps+=("grep")
|
||||
fi
|
||||
|
||||
if ! command -v sed &> /dev/null; then
|
||||
missing_deps+=("sed")
|
||||
fi
|
||||
|
||||
if [ ${#missing_deps[@]} -ne 0 ]; then
|
||||
print_error "Missing required dependencies: ${missing_deps[*]}"
|
||||
print_error "Please install them and try again."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to URL encode a string
|
||||
url_encode() {
|
||||
local string="${1}"
|
||||
local strlen=${#string}
|
||||
local encoded=""
|
||||
local pos c o
|
||||
|
||||
for ((pos=0; pos<strlen; pos++)); do
|
||||
c=${string:$pos:1}
|
||||
case "$c" in
|
||||
[-_.~a-zA-Z0-9] ) o="${c}" ;;
|
||||
* ) printf -v o '%%%02x' "'$c"
|
||||
esac
|
||||
encoded+="${o}"
|
||||
done
|
||||
echo "${encoded}"
|
||||
}
|
||||
|
||||
# Function to create directory if it doesn't exist
|
||||
create_dir() {
|
||||
local dir="$1"
|
||||
if [ ! -d "$dir" ]; then
|
||||
mkdir -p "$dir"
|
||||
print_status "Created directory: $dir"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to resolve "latest" version to actual version number
|
||||
resolve_latest_version() {
|
||||
local package_name="$1"
|
||||
local version="$2"
|
||||
|
||||
# If version is not "latest", return as-is
|
||||
if [[ "$version" != "latest" ]]; then
|
||||
echo "$version"
|
||||
return
|
||||
fi
|
||||
|
||||
print_status "Resolving 'latest' version for $package_name..." >&2
|
||||
|
||||
# URL encode the package name
|
||||
local encoded_package=$(url_encode "$package_name")
|
||||
local latest_url="https://app.unpkg.com/${encoded_package}@latest"
|
||||
|
||||
# Use curl to follow redirects and get the final URL
|
||||
local final_url
|
||||
final_url=$(curl -L -s -o /dev/null -w '%{url_effective}' "$latest_url")
|
||||
|
||||
if [[ -z "$final_url" ]]; then
|
||||
print_error "Failed to resolve latest version for $package_name" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Extract version from the final URL
|
||||
# Format: https://app.unpkg.com/@solidjs/signals@0.4.1
|
||||
local resolved_version
|
||||
# Use a different delimiter (#) to avoid issues with / in package names
|
||||
resolved_version=$(echo "$final_url" | sed -n "s#.*${package_name}@\([^\/]*\).*#\1#p")
|
||||
|
||||
if [[ -z "$resolved_version" ]]; then
|
||||
print_error "Could not extract version from URL: $final_url" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
print_success "Resolved 'latest' to version: $resolved_version" >&2
|
||||
echo "$resolved_version"
|
||||
}
|
||||
|
||||
# Function to download a file
|
||||
download_file() {
|
||||
local file_url="$1"
|
||||
local local_path="$2"
|
||||
local dir=$(dirname "$local_path")
|
||||
|
||||
create_dir "$dir"
|
||||
|
||||
print_status "Downloading: $file_url"
|
||||
if curl -L -s -f "$file_url" -o "$local_path"; then
|
||||
print_success "Downloaded: $local_path"
|
||||
return 0
|
||||
else
|
||||
print_error "Failed to download: $file_url"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to parse HTML and extract file/folder links using a much simpler approach
|
||||
parse_directory() {
|
||||
local html_content="$1"
|
||||
local current_path="$2"
|
||||
local package_name="$3"
|
||||
local version="$4"
|
||||
|
||||
print_debug "Parsing directory for path: '$current_path'"
|
||||
|
||||
# The HTML contains the original (unencoded) package name in URLs
|
||||
# So we search for the original package name, not the encoded version
|
||||
|
||||
# Find all links that point to files/folders in this package
|
||||
# Look for the pattern: <a href="...">filename</a> or <a href="...">foldername/</a>
|
||||
local links=$(echo "$html_content" | grep -o '<a href="[^"]*"[^>]*>[^<]*</a>' | grep "${package_name}@${version}/files")
|
||||
|
||||
print_debug "Found $(echo "$links" | wc -l) total links"
|
||||
|
||||
if [[ "${DEBUG:-}" == "1" ]]; then
|
||||
print_debug "All found links:"
|
||||
echo "$links" | while read -r link; do
|
||||
[[ -n "$link" ]] && print_debug " $link"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$links" | while read -r link_line; do
|
||||
if [[ -z "$link_line" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract the href URL
|
||||
local href=$(echo "$link_line" | sed -n 's/.*href="\([^"]*\)".*/\1/p')
|
||||
# Extract the link text (what's between <a> and </a>)
|
||||
local link_text=$(echo "$link_line" | sed -n 's/.*<a[^>]*>\([^<]*\)<\/a>.*/\1/p')
|
||||
|
||||
print_debug "Processing link: href='$href' text='$link_text'"
|
||||
|
||||
# Skip if we couldn't extract both parts
|
||||
if [[ -z "$href" ]] || [[ -z "$link_text" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Skip parent directory links
|
||||
if [[ "$link_text" == "../" ]] || [[ "$link_text" == ".." ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract the file/folder path from the URL
|
||||
# URL format: https://app.unpkg.com/@solidjs/signals@0.4.1/files/path/to/item
|
||||
# Note: href contains the original (unencoded) package name
|
||||
local url_path="${href#*${package_name}@${version}/files}"
|
||||
url_path="${url_path#/}" # Remove leading slash
|
||||
|
||||
print_debug "URL path extracted: '$url_path'"
|
||||
|
||||
# Skip if this is not a direct child of current directory
|
||||
if [[ -n "$current_path" ]]; then
|
||||
# We're in a subdirectory, so the URL path should start with current_path
|
||||
local current_clean="${current_path#/}"
|
||||
if [[ "$url_path" != "${current_clean}"* ]]; then
|
||||
print_debug "Skipping - not in current path"
|
||||
continue
|
||||
fi
|
||||
# Get the relative path from current directory
|
||||
local relative_path="${url_path#${current_clean}}"
|
||||
relative_path="${relative_path#/}"
|
||||
else
|
||||
# We're in root, so relative_path is the same as url_path
|
||||
local relative_path="$url_path"
|
||||
fi
|
||||
|
||||
print_debug "Relative path: '$relative_path'"
|
||||
|
||||
# Skip if this contains subdirectories (we only want direct children)
|
||||
if [[ "$relative_path" == *"/"* ]]; then
|
||||
print_debug "Skipping - contains subdirectories"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Skip empty paths
|
||||
if [[ -z "$relative_path" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Determine if it's a folder or file based on the link text
|
||||
if [[ "$link_text" == *"/" ]]; then
|
||||
# It's a folder
|
||||
local folder_name="${relative_path%/}"
|
||||
if [[ -n "$current_path" ]]; then
|
||||
echo "FOLDER:${current_path}/${folder_name}"
|
||||
else
|
||||
echo "FOLDER:/${folder_name}"
|
||||
fi
|
||||
else
|
||||
# It's a file
|
||||
if [[ -n "$current_path" ]]; then
|
||||
echo "FILE:${current_path}/${relative_path}"
|
||||
else
|
||||
echo "FILE:/${relative_path}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Function to check if item was already processed
|
||||
is_processed() {
|
||||
local item="$1"
|
||||
local processed_list="$2"
|
||||
|
||||
[[ "$processed_list" == *"|${item}|"* ]]
|
||||
}
|
||||
|
||||
# Function to add item to processed list
|
||||
add_processed() {
|
||||
local item="$1"
|
||||
local processed_list="$2"
|
||||
|
||||
echo "${processed_list}|${item}|"
|
||||
}
|
||||
|
||||
# Function to process a directory (download files and recurse into subdirectories)
|
||||
process_directory() {
|
||||
local package_name="$1"
|
||||
local version="$2"
|
||||
local dir_path="$3"
|
||||
local output_dir="$4"
|
||||
local processed_dirs="$5"
|
||||
|
||||
# Encode the package name for URL
|
||||
local encoded_package=$(url_encode "$package_name")
|
||||
local app_url="https://app.unpkg.com/${encoded_package}@${version}/files${dir_path}"
|
||||
local download_base_url="https://unpkg.com/${encoded_package}@${version}"
|
||||
|
||||
# Check if we've already processed this directory
|
||||
if is_processed "$dir_path" "$processed_dirs"; then
|
||||
print_warning "Already processed directory: $dir_path"
|
||||
return
|
||||
fi
|
||||
|
||||
print_status "Processing directory: ${dir_path:-'(root)'}"
|
||||
print_status "Fetching: $app_url"
|
||||
|
||||
# Download the directory listing HTML
|
||||
local html_content
|
||||
if ! html_content=$(curl -L -s -f "$app_url"); then
|
||||
print_error "Failed to fetch directory listing: $app_url"
|
||||
return
|
||||
fi
|
||||
|
||||
print_status "Fetched HTML content (${#html_content} characters)"
|
||||
|
||||
# Mark this directory as processed
|
||||
processed_dirs=$(add_processed "$dir_path" "$processed_dirs")
|
||||
|
||||
# Parse the HTML to find files and folders
|
||||
local items
|
||||
items=$(parse_directory "$html_content" "$dir_path" "$package_name" "$version")
|
||||
|
||||
print_debug "Parsed items:"
|
||||
print_debug "$items"
|
||||
|
||||
# Collect unique files and folders
|
||||
local files=()
|
||||
local folders=()
|
||||
local seen_files=""
|
||||
local seen_folders=""
|
||||
|
||||
while IFS= read -r item; do
|
||||
[[ -z "$item" ]] && continue
|
||||
|
||||
if [[ "$item" == FILE:* ]]; then
|
||||
local file_path="${item#FILE:}"
|
||||
if ! is_processed "$file_path" "$seen_files"; then
|
||||
files+=("$file_path")
|
||||
seen_files=$(add_processed "$file_path" "$seen_files")
|
||||
print_debug "Added file: $file_path"
|
||||
fi
|
||||
elif [[ "$item" == FOLDER:* ]]; then
|
||||
local folder_path="${item#FOLDER:}"
|
||||
if ! is_processed "$folder_path" "$seen_folders"; then
|
||||
folders+=("$folder_path")
|
||||
seen_folders=$(add_processed "$folder_path" "$seen_folders")
|
||||
print_debug "Added folder: $folder_path"
|
||||
fi
|
||||
fi
|
||||
done <<< "$items"
|
||||
|
||||
print_status "Found ${#files[@]} files and ${#folders[@]} folders"
|
||||
|
||||
# Download all files in this directory
|
||||
for file_path in "${files[@]}"; do
|
||||
if [[ -n "$file_path" ]]; then
|
||||
local file_url="${download_base_url}${file_path}"
|
||||
local local_path="${output_dir}${file_path}"
|
||||
download_file "$file_url" "$local_path"
|
||||
fi
|
||||
done
|
||||
|
||||
# Recursively process all folders
|
||||
for folder_path in "${folders[@]}"; do
|
||||
if [[ -n "$folder_path" ]]; then
|
||||
process_directory "$package_name" "$version" "$folder_path" "$output_dir" "$processed_dirs"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
# Check dependencies
|
||||
check_dependencies
|
||||
|
||||
# Parse command line arguments
|
||||
if [ $# -lt 1 ] || [ $# -gt 3 ]; then
|
||||
echo "Usage: $0 <package-name> [version] [output-dir]"
|
||||
echo "Example: $0 \"@solidjs/signals\""
|
||||
echo "Example: $0 \"@solidjs/signals\" \"0.4.1\""
|
||||
echo "Example: $0 \"@solidjs/signals\" \"latest\""
|
||||
echo "Example: $0 \"@solidjs/signals\" \"latest\" \"./downloads\""
|
||||
echo "Example: $0 \"lodash\" \"4.17.21\" \"./downloads\""
|
||||
echo ""
|
||||
echo "Version defaults to 'latest' if not specified"
|
||||
echo "Set DEBUG=1 environment variable for verbose output"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local package_name="$1"
|
||||
local version="${2:-latest}"
|
||||
|
||||
# Resolve latest version if needed (do this once at the start)
|
||||
local resolved_version
|
||||
if ! resolved_version=$(resolve_latest_version "$package_name" "$version"); then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use resolved version for output directory
|
||||
local output_dir="${3:-./$(echo "${package_name}" | sed 's/@//g' | sed 's/\//-/g')/${resolved_version}}"
|
||||
|
||||
print_status "Starting download of package: $package_name@$version"
|
||||
if [[ "$version" == "latest" ]]; then
|
||||
print_status "Resolved to actual version: $resolved_version"
|
||||
fi
|
||||
print_status "Output directory: $output_dir"
|
||||
|
||||
# Check if the directory already exists and has content
|
||||
if [[ -d "$output_dir" ]] && [[ -n "$(ls -A "$output_dir" 2>/dev/null)" ]]; then
|
||||
print_warning "Directory already exists and is not empty: $output_dir"
|
||||
print_warning "Package $package_name@$resolved_version appears to already be downloaded."
|
||||
print_warning "Remove the directory or choose a different output location to proceed."
|
||||
return
|
||||
fi
|
||||
|
||||
# Create the base output directory
|
||||
create_dir "$output_dir"
|
||||
|
||||
# Start processing from the root directory using the resolved version
|
||||
process_directory "$package_name" "$resolved_version" "" "$output_dir" ""
|
||||
|
||||
print_success "Package download completed!"
|
||||
print_status "Files downloaded to: $output_dir"
|
||||
}
|
||||
|
||||
# Run the main function with all arguments
|
||||
# main "$@"
|
||||
|
||||
main "quickmatch-js"
|
||||
main "lean-qr"
|
||||
main "lightweight-charts"
|
||||
@@ -33,6 +33,7 @@ export function buildCohortData() {
|
||||
AMOUNT_RANGE_NAMES,
|
||||
SPENDABLE_TYPE_NAMES,
|
||||
CLASS_NAMES,
|
||||
ENTRY_NAMES,
|
||||
PROFITABILITY_RANGE_NAMES,
|
||||
PROFIT_NAMES,
|
||||
LOSS_NAMES,
|
||||
@@ -201,6 +202,18 @@ export function buildCohortData() {
|
||||
tree: utxoCohorts.class[key],
|
||||
}));
|
||||
|
||||
const entryColors = {
|
||||
discount: colors.arr[11],
|
||||
premium: colors.arr[0],
|
||||
};
|
||||
|
||||
const entry = entries(ENTRY_NAMES).map(([key, names]) => ({
|
||||
name: names.short,
|
||||
title: `UTXOs ${names.long}`,
|
||||
color: entryColors[key],
|
||||
tree: utxoCohorts.entry[key],
|
||||
}));
|
||||
|
||||
const { range, profit, loss } = utxoCohorts.profitability;
|
||||
|
||||
const profitabilityRange = entries(PROFITABILITY_RANGE_NAMES).map(
|
||||
@@ -242,6 +255,7 @@ export function buildCohortData() {
|
||||
typeAddressable,
|
||||
typeOther,
|
||||
class: class_,
|
||||
entry,
|
||||
profitabilityRange,
|
||||
profitabilityProfit,
|
||||
profitabilityLoss,
|
||||
|
||||
@@ -226,7 +226,7 @@ function historicalSubSection(name, periods) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createMarketSection() {
|
||||
const { market, supply, cohorts, prices, indicators } = brk.series;
|
||||
const { market, supply, cohorts, price: prices, indicators } = brk.series;
|
||||
const {
|
||||
movingAverage: ma,
|
||||
ath,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
createCohortFolderAll,
|
||||
createCohortFolderFull,
|
||||
createCohortFolderWithAdjusted,
|
||||
createCohortFolderWithNupl,
|
||||
createCohortFolderLongTerm,
|
||||
createCohortFolderAgeRangeWithMatured,
|
||||
createCohortFolderBasicWithMarketCap,
|
||||
@@ -53,6 +54,7 @@ export function createPartialOptions() {
|
||||
overAge,
|
||||
ageRange,
|
||||
epoch,
|
||||
entry,
|
||||
utxosOverAmount,
|
||||
addressesOverAmount,
|
||||
utxosUnderAmount,
|
||||
@@ -99,6 +101,19 @@ export function createPartialOptions() {
|
||||
|
||||
createCohortFolderLongTerm(termLong),
|
||||
|
||||
{
|
||||
name: "Entry",
|
||||
tree: [
|
||||
createGroupedCohortFolderWithNupl({
|
||||
name: "Compare",
|
||||
title: "Veteran vs Rookie",
|
||||
list: entry,
|
||||
all: cohortAll,
|
||||
}),
|
||||
...entry.map(createCohortFolderWithNupl),
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
name: "UTXO Age",
|
||||
tree: [
|
||||
|
||||
@@ -40,7 +40,7 @@ export function init() {
|
||||
/** @type {Map<Unit, AnyFetchedSeriesBlueprint[]>} */
|
||||
const result = new Map();
|
||||
|
||||
const { ohlc, spot } = brk.series.prices;
|
||||
const { ohlc, spot } = brk.series.price;
|
||||
|
||||
result.set(Unit.usd, [
|
||||
/** @type {AnyFetchedSeriesBlueprint} */ ({
|
||||
|
||||
Reference in New Issue
Block a user