mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-21 07:58:11 -07:00
global: replace most bps with ppm
This commit is contained in:
Generated
+110
-89
@@ -73,9 +73,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.103"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
||||
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
@@ -222,7 +222,7 @@ dependencies = [
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex 1.3.0",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -658,7 +658,6 @@ dependencies = [
|
||||
"byteview",
|
||||
"fjall",
|
||||
"rustc-hash",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -680,7 +679,7 @@ version = "0.3.6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -750,9 +749,9 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.25.1"
|
||||
version = "1.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424"
|
||||
checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
@@ -780,9 +779,9 @@ checksum = "1c53ba0f290bfc610084c05582d9c5d421662128fc69f4bf236707af6fd321b9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.67"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38"
|
||||
checksum = "c89588d05638b5b4594a3348a2d6c20277e43a7f5c5202b05cc56888475a47b8"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
@@ -1109,7 +1108,7 @@ dependencies = [
|
||||
"defmt-parser",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1146,7 +1145,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
@@ -1179,7 +1178,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1239,7 +1238,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1270,9 +1269,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.4.1"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
||||
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
@@ -1291,9 +1290,9 @@ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "fjall"
|
||||
version = "3.1.6"
|
||||
version = "3.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fcdc69609906151dff9b534e30eaf8515082055d36f628e382bd0b5d6a1d362"
|
||||
checksum = "420a84699b8ccbb1ed573e38e88f4f23637b45beab6432066452f834be469c57"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"byteview",
|
||||
@@ -1374,7 +1373,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1405,36 +1404,36 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.32"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
|
||||
checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.32"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||
checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.32"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
|
||||
checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.32"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
|
||||
checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.32"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||
checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -1598,9 +1597,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.10.1"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498"
|
||||
checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
@@ -1863,11 +1862,12 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.32"
|
||||
version = "0.2.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "961d16382652bfdd8c6f68b223b26a8c93e0d475c672f414411db31c6c5c900e"
|
||||
checksum = "e184d09547b80eb7e20d141ba2fb1fbac843ca53f4cf1b31210adc4c1adc6e16"
|
||||
dependencies = [
|
||||
"defmt",
|
||||
"jiff-core",
|
||||
"jiff-static",
|
||||
"log",
|
||||
"portable-atomic",
|
||||
@@ -1877,14 +1877,24 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.32"
|
||||
name = "jiff-core"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0879bd39df99c4c5e2c6615ccc026391a423dde10532c573e6086eb94a802cc"
|
||||
checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09"
|
||||
dependencies = [
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "323da076b7a6faf914dc677cb05a4b907742ff7375c8322c9e7f5061e5e0e9de"
|
||||
dependencies = [
|
||||
"jiff-core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2018,9 +2028,9 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
||||
|
||||
[[package]]
|
||||
name = "lsm-tree"
|
||||
version = "3.1.6"
|
||||
version = "3.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ca67401338b98d58447387dd5230552d2241bc388206e491d137b18dfea9d6"
|
||||
checksum = "055a908d502129cf63bedae52f2db222e4436d2da32a69df9b84ac9fb9147761"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"byteview",
|
||||
@@ -2330,9 +2340,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
@@ -2360,9 +2370,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -2388,9 +2398,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.46"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -2482,22 +2492,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast"
|
||||
version = "1.0.25"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
|
||||
checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d"
|
||||
dependencies = [
|
||||
"ref-cast-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast-impl"
|
||||
version = "1.0.25"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
||||
checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2665,7 +2675,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2708,9 +2718,9 @@ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
@@ -2728,22 +2738,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2754,14 +2764,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.150"
|
||||
version = "1.0.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
@@ -2909,7 +2919,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2948,6 +2958,17 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a207d6d6a2b7fc470b80443726053f18a2481b7e1eee970597051596567987a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.2"
|
||||
@@ -2962,7 +2983,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2980,22 +3001,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
version = "2.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.18"
|
||||
version = "2.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3009,9 +3030,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.53"
|
||||
version = "0.3.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50"
|
||||
checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"num-conv",
|
||||
@@ -3029,9 +3050,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.31"
|
||||
version = "0.2.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f"
|
||||
checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
@@ -3049,9 +3070,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.52.4"
|
||||
version = "1.53.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317fafbbe3f02fc663dad00ea6186197de963cd4190e86a26d8d0fae095539af"
|
||||
checksum = "d988bcd52dbe076d3d46903332f58c912b87a2c49b1428419a5845154762ffee"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
@@ -3063,13 +3084,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.7.0"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
|
||||
checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3193,7 +3214,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3246,9 +3267,9 @@ checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
|
||||
|
||||
[[package]]
|
||||
name = "twox-hash"
|
||||
version = "2.1.2"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c"
|
||||
checksum = "8464ec13c3691491391d9fce00f6416c9a48e46972f72d7865688be2080192c9"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@@ -3373,7 +3394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87e6ddc694828bd6d372573727e02ea07047f4b65f78aaf859dae2fbf2dbbcfe"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3430,7 +3451,7 @@ dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -3455,9 +3476,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "1.0.8"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf"
|
||||
checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
@@ -3520,7 +3541,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3531,7 +3552,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3697,7 +3718,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -3718,7 +3739,7 @@ checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3738,7 +3759,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -3778,7 +3799,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
+6
-6
@@ -64,9 +64,9 @@ color-eyre = "0.6.5"
|
||||
corepc-jsonrpc = { package = "jsonrpc", version = "0.19.0", features = ["simple_http"], default-features = false }
|
||||
corepc-types = { version = "0.15.0", features = ["std"], default-features = false }
|
||||
derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
|
||||
fjall = "3.1.6"
|
||||
fjall = "3.1.8"
|
||||
indexmap = { version = "2.14.0", features = ["serde"] }
|
||||
jiff = { version = "0.2.32", features = ["perf-inline", "tz-system"], default-features = false }
|
||||
jiff = { version = "0.2.34", features = ["perf-inline", "tz-system"], default-features = false }
|
||||
owo-colors = "4.3.0"
|
||||
parking_lot = "0.12.5"
|
||||
pco = "1.0.2"
|
||||
@@ -74,12 +74,12 @@ rayon = "1.12.0"
|
||||
rapidhash = "4.5.1"
|
||||
rustc-hash = "2.1.3"
|
||||
schemars = { version = "1.2.1", features = ["indexmap2"] }
|
||||
serde = "1.0.228"
|
||||
serde = "1.0.229"
|
||||
serde_bytes = "0.11.19"
|
||||
serde_derive = "1.0.228"
|
||||
serde_json = { version = "1.0.150", features = ["float_roundtrip", "preserve_order"] }
|
||||
serde_derive = "1.0.229"
|
||||
serde_json = { version = "1.0.151", features = ["float_roundtrip", "preserve_order"] }
|
||||
smallvec = "1.15.2"
|
||||
tokio = { version = "1.52.4", features = ["rt-multi-thread"] }
|
||||
tokio = { version = "1.53.0", features = ["rt-multi-thread"] }
|
||||
tower-http = { version = "0.7.0", features = ["catch-panic", "compression-br", "compression-gzip", "compression-zstd", "cors", "normalize-path", "timeout", "trace"] }
|
||||
tower-layer = "0.3"
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
|
||||
@@ -291,7 +291,7 @@ fn collect_instance_analyses(
|
||||
///
|
||||
/// Supports two cases:
|
||||
/// 1. **Embedded discriminator**: a substring varies per instance within field_parts.
|
||||
/// E.g., `ratio_pct99_bps` vs `ratio_pct1_bps` → template `ratio_{disc}_bps`
|
||||
/// E.g., `ratio_pct99_ppm` vs `ratio_pct1_ppm` → template `ratio_{disc}_ppm`
|
||||
/// 2. **Suffix discriminator**: a common suffix is appended to all field_parts.
|
||||
/// E.g., `ratio_sd` vs `ratio_sd_4y` → template `ratio_sd{disc}`
|
||||
fn try_detect_template(
|
||||
@@ -307,11 +307,11 @@ fn try_detect_template(
|
||||
return Some(mode);
|
||||
}
|
||||
|
||||
// Strategy 2: embedded discriminator (e.g., ratio_pct99_bps vs ratio_pct1_bps)
|
||||
// Strategy 2: embedded discriminator (e.g., ratio_pct99_ppm vs ratio_pct1_ppm)
|
||||
try_embedded_disc(majority, fields)
|
||||
}
|
||||
|
||||
/// Strategy 1: embedded discriminator (e.g., pct99 inside ratio_pct99_bps)
|
||||
/// Strategy 1: embedded discriminator (e.g., pct99 inside ratio_pct99_ppm)
|
||||
fn try_embedded_disc(
|
||||
majority: &[&InstanceAnalysis],
|
||||
fields: &[PatternField],
|
||||
@@ -772,7 +772,7 @@ mod tests {
|
||||
use std::collections::BTreeSet;
|
||||
let fields = vec![
|
||||
PatternField {
|
||||
name: "bps".into(),
|
||||
name: "ppm".into(),
|
||||
rust_type: "T".into(),
|
||||
json_type: "n".into(),
|
||||
indexes: BTreeSet::new(),
|
||||
@@ -796,7 +796,7 @@ mod tests {
|
||||
let pct99 = InstanceAnalysis {
|
||||
base: "realized_price".into(),
|
||||
field_parts: [
|
||||
("bps".into(), "ratio_pct99_bps".into()),
|
||||
("ppm".into(), "ratio_pct99_ppm".into()),
|
||||
("price".into(), "pct99".into()),
|
||||
("ratio".into(), "ratio_pct99".into()),
|
||||
]
|
||||
@@ -808,7 +808,7 @@ mod tests {
|
||||
let pct1 = InstanceAnalysis {
|
||||
base: "realized_price".into(),
|
||||
field_parts: [
|
||||
("bps".into(), "ratio_pct1_bps".into()),
|
||||
("ppm".into(), "ratio_pct1_ppm".into()),
|
||||
("price".into(), "pct1".into()),
|
||||
("ratio".into(), "ratio_pct1".into()),
|
||||
]
|
||||
@@ -821,7 +821,7 @@ mod tests {
|
||||
assert!(mode.is_some());
|
||||
match mode.unwrap() {
|
||||
PatternMode::Templated { templates } => {
|
||||
assert_eq!(templates.get("bps").unwrap(), "ratio_{disc}_bps");
|
||||
assert_eq!(templates.get("ppm").unwrap(), "ratio_{disc}_ppm");
|
||||
assert_eq!(templates.get("price").unwrap(), "{disc}");
|
||||
assert_eq!(templates.get("ratio").unwrap(), "ratio_{disc}");
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ impl LanguageSyntax for JavaScriptSyntax {
|
||||
format!("_m({}, '{}')", var_name, template)
|
||||
} else {
|
||||
// Template with {disc}: use nested _m for proper separator handling
|
||||
// "ratio_{disc}_bps" → split on {disc} → _m(_m(acc, 'ratio'), disc) then _bps
|
||||
// "ratio_{disc}_ppm" → split on {disc} → _m(_m(acc, 'ratio'), disc) then _ppm
|
||||
// But this is complex. For embedded disc, use string interpolation.
|
||||
// For suffix disc (ends with {disc}), use _m composition.
|
||||
if let Some(static_part) = template.strip_suffix("{disc}") {
|
||||
|
||||
@@ -107,7 +107,7 @@ pub trait LanguageSyntax {
|
||||
/// - `"pct99"` (static) → `'pct99'` (JS) / `"pct99".to_string()` (Rust)
|
||||
/// - `""` (empty) → `disc` (pass parent's disc through)
|
||||
/// - `"p1sd{disc}"` (suffix) → `_m('p1sd', disc)` (composed)
|
||||
/// - `"ratio_{disc}_bps"` (embedded) → `` `ratio_${disc}_bps` `` (template literal)
|
||||
/// - `"ratio_{disc}_ppm"` (embedded) → `` `ratio_${disc}_ppm` `` (template literal)
|
||||
fn disc_arg_expr(&self, template: &str) -> String;
|
||||
|
||||
/// Format a templated mode expression: substitute `{disc}` at runtime.
|
||||
@@ -117,6 +117,6 @@ pub trait LanguageSyntax {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `acc_var` - The accumulator variable (e.g., "acc")
|
||||
/// * `template` - Template like `"ratio_{disc}_bps"` or `"{disc}"`
|
||||
/// * `template` - Template like `"ratio_{disc}_ppm"` or `"{disc}"`
|
||||
fn template_expr(&self, acc_var: &str, template: &str) -> String;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ pub enum PatternMode {
|
||||
/// Fields construct series names using a template with a discriminator placeholder.
|
||||
/// Factory takes two params: `acc` (base) and `disc` (discriminator).
|
||||
/// Formula: `_m(acc, template.replace("{disc}", disc))`
|
||||
/// Example: template `"ratio_{disc}_bps"` with disc `"pct99"` → `_m(acc, "ratio_pct99_bps")`
|
||||
/// Example: template `"ratio_{disc}_ppm"` with disc `"pct99"` → `_m(acc, "ratio_pct99_ppm")`
|
||||
Templated {
|
||||
/// Maps field name to its template string containing `{disc}` placeholder
|
||||
templates: BTreeMap<String, String>,
|
||||
|
||||
@@ -128,7 +128,7 @@ impl StructuralPattern {
|
||||
}
|
||||
|
||||
/// Extract the discriminator value by matching a template against a concrete string.
|
||||
/// E.g., template `"ratio_{disc}_bps"` matched against `"ratio_pct99_bps"` yields `"pct99"`.
|
||||
/// E.g., template `"ratio_{disc}_ppm"` matched against `"ratio_pct99_ppm"` yields `"pct99"`.
|
||||
fn extract_disc(template: &str, value: &str) -> Option<String> {
|
||||
let (prefix, suffix) = template.split_once("{disc}")?;
|
||||
if value.starts_with(prefix) && value.ends_with(suffix) {
|
||||
|
||||
+688
-690
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ impl Vecs {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let starting_height = indexer.safe_lengths().height;
|
||||
self.adjustment.bps.height.compute_ratio_change(
|
||||
self.adjustment.raw.height.compute_ratio_change(
|
||||
starting_height,
|
||||
&indexer.vecs.blocks.difficulty,
|
||||
2016,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Epoch, StoredF32, StoredF64, StoredU32};
|
||||
use brk_types::{Epoch, PartsPerMillionSigned32, StoredF32, StoredF64, StoredU32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{LazyPerBlock, PerBlock, PercentPerBlock, Resolutions};
|
||||
@@ -7,7 +7,7 @@ use crate::internal::{LazyPerBlock, PerBlock, PercentPerBlock, Resolutions};
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub value: Resolutions<StoredF64>,
|
||||
pub hashrate: LazyPerBlock<StoredF64>,
|
||||
pub adjustment: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub adjustment: PercentPerBlock<PartsPerMillionSigned32, M>,
|
||||
pub epoch: PerBlock<Epoch, M>,
|
||||
pub blocks_to_retarget: PerBlock<StoredU32, M>,
|
||||
pub days_to_retarget: LazyPerBlock<StoredF32, StoredU32>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::BasisPoints16;
|
||||
use brk_types::PartsPerMillion32;
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
@@ -8,10 +8,10 @@ use super::Vecs;
|
||||
impl Vecs {
|
||||
pub(crate) fn compute(&mut self, indexer: &Indexer, exit: &Exit) -> Result<()> {
|
||||
let starting_height = indexer.safe_lengths().height;
|
||||
self.fullness.bps.compute_transform(
|
||||
self.fullness.raw.compute_transform(
|
||||
starting_height,
|
||||
&indexer.vecs.blocks.weight,
|
||||
|(h, weight, ..)| (h, BasisPoints16::from(weight.fullness())),
|
||||
|(h, weight, ..)| (h, PartsPerMillion32::from(weight.fullness())),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, StoredU64, Weight};
|
||||
use brk_types::{PartsPerMillion32, StoredU64, Weight};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{LazyPerBlockRolling, PercentVec};
|
||||
@@ -7,5 +7,5 @@ use crate::internal::{LazyPerBlockRolling, PercentVec};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub weight: LazyPerBlockRolling<Weight, StoredU64>,
|
||||
pub fullness: PercentVec<BasisPoints16, M>,
|
||||
pub fullness: PercentVec<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::BasisPointsSigned32;
|
||||
use brk_types::PartsPerMillionSigned64;
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::super::activity;
|
||||
@@ -17,14 +17,14 @@ impl Vecs {
|
||||
) -> Result<()> {
|
||||
let starting_height = indexer.safe_lengths().height;
|
||||
|
||||
self.inflation_rate.bps.height.compute_transform2(
|
||||
self.inflation_rate.raw.height.compute_transform2(
|
||||
starting_height,
|
||||
&activity.ratio.height,
|
||||
&supply.inflation_rate.bps.height,
|
||||
&supply.inflation_rate.raw.height,
|
||||
|(h, a2vr, inflation, ..)| {
|
||||
(
|
||||
h,
|
||||
BasisPointsSigned32::from(f64::from(a2vr) * f64::from(inflation)),
|
||||
PartsPerMillionSigned64::from(f64::from(a2vr) * f64::from(inflation)),
|
||||
)
|
||||
},
|
||||
exit,
|
||||
|
||||
@@ -18,7 +18,7 @@ impl Vecs {
|
||||
inflation_rate: PercentPerBlock::forced_import(
|
||||
db,
|
||||
"cointime_adj_inflation_rate",
|
||||
version + Version::ONE,
|
||||
version + Version::TWO,
|
||||
indexes,
|
||||
)?,
|
||||
tx_velocity_native: PerBlock::forced_import(
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, StoredF64};
|
||||
use brk_types::{PartsPerMillionSigned64, StoredF64};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{PerBlock, PercentPerBlock};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub inflation_rate: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub inflation_rate: PercentPerBlock<PartsPerMillionSigned64, M>,
|
||||
pub tx_velocity_native: PerBlock<StoredF64, M>,
|
||||
pub tx_velocity_fiat: PerBlock<StoredF64, M>,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints32, Cents};
|
||||
use brk_types::{Cents, PartsPerMillion32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{FiatPerBlock, RatioPerBlock};
|
||||
@@ -11,5 +11,5 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub vaulted: FiatPerBlock<Cents, M>,
|
||||
pub active: FiatPerBlock<Cents, M>,
|
||||
pub cointime: FiatPerBlock<Cents, M>,
|
||||
pub aviv: RatioPerBlock<BasisPoints32, M>,
|
||||
pub aviv: RatioPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, StoredI64, StoredU64, Version};
|
||||
use brk_types::{PartsPerMillionSigned64, StoredI64, StoredU64, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
|
||||
use crate::{
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
|
||||
use super::AddrCountsVecs;
|
||||
|
||||
type AddrDelta = LazyRollingDeltasFromHeight<StoredU64, StoredI64, BasisPointsSigned32>;
|
||||
type AddrDelta = LazyRollingDeltasFromHeight<StoredU64, StoredI64, PartsPerMillionSigned64>;
|
||||
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
pub struct DeltaVecs(#[traversable(flatten)] pub WithAddrTypes<AddrDelta>);
|
||||
@@ -21,7 +21,7 @@ impl DeltaVecs {
|
||||
cached_starts: &Windows<&WindowStartVec>,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Self {
|
||||
let version = version + Version::TWO;
|
||||
let version = version + Version::new(3);
|
||||
|
||||
let all = LazyRollingDeltasFromHeight::new(
|
||||
"addr_count",
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_cohort::ByAddrType;
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, OutputType, StoredF32, StoredU32, StoredU64, Version};
|
||||
use brk_types::{OutputType, PartsPerMillion32, StoredF32, StoredU32, StoredU64, Version};
|
||||
use rayon::prelude::*;
|
||||
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, Rw, StorageMode, WritableVec};
|
||||
|
||||
@@ -67,11 +67,11 @@ use super::state::AddrTypeToAddrEventCount;
|
||||
pub struct AddrEventsVecs<M: StorageMode = Rw> {
|
||||
pub output_to_reused_addr_count:
|
||||
WithAddrTypes<PerBlockCumulativeRolling<StoredU64, StoredU64, M>>,
|
||||
pub output_to_reused_addr_share: WithAddrTypes<PercentCumulativeRolling<BasisPoints16, M>>,
|
||||
pub spendable_output_to_reused_addr_share: PercentCumulativeRolling<BasisPoints16, M>,
|
||||
pub output_to_reused_addr_share: WithAddrTypes<PercentCumulativeRolling<PartsPerMillion32, M>>,
|
||||
pub spendable_output_to_reused_addr_share: PercentCumulativeRolling<PartsPerMillion32, M>,
|
||||
pub input_from_reused_addr_count:
|
||||
WithAddrTypes<PerBlockCumulativeRolling<StoredU64, StoredU64, M>>,
|
||||
pub input_from_reused_addr_share: WithAddrTypes<PercentCumulativeRolling<BasisPoints16, M>>,
|
||||
pub input_from_reused_addr_share: WithAddrTypes<PercentCumulativeRolling<PartsPerMillion32, M>>,
|
||||
pub active_reused_addr_count: PerBlockRollingAverage<StoredU32, StoredU64, M>,
|
||||
pub active_reused_addr_share: PerBlockRollingAverage<StoredF32, StoredF32, M>,
|
||||
}
|
||||
@@ -94,7 +94,7 @@ impl AddrEventsVecs {
|
||||
)
|
||||
};
|
||||
let import_percent =
|
||||
|name: &str| -> Result<WithAddrTypes<PercentCumulativeRolling<BasisPoints16>>> {
|
||||
|name: &str| -> Result<WithAddrTypes<PercentCumulativeRolling<PartsPerMillion32>>> {
|
||||
Ok(WithAddrTypes {
|
||||
all: PercentCumulativeRolling::forced_import(db, name, version, indexes)?,
|
||||
by_addr_type: ByAddrType::new_with_name(|type_name| {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use brk_cohort::ByAddrType;
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Height, Sats, Version};
|
||||
use brk_types::{Height, PartsPerMillion32, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{PercentPerBlock, RatioSatsBp16, WithAddrTypes},
|
||||
internal::{PercentPerBlock, RatioSats, WithAddrTypes},
|
||||
};
|
||||
|
||||
use super::vecs::AddrSupplyVecs;
|
||||
@@ -18,7 +18,7 @@ use super::vecs::AddrSupplyVecs;
|
||||
/// - Per-type: type's category supply / type's total supply
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
pub struct AddrSupplyShareVecs<M: StorageMode = Rw>(
|
||||
#[traversable(flatten)] pub WithAddrTypes<PercentPerBlock<BasisPoints16, M>>,
|
||||
#[traversable(flatten)] pub WithAddrTypes<PercentPerBlock<PartsPerMillion32, M>>,
|
||||
);
|
||||
|
||||
impl AddrSupplyShareVecs {
|
||||
@@ -29,7 +29,7 @@ impl AddrSupplyShareVecs {
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self(
|
||||
WithAddrTypes::<PercentPerBlock<BasisPoints16>>::forced_import(
|
||||
WithAddrTypes::<PercentPerBlock<PartsPerMillion32>>::forced_import(
|
||||
db,
|
||||
&format!("{name}_addr_supply_share"),
|
||||
version,
|
||||
@@ -46,7 +46,8 @@ impl AddrSupplyShareVecs {
|
||||
type_supply_sats: &ByAddrType<&impl ReadableVec<Height, Sats>>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.all.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
self.all
|
||||
.compute_binary::<Sats, Sats, RatioSats<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&supply.all.sats.height,
|
||||
all_supply_sats,
|
||||
@@ -57,7 +58,7 @@ impl AddrSupplyShareVecs {
|
||||
.iter_mut()
|
||||
.zip(supply.by_addr_type.iter().zip(type_supply_sats.iter()))
|
||||
{
|
||||
share.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
share.compute_binary::<Sats, Sats, RatioSats<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&cat.sats.height,
|
||||
*denom,
|
||||
|
||||
@@ -4,7 +4,7 @@ use brk_cohort::{CohortContext, Filter, Filtered};
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Cents, Height, Sats, StoredI64, StoredU64, Version};
|
||||
use brk_types::{Cents, Height, PartsPerMillionSigned64, Sats, StoredI64, StoredU64, Version};
|
||||
use rayon::prelude::*;
|
||||
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
@@ -28,7 +28,7 @@ pub struct AddrCohortVecs<M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub metrics: MinimalCohortMetrics<M>,
|
||||
|
||||
pub addr_count: PerBlockWithDeltas<StoredU64, StoredI64, BasisPointsSigned32, M>,
|
||||
pub addr_count: PerBlockWithDeltas<StoredU64, StoredI64, PartsPerMillionSigned64, M>,
|
||||
}
|
||||
|
||||
impl AddrCohortVecs {
|
||||
@@ -56,7 +56,7 @@ impl AddrCohortVecs {
|
||||
db,
|
||||
&cfg.name("addr_count"),
|
||||
version,
|
||||
Version::ONE,
|
||||
Version::TWO,
|
||||
indexes,
|
||||
cached_starts,
|
||||
)?;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_cohort::{Filter, PROFITABILITY_RANGE_COUNT, compute_profitability_boundaries};
|
||||
use brk_types::{Cents, CentsCompact, Sats};
|
||||
use brk_types::{Cents, CentsCompact, PartsPerMillion32, Sats};
|
||||
|
||||
use crate::{
|
||||
distribution::state::PendingDelta,
|
||||
@@ -332,10 +332,16 @@ impl CostBasisFenwick {
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/// Compute supply density: % of supply with cost basis within ±5% of spot.
|
||||
/// Returns (all_bps, sth_bps, lth_bps) as basis points (0-10000).
|
||||
pub(super) fn density(&self, spot_price: Cents) -> (u16, u16, u16) {
|
||||
pub(super) fn density(
|
||||
&self,
|
||||
spot_price: Cents,
|
||||
) -> (PartsPerMillion32, PartsPerMillion32, PartsPerMillion32) {
|
||||
if self.totals.all_sats <= 0 {
|
||||
return (0, 0, 0);
|
||||
return (
|
||||
PartsPerMillion32::ZERO,
|
||||
PartsPerMillion32::ZERO,
|
||||
PartsPerMillion32::ZERO,
|
||||
);
|
||||
}
|
||||
|
||||
let range = self.density_range(spot_price);
|
||||
@@ -345,16 +351,19 @@ impl CostBasisFenwick {
|
||||
|
||||
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),
|
||||
Self::to_ppm(all_range, self.totals.all_sats),
|
||||
Self::to_ppm(sth_range, self.totals.sth_sats),
|
||||
Self::to_ppm(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) {
|
||||
/// Compute supply density for entry cohorts: (discount, premium).
|
||||
pub(super) fn entry_density(
|
||||
&self,
|
||||
spot_price: Cents,
|
||||
) -> (PartsPerMillion32, PartsPerMillion32) {
|
||||
if self.totals.all_sats <= 0 {
|
||||
return (0, 0);
|
||||
return (PartsPerMillion32::ZERO, PartsPerMillion32::ZERO);
|
||||
}
|
||||
|
||||
let range = self.density_range(spot_price);
|
||||
@@ -363,8 +372,8 @@ impl CostBasisFenwick {
|
||||
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),
|
||||
Self::to_ppm(discount_range, self.totals.discount_sats),
|
||||
Self::to_ppm(premium_range, premium_total),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -394,11 +403,11 @@ impl CostBasisFenwick {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn to_bps(range: i64, total: i64) -> u16 {
|
||||
fn to_ppm(range: i64, total: i64) -> PartsPerMillion32 {
|
||||
if total <= 0 {
|
||||
0
|
||||
PartsPerMillion32::ZERO
|
||||
} else {
|
||||
(range as f64 / total as f64 * 10000.0).round() as u16
|
||||
PartsPerMillion32::from(range as f64 / total as f64)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{cmp::Reverse, collections::BinaryHeap, fs, path::Path};
|
||||
|
||||
use brk_cohort::{AGE_RANGE_NAMES, CohortContext, Filtered, PROFITABILITY_RANGE_COUNT, TERM_NAMES};
|
||||
use brk_error::Result;
|
||||
use brk_types::{BasisPoints16, Cents, CentsCompact, Date, Dollars, Sats, UrpdRaw};
|
||||
use brk_types::{Cents, CentsCompact, Date, Dollars, PartsPerMillion32, Sats, UrpdRaw};
|
||||
use rayon::prelude::*;
|
||||
|
||||
use crate::distribution::metrics::{CostBasis, ProfitabilityMetrics};
|
||||
@@ -139,10 +139,14 @@ impl UTXOCohorts {
|
||||
|
||||
/// Push percentiles + density to cost basis vecs.
|
||||
#[inline(always)]
|
||||
fn push_cost_basis(percentiles: &PercentileResult, density_bps: u16, cost_basis: &mut CostBasis) {
|
||||
fn push_cost_basis(
|
||||
percentiles: &PercentileResult,
|
||||
density: PartsPerMillion32,
|
||||
cost_basis: &mut CostBasis,
|
||||
) {
|
||||
cost_basis.push_minmax(percentiles.min_price, percentiles.max_price);
|
||||
cost_basis.push_percentiles(&percentiles.sat_prices, &percentiles.usd_prices);
|
||||
cost_basis.push_density(BasisPoints16::from(density_bps));
|
||||
cost_basis.push_density(density);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use brk_cohort::Filter;
|
||||
use brk_error::Result;
|
||||
use brk_types::{BasisPoints16, BasisPoints32, BasisPointsSigned32, Cents, Height, Version};
|
||||
use brk_types::{
|
||||
Cents, Height, PartsPerMillion32, PartsPerMillionSigned32, PartsPerMillionSigned64, Version,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{BytesVec, BytesVecValue, Database, ImportableVec};
|
||||
|
||||
@@ -39,12 +41,11 @@ impl_config_import!(
|
||||
ValuePerBlockCumulative,
|
||||
PriceWithRatioPerBlock,
|
||||
PriceWithRatioExtendedPerBlock,
|
||||
RatioPerBlock<BasisPoints32>,
|
||||
RatioPerBlock<BasisPointsSigned32>,
|
||||
PercentPerBlock<BasisPoints16>,
|
||||
PercentPerBlock<BasisPoints32>,
|
||||
PercentPerBlock<BasisPointsSigned32>,
|
||||
PercentRollingWindows<BasisPoints32>,
|
||||
RatioPerBlock<PartsPerMillionSigned32>,
|
||||
PercentPerBlock<PartsPerMillion32>,
|
||||
PercentPerBlock<PartsPerMillionSigned32>,
|
||||
PercentPerBlock<PartsPerMillionSigned64>,
|
||||
PercentRollingWindows<PartsPerMillion32>,
|
||||
Price<PerBlock<Cents>>,
|
||||
);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::CentsSquaredSats;
|
||||
use brk_types::{BasisPoints16, Cents, Height, Sats, Version};
|
||||
use brk_types::{Cents, Height, PartsPerMillion32, Sats, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::internal::{PERCENTILES_LEN, PerBlock, PercentPerBlock, PercentilesVecs, Price};
|
||||
@@ -25,7 +25,7 @@ pub struct CostBasis<M: StorageMode = Rw> {
|
||||
pub max: Price<PerBlock<Cents, M>>,
|
||||
pub per_coin: PercentilesVecs<M>,
|
||||
pub per_dollar: PercentilesVecs<M>,
|
||||
pub supply_density: PercentPerBlock<BasisPoints16, M>,
|
||||
pub supply_density: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
impl CostBasis {
|
||||
@@ -88,7 +88,7 @@ impl CostBasis {
|
||||
.height
|
||||
.len()
|
||||
.min(self.max.cents.height.len())
|
||||
.min(self.supply_density.bps.height.len())
|
||||
.min(self.supply_density.raw.height.len())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -108,8 +108,8 @@ impl CostBasis {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn push_density(&mut self, density_bps: BasisPoints16) {
|
||||
self.supply_density.bps.height.push(density_bps);
|
||||
pub(crate) fn push_density(&mut self, density: PartsPerMillion32) {
|
||||
self.supply_density.raw.height.push(density);
|
||||
}
|
||||
|
||||
pub(crate) fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
|
||||
@@ -128,7 +128,7 @@ impl CostBasis {
|
||||
&mut self.in_loss.per_dollar.cents.height,
|
||||
&mut self.min.cents.height,
|
||||
&mut self.max.cents.height,
|
||||
&mut self.supply_density.bps.height,
|
||||
&mut self.supply_density.raw.height,
|
||||
];
|
||||
vecs.extend(
|
||||
self.per_coin
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Height, StoredF32, StoredI64, StoredU32, StoredU64, Version};
|
||||
use brk_types::{
|
||||
Height, PartsPerMillionSigned64, StoredF32, StoredI64, StoredU32, StoredU64, Version,
|
||||
};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
@@ -15,7 +17,7 @@ use crate::{
|
||||
/// Base output metrics: utxo_count + delta.
|
||||
#[derive(Traversable)]
|
||||
pub struct OutputsBase<M: StorageMode = Rw> {
|
||||
pub unspent_count: PerBlockWithDeltas<StoredU64, StoredI64, BasisPointsSigned32, M>,
|
||||
pub unspent_count: PerBlockWithDeltas<StoredU64, StoredI64, PartsPerMillionSigned64, M>,
|
||||
pub spent_count: PerBlockCumulativeRolling<StoredU32, StoredU64, M>,
|
||||
pub spending_rate: PerBlock<StoredF32, M>,
|
||||
}
|
||||
@@ -28,7 +30,7 @@ impl OutputsBase {
|
||||
cfg.db,
|
||||
&cfg.name("utxo_count"),
|
||||
cfg.version,
|
||||
v1,
|
||||
Version::TWO,
|
||||
cfg.indexes,
|
||||
cfg.cached_starts,
|
||||
)?,
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_cohort::{Loss, Profit, ProfitabilityRange};
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Bitcoin, Cents, Dollars, Sats, Version};
|
||||
use brk_types::{Bitcoin, Cents, Dollars, PartsPerMillionSigned32, Sats, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
@@ -24,7 +24,7 @@ pub struct ProfitabilityBucket<M: StorageMode = Rw> {
|
||||
pub supply: WithSth<ValuePerBlockWithDeltas<M>, ValuePerBlock<M>>,
|
||||
pub realized_cap: WithSth<PerBlock<Dollars, M>>,
|
||||
pub unrealized_pnl: WithSth<PerBlock<Dollars, M>>,
|
||||
pub nupl: RatioPerBlock<BasisPointsSigned32, M>,
|
||||
pub nupl: RatioPerBlock<PartsPerMillionSigned32, M>,
|
||||
}
|
||||
|
||||
impl<M: StorageMode> ProfitabilityBucket<M> {
|
||||
@@ -152,7 +152,7 @@ impl ProfitabilityBucket {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.nupl.bps.height.compute_transform3(
|
||||
self.nupl.raw.height.compute_transform3(
|
||||
max_from,
|
||||
&prices.spot.cents.height,
|
||||
&self.realized_cap.all.height,
|
||||
@@ -161,11 +161,11 @@ impl ProfitabilityBucket {
|
||||
let p = spot.as_u128();
|
||||
let supply = supply_sats.as_u128();
|
||||
if p == 0 || supply == 0 {
|
||||
(i, BasisPointsSigned32::ZERO)
|
||||
(i, PartsPerMillionSigned32::ZERO)
|
||||
} else {
|
||||
let rp = Cents::from(cap_dollars).as_u128() * Sats::ONE_BTC_U128 / supply;
|
||||
let bps = ((p as i128 - rp as i128) * 10000) / p as i128;
|
||||
(i, BasisPointsSigned32::from(bps as i32))
|
||||
let ratio = (p as f64 - rp as f64) / p as f64;
|
||||
(i, PartsPerMillionSigned32::from(ratio))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
@@ -230,7 +230,7 @@ impl ProfitabilityBucket {
|
||||
&mut self.realized_cap.sth.height,
|
||||
&mut self.unrealized_pnl.all.height,
|
||||
&mut self.unrealized_pnl.sth.height,
|
||||
&mut self.nupl.bps.height,
|
||||
&mut self.nupl.raw.height,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Dollars, Height, StoredF64, Version,
|
||||
Bitcoin, Cents, CentsSigned, Dollars, Height, PartsPerMillionSigned64, StoredF64, Version,
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{
|
||||
@@ -45,8 +45,12 @@ pub struct RealizedCore<M: StorageMode = Rw> {
|
||||
|
||||
#[traversable(wrap = "loss", rename = "negative")]
|
||||
pub neg_loss: NegRealizedLoss,
|
||||
pub net_pnl:
|
||||
FiatPerBlockCumulativeWithSumsAndDeltas<CentsSigned, CentsSigned, BasisPointsSigned32, M>,
|
||||
pub net_pnl: FiatPerBlockCumulativeWithSumsAndDeltas<
|
||||
CentsSigned,
|
||||
CentsSigned,
|
||||
PartsPerMillionSigned64,
|
||||
M,
|
||||
>,
|
||||
pub sopr: RealizedSoprCore<M>,
|
||||
}
|
||||
|
||||
@@ -80,7 +84,7 @@ impl RealizedCore {
|
||||
cfg.db,
|
||||
&cfg.name("net_realized_pnl"),
|
||||
cfg.version + v1,
|
||||
Version::new(4),
|
||||
Version::new(5),
|
||||
cfg.indexes,
|
||||
cfg.cached_starts,
|
||||
)?;
|
||||
|
||||
@@ -2,8 +2,8 @@ use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
BasisPoints32, BasisPointsSigned32, Bitcoin, Cents, CentsSats, CentsSigned, CentsSquaredSats,
|
||||
Dollars, Height, StoredF64, Version,
|
||||
Bitcoin, Cents, CentsSats, CentsSigned, CentsSquaredSats, Dollars, Height, PartsPerMillion32,
|
||||
PartsPerMillionSigned64, StoredF64, Version,
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{AnyStoredVec, AnyVec, BytesVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
@@ -13,10 +13,9 @@ use crate::{
|
||||
distribution::state::{CohortState, CostBasisData, RealizedState, WithCapital},
|
||||
internal::{
|
||||
FiatPerBlockCumulativeWithSums, PercentPerBlock, PercentRollingWindows,
|
||||
PriceWithRatioExtendedPerBlock, RatioCents64, RatioCentsBp32, RatioCentsSignedCentsBps32,
|
||||
RatioCentsSignedDollarsBps32, RatioDollarsBp32, RatioPerBlockPercentiles,
|
||||
RatioPerBlockStdDevBands, RatioSma, RollingWindows, RollingWindowsFrom1w,
|
||||
ValuePerBlockCumulativeRolling,
|
||||
PriceWithRatioExtendedPerBlock, RatioCents, RatioCents64, RatioCentsSignedCents,
|
||||
RatioCentsSignedDollars, RatioDollars, RatioPerBlockPercentiles, RatioPerBlockStdDevBands,
|
||||
RatioSma, RollingWindows, RollingWindowsFrom1w, ValuePerBlockCumulativeRolling,
|
||||
},
|
||||
price,
|
||||
};
|
||||
@@ -28,9 +27,9 @@ use super::RealizedCore;
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedNetPnl<M: StorageMode = Rw> {
|
||||
#[traversable(wrap = "change_1m", rename = "to_rcap")]
|
||||
pub change_1m_to_rcap: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub change_1m_to_rcap: PercentPerBlock<PartsPerMillionSigned64, M>,
|
||||
#[traversable(wrap = "change_1m", rename = "to_mcap")]
|
||||
pub change_1m_to_mcap: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub change_1m_to_mcap: PercentPerBlock<PartsPerMillionSigned64, M>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -60,7 +59,7 @@ pub struct RealizedFull<M: StorageMode = Rw> {
|
||||
pub core: RealizedCore<M>,
|
||||
|
||||
pub gross_pnl: FiatPerBlockCumulativeWithSums<Cents, M>,
|
||||
pub sell_side_risk_ratio: PercentRollingWindows<BasisPoints32, M>,
|
||||
pub sell_side_risk_ratio: PercentRollingWindows<PartsPerMillion32, M>,
|
||||
pub net_pnl: RealizedNetPnl<M>,
|
||||
pub sopr: RealizedSopr<M>,
|
||||
pub peak_regret: RealizedPeakRegret<M>,
|
||||
@@ -71,7 +70,7 @@ pub struct RealizedFull<M: StorageMode = Rw> {
|
||||
#[traversable(hidden)]
|
||||
pub cap_raw: M::Stored<BytesVec<Height, CentsSats>>,
|
||||
#[traversable(wrap = "cap", rename = "to_own_mcap")]
|
||||
pub cap_to_own_mcap: PercentPerBlock<BasisPoints32, M>,
|
||||
pub cap_to_own_mcap: PercentPerBlock<PartsPerMillion32, M>,
|
||||
|
||||
#[traversable(wrap = "price", rename = "percentiles")]
|
||||
pub price_ratio_percentiles: RatioPerBlockPercentiles<M>,
|
||||
@@ -95,8 +94,8 @@ impl RealizedFull {
|
||||
|
||||
// Net PnL
|
||||
let net_pnl = RealizedNetPnl {
|
||||
change_1m_to_rcap: cfg.import("net_pnl_change_1m_to_rcap", Version::new(4))?,
|
||||
change_1m_to_mcap: cfg.import("net_pnl_change_1m_to_mcap", Version::new(4))?,
|
||||
change_1m_to_rcap: cfg.import("net_pnl_change_1m_to_rcap", Version::new(5))?,
|
||||
change_1m_to_mcap: cfg.import("net_pnl_change_1m_to_mcap", Version::new(5))?,
|
||||
};
|
||||
|
||||
// SOPR
|
||||
@@ -286,7 +285,7 @@ impl RealizedFull {
|
||||
// Net PnL 1m change relative to rcap and mcap
|
||||
self.net_pnl
|
||||
.change_1m_to_rcap
|
||||
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCentsBps32>(
|
||||
.compute_binary::<CentsSigned, Cents, RatioCentsSignedCents<PartsPerMillionSigned64>>(
|
||||
starting_lengths.height,
|
||||
&self.core.net_pnl.delta.absolute._1m.cents.height,
|
||||
&self.core.minimal.cap.cents.height,
|
||||
@@ -294,7 +293,11 @@ impl RealizedFull {
|
||||
)?;
|
||||
self.net_pnl
|
||||
.change_1m_to_mcap
|
||||
.compute_binary::<CentsSigned, Dollars, RatioCentsSignedDollarsBps32>(
|
||||
.compute_binary::<
|
||||
CentsSigned,
|
||||
Dollars,
|
||||
RatioCentsSignedDollars<PartsPerMillionSigned64>,
|
||||
>(
|
||||
starting_lengths.height,
|
||||
&self.core.net_pnl.delta.absolute._1m.cents.height,
|
||||
height_to_market_cap,
|
||||
@@ -313,7 +316,7 @@ impl RealizedFull {
|
||||
.into_iter()
|
||||
.zip(self.gross_pnl.sum.as_array())
|
||||
{
|
||||
ssrr.compute_binary::<Cents, Cents, RatioCentsBp32>(
|
||||
ssrr.compute_binary::<Cents, Cents, RatioCents<PartsPerMillion32>>(
|
||||
starting_lengths.height,
|
||||
&rv.cents.height,
|
||||
&self.core.minimal.cap.cents.height,
|
||||
@@ -323,7 +326,7 @@ impl RealizedFull {
|
||||
|
||||
// Realized cap relative to own market cap
|
||||
self.cap_to_own_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
|
||||
starting_lengths.height,
|
||||
&self.core.minimal.cap.usd.height,
|
||||
height_to_market_cap,
|
||||
|
||||
@@ -2,8 +2,8 @@ use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
BasisPoints32, BasisPointsSigned32, Bitcoin, Cents, CentsSigned, Height, Sats, StoredF32,
|
||||
Version,
|
||||
Bitcoin, Cents, CentsSigned, Height, PartsPerMillion64, PartsPerMillionSigned64, Sats,
|
||||
StoredF32, Version,
|
||||
};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::distribution::metrics::ImportConfig;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RealizedMinimal<M: StorageMode = Rw> {
|
||||
pub cap: FiatPerBlockWithDeltas<Cents, CentsSigned, BasisPointsSigned32, M>,
|
||||
pub cap: FiatPerBlockWithDeltas<Cents, CentsSigned, PartsPerMillionSigned64, M>,
|
||||
pub profit: FiatPerBlockCumulativeWithSums<Cents, M>,
|
||||
pub loss: FiatPerBlockCumulativeWithSums<Cents, M>,
|
||||
pub price: PriceWithRatioPerBlock<M>,
|
||||
@@ -35,13 +35,13 @@ impl RealizedMinimal {
|
||||
cfg.db,
|
||||
&cfg.name("realized_cap"),
|
||||
cfg.version,
|
||||
v1,
|
||||
Version::TWO,
|
||||
cfg.indexes,
|
||||
cfg.cached_starts,
|
||||
)?;
|
||||
|
||||
let price: PriceWithRatioPerBlock = cfg.import("realized_price", v1)?;
|
||||
let mvrv = LazyPerBlock::from_lazy::<Identity<StoredF32>, BasisPoints32>(
|
||||
let mvrv = LazyPerBlock::from_lazy::<Identity<StoredF32>, PartsPerMillion64>(
|
||||
&cfg.name("mvrv"),
|
||||
cfg.version,
|
||||
&price.ratio,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, BasisPoints32, BasisPointsSigned32, Dollars, Height, Version};
|
||||
use brk_types::{Dollars, Height, PartsPerMillion32, PartsPerMillionSigned32, Version};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{PercentPerBlock, RatioDollarsBp16, RatioDollarsBp32, RatioDollarsBps32};
|
||||
use crate::internal::{PercentPerBlock, RatioDollars};
|
||||
|
||||
use crate::distribution::metrics::{ImportConfig, UnrealizedCore};
|
||||
|
||||
@@ -11,11 +11,11 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedCore};
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeExtendedOwnMarketCap<M: StorageMode = Rw> {
|
||||
#[traversable(wrap = "unrealized/profit", rename = "to_own_mcap")]
|
||||
pub unrealized_profit_to_own_mcap: PercentPerBlock<BasisPoints16, M>,
|
||||
pub unrealized_profit_to_own_mcap: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(wrap = "unrealized/loss", rename = "to_own_mcap")]
|
||||
pub unrealized_loss_to_own_mcap: PercentPerBlock<BasisPoints32, M>,
|
||||
pub unrealized_loss_to_own_mcap: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(wrap = "unrealized/net_pnl", rename = "to_own_mcap")]
|
||||
pub net_unrealized_pnl_to_own_mcap: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub net_unrealized_pnl_to_own_mcap: PercentPerBlock<PartsPerMillionSigned32, M>,
|
||||
}
|
||||
|
||||
impl RelativeExtendedOwnMarketCap {
|
||||
@@ -39,21 +39,21 @@ impl RelativeExtendedOwnMarketCap {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.unrealized_profit_to_own_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&unrealized.profit.usd.height,
|
||||
own_market_cap,
|
||||
exit,
|
||||
)?;
|
||||
self.unrealized_loss_to_own_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&unrealized.loss.usd.height,
|
||||
own_market_cap,
|
||||
exit,
|
||||
)?;
|
||||
self.net_unrealized_pnl_to_own_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBps32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillionSigned32>>(
|
||||
max_from,
|
||||
&unrealized.net_pnl.usd.height,
|
||||
own_market_cap,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, BasisPointsSigned32, Dollars, Height, Version};
|
||||
use brk_types::{Dollars, Height, PartsPerMillion32, PartsPerMillionSigned32, Version};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{PercentPerBlock, RatioDollarsBp16, RatioDollarsBps32};
|
||||
use crate::internal::{PercentPerBlock, RatioDollars};
|
||||
|
||||
use crate::distribution::metrics::{ImportConfig, UnrealizedCore};
|
||||
|
||||
@@ -11,11 +11,11 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedCore};
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeExtendedOwnPnl<M: StorageMode = Rw> {
|
||||
#[traversable(wrap = "unrealized/profit", rename = "to_own_gross_pnl")]
|
||||
pub unrealized_profit_to_own_gross_pnl: PercentPerBlock<BasisPoints16, M>,
|
||||
pub unrealized_profit_to_own_gross_pnl: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(wrap = "unrealized/loss", rename = "to_own_gross_pnl")]
|
||||
pub unrealized_loss_to_own_gross_pnl: PercentPerBlock<BasisPoints16, M>,
|
||||
pub unrealized_loss_to_own_gross_pnl: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(wrap = "unrealized/net_pnl", rename = "to_own_gross_pnl")]
|
||||
pub net_unrealized_pnl_to_own_gross_pnl: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub net_unrealized_pnl_to_own_gross_pnl: PercentPerBlock<PartsPerMillionSigned32, M>,
|
||||
}
|
||||
|
||||
impl RelativeExtendedOwnPnl {
|
||||
@@ -39,21 +39,21 @@ impl RelativeExtendedOwnPnl {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.unrealized_profit_to_own_gross_pnl
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&unrealized.profit.usd.height,
|
||||
gross_pnl_usd,
|
||||
exit,
|
||||
)?;
|
||||
self.unrealized_loss_to_own_gross_pnl
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&unrealized.loss.usd.height,
|
||||
gross_pnl_usd,
|
||||
exit,
|
||||
)?;
|
||||
self.net_unrealized_pnl_to_own_gross_pnl
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBps32>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillionSigned32>>(
|
||||
max_from,
|
||||
&unrealized.net_pnl.usd.height,
|
||||
gross_pnl_usd,
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Dollars, Height, Sats, Version};
|
||||
use brk_types::{Dollars, Height, PartsPerMillion32, Sats, Version};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
distribution::metrics::{ImportConfig, SupplyCore, UnrealizedBasic},
|
||||
internal::{PercentPerBlock, RatioDollarsBp16, RatioSatsBp16},
|
||||
internal::{PercentPerBlock, RatioDollars, RatioSats},
|
||||
};
|
||||
|
||||
/// Full relative metrics (sth/lth/all tier).
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeFull<M: StorageMode = Rw> {
|
||||
#[traversable(wrap = "supply/in_profit", rename = "share")]
|
||||
pub supply_in_profit_share: PercentPerBlock<BasisPoints16, M>,
|
||||
pub supply_in_profit_share: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(wrap = "supply/in_loss", rename = "share")]
|
||||
pub supply_in_loss_share: PercentPerBlock<BasisPoints16, M>,
|
||||
pub supply_in_loss_share: PercentPerBlock<PartsPerMillion32, M>,
|
||||
|
||||
#[traversable(wrap = "unrealized/profit", rename = "to_mcap")]
|
||||
pub unrealized_profit_to_mcap: PercentPerBlock<BasisPoints16, M>,
|
||||
pub unrealized_profit_to_mcap: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(wrap = "unrealized/loss", rename = "to_mcap")]
|
||||
pub unrealized_loss_to_mcap: PercentPerBlock<BasisPoints16, M>,
|
||||
pub unrealized_loss_to_mcap: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
impl RelativeFull {
|
||||
@@ -44,14 +44,14 @@ impl RelativeFull {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.supply_in_profit_share
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
.compute_binary::<Sats, Sats, RatioSats<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&supply.in_profit.sats.height,
|
||||
&supply.total.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
self.supply_in_loss_share
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
.compute_binary::<Sats, Sats, RatioSats<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&supply.in_loss.sats.height,
|
||||
&supply.total.sats.height,
|
||||
@@ -59,14 +59,14 @@ impl RelativeFull {
|
||||
)?;
|
||||
|
||||
self.unrealized_profit_to_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&unrealized.profit.usd.height,
|
||||
market_cap,
|
||||
exit,
|
||||
)?;
|
||||
self.unrealized_loss_to_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&unrealized.loss.usd.height,
|
||||
market_cap,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Cents, Height, Version};
|
||||
use brk_types::{Cents, Height, PartsPerMillion32, Version};
|
||||
use vecdb::{Exit, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{PercentPerBlock, RatioCentsBp16};
|
||||
use crate::internal::{PercentPerBlock, RatioCents};
|
||||
|
||||
use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
|
||||
|
||||
@@ -12,9 +12,9 @@ use crate::distribution::metrics::{ImportConfig, RealizedFull, UnrealizedFull};
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeInvestedCapital<M: StorageMode = Rw> {
|
||||
#[traversable(wrap = "invested_capital/in_profit", rename = "share")]
|
||||
pub in_profit_share: PercentPerBlock<BasisPoints16, M>,
|
||||
pub in_profit_share: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(wrap = "invested_capital/in_loss", rename = "share")]
|
||||
pub in_loss_share: PercentPerBlock<BasisPoints16, M>,
|
||||
pub in_loss_share: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
impl RelativeInvestedCapital {
|
||||
@@ -35,14 +35,14 @@ impl RelativeInvestedCapital {
|
||||
) -> Result<()> {
|
||||
let realized_cap = &realized.core.minimal.cap.cents.height;
|
||||
self.in_profit_share
|
||||
.compute_binary::<Cents, Cents, RatioCentsBp16>(
|
||||
.compute_binary::<Cents, Cents, RatioCents<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&unrealized.invested_capital.in_profit.cents.height,
|
||||
realized_cap,
|
||||
exit,
|
||||
)?;
|
||||
self.in_loss_share
|
||||
.compute_binary::<Cents, Cents, RatioCentsBp16>(
|
||||
.compute_binary::<Cents, Cents, RatioCents<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&unrealized.invested_capital.in_loss.cents.height,
|
||||
realized_cap,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, BasisPointsSigned32, Height, Sats, SatsSigned, Version};
|
||||
use brk_types::{Height, PartsPerMillion32, PartsPerMillionSigned64, Sats, SatsSigned, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use crate::internal::{
|
||||
LazyRollingDeltasAmountFromHeight, PercentPerBlock, RatioSatsBp16, ValuePerBlock,
|
||||
LazyRollingDeltasAmountFromHeight, PercentPerBlock, RatioSats, ValuePerBlock,
|
||||
};
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
@@ -19,9 +19,9 @@ use crate::distribution::metrics::ImportConfig;
|
||||
#[derive(Traversable)]
|
||||
pub struct SupplyBase<M: StorageMode = Rw> {
|
||||
pub total: ValuePerBlock<M>,
|
||||
pub delta: LazyRollingDeltasAmountFromHeight<Sats, SatsSigned, BasisPointsSigned32>,
|
||||
pub delta: LazyRollingDeltasAmountFromHeight<Sats, SatsSigned, PartsPerMillionSigned64>,
|
||||
#[traversable(rename = "dominance")]
|
||||
pub dominance: PercentPerBlock<BasisPoints16, M>,
|
||||
pub dominance: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
impl SupplyBase {
|
||||
@@ -30,7 +30,7 @@ impl SupplyBase {
|
||||
|
||||
let delta = LazyRollingDeltasAmountFromHeight::new(
|
||||
&cfg.name("supply_delta"),
|
||||
cfg.version + Version::ONE,
|
||||
cfg.version + Version::TWO,
|
||||
&supply.sats.height,
|
||||
cfg.cached_starts,
|
||||
cfg.indexes,
|
||||
@@ -58,7 +58,7 @@ impl SupplyBase {
|
||||
vec![
|
||||
&mut self.total.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.total.cents.height,
|
||||
&mut self.dominance.bps.height,
|
||||
&mut self.dominance.raw.height,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -77,12 +77,13 @@ impl SupplyBase {
|
||||
all_supply_sats: &impl ReadableVec<Height, Sats>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.dominance.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from,
|
||||
&self.total.sats.height,
|
||||
all_supply_sats,
|
||||
exit,
|
||||
)
|
||||
self.dominance
|
||||
.compute_binary::<Sats, Sats, RatioSats<PartsPerMillion32>>(
|
||||
max_from,
|
||||
&self.total.sats.height,
|
||||
all_supply_sats,
|
||||
exit,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn compute_from_stateful(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Cents, Height, Version};
|
||||
use brk_types::{Cents, Height, PartsPerMillionSigned32, Version};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::RatioPerBlock;
|
||||
@@ -9,7 +9,7 @@ use crate::distribution::metrics::ImportConfig;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct UnrealizedMinimal<M: StorageMode = Rw> {
|
||||
pub nupl: RatioPerBlock<BasisPointsSigned32, M>,
|
||||
pub nupl: RatioPerBlock<PartsPerMillionSigned32, M>,
|
||||
}
|
||||
|
||||
impl UnrealizedMinimal {
|
||||
@@ -31,18 +31,18 @@ impl UnrealizedMinimal {
|
||||
realized_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.nupl.bps.height.compute_transform2(
|
||||
self.nupl.raw.height.compute_transform2(
|
||||
max_from,
|
||||
spot_price,
|
||||
realized_price,
|
||||
|(i, price, realized_price, ..)| {
|
||||
let p = price.as_u128();
|
||||
if p == 0 {
|
||||
(i, BasisPointsSigned32::ZERO)
|
||||
(i, PartsPerMillionSigned32::ZERO)
|
||||
} else {
|
||||
let rp = realized_price.as_u128();
|
||||
let nupl_bps = ((p as i128 - rp as i128) * 10000) / p as i128;
|
||||
(i, BasisPointsSigned32::from(nupl_bps as i32))
|
||||
let ratio = (p as f64 - rp as f64) / p as f64;
|
||||
(i, PartsPerMillionSigned32::from(ratio))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{Bitcoin, Dollars, StoredF32};
|
||||
use brk_types::{Bitcoin, Dollars, PartsPerMillion64, StoredF32};
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::{Vecs, gini};
|
||||
use crate::{distribution, internal::RatioDollarsBp32, market, mining, transactions};
|
||||
use crate::{distribution, internal::RatioDollars, market, mining, transactions};
|
||||
|
||||
impl Vecs {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -23,8 +23,8 @@ impl Vecs {
|
||||
|
||||
// Puell Multiple: daily_subsidy_usd / sma_365d_subsidy_usd
|
||||
self.puell_multiple
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
.raw
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion64>>(
|
||||
starting_lengths.height,
|
||||
&mining.rewards.subsidy.block.usd,
|
||||
&mining.rewards.subsidy.average._1y.usd.height,
|
||||
@@ -36,8 +36,8 @@ impl Vecs {
|
||||
|
||||
// RHODL Ratio: 1d-1w realized cap / 1y-2y realized cap
|
||||
self.rhodl_ratio
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
.raw
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion64>>(
|
||||
starting_lengths.height,
|
||||
&distribution
|
||||
.utxo_cohorts
|
||||
@@ -70,8 +70,8 @@ impl Vecs {
|
||||
.usd
|
||||
.height;
|
||||
self.nvt
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
.raw
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion64>>(
|
||||
starting_lengths.height,
|
||||
market_cap,
|
||||
&transactions.volume.transfer_volume.sum._24h.usd.height,
|
||||
@@ -80,8 +80,8 @@ impl Vecs {
|
||||
|
||||
// Thermocap Multiple: market_cap / thermo_cap
|
||||
self.thermo_cap_multiple
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
.raw
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion64>>(
|
||||
starting_lengths.height,
|
||||
market_cap,
|
||||
&mining.rewards.subsidy.cumulative.usd.height,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{BasisPoints16, Sats, StoredU64, Version};
|
||||
use brk_types::{PartsPerMillion32, Sats, StoredU64, Version};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, VecIndex, WritableVec};
|
||||
|
||||
use crate::{distribution, internal::PercentPerBlock};
|
||||
|
||||
pub(super) fn compute(
|
||||
gini: &mut PercentPerBlock<BasisPoints16>,
|
||||
gini: &mut PercentPerBlock<PartsPerMillion32>,
|
||||
distribution: &distribution::Vecs,
|
||||
indexer: &Indexer,
|
||||
exit: &Exit,
|
||||
@@ -34,13 +34,13 @@ pub(super) fn compute(
|
||||
.iter()
|
||||
.fold(Version::ZERO, |acc, v| acc + v.version());
|
||||
|
||||
gini.bps
|
||||
gini.raw
|
||||
.height
|
||||
.validate_computed_version_or_reset(source_version)?;
|
||||
|
||||
let min_len = gini.bps.height.len().min(starting_height.to_usize());
|
||||
let min_len = gini.raw.height.len().min(starting_height.to_usize());
|
||||
|
||||
gini.bps.height.truncate_if_needed_at(min_len)?;
|
||||
gini.raw.height.truncate_if_needed_at(min_len)?;
|
||||
|
||||
let total_heights = supply_vecs
|
||||
.iter()
|
||||
@@ -49,7 +49,7 @@ pub(super) fn compute(
|
||||
.unwrap_or(0)
|
||||
.min(count_vecs.iter().map(|v| v.len()).min().unwrap_or(0));
|
||||
|
||||
let start_height = gini.bps.height.len();
|
||||
let start_height = gini.raw.height.len();
|
||||
if start_height >= total_heights {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -73,23 +73,23 @@ pub(super) fn compute(
|
||||
let count: u64 = count_data[c][offset].into();
|
||||
buckets.push((count, supply));
|
||||
}
|
||||
gini.bps.height.push(gini_from_lorenz(&buckets));
|
||||
gini.raw.height.push(gini_from_lorenz(&buckets));
|
||||
}
|
||||
|
||||
{
|
||||
let _lock = exit.lock();
|
||||
gini.bps.height.write()?;
|
||||
gini.raw.height.write()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gini_from_lorenz(buckets: &[(u64, u64)]) -> BasisPoints16 {
|
||||
fn gini_from_lorenz(buckets: &[(u64, u64)]) -> PartsPerMillion32 {
|
||||
let total_count: u64 = buckets.iter().map(|(c, _)| c).sum();
|
||||
let total_supply: u64 = buckets.iter().map(|(_, s)| s).sum();
|
||||
|
||||
if total_count == 0 || total_supply == 0 {
|
||||
return BasisPoints16::ZERO;
|
||||
return PartsPerMillion32::ZERO;
|
||||
}
|
||||
|
||||
let (mut cumulative_count, mut cumulative_supply, mut area) = (0u64, 0u64, 0.0f64);
|
||||
@@ -103,5 +103,5 @@ fn gini_from_lorenz(buckets: &[(u64, u64)]) -> BasisPoints16 {
|
||||
area += (p1 - p0) * (w0 + w1) / 2.0;
|
||||
}
|
||||
|
||||
BasisPoints16::from(1.0 - 2.0 * area)
|
||||
PartsPerMillion32::from(1.0 - 2.0 * area)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, BasisPoints32, StoredF32};
|
||||
use brk_types::{PartsPerMillion32, PartsPerMillion64, StoredF32};
|
||||
use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
use super::rarity_meter::RarityMeter;
|
||||
@@ -15,11 +15,11 @@ pub struct DormancyVecs<M: StorageMode = Rw> {
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
#[traversable(skip)]
|
||||
pub(crate) db: Database,
|
||||
pub puell_multiple: RatioPerBlock<BasisPoints32, M>,
|
||||
pub nvt: RatioPerBlock<BasisPoints32, M>,
|
||||
pub gini: PercentPerBlock<BasisPoints16, M>,
|
||||
pub rhodl_ratio: RatioPerBlock<BasisPoints32, M>,
|
||||
pub thermo_cap_multiple: RatioPerBlock<BasisPoints32, M>,
|
||||
pub puell_multiple: RatioPerBlock<PartsPerMillion64, M>,
|
||||
pub nvt: RatioPerBlock<PartsPerMillion64, M>,
|
||||
pub gini: PercentPerBlock<PartsPerMillion32, M>,
|
||||
pub rhodl_ratio: RatioPerBlock<PartsPerMillion64, M>,
|
||||
pub thermo_cap_multiple: RatioPerBlock<PartsPerMillion64, M>,
|
||||
pub coindays_destroyed_supply_adj: PerBlock<StoredF32, M>,
|
||||
pub coinyears_destroyed_supply_adj: PerBlock<StoredF32, M>,
|
||||
pub dormancy: DormancyVecs<M>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_cohort::SpendableType;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, StoredU64};
|
||||
use brk_types::{PartsPerMillion32, StoredU64};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use super::WithInputTypes;
|
||||
@@ -9,7 +9,7 @@ use crate::internal::{PerBlockCumulativeRolling, PercentCumulativeRolling};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub input_count: WithInputTypes<PerBlockCumulativeRolling<StoredU64, StoredU64, M>>,
|
||||
pub input_share: SpendableType<PercentCumulativeRolling<BasisPoints16, M>>,
|
||||
pub input_share: SpendableType<PercentCumulativeRolling<PartsPerMillion32, M>>,
|
||||
pub tx_count: WithInputTypes<PerBlockCumulativeRolling<StoredU64, StoredU64, M>>,
|
||||
pub tx_share: SpendableType<PercentCumulativeRolling<BasisPoints16, M>>,
|
||||
pub tx_share: SpendableType<PercentCumulativeRolling<PartsPerMillion32, M>>,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::BasisPointsSigned16;
|
||||
use brk_types::PartsPerMillionSigned32;
|
||||
use vecdb::{EagerVec, Exit, PcoVec, ReadableVec, VecIndex, VecValue};
|
||||
|
||||
pub trait ComputeDrawdown<I: VecIndex> {
|
||||
@@ -16,7 +16,7 @@ pub trait ComputeDrawdown<I: VecIndex> {
|
||||
f64: From<C> + From<A>;
|
||||
}
|
||||
|
||||
impl<I> ComputeDrawdown<I> for EagerVec<PcoVec<I, BasisPointsSigned16>>
|
||||
impl<I> ComputeDrawdown<I> for EagerVec<PcoVec<I, PartsPerMillionSigned32>>
|
||||
where
|
||||
I: VecIndex,
|
||||
{
|
||||
@@ -39,9 +39,9 @@ where
|
||||
|(i, current, ath, _)| {
|
||||
let ath_f64 = f64::from(ath);
|
||||
let drawdown = if ath_f64 == 0.0 {
|
||||
BasisPointsSigned16::default()
|
||||
PartsPerMillionSigned32::default()
|
||||
} else {
|
||||
BasisPointsSigned16::from((f64::from(current) - ath_f64) / ath_f64)
|
||||
PartsPerMillionSigned32::from((f64::from(current) - ath_f64) / ath_f64)
|
||||
};
|
||||
(i, drawdown)
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ use super::fenwick::FenwickTree;
|
||||
|
||||
/// Fast expanding percentile tracker using a Fenwick tree (Binary Indexed Tree).
|
||||
///
|
||||
/// Values are discretized to 10 BPS (0.1%) resolution and tracked in
|
||||
/// Values are discretized to 0.001 ratio resolution and tracked in
|
||||
/// a fixed-size frequency array with Fenwick prefix sums. This gives:
|
||||
/// - O(log N) insert (N = tree size, ~16 ops for 43k buckets)
|
||||
/// - O(log N) percentile query via prefix-sum walk
|
||||
@@ -15,11 +15,9 @@ pub(crate) struct ExpandingPercentiles {
|
||||
count: u32,
|
||||
}
|
||||
|
||||
/// Bucket granularity in BPS. 10 BPS = 0.1% = 0.001 ratio.
|
||||
const BUCKET_BPS: i32 = 10;
|
||||
/// Max ratio supported: 43.0 = 430,000 BPS.
|
||||
const MAX_BPS: i32 = 430_000;
|
||||
const TREE_SIZE: usize = (MAX_BPS / BUCKET_BPS) as usize + 1;
|
||||
const BUCKET_WIDTH: f64 = 0.001;
|
||||
const MAX_RATIO: f64 = 43.0;
|
||||
const TREE_SIZE: usize = (MAX_RATIO / BUCKET_WIDTH) as usize + 1;
|
||||
|
||||
impl Default for ExpandingPercentiles {
|
||||
fn default() -> Self {
|
||||
@@ -43,8 +41,9 @@ impl ExpandingPercentiles {
|
||||
/// Convert f32 ratio to 0-indexed bucket.
|
||||
#[inline]
|
||||
fn to_bucket(value: f32) -> usize {
|
||||
let bps = (value as f64 * 10000.0).round() as i32;
|
||||
(bps / BUCKET_BPS).clamp(0, TREE_SIZE as i32 - 1) as usize
|
||||
(value as f64 / BUCKET_WIDTH)
|
||||
.round()
|
||||
.clamp(0.0, (TREE_SIZE - 1) as f64) as usize
|
||||
}
|
||||
|
||||
/// Bulk-load values in O(n + N) instead of O(n log N).
|
||||
@@ -73,10 +72,10 @@ impl ExpandingPercentiles {
|
||||
|
||||
/// Compute 8 percentiles in one call via kth. O(8 × log N) but with
|
||||
/// shared tree traversal across all 8 targets for better cache locality.
|
||||
/// Quantiles q must be sorted ascending in (0, 1). Output is in BPS.
|
||||
pub fn quantiles(&self, qs: &[f64; 8], out: &mut [u32; 8]) {
|
||||
/// Quantiles q must be sorted ascending in (0, 1). Output values are ratios.
|
||||
pub fn quantiles(&self, qs: &[f64; 8], out: &mut [f64; 8]) {
|
||||
if self.count == 0 {
|
||||
out.iter_mut().for_each(|o| *o = 0);
|
||||
out.fill(0.0);
|
||||
return;
|
||||
}
|
||||
let mut targets = [0u32; 8];
|
||||
@@ -87,7 +86,7 @@ impl ExpandingPercentiles {
|
||||
let mut buckets = [0usize; 8];
|
||||
self.tree.kth(&targets, &|n: &u32| *n, &mut buckets);
|
||||
for (i, bucket) in buckets.iter().enumerate() {
|
||||
out[i] = *bucket as u32 * BUCKET_BPS as u32;
|
||||
out[i] = *bucket as f64 * BUCKET_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,8 +95,8 @@ impl ExpandingPercentiles {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn quantile(ep: &ExpandingPercentiles, q: f64) -> u32 {
|
||||
let mut out = [0u32; 8];
|
||||
fn quantile(ep: &ExpandingPercentiles, q: f64) -> f64 {
|
||||
let mut out = [0.0; 8];
|
||||
ep.quantiles(&[q, q, q, q, q, q, q, q], &mut out);
|
||||
out[0]
|
||||
}
|
||||
@@ -111,20 +110,20 @@ mod tests {
|
||||
assert_eq!(ep.count(), 1000);
|
||||
|
||||
let median = quantile(&ep, 0.5);
|
||||
assert!((median as i32 - 5000).abs() < 100, "median was {median}");
|
||||
assert!((median - 0.5).abs() < 0.01, "median was {median}");
|
||||
|
||||
let p99 = quantile(&ep, 0.99);
|
||||
assert!((p99 as i32 - 9900).abs() < 100, "p99 was {p99}");
|
||||
assert!((p99 - 0.99).abs() < 0.01, "p99 was {p99}");
|
||||
|
||||
let p01 = quantile(&ep, 0.01);
|
||||
assert!((p01 as i32 - 100).abs() < 100, "p01 was {p01}");
|
||||
assert!((p01 - 0.01).abs() < 0.01, "p01 was {p01}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let ep = ExpandingPercentiles::default();
|
||||
assert_eq!(ep.count(), 0);
|
||||
assert_eq!(quantile(&ep, 0.5), 0);
|
||||
assert_eq!(quantile(&ep, 0.5), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -132,7 +131,7 @@ mod tests {
|
||||
let mut ep = ExpandingPercentiles::default();
|
||||
ep.add(0.42);
|
||||
let v = quantile(&ep, 0.5);
|
||||
assert!((v as i32 - 4200).abs() <= BUCKET_BPS, "got {v}");
|
||||
assert!((v - 0.42).abs() <= BUCKET_WIDTH, "got {v}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -144,6 +143,6 @@ mod tests {
|
||||
assert_eq!(ep.count(), 100);
|
||||
ep.reset();
|
||||
assert_eq!(ep.count(), 0);
|
||||
assert_eq!(quantile(&ep, 0.5), 0);
|
||||
assert_eq!(quantile(&ep, 0.5), 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_traversable::Traversable;
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Percent<A, B = A, C = B> {
|
||||
pub bps: A,
|
||||
pub raw: A,
|
||||
pub ratio: B,
|
||||
pub percent: C,
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use vecdb::{Rw, StorageMode};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
BpsType, LazyRollingDeltasFromHeight, NumericValue, PerBlock, WindowStartVec, Windows,
|
||||
FixedRatio, LazyRollingDeltasFromHeight, NumericValue, PerBlock, WindowStartVec, Windows,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct PerBlockWithDeltas<S, C, B, M: StorageMode = Rw>
|
||||
where
|
||||
S: NumericValue + JsonSchema + Into<f64>,
|
||||
C: NumericValue + JsonSchema + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
@@ -29,7 +29,7 @@ impl<S, C, B> PerBlockWithDeltas<S, C, B>
|
||||
where
|
||||
S: NumericValue + JsonSchema + Into<f64>,
|
||||
C: NumericValue + JsonSchema + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
pub(crate) fn forced_import(
|
||||
db: &vecdb::Database,
|
||||
|
||||
@@ -6,7 +6,7 @@ use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BpsType, LazyRollingDeltasFiatFromHeight, WindowStartVec, Windows},
|
||||
internal::{FixedRatio, LazyRollingDeltasFiatFromHeight, WindowStartVec, Windows},
|
||||
};
|
||||
|
||||
use super::{FiatPerBlockCumulativeWithSums, FiatType};
|
||||
@@ -16,7 +16,7 @@ pub struct FiatPerBlockCumulativeWithSumsAndDeltas<C, CS, B, M: StorageMode = Rw
|
||||
where
|
||||
C: FiatType + Into<f64>,
|
||||
CS: FiatType + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
@@ -29,7 +29,7 @@ impl<C, CS, B> FiatPerBlockCumulativeWithSumsAndDeltas<C, CS, B>
|
||||
where
|
||||
C: FiatType + Into<f64>,
|
||||
CS: FiatType + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
|
||||
@@ -7,7 +7,7 @@ use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BpsType, LazyRollingDeltasFiatFromHeight, WindowStartVec, Windows},
|
||||
internal::{FixedRatio, LazyRollingDeltasFiatFromHeight, WindowStartVec, Windows},
|
||||
};
|
||||
|
||||
use super::{FiatPerBlock, FiatType};
|
||||
@@ -17,7 +17,7 @@ pub struct FiatPerBlockWithDeltas<C, CS, B, M: StorageMode = Rw>
|
||||
where
|
||||
C: FiatType + Into<f64>,
|
||||
CS: FiatType + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
@@ -30,7 +30,7 @@ impl<C, CS, B> FiatPerBlockWithDeltas<C, CS, B>
|
||||
where
|
||||
C: FiatType + JsonSchema + Into<f64>,
|
||||
CS: FiatType + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
|
||||
@@ -8,44 +8,39 @@ use vecdb::{
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BpsType, Percent, algo::ComputeDrawdown},
|
||||
internal::{FixedRatio, Percent, algo::ComputeDrawdown},
|
||||
};
|
||||
|
||||
use crate::internal::{LazyPerBlock, PerBlock};
|
||||
|
||||
/// Basis-point storage with both ratio and percentage float views.
|
||||
///
|
||||
/// Stores integer basis points on disk (Pco-compressed),
|
||||
/// exposes two lazy StoredF32 views:
|
||||
/// - `ratio`: bps / 10000 (e.g., 4523 bps -> 0.4523)
|
||||
/// - `percent`: bps / 100 (e.g., 4523 bps -> 45.23%)
|
||||
/// Fixed-point storage with lazy ratio and percentage float views.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct PercentPerBlock<B: BpsType, M: StorageMode = Rw>(
|
||||
pub struct PercentPerBlock<B: FixedRatio, M: StorageMode = Rw>(
|
||||
pub Percent<PerBlock<B, M>, LazyPerBlock<StoredF32, B>>,
|
||||
);
|
||||
|
||||
impl<B: BpsType> PercentPerBlock<B> {
|
||||
impl<B: FixedRatio> PercentPerBlock<B> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let bps = PerBlock::forced_import(db, &format!("{name}_bps"), version, indexes)?;
|
||||
let bps_clone = bps.height.read_only_boxed_clone();
|
||||
let raw = PerBlock::forced_import(db, &format!("{name}_{}", B::SUFFIX), version, indexes)?;
|
||||
let raw_clone = raw.height.read_only_boxed_clone();
|
||||
|
||||
let ratio = LazyPerBlock::from_computed::<B::ToRatio>(
|
||||
&format!("{name}_ratio"),
|
||||
version,
|
||||
bps_clone.clone(),
|
||||
&bps,
|
||||
raw_clone.clone(),
|
||||
&raw,
|
||||
);
|
||||
|
||||
let percent = LazyPerBlock::from_computed::<B::ToPercent>(name, version, bps_clone, &bps);
|
||||
let percent = LazyPerBlock::from_computed::<B::ToPercent>(name, version, raw_clone, &raw);
|
||||
|
||||
Ok(Self(Percent {
|
||||
bps,
|
||||
raw,
|
||||
ratio,
|
||||
percent,
|
||||
}))
|
||||
@@ -63,7 +58,7 @@ impl<B: BpsType> PercentPerBlock<B> {
|
||||
S2T: VecValue,
|
||||
F: BinaryTransform<S1T, S2T, B>,
|
||||
{
|
||||
self.bps
|
||||
self.raw
|
||||
.compute_binary::<S1T, S2T, F>(max_from, source1, source2, exit)
|
||||
}
|
||||
|
||||
@@ -80,7 +75,7 @@ impl<B: BpsType> PercentPerBlock<B> {
|
||||
f64: From<C> + From<A>,
|
||||
vecdb::EagerVec<vecdb::PcoVec<Height, B>>: ComputeDrawdown<Height>,
|
||||
{
|
||||
self.bps
|
||||
self.raw
|
||||
.height
|
||||
.compute_drawdown(max_from, current, ath, exit)
|
||||
}
|
||||
|
||||
@@ -5,25 +5,25 @@
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Height, StoredU64, Version};
|
||||
use brk_types::{Height, PartsPerMillion32, StoredU64, Version};
|
||||
use vecdb::{BinaryTransform, Database, Exit, ReadableVec, Rw, StorageMode, VecValue};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
BpsType, PerBlockCumulativeRolling, PercentPerBlock, PercentRollingWindows, RatioU64Bp16,
|
||||
FixedRatio, PerBlockCumulativeRolling, PercentPerBlock, PercentRollingWindows, RatioU64,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct PercentCumulativeRolling<B: BpsType, M: StorageMode = Rw> {
|
||||
pub struct PercentCumulativeRolling<B: FixedRatio, M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub cumulative: PercentPerBlock<B, M>,
|
||||
#[traversable(flatten)]
|
||||
pub rolling: PercentRollingWindows<B, M>,
|
||||
}
|
||||
|
||||
impl<B: BpsType> PercentCumulativeRolling<B> {
|
||||
impl<B: FixedRatio> PercentCumulativeRolling<B> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
@@ -73,7 +73,7 @@ impl<B: BpsType> PercentCumulativeRolling<B> {
|
||||
}
|
||||
}
|
||||
|
||||
impl PercentCumulativeRolling<BasisPoints16> {
|
||||
impl PercentCumulativeRolling<PartsPerMillion32> {
|
||||
/// Derive a percent from two `PerBlockCumulativeRolling<StoredU64>`
|
||||
/// sources (numerator and denominator). Both sources must already have
|
||||
/// their cumulative and rolling sums computed.
|
||||
@@ -85,7 +85,15 @@ impl PercentCumulativeRolling<BasisPoints16> {
|
||||
starting_height: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.compute_binary::<StoredU64, StoredU64, RatioU64Bp16, _, _, _, _>(
|
||||
self.compute_binary::<
|
||||
StoredU64,
|
||||
StoredU64,
|
||||
RatioU64<PartsPerMillion32>,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
>(
|
||||
starting_height,
|
||||
&numerator.cumulative.height,
|
||||
&denominator.cumulative.height,
|
||||
|
||||
@@ -3,39 +3,39 @@ use brk_types::{StoredF32, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{ReadableCloneableVec, UnaryTransform};
|
||||
|
||||
use crate::internal::{BpsType, LazyPerBlock, Percent, PercentPerBlock};
|
||||
use crate::internal::{FixedRatio, LazyPerBlock, Percent, PercentPerBlock};
|
||||
|
||||
/// Fully lazy variant of `PercentPerBlock` — no stored vecs.
|
||||
///
|
||||
/// BPS values are lazily derived from a source `PercentPerBlock` via a unary transform,
|
||||
/// and ratio/percent float views are chained from the lazy BPS.
|
||||
/// Raw values are lazily derived from a source `PercentPerBlock` via a unary transform,
|
||||
/// and ratio/percent float views are chained from them.
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct LazyPercentPerBlock<B: BpsType>(
|
||||
pub struct LazyPercentPerBlock<B: FixedRatio>(
|
||||
pub Percent<LazyPerBlock<B, B>, LazyPerBlock<StoredF32, B>>,
|
||||
);
|
||||
|
||||
impl<B: BpsType> LazyPercentPerBlock<B> {
|
||||
/// Create from a stored `PercentPerBlock` source via a BPS-to-BPS unary transform.
|
||||
impl<B: FixedRatio> LazyPercentPerBlock<B> {
|
||||
/// Create from a stored `PercentPerBlock` source via a same-unit unary transform.
|
||||
pub(crate) fn from_percent<F: UnaryTransform<B, B>>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
source: &PercentPerBlock<B>,
|
||||
) -> Self {
|
||||
let bps = LazyPerBlock::from_computed::<F>(
|
||||
&format!("{name}_bps"),
|
||||
let raw = LazyPerBlock::from_computed::<F>(
|
||||
&format!("{name}_{}", B::SUFFIX),
|
||||
version,
|
||||
source.bps.height.read_only_boxed_clone(),
|
||||
&source.bps,
|
||||
source.raw.height.read_only_boxed_clone(),
|
||||
&source.raw,
|
||||
);
|
||||
|
||||
let ratio =
|
||||
LazyPerBlock::from_lazy::<B::ToRatio, B>(&format!("{name}_ratio"), version, &bps);
|
||||
LazyPerBlock::from_lazy::<B::ToRatio, B>(&format!("{name}_ratio"), version, &raw);
|
||||
|
||||
let percent = LazyPerBlock::from_lazy::<B::ToPercent, B>(name, version, &bps);
|
||||
let percent = LazyPerBlock::from_lazy::<B::ToPercent, B>(name, version, &raw);
|
||||
|
||||
Self(Percent {
|
||||
bps,
|
||||
raw,
|
||||
ratio,
|
||||
percent,
|
||||
})
|
||||
|
||||
@@ -3,25 +3,25 @@ use brk_types::Version;
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
use crate::internal::{
|
||||
BpsType, LazyPercentPerBlock, LazyPercentRollingWindows, PercentCumulativeRolling,
|
||||
FixedRatio, LazyPercentPerBlock, LazyPercentRollingWindows, PercentCumulativeRolling,
|
||||
};
|
||||
|
||||
/// Fully lazy variant of `PercentCumulativeRolling` — no stored vecs.
|
||||
///
|
||||
/// Mirrors the flat shape of `PercentCumulativeRolling`: cumulative and
|
||||
/// rolling window fields are both flattened to the same tree level, so
|
||||
/// consumers see `{ bps, percent, ratio, _24h, _1w, _1m, _1y }`.
|
||||
/// consumers see `{ raw, percent, ratio, _24h, _1w, _1m, _1y }`.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyPercentCumulativeRolling<B: BpsType> {
|
||||
pub struct LazyPercentCumulativeRolling<B: FixedRatio> {
|
||||
#[traversable(flatten)]
|
||||
pub cumulative: LazyPercentPerBlock<B>,
|
||||
#[traversable(flatten)]
|
||||
pub rolling: LazyPercentRollingWindows<B>,
|
||||
}
|
||||
|
||||
impl<B: BpsType> LazyPercentCumulativeRolling<B> {
|
||||
impl<B: FixedRatio> LazyPercentCumulativeRolling<B> {
|
||||
/// Derive from a stored `PercentCumulativeRolling` source via a
|
||||
/// BPS-to-BPS unary transform applied to both cumulative and rolling.
|
||||
/// same-unit unary transform applied to both cumulative and rolling.
|
||||
pub(crate) fn from_source<F: UnaryTransform<B, B>>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
|
||||
@@ -3,20 +3,20 @@ use brk_types::Version;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
use crate::internal::{BpsType, PercentRollingWindows, Windows};
|
||||
use crate::internal::{FixedRatio, PercentRollingWindows, Windows};
|
||||
|
||||
use super::LazyPercentPerBlock;
|
||||
|
||||
/// Fully lazy rolling percent windows — 4 windows (24h, 1w, 1m, 1y),
|
||||
/// each with lazy BPS + lazy ratio/percent float views.
|
||||
/// each with lazy raw + lazy ratio/percent float views.
|
||||
///
|
||||
/// No stored vecs. All values derived from a source `PercentRollingWindows`.
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct LazyPercentRollingWindows<B: BpsType>(pub Windows<LazyPercentPerBlock<B>>);
|
||||
pub struct LazyPercentRollingWindows<B: FixedRatio>(pub Windows<LazyPercentPerBlock<B>>);
|
||||
|
||||
impl<B: BpsType> LazyPercentRollingWindows<B> {
|
||||
/// Create from a stored `PercentRollingWindows` source via a BPS-to-BPS unary transform.
|
||||
impl<B: FixedRatio> LazyPercentRollingWindows<B> {
|
||||
/// Create from a stored source via a same-unit unary transform.
|
||||
pub(crate) fn from_rolling<F: UnaryTransform<B, B>>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
|
||||
@@ -5,37 +5,37 @@ use vecdb::{
|
||||
Database, EagerVec, ImportableVec, LazyVecFrom1, PcoVec, ReadableCloneableVec, Rw, StorageMode,
|
||||
};
|
||||
|
||||
use crate::internal::{BpsType, Percent};
|
||||
use crate::internal::{FixedRatio, Percent};
|
||||
|
||||
/// Lightweight percent container: BPS height vec + lazy ratio + lazy percent.
|
||||
/// Lightweight percent container: fixed-point height vec + lazy ratio + lazy percent.
|
||||
/// No resolutions, no rolling stats.
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct PercentVec<B: BpsType, M: StorageMode = Rw>(
|
||||
pub struct PercentVec<B: FixedRatio, M: StorageMode = Rw>(
|
||||
pub Percent<M::Stored<EagerVec<PcoVec<Height, B>>>, LazyVecFrom1<Height, StoredF32, Height, B>>,
|
||||
);
|
||||
|
||||
impl<B: BpsType> PercentVec<B> {
|
||||
impl<B: FixedRatio> PercentVec<B> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
) -> brk_error::Result<Self> {
|
||||
let bps: EagerVec<PcoVec<Height, B>> =
|
||||
EagerVec::forced_import(db, &format!("{name}_bps"), version)?;
|
||||
let bps_clone = bps.read_only_boxed_clone();
|
||||
let raw: EagerVec<PcoVec<Height, B>> =
|
||||
EagerVec::forced_import(db, &format!("{name}_{}", B::SUFFIX), version)?;
|
||||
let raw_clone = raw.read_only_boxed_clone();
|
||||
|
||||
let ratio = LazyVecFrom1::transformed::<B::ToRatio>(
|
||||
&format!("{name}_ratio"),
|
||||
version,
|
||||
bps_clone.clone(),
|
||||
raw_clone.clone(),
|
||||
);
|
||||
|
||||
let percent = LazyVecFrom1::transformed::<B::ToPercent>(name, version, bps_clone);
|
||||
let percent = LazyVecFrom1::transformed::<B::ToPercent>(name, version, raw_clone);
|
||||
|
||||
Ok(Self(Percent {
|
||||
bps,
|
||||
raw,
|
||||
ratio,
|
||||
percent,
|
||||
}))
|
||||
|
||||
@@ -6,18 +6,18 @@ use vecdb::{BinaryTransform, Database, Exit, ReadableVec, Rw, StorageMode, VecVa
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BpsType, PercentPerBlock, Windows},
|
||||
internal::{FixedRatio, PercentPerBlock, Windows},
|
||||
};
|
||||
|
||||
/// 4 rolling window vecs (24h, 1w, 1m, 1y), each storing basis points
|
||||
/// 4 rolling window vecs (24h, 1w, 1m, 1y), each storing fixed-point values
|
||||
/// with lazy ratio and percent float views.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct PercentRollingWindows<B: BpsType, M: StorageMode = Rw>(
|
||||
pub struct PercentRollingWindows<B: FixedRatio, M: StorageMode = Rw>(
|
||||
pub Windows<PercentPerBlock<B, M>>,
|
||||
);
|
||||
|
||||
impl<B: BpsType> PercentRollingWindows<B> {
|
||||
impl<B: FixedRatio> PercentRollingWindows<B> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints32, Cents, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, StoredF32, Version};
|
||||
use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BpsType, LazyPerBlock, PerBlock},
|
||||
internal::{FixedRatio, LazyPerBlock, PerBlock},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RatioPerBlock<B: BpsType = BasisPoints32, M: StorageMode = Rw> {
|
||||
pub bps: PerBlock<B, M>,
|
||||
pub ratio: LazyPerBlock<StoredF32, B>,
|
||||
pub struct RatioPerBlock<R: FixedRatio, M: StorageMode = Rw> {
|
||||
pub raw: PerBlock<R, M>,
|
||||
pub ratio: LazyPerBlock<StoredF32, R>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::TWO;
|
||||
const VERSION: Version = Version::new(3);
|
||||
|
||||
impl<B: BpsType> RatioPerBlock<B> {
|
||||
impl<R: FixedRatio> RatioPerBlock<R> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
@@ -35,20 +35,18 @@ impl<B: BpsType> RatioPerBlock<B> {
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
|
||||
let bps = PerBlock::forced_import(db, &format!("{name}_bps"), v, indexes)?;
|
||||
let raw = PerBlock::forced_import(db, &format!("{name}_{}", R::SUFFIX), v, indexes)?;
|
||||
|
||||
let ratio = LazyPerBlock::from_computed::<B::ToRatio>(
|
||||
let ratio = LazyPerBlock::from_computed::<R::ToRatio>(
|
||||
name,
|
||||
v,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
&bps,
|
||||
raw.height.read_only_boxed_clone(),
|
||||
&raw,
|
||||
);
|
||||
|
||||
Ok(Self { bps, ratio })
|
||||
Ok(Self { raw, ratio })
|
||||
}
|
||||
}
|
||||
|
||||
impl RatioPerBlock<BasisPoints32> {
|
||||
pub(crate) fn compute_ratio(
|
||||
&mut self,
|
||||
starting_lengths: &Lengths,
|
||||
@@ -56,15 +54,15 @@ impl RatioPerBlock<BasisPoints32> {
|
||||
series_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.bps.height.compute_transform2(
|
||||
self.raw.height.compute_transform2(
|
||||
starting_lengths.height,
|
||||
close_price,
|
||||
series_price,
|
||||
|(i, close, price, ..)| {
|
||||
if price == Cents::ZERO {
|
||||
(i, BasisPoints32::from(1.0))
|
||||
(i, R::from(1.0))
|
||||
} else {
|
||||
(i, BasisPoints32::from(f64::from(close) / f64::from(price)))
|
||||
(i, R::from(f64::from(close) / f64::from(price)))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints32, Cents, Height, StoredF32, Version};
|
||||
use brk_types::{Cents, Height, PartsPerMillion32, StoredF32, Version};
|
||||
use vecdb::{
|
||||
AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, VecIndex,
|
||||
WritableVec,
|
||||
@@ -9,7 +9,7 @@ use vecdb::{
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{Price, PriceTimesRatioBp32Cents, algo::ExpandingPercentiles},
|
||||
internal::{Price, PriceTimesRatio, algo::ExpandingPercentiles},
|
||||
};
|
||||
|
||||
use super::{super::PerBlock, RatioPerBlock};
|
||||
@@ -17,7 +17,7 @@ use super::{super::PerBlock, RatioPerBlock};
|
||||
#[derive(Traversable)]
|
||||
pub struct RatioBand<M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub ratio: RatioPerBlock<BasisPoints32, M>,
|
||||
pub ratio: RatioPerBlock<PartsPerMillion32, M>,
|
||||
pub price: Price<PerBlock<Cents, M>>,
|
||||
}
|
||||
|
||||
@@ -119,18 +119,18 @@ impl RatioPerBlockPercentiles {
|
||||
}
|
||||
|
||||
let new_ratios = ratio_source.collect_range_at(start, ratio_len);
|
||||
let mut pct_vecs: [&mut EagerVec<PcoVec<Height, BasisPoints32>>; 8] = [
|
||||
&mut self.pct0_5.ratio.bps.height,
|
||||
&mut self.pct1.ratio.bps.height,
|
||||
&mut self.pct2.ratio.bps.height,
|
||||
&mut self.pct5.ratio.bps.height,
|
||||
&mut self.pct95.ratio.bps.height,
|
||||
&mut self.pct98.ratio.bps.height,
|
||||
&mut self.pct99.ratio.bps.height,
|
||||
&mut self.pct99_5.ratio.bps.height,
|
||||
let mut pct_vecs: [&mut EagerVec<PcoVec<Height, PartsPerMillion32>>; 8] = [
|
||||
&mut self.pct0_5.ratio.raw.height,
|
||||
&mut self.pct1.ratio.raw.height,
|
||||
&mut self.pct2.ratio.raw.height,
|
||||
&mut self.pct5.ratio.raw.height,
|
||||
&mut self.pct95.ratio.raw.height,
|
||||
&mut self.pct98.ratio.raw.height,
|
||||
&mut self.pct99.ratio.raw.height,
|
||||
&mut self.pct99_5.ratio.raw.height,
|
||||
];
|
||||
const PCTS: [f64; 8] = [0.005, 0.01, 0.02, 0.05, 0.95, 0.98, 0.99, 0.995];
|
||||
let mut out = [0u32; 8];
|
||||
let mut out = [0.0; 8];
|
||||
|
||||
for vec in pct_vecs.iter_mut() {
|
||||
vec.truncate_if_needed_at(start)?;
|
||||
@@ -142,7 +142,7 @@ impl RatioPerBlockPercentiles {
|
||||
}
|
||||
self.expanding_pct.quantiles(&PCTS, &mut out);
|
||||
for (vec, &val) in pct_vecs.iter_mut().zip(out.iter()) {
|
||||
vec.push(BasisPoints32::from(val));
|
||||
vec.push(PartsPerMillion32::from(val));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,10 +159,14 @@ impl RatioPerBlockPercentiles {
|
||||
self.$band
|
||||
.price
|
||||
.cents
|
||||
.compute_binary::<Cents, BasisPoints32, PriceTimesRatioBp32Cents>(
|
||||
.compute_binary::<
|
||||
Cents,
|
||||
PartsPerMillion32,
|
||||
PriceTimesRatio<PartsPerMillion32>,
|
||||
>(
|
||||
starting_lengths.height,
|
||||
series_price,
|
||||
&self.$band.ratio.bps.height,
|
||||
&self.$band.ratio.raw.height,
|
||||
exit,
|
||||
)?;
|
||||
};
|
||||
@@ -182,16 +186,16 @@ impl RatioPerBlockPercentiles {
|
||||
|
||||
fn mut_pct_vecs(
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = &mut EagerVec<PcoVec<Height, BasisPoints32>>> {
|
||||
) -> impl Iterator<Item = &mut EagerVec<PcoVec<Height, PartsPerMillion32>>> {
|
||||
[
|
||||
&mut self.pct0_5.ratio.bps.height,
|
||||
&mut self.pct1.ratio.bps.height,
|
||||
&mut self.pct2.ratio.bps.height,
|
||||
&mut self.pct5.ratio.bps.height,
|
||||
&mut self.pct95.ratio.bps.height,
|
||||
&mut self.pct98.ratio.bps.height,
|
||||
&mut self.pct99.ratio.bps.height,
|
||||
&mut self.pct99_5.ratio.bps.height,
|
||||
&mut self.pct0_5.ratio.raw.height,
|
||||
&mut self.pct1.ratio.raw.height,
|
||||
&mut self.pct2.ratio.raw.height,
|
||||
&mut self.pct5.ratio.raw.height,
|
||||
&mut self.pct95.ratio.raw.height,
|
||||
&mut self.pct98.ratio.raw.height,
|
||||
&mut self.pct99.ratio.raw.height,
|
||||
&mut self.pct99_5.ratio.raw.height,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints32, Cents, Dollars, Height, SatsFract, StoredF32, Version};
|
||||
use brk_types::{Cents, Dollars, Height, PartsPerMillion64, SatsFract, StoredF32, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode};
|
||||
|
||||
@@ -15,8 +15,8 @@ pub struct PriceWithRatioPerBlock<M: StorageMode = Rw> {
|
||||
pub usd: LazyPerBlock<Dollars, Cents>,
|
||||
pub cents: PerBlock<Cents, M>,
|
||||
pub sats: LazyPerBlock<SatsFract, Dollars>,
|
||||
pub bps: PerBlock<BasisPoints32, M>,
|
||||
pub ratio: LazyPerBlock<StoredF32, BasisPoints32>,
|
||||
pub raw: PerBlock<PartsPerMillion64, M>,
|
||||
pub ratio: LazyPerBlock<StoredF32, PartsPerMillion64>,
|
||||
}
|
||||
|
||||
impl PriceWithRatioPerBlock {
|
||||
@@ -32,7 +32,7 @@ impl PriceWithRatioPerBlock {
|
||||
usd: price.usd,
|
||||
cents: price.cents,
|
||||
sats: price.sats,
|
||||
bps: ratio.bps,
|
||||
raw: ratio.raw,
|
||||
ratio: ratio.ratio,
|
||||
})
|
||||
}
|
||||
@@ -44,15 +44,18 @@ impl PriceWithRatioPerBlock {
|
||||
close_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.bps.height.compute_transform2(
|
||||
self.raw.height.compute_transform2(
|
||||
starting_lengths.height,
|
||||
close_price,
|
||||
&self.cents.height,
|
||||
|(i, close, price, ..)| {
|
||||
if price == Cents::ZERO {
|
||||
(i, BasisPoints32::from(1.0))
|
||||
(i, PartsPerMillion64::from(1.0))
|
||||
} else {
|
||||
(i, BasisPoints32::from(f64::from(close) / f64::from(price)))
|
||||
(
|
||||
i,
|
||||
PartsPerMillion64::from(f64::from(close) / f64::from(price)),
|
||||
)
|
||||
}
|
||||
},
|
||||
exit,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Lengths;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints32, Height, StoredF32, Version};
|
||||
use brk_types::{Height, PartsPerMillion32, StoredF32, Version};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{blocks, indexes};
|
||||
@@ -10,12 +10,12 @@ use super::RatioPerBlock;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RatioSma<M: StorageMode = Rw> {
|
||||
pub all: RatioPerBlock<BasisPoints32, M>,
|
||||
pub _1w: RatioPerBlock<BasisPoints32, M>,
|
||||
pub _1m: RatioPerBlock<BasisPoints32, M>,
|
||||
pub _1y: RatioPerBlock<BasisPoints32, M>,
|
||||
pub _2y: RatioPerBlock<BasisPoints32, M>,
|
||||
pub _4y: RatioPerBlock<BasisPoints32, M>,
|
||||
pub all: RatioPerBlock<PartsPerMillion32, M>,
|
||||
pub _1w: RatioPerBlock<PartsPerMillion32, M>,
|
||||
pub _1m: RatioPerBlock<PartsPerMillion32, M>,
|
||||
pub _1y: RatioPerBlock<PartsPerMillion32, M>,
|
||||
pub _2y: RatioPerBlock<PartsPerMillion32, M>,
|
||||
pub _4y: RatioPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::new(4);
|
||||
@@ -58,7 +58,7 @@ impl RatioSma {
|
||||
ratio_source: &impl ReadableVec<Height, StoredF32>,
|
||||
) -> Result<()> {
|
||||
// Expanding SMA (all history)
|
||||
self.all.bps.height.compute_sma_(
|
||||
self.all.raw.height.compute_sma_(
|
||||
starting_lengths.height,
|
||||
ratio_source,
|
||||
usize::MAX,
|
||||
@@ -74,7 +74,7 @@ impl RatioSma {
|
||||
(&mut self._2y, &blocks.lookback._2y),
|
||||
(&mut self._4y, &blocks.lookback._4y),
|
||||
] {
|
||||
sma.bps.height.compute_rolling_average(
|
||||
sma.raw.height.compute_rolling_average(
|
||||
starting_lengths.height,
|
||||
lookback,
|
||||
ratio_source,
|
||||
|
||||
@@ -6,16 +6,17 @@ use vecdb::{BinaryTransform, Database, Exit, ReadableVec, Rw, StorageMode, VecVa
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BpsType, RatioPerBlock, Windows},
|
||||
internal::{FixedRatio, RatioPerBlock, Windows},
|
||||
};
|
||||
|
||||
/// 4 rolling window vecs (24h, 1w, 1m, 1y), each storing basis points
|
||||
/// with a lazy ratio float view.
|
||||
/// Four rolling-window ratios with fixed-point storage and lazy float views.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct RatioRollingWindows<B: BpsType, M: StorageMode = Rw>(pub Windows<RatioPerBlock<B, M>>);
|
||||
pub struct RatioRollingWindows<B: FixedRatio, M: StorageMode = Rw>(
|
||||
pub Windows<RatioPerBlock<B, M>>,
|
||||
);
|
||||
|
||||
impl<B: BpsType> RatioRollingWindows<B> {
|
||||
impl<B: FixedRatio> RatioRollingWindows<B> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
@@ -49,7 +50,7 @@ impl<B: BpsType> RatioRollingWindows<B> {
|
||||
.zip(sources2)
|
||||
{
|
||||
target
|
||||
.bps
|
||||
.raw
|
||||
.compute_binary::<S1T, S2T, F>(max_from, s1, s2, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -10,7 +10,7 @@ use vecdb::{
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
AmountType, BpsType, DerivedResolutions, FiatType, LazyPerBlock, NumericValue, Percent,
|
||||
AmountType, DerivedResolutions, FiatType, FixedRatio, LazyPerBlock, NumericValue, Percent,
|
||||
Resolutions, WindowStartVec, Windows,
|
||||
},
|
||||
};
|
||||
@@ -19,7 +19,7 @@ use crate::{
|
||||
///
|
||||
/// Used as building block for both change and rate deltas.
|
||||
/// - Change: `LazyDeltaFromHeight<S, C, DeltaChange>`
|
||||
/// - Rate BPS: `LazyDeltaFromHeight<S, B, DeltaRate>`
|
||||
/// - Rate: `LazyDeltaFromHeight<S, B, DeltaRate>`
|
||||
#[derive(Clone, Traversable)]
|
||||
#[traversable(merge)]
|
||||
pub struct LazyDeltaFromHeight<S, T, Op: 'static>
|
||||
@@ -32,9 +32,9 @@ where
|
||||
pub resolutions: Box<Resolutions<T>>,
|
||||
}
|
||||
|
||||
/// Single-slot lazy delta percent: BPS delta + lazy ratio + lazy percent views.
|
||||
/// Single-slot lazy delta percent: fixed-point delta + lazy ratio + lazy percent views.
|
||||
///
|
||||
/// Mirrors `PercentPerBlock<B>` but with lazy delta for the BPS source.
|
||||
/// Mirrors `PercentPerBlock<B>` but with a lazy delta source.
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct LazyDeltaPercentFromHeight<S, B>(
|
||||
@@ -42,7 +42,7 @@ pub struct LazyDeltaPercentFromHeight<S, B>(
|
||||
)
|
||||
where
|
||||
S: VecValue,
|
||||
B: BpsType;
|
||||
B: FixedRatio;
|
||||
|
||||
/// Lazy rolling deltas for all 4 window durations (24h, 1w, 1m, 1y).
|
||||
///
|
||||
@@ -55,7 +55,7 @@ pub struct LazyRollingDeltasFromHeight<S, C, B>
|
||||
where
|
||||
S: VecValue,
|
||||
C: NumericValue + JsonSchema,
|
||||
B: BpsType,
|
||||
B: FixedRatio,
|
||||
{
|
||||
pub absolute: Windows<LazyDeltaFromHeight<S, C, DeltaChange>>,
|
||||
pub rate: Windows<LazyDeltaPercentFromHeight<S, B>>,
|
||||
@@ -65,7 +65,7 @@ impl<S, C, B> LazyRollingDeltasFromHeight<S, C, B>
|
||||
where
|
||||
S: VecValue + Into<f64>,
|
||||
C: NumericValue + JsonSchema + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
pub fn new(
|
||||
name: &str,
|
||||
@@ -99,54 +99,52 @@ where
|
||||
resolutions: Box::new(change_resolutions),
|
||||
};
|
||||
|
||||
// Rate BPS: (source[h] - source[ago]) / source[ago] as B (via f64)
|
||||
let rate_bps_name = format!("{full_name}_rate_bps");
|
||||
// Rate: (source[h] - source[ago]) / source[ago] as B (via f64)
|
||||
let rate_raw_name = format!("{full_name}_rate_{}", B::SUFFIX);
|
||||
let rate_vec = LazyDeltaVec::<Height, S, B, DeltaRate>::new(
|
||||
&rate_bps_name,
|
||||
&rate_raw_name,
|
||||
version,
|
||||
src.clone(),
|
||||
starts_version,
|
||||
move || cached.cached(),
|
||||
);
|
||||
let rate_resolutions =
|
||||
Resolutions::forced_import(&rate_bps_name, rate_vec.clone(), version, indexes);
|
||||
let bps = LazyDeltaFromHeight {
|
||||
Resolutions::forced_import(&rate_raw_name, rate_vec.clone(), version, indexes);
|
||||
let raw = LazyDeltaFromHeight {
|
||||
height: rate_vec,
|
||||
resolutions: Box::new(rate_resolutions),
|
||||
};
|
||||
|
||||
// Ratio: bps / 10000
|
||||
let rate_ratio_name = format!("{full_name}_rate_ratio");
|
||||
let ratio = LazyPerBlock {
|
||||
height: LazyVecFrom1::transformed::<B::ToRatio>(
|
||||
&rate_ratio_name,
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
raw.height.read_only_boxed_clone(),
|
||||
),
|
||||
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToRatio>(
|
||||
&rate_ratio_name,
|
||||
version,
|
||||
&bps.resolutions,
|
||||
&raw.resolutions,
|
||||
)),
|
||||
};
|
||||
|
||||
// Percent: bps / 100
|
||||
let rate_name = format!("{full_name}_rate");
|
||||
let percent = LazyPerBlock {
|
||||
height: LazyVecFrom1::transformed::<B::ToPercent>(
|
||||
&rate_name,
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
raw.height.read_only_boxed_clone(),
|
||||
),
|
||||
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToPercent>(
|
||||
&rate_name,
|
||||
version,
|
||||
&bps.resolutions,
|
||||
&raw.resolutions,
|
||||
)),
|
||||
};
|
||||
|
||||
let rate = LazyDeltaPercentFromHeight(Percent {
|
||||
bps,
|
||||
raw,
|
||||
ratio,
|
||||
percent,
|
||||
});
|
||||
@@ -186,7 +184,7 @@ pub struct LazyRollingDeltasAmountFromHeight<S, C, B>
|
||||
where
|
||||
S: VecValue,
|
||||
C: AmountType,
|
||||
B: BpsType,
|
||||
B: FixedRatio,
|
||||
{
|
||||
pub absolute: Windows<LazyDeltaAmountFromHeight<S, C>>,
|
||||
pub rate: Windows<LazyDeltaPercentFromHeight<S, B>>,
|
||||
@@ -196,7 +194,7 @@ impl<S, C, B> LazyRollingDeltasAmountFromHeight<S, C, B>
|
||||
where
|
||||
S: VecValue + Into<f64>,
|
||||
C: AmountType + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
pub fn new(
|
||||
name: &str,
|
||||
@@ -247,18 +245,18 @@ where
|
||||
|
||||
let absolute = LazyDeltaAmountFromHeight { btc, sats };
|
||||
|
||||
// Rate BPS: (source[h] - source[ago]) / source[ago] as B (via f64)
|
||||
let rate_bps_name = format!("{full_name}_rate_bps");
|
||||
// Rate: (source[h] - source[ago]) / source[ago] as B (via f64)
|
||||
let rate_raw_name = format!("{full_name}_rate_{}", B::SUFFIX);
|
||||
let rate_vec = LazyDeltaVec::<Height, S, B, DeltaRate>::new(
|
||||
&rate_bps_name,
|
||||
&rate_raw_name,
|
||||
version,
|
||||
src.clone(),
|
||||
starts_version,
|
||||
move || cached.cached(),
|
||||
);
|
||||
let rate_resolutions =
|
||||
Resolutions::forced_import(&rate_bps_name, rate_vec.clone(), version, indexes);
|
||||
let bps = LazyDeltaFromHeight {
|
||||
Resolutions::forced_import(&rate_raw_name, rate_vec.clone(), version, indexes);
|
||||
let raw = LazyDeltaFromHeight {
|
||||
height: rate_vec,
|
||||
resolutions: Box::new(rate_resolutions),
|
||||
};
|
||||
@@ -268,12 +266,12 @@ where
|
||||
height: LazyVecFrom1::transformed::<B::ToRatio>(
|
||||
&rate_ratio_name,
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
raw.height.read_only_boxed_clone(),
|
||||
),
|
||||
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToRatio>(
|
||||
&rate_ratio_name,
|
||||
version,
|
||||
&bps.resolutions,
|
||||
&raw.resolutions,
|
||||
)),
|
||||
};
|
||||
|
||||
@@ -282,17 +280,17 @@ where
|
||||
height: LazyVecFrom1::transformed::<B::ToPercent>(
|
||||
&rate_name,
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
raw.height.read_only_boxed_clone(),
|
||||
),
|
||||
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToPercent>(
|
||||
&rate_name,
|
||||
version,
|
||||
&bps.resolutions,
|
||||
&raw.resolutions,
|
||||
)),
|
||||
};
|
||||
|
||||
let rate = LazyDeltaPercentFromHeight(Percent {
|
||||
bps,
|
||||
raw,
|
||||
ratio,
|
||||
percent,
|
||||
});
|
||||
@@ -331,7 +329,7 @@ pub struct LazyRollingDeltasFiatFromHeight<S, C, B>
|
||||
where
|
||||
S: VecValue,
|
||||
C: FiatType,
|
||||
B: BpsType,
|
||||
B: FixedRatio,
|
||||
{
|
||||
pub absolute: Windows<LazyDeltaFiatFromHeight<S, C>>,
|
||||
pub rate: Windows<LazyDeltaPercentFromHeight<S, B>>,
|
||||
@@ -341,7 +339,7 @@ impl<S, C, B> LazyRollingDeltasFiatFromHeight<S, C, B>
|
||||
where
|
||||
S: VecValue + Into<f64>,
|
||||
C: FiatType + From<f64>,
|
||||
B: BpsType + From<f64>,
|
||||
B: FixedRatio + From<f64>,
|
||||
{
|
||||
pub fn new(
|
||||
name: &str,
|
||||
@@ -392,18 +390,18 @@ where
|
||||
|
||||
let absolute = LazyDeltaFiatFromHeight { usd, cents };
|
||||
|
||||
// Rate BPS: (source[h] - source[ago]) / source[ago] as B (via f64)
|
||||
let rate_bps_name = format!("{full_name}_rate_bps");
|
||||
// Rate: (source[h] - source[ago]) / source[ago] as B (via f64)
|
||||
let rate_raw_name = format!("{full_name}_rate_{}", B::SUFFIX);
|
||||
let rate_vec = LazyDeltaVec::<Height, S, B, DeltaRate>::new(
|
||||
&rate_bps_name,
|
||||
&rate_raw_name,
|
||||
version,
|
||||
src.clone(),
|
||||
starts_version,
|
||||
move || cached.cached(),
|
||||
);
|
||||
let rate_resolutions =
|
||||
Resolutions::forced_import(&rate_bps_name, rate_vec.clone(), version, indexes);
|
||||
let bps = LazyDeltaFromHeight {
|
||||
Resolutions::forced_import(&rate_raw_name, rate_vec.clone(), version, indexes);
|
||||
let raw = LazyDeltaFromHeight {
|
||||
height: rate_vec,
|
||||
resolutions: Box::new(rate_resolutions),
|
||||
};
|
||||
@@ -413,12 +411,12 @@ where
|
||||
height: LazyVecFrom1::transformed::<B::ToRatio>(
|
||||
&rate_ratio_name,
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
raw.height.read_only_boxed_clone(),
|
||||
),
|
||||
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToRatio>(
|
||||
&rate_ratio_name,
|
||||
version,
|
||||
&bps.resolutions,
|
||||
&raw.resolutions,
|
||||
)),
|
||||
};
|
||||
|
||||
@@ -427,17 +425,17 @@ where
|
||||
height: LazyVecFrom1::transformed::<B::ToPercent>(
|
||||
&rate_name,
|
||||
version,
|
||||
bps.height.read_only_boxed_clone(),
|
||||
raw.height.read_only_boxed_clone(),
|
||||
),
|
||||
resolutions: Box::new(DerivedResolutions::from_derived_computed::<B::ToPercent>(
|
||||
&rate_name,
|
||||
version,
|
||||
&bps.resolutions,
|
||||
&raw.resolutions,
|
||||
)),
|
||||
};
|
||||
|
||||
let rate = LazyDeltaPercentFromHeight(Percent {
|
||||
bps,
|
||||
raw,
|
||||
ratio,
|
||||
percent,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Sats, SatsSigned, Version};
|
||||
use brk_types::{PartsPerMillionSigned64, Sats, SatsSigned, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct ValuePerBlockWithDeltas<M: StorageMode = Rw> {
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
pub inner: ValuePerBlock<M>,
|
||||
pub delta: LazyRollingDeltasAmountFromHeight<Sats, SatsSigned, BasisPointsSigned32>,
|
||||
pub delta: LazyRollingDeltasAmountFromHeight<Sats, SatsSigned, PartsPerMillionSigned64>,
|
||||
}
|
||||
|
||||
impl ValuePerBlockWithDeltas {
|
||||
@@ -30,7 +30,7 @@ impl ValuePerBlockWithDeltas {
|
||||
|
||||
let delta = LazyRollingDeltasAmountFromHeight::new(
|
||||
&format!("{name}_delta"),
|
||||
version + Version::ONE,
|
||||
version + Version::TWO,
|
||||
&inner.sats.height,
|
||||
cached_starts,
|
||||
indexes,
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
use std::ops::{Add, AddAssign, Div};
|
||||
|
||||
use brk_types::{
|
||||
BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, StoredF32,
|
||||
PartsPerMillion32, PartsPerMillion64, PartsPerMillionSigned32, PartsPerMillionSigned64,
|
||||
StoredF32,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use vecdb::{CheckedSub, Formattable, PcoVecValue, UnaryTransform};
|
||||
|
||||
use crate::internal::{
|
||||
Bp16ToFloat, Bp16ToPercent, Bp32ToFloat, Bp32ToPercent, Bps16ToFloat, Bps16ToPercent,
|
||||
Bps32ToFloat, Bps32ToPercent,
|
||||
};
|
||||
use crate::internal::{FixedToPercent, FixedToRatio};
|
||||
|
||||
pub trait ComputedVecValue
|
||||
where
|
||||
@@ -40,28 +38,38 @@ pub trait NumericValue: ComputedVecValue + CheckedSub + Default + From<f64> + In
|
||||
|
||||
impl<T> NumericValue for T where T: ComputedVecValue + CheckedSub + Default + From<f64> + Into<f64> {}
|
||||
|
||||
/// Trait that associates a basis-point type with its transforms to ratio and percent.
|
||||
pub trait BpsType: NumericValue + JsonSchema {
|
||||
/// A stored fixed-point ratio and its public representations.
|
||||
pub trait FixedRatio: NumericValue + JsonSchema {
|
||||
const SUFFIX: &'static str;
|
||||
|
||||
type ToRatio: UnaryTransform<Self, StoredF32>;
|
||||
type ToPercent: UnaryTransform<Self, StoredF32>;
|
||||
}
|
||||
|
||||
impl BpsType for BasisPoints16 {
|
||||
type ToRatio = Bp16ToFloat;
|
||||
type ToPercent = Bp16ToPercent;
|
||||
impl FixedRatio for PartsPerMillion32 {
|
||||
const SUFFIX: &'static str = "ppm";
|
||||
|
||||
type ToRatio = FixedToRatio;
|
||||
type ToPercent = FixedToPercent;
|
||||
}
|
||||
|
||||
impl BpsType for BasisPoints32 {
|
||||
type ToRatio = Bp32ToFloat;
|
||||
type ToPercent = Bp32ToPercent;
|
||||
impl FixedRatio for PartsPerMillionSigned32 {
|
||||
const SUFFIX: &'static str = "ppm";
|
||||
|
||||
type ToRatio = FixedToRatio;
|
||||
type ToPercent = FixedToPercent;
|
||||
}
|
||||
|
||||
impl BpsType for BasisPointsSigned16 {
|
||||
type ToRatio = Bps16ToFloat;
|
||||
type ToPercent = Bps16ToPercent;
|
||||
impl FixedRatio for PartsPerMillion64 {
|
||||
const SUFFIX: &'static str = "ppm";
|
||||
|
||||
type ToRatio = FixedToRatio;
|
||||
type ToPercent = FixedToPercent;
|
||||
}
|
||||
|
||||
impl BpsType for BasisPointsSigned32 {
|
||||
type ToRatio = Bps32ToFloat;
|
||||
type ToPercent = Bps32ToPercent;
|
||||
impl FixedRatio for PartsPerMillionSigned64 {
|
||||
const SUFFIX: &'static str = "ppm";
|
||||
|
||||
type ToRatio = FixedToRatio;
|
||||
type ToPercent = FixedToPercent;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use brk_types::{
|
||||
BasisPoints16, Bitcoin, Cents, Dollars, Sats, StoredF32, StoredF64, StoredI8, StoredU16,
|
||||
Bitcoin, Cents, Dollars, PartsPerMillion32, Sats, StoredF32, StoredF64, StoredI8, StoredU16,
|
||||
StoredU32, StoredU64, VSize, Weight,
|
||||
};
|
||||
use vecdb::{BinaryTransform, UnaryTransform, VecValue};
|
||||
@@ -128,12 +128,12 @@ impl UnaryTransform<StoredF64, StoredF64> for DifficultyToHashF64 {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OneMinusBp16;
|
||||
pub struct OneMinusPpm;
|
||||
|
||||
impl UnaryTransform<BasisPoints16, BasisPoints16> for OneMinusBp16 {
|
||||
impl UnaryTransform<PartsPerMillion32, PartsPerMillion32> for OneMinusPpm {
|
||||
#[inline(always)]
|
||||
fn apply(v: BasisPoints16) -> BasisPoints16 {
|
||||
BasisPoints16::ONE - v
|
||||
fn apply(value: PartsPerMillion32) -> PartsPerMillion32 {
|
||||
PartsPerMillion32::ONE - value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
use brk_types::{
|
||||
BasisPoints16, BasisPoints32, BasisPointsSigned16, BasisPointsSigned32, StoredF32,
|
||||
};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct Bp16ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints16) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bp32ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints32) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bps16ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bps32ToFloat;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToFloat {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bp16ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPoints16, StoredF32> for Bp16ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints16) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bp32ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPoints32, StoredF32> for Bp32ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPoints32) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bps16ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned16, StoredF32> for Bps16ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned16) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bps32ToPercent;
|
||||
|
||||
impl UnaryTransform<BasisPointsSigned32, StoredF32> for Bps32ToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(bp: BasisPointsSigned32) -> StoredF32 {
|
||||
StoredF32::from(bp.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use brk_types::{BasisPoints32, Cents, StoredF32, StoredF64};
|
||||
use brk_types::{Cents, StoredF32, StoredF64};
|
||||
use vecdb::{BinaryTransform, UnaryTransform};
|
||||
|
||||
use crate::internal::FixedRatio;
|
||||
|
||||
pub struct DaysToYears;
|
||||
|
||||
impl UnaryTransform<StoredF32, StoredF32> for DaysToYears {
|
||||
@@ -54,12 +56,12 @@ impl BinaryTransform<Cents, StoredF32, Cents> for PriceTimesRatioCents {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PriceTimesRatioBp32Cents;
|
||||
pub struct PriceTimesRatio<R>(PhantomData<R>);
|
||||
|
||||
impl BinaryTransform<Cents, BasisPoints32, Cents> for PriceTimesRatioBp32Cents {
|
||||
impl<R: FixedRatio> BinaryTransform<Cents, R, Cents> for PriceTimesRatio<R> {
|
||||
#[inline(always)]
|
||||
fn apply(price: Cents, ratio: BasisPoints32) -> Cents {
|
||||
Cents::from(f64::from(price) * f64::from(ratio))
|
||||
fn apply(price: Cents, ratio: R) -> Cents {
|
||||
Cents::from(f64::from(price) * ratio.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use brk_types::{
|
||||
PartsPerMillion32, PartsPerMillion64, PartsPerMillionSigned32, PartsPerMillionSigned64,
|
||||
StoredF32,
|
||||
};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
pub struct FixedToRatio;
|
||||
pub struct FixedToPercent;
|
||||
|
||||
macro_rules! impl_fixed_ratio {
|
||||
($($type:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl UnaryTransform<$type, StoredF32> for FixedToRatio {
|
||||
#[inline(always)]
|
||||
fn apply(value: $type) -> StoredF32 {
|
||||
StoredF32::from(value.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<$type, StoredF32> for FixedToPercent {
|
||||
#[inline(always)]
|
||||
fn apply(value: $type) -> StoredF32 {
|
||||
StoredF32::from(value.to_f32() * 100.0)
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
impl_fixed_ratio!(
|
||||
PartsPerMillion32,
|
||||
PartsPerMillionSigned32,
|
||||
PartsPerMillion64,
|
||||
PartsPerMillionSigned64,
|
||||
);
|
||||
@@ -1,32 +1,28 @@
|
||||
mod arithmetic;
|
||||
mod bps;
|
||||
mod currency;
|
||||
mod derived;
|
||||
mod fixed_ratio;
|
||||
mod ratio;
|
||||
mod specialized;
|
||||
|
||||
pub use arithmetic::{
|
||||
BlocksToDaysF32, DifficultyToHashF64, HalveCents, HalveDollars, HalveSats, HalveSatsToBitcoin,
|
||||
Identity, MaskSats, OneMinusBp16, OneMinusF64, ReturnF32Tenths, ReturnI8, ReturnU16,
|
||||
Identity, MaskSats, OneMinusF64, OneMinusPpm, ReturnF32Tenths, ReturnI8, ReturnU16,
|
||||
ThsToPhsF32, VBytesToWeight, WeightToVSize,
|
||||
};
|
||||
pub use bps::{
|
||||
Bp16ToFloat, Bp16ToPercent, Bp32ToFloat, Bp32ToPercent, Bps16ToFloat, Bps16ToPercent,
|
||||
Bps32ToFloat, Bps32ToPercent,
|
||||
};
|
||||
pub use currency::{
|
||||
AvgCentsToUsd, AvgSatsToBtc, CentsSignedToDollars, CentsSubtractToCentsSigned,
|
||||
CentsTimesTenths, CentsUnsignedToDollars, CentsUnsignedToSats, DollarsToSatsFract,
|
||||
NegCentsUnsignedToDollars, SatsSignedToBitcoin, SatsToBitcoin, SatsToCents,
|
||||
};
|
||||
pub use derived::{
|
||||
Days1, Days7, Days30, Days365, DaysToYears, PriceTimesRatioBp32Cents, PriceTimesRatioCents,
|
||||
RatioCents64, TimesSqrt,
|
||||
Days1, Days7, Days30, Days365, DaysToYears, PriceTimesRatio, PriceTimesRatioCents, RatioCents64,
|
||||
TimesSqrt,
|
||||
};
|
||||
pub use fixed_ratio::{FixedToPercent, FixedToRatio};
|
||||
pub use ratio::{
|
||||
RatioCentsBp16, RatioCentsBp32, RatioCentsSignedCentsBps32, RatioCentsSignedDollarsBps32,
|
||||
RatioDiffCentsBps32, RatioDiffDollarsBps32, RatioDiffF32Bps32, RatioDollarsBp16,
|
||||
RatioDollarsBp32, RatioDollarsBps32, RatioSatsBp16, RatioU64Bp16, RatioU64F32,
|
||||
RatioCents, RatioCentsSignedCents, RatioCentsSignedDollars, RatioDiffCents,
|
||||
RatioDiffDollars, RatioDiffF32, RatioDollars, RatioSats, RatioU64, RatioU64F32,
|
||||
};
|
||||
pub use specialized::{
|
||||
BlockCountTarget1m, BlockCountTarget1w, BlockCountTarget1y, BlockCountTarget24h,
|
||||
|
||||
@@ -1,126 +1,86 @@
|
||||
use brk_types::{
|
||||
BasisPoints16, BasisPoints32, BasisPointsSigned32, Cents, CentsSigned, Dollars, Sats,
|
||||
StoredF32, StoredU64,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use brk_types::{Cents, CentsSigned, Dollars, Sats, StoredF32, StoredU64};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
pub struct RatioU64Bp16;
|
||||
use crate::internal::FixedRatio;
|
||||
|
||||
impl BinaryTransform<StoredU64, StoredU64, BasisPoints16> for RatioU64Bp16 {
|
||||
pub struct RatioU64<P>(PhantomData<P>);
|
||||
|
||||
impl<P: FixedRatio> BinaryTransform<StoredU64, StoredU64, P> for RatioU64<P> {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: StoredU64, denominator: StoredU64) -> BasisPoints16 {
|
||||
fn apply(numerator: StoredU64, denominator: StoredU64) -> P {
|
||||
if *denominator > 0 {
|
||||
BasisPoints16::from(*numerator as f64 / *denominator as f64)
|
||||
P::from(*numerator as f64 / *denominator as f64)
|
||||
} else {
|
||||
BasisPoints16::ZERO
|
||||
P::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioSatsBp16;
|
||||
pub struct RatioSats<P>(PhantomData<P>);
|
||||
|
||||
impl BinaryTransform<Sats, Sats, BasisPoints16> for RatioSatsBp16 {
|
||||
impl<P: FixedRatio> BinaryTransform<Sats, Sats, P> for RatioSats<P> {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Sats, denominator: Sats) -> BasisPoints16 {
|
||||
fn apply(numerator: Sats, denominator: Sats) -> P {
|
||||
if *denominator > 0 {
|
||||
BasisPoints16::from(*numerator as f64 / *denominator as f64)
|
||||
P::from(*numerator as f64 / *denominator as f64)
|
||||
} else {
|
||||
BasisPoints16::ZERO
|
||||
P::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioCentsBp32;
|
||||
pub struct RatioCents<P>(PhantomData<P>);
|
||||
|
||||
impl BinaryTransform<Cents, Cents, BasisPoints32> for RatioCentsBp32 {
|
||||
impl<P: FixedRatio> BinaryTransform<Cents, Cents, P> for RatioCents<P> {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Cents, denominator: Cents) -> BasisPoints32 {
|
||||
fn apply(numerator: Cents, denominator: Cents) -> P {
|
||||
if denominator == Cents::ZERO {
|
||||
BasisPoints32::ZERO
|
||||
P::default()
|
||||
} else {
|
||||
BasisPoints32::from(numerator.inner() as f64 / denominator.inner() as f64)
|
||||
P::from(numerator.inner() as f64 / denominator.inner() as f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioCentsBp16;
|
||||
pub struct RatioDollars<P>(PhantomData<P>);
|
||||
|
||||
impl BinaryTransform<Cents, Cents, BasisPoints16> for RatioCentsBp16 {
|
||||
impl<P: FixedRatio> BinaryTransform<Dollars, Dollars, P> for RatioDollars<P> {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Cents, denominator: Cents) -> BasisPoints16 {
|
||||
if denominator == Cents::ZERO {
|
||||
BasisPoints16::ZERO
|
||||
} else {
|
||||
BasisPoints16::from(numerator.inner() as f64 / denominator.inner() as f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioDollarsBp16;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, BasisPoints16> for RatioDollarsBp16 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPoints16 {
|
||||
let ratio = *(numerator / denominator);
|
||||
if ratio.is_finite() {
|
||||
BasisPoints16::from(ratio)
|
||||
} else {
|
||||
BasisPoints16::ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioDollarsBps32;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, BasisPointsSigned32> for RatioDollarsBps32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPointsSigned32 {
|
||||
let ratio = *(numerator / denominator);
|
||||
if ratio.is_finite() {
|
||||
BasisPointsSigned32::from(ratio)
|
||||
} else {
|
||||
BasisPointsSigned32::ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioCentsSignedCentsBps32;
|
||||
|
||||
impl BinaryTransform<CentsSigned, Cents, BasisPointsSigned32> for RatioCentsSignedCentsBps32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Cents) -> BasisPointsSigned32 {
|
||||
if denominator == Cents::ZERO {
|
||||
BasisPointsSigned32::ZERO
|
||||
} else {
|
||||
BasisPointsSigned32::from(numerator.inner() as f64 / denominator.inner() as f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioCentsSignedDollarsBps32;
|
||||
|
||||
impl BinaryTransform<CentsSigned, Dollars, BasisPointsSigned32> for RatioCentsSignedDollarsBps32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Dollars) -> BasisPointsSigned32 {
|
||||
let d: f64 = denominator.into();
|
||||
if d > 0.0 {
|
||||
BasisPointsSigned32::from(numerator.inner() as f64 / 100.0 / d)
|
||||
} else {
|
||||
BasisPointsSigned32::ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioDollarsBp32;
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, BasisPoints32> for RatioDollarsBp32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> BasisPoints32 {
|
||||
fn apply(numerator: Dollars, denominator: Dollars) -> P {
|
||||
let ratio = f64::from(numerator) / f64::from(denominator);
|
||||
if ratio.is_finite() {
|
||||
BasisPoints32::from(ratio)
|
||||
P::from(ratio)
|
||||
} else {
|
||||
BasisPoints32::ZERO
|
||||
P::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioCentsSignedCents<P>(PhantomData<P>);
|
||||
|
||||
impl<P: FixedRatio> BinaryTransform<CentsSigned, Cents, P> for RatioCentsSignedCents<P> {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Cents) -> P {
|
||||
if denominator == Cents::ZERO {
|
||||
P::default()
|
||||
} else {
|
||||
P::from(numerator.inner() as f64 / denominator.inner() as f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioCentsSignedDollars<P>(PhantomData<P>);
|
||||
|
||||
impl<P: FixedRatio> BinaryTransform<CentsSigned, Dollars, P> for RatioCentsSignedDollars<P> {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: CentsSigned, denominator: Dollars) -> P {
|
||||
let denominator = f64::from(denominator);
|
||||
if denominator > 0.0 {
|
||||
P::from(numerator.inner() as f64 / 100.0 / denominator)
|
||||
} else {
|
||||
P::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,43 +98,43 @@ impl BinaryTransform<StoredU64, StoredU64, StoredF32> for RatioU64F32 {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioDiffF32Bps32;
|
||||
pub struct RatioDiffF32<P>(PhantomData<P>);
|
||||
|
||||
impl BinaryTransform<StoredF32, StoredF32, BasisPointsSigned32> for RatioDiffF32Bps32 {
|
||||
impl<P: FixedRatio> BinaryTransform<StoredF32, StoredF32, P> for RatioDiffF32<P> {
|
||||
#[inline(always)]
|
||||
fn apply(value: StoredF32, base: StoredF32) -> BasisPointsSigned32 {
|
||||
fn apply(value: StoredF32, base: StoredF32) -> P {
|
||||
if base.is_nan() || *base == 0.0 {
|
||||
BasisPointsSigned32::ZERO
|
||||
P::default()
|
||||
} else {
|
||||
BasisPointsSigned32::from((*value / *base - 1.0) as f64)
|
||||
P::from((*value / *base - 1.0) as f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioDiffDollarsBps32;
|
||||
pub struct RatioDiffDollars<P>(PhantomData<P>);
|
||||
|
||||
impl BinaryTransform<Dollars, Dollars, BasisPointsSigned32> for RatioDiffDollarsBps32 {
|
||||
impl<P: FixedRatio> BinaryTransform<Dollars, Dollars, P> for RatioDiffDollars<P> {
|
||||
#[inline(always)]
|
||||
fn apply(close: Dollars, base: Dollars) -> BasisPointsSigned32 {
|
||||
let base_f64: f64 = base.into();
|
||||
if base_f64 == 0.0 {
|
||||
BasisPointsSigned32::ZERO
|
||||
fn apply(close: Dollars, base: Dollars) -> P {
|
||||
let base = f64::from(base);
|
||||
if base == 0.0 {
|
||||
P::default()
|
||||
} else {
|
||||
BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0)
|
||||
P::from(f64::from(close) / base - 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RatioDiffCentsBps32;
|
||||
pub struct RatioDiffCents<P>(PhantomData<P>);
|
||||
|
||||
impl BinaryTransform<Cents, Cents, BasisPointsSigned32> for RatioDiffCentsBps32 {
|
||||
impl<P: FixedRatio> BinaryTransform<Cents, Cents, P> for RatioDiffCents<P> {
|
||||
#[inline(always)]
|
||||
fn apply(close: Cents, base: Cents) -> BasisPointsSigned32 {
|
||||
let base_f64 = f64::from(base);
|
||||
if base_f64 == 0.0 {
|
||||
BasisPointsSigned32::ZERO
|
||||
fn apply(close: Cents, base: Cents) -> P {
|
||||
let base = f64::from(base);
|
||||
if base == 0.0 {
|
||||
P::default()
|
||||
} else {
|
||||
BasisPointsSigned32::from(f64::from(close) / base_f64 - 1.0)
|
||||
P::from(f64::from(close) / base - 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, WritableVec}
|
||||
use crate::{indexes, price};
|
||||
|
||||
use super::{
|
||||
BpsType, NumericValue, PerBlock, PerBlockCumulativeRolling, PercentPerBlock, ValuePerBlock,
|
||||
FixedRatio, NumericValue, PerBlock, PerBlockCumulativeRolling, PercentPerBlock, ValuePerBlock,
|
||||
WindowStartVec, Windows,
|
||||
};
|
||||
|
||||
@@ -276,7 +276,7 @@ impl WithAddrTypes<AvgAmountMetrics> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: BpsType> WithAddrTypes<PercentPerBlock<B>> {
|
||||
impl<B: FixedRatio> WithAddrTypes<PercentPerBlock<B>> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
@@ -291,9 +291,9 @@ impl<B: BpsType> WithAddrTypes<PercentPerBlock<B>> {
|
||||
}
|
||||
|
||||
pub(crate) fn reset_height(&mut self) -> Result<()> {
|
||||
self.all.bps.height.reset()?;
|
||||
self.all.raw.height.reset()?;
|
||||
for v in self.by_addr_type.values_mut() {
|
||||
v.bps.height.reset()?;
|
||||
v.raw.height.reset()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{BasisPointsSigned32, Bitcoin, Cents, Date, Day1, Dollars, Sats};
|
||||
use brk_types::{Bitcoin, Cents, Date, Day1, Dollars, PartsPerMillionSigned64, Sats};
|
||||
use vecdb::{AnyVec, Exit, ReadableOptionVec, ReadableVec, VecIndex};
|
||||
|
||||
use super::{ByDcaPeriod, Vecs};
|
||||
use crate::{blocks, indexes, internal::RatioDiffCentsBps32, market, price};
|
||||
use crate::{blocks, indexes, internal::RatioDiffCents, market, price};
|
||||
|
||||
const DCA_AMOUNT: Dollars = Dollars::mint(100.0);
|
||||
|
||||
@@ -102,7 +102,7 @@ impl Vecs {
|
||||
.iter_mut()
|
||||
.zip(self.period.dca_cost_basis.iter_with_days())
|
||||
{
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCentsBps32>(
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCents<PartsPerMillionSigned64>>(
|
||||
starting_lengths.height,
|
||||
&prices.spot.cents.height,
|
||||
&average_price.cents.height,
|
||||
@@ -117,13 +117,13 @@ impl Vecs {
|
||||
.zip_mut_with_period(&self.period.dca_return)
|
||||
{
|
||||
let years = days as f64 / 365.0;
|
||||
cagr.bps.height.compute_transform(
|
||||
cagr.raw.height.compute_transform(
|
||||
starting_lengths.height,
|
||||
&returns.bps.height,
|
||||
&returns.raw.height,
|
||||
|(h, r, ..)| {
|
||||
let ratio = f64::from(r);
|
||||
let v = (ratio + 1.0).powf(1.0 / years) - 1.0;
|
||||
(h, BasisPointsSigned32::from(v))
|
||||
(h, PartsPerMillionSigned64::from(v))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
@@ -163,7 +163,7 @@ impl Vecs {
|
||||
.iter_mut()
|
||||
.zip(lookback_dca.iter_with_days())
|
||||
{
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCentsBps32>(
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCents<PartsPerMillionSigned64>>(
|
||||
starting_lengths.height,
|
||||
&prices.spot.cents.height,
|
||||
&lookback_price.cents.height,
|
||||
@@ -266,7 +266,7 @@ impl Vecs {
|
||||
.iter_mut()
|
||||
.zip(self.class.dca_cost_basis.iter())
|
||||
{
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCentsBps32>(
|
||||
returns.compute_binary::<Cents, Cents, RatioDiffCents<PartsPerMillionSigned64>>(
|
||||
starting_lengths.height,
|
||||
&prices.spot.cents.height,
|
||||
&average_price.cents.height,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Cents, Height, Sats};
|
||||
use brk_types::{Cents, Height, PartsPerMillionSigned64, Sats};
|
||||
use vecdb::{Database, EagerVec, PcoVec, Rw, StorageMode};
|
||||
|
||||
use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod};
|
||||
@@ -9,17 +9,17 @@ use crate::internal::{PerBlock, PercentPerBlock, Price, ValuePerBlock};
|
||||
pub struct PeriodVecs<M: StorageMode = Rw> {
|
||||
pub dca_stack: ByDcaPeriod<ValuePerBlock<M>>,
|
||||
pub dca_cost_basis: ByDcaPeriod<Price<PerBlock<Cents, M>>>,
|
||||
pub dca_return: ByDcaPeriod<PercentPerBlock<BasisPointsSigned32, M>>,
|
||||
pub dca_cagr: ByDcaCagr<PercentPerBlock<BasisPointsSigned32, M>>,
|
||||
pub dca_return: ByDcaPeriod<PercentPerBlock<PartsPerMillionSigned64, M>>,
|
||||
pub dca_cagr: ByDcaCagr<PercentPerBlock<PartsPerMillionSigned64, M>>,
|
||||
pub lump_sum_stack: ByDcaPeriod<ValuePerBlock<M>>,
|
||||
pub lump_sum_return: ByDcaPeriod<PercentPerBlock<BasisPointsSigned32, M>>,
|
||||
pub lump_sum_return: ByDcaPeriod<PercentPerBlock<PartsPerMillionSigned64, M>>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct ClassVecs<M: StorageMode = Rw> {
|
||||
pub dca_stack: ByDcaClass<ValuePerBlock<M>>,
|
||||
pub dca_cost_basis: ByDcaClass<Price<PerBlock<Cents, M>>>,
|
||||
pub dca_return: ByDcaClass<PercentPerBlock<BasisPointsSigned32, M>>,
|
||||
pub dca_return: ByDcaClass<PercentPerBlock<PartsPerMillionSigned64, M>>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned16, Cents, StoredF32};
|
||||
use brk_types::{Cents, PartsPerMillionSigned32, StoredF32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{LazyPerBlock, PerBlock, PercentPerBlock, Price};
|
||||
@@ -7,7 +7,7 @@ use crate::internal::{LazyPerBlock, PerBlock, PercentPerBlock, Price};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub high: Price<PerBlock<Cents, M>>,
|
||||
pub drawdown: PercentPerBlock<BasisPointsSigned16, M>,
|
||||
pub drawdown: PercentPerBlock<PartsPerMillionSigned32, M>,
|
||||
pub days_since: PerBlock<StoredF32, M>,
|
||||
pub years_since: LazyPerBlock<StoredF32>,
|
||||
pub max_days_between: PerBlock<StoredF32, M>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{BasisPoints16, StoredF32};
|
||||
use brk_types::{PartsPerMillion32, StoredF32};
|
||||
use vecdb::{Exit, ReadableVec, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
@@ -72,7 +72,7 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.choppiness_index_2w.bps.height.compute_transform4(
|
||||
self.choppiness_index_2w.raw.height.compute_transform4(
|
||||
starting_height,
|
||||
&self.true_range_sum_2w.height,
|
||||
&self.max._2w.cents.height,
|
||||
@@ -82,9 +82,11 @@ impl Vecs {
|
||||
let range = f64::from(max) - f64::from(min);
|
||||
let n = (h.to_usize() - window_start.to_usize() + 1) as f32;
|
||||
let ci = if range > 0.0 && n > 1.0 {
|
||||
BasisPoints16::from((*tr_sum / range as f32).log10() as f64 / n.log10() as f64)
|
||||
PartsPerMillion32::from(
|
||||
(*tr_sum / range as f32).log10() as f64 / n.log10() as f64,
|
||||
)
|
||||
} else {
|
||||
BasisPoints16::ZERO
|
||||
PartsPerMillion32::ZERO
|
||||
};
|
||||
(h, ci)
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Cents, StoredF32};
|
||||
use brk_types::{Cents, PartsPerMillion32, StoredF32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{PerBlock, PercentPerBlock, Price};
|
||||
@@ -18,5 +18,5 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub max: PriceMinMaxVecs<M>,
|
||||
pub true_range: PerBlock<StoredF32, M>,
|
||||
pub true_range_sum_2w: PerBlock<StoredF32, M>,
|
||||
pub choppiness_index_2w: PercentPerBlock<BasisPoints16, M>,
|
||||
pub choppiness_index_2w: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{BasisPointsSigned32, Dollars};
|
||||
use brk_types::{Dollars, PartsPerMillionSigned64};
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
blocks, internal::RatioDiffDollarsBps32, investing::ByDcaPeriod, market::lookback, price,
|
||||
};
|
||||
use crate::{blocks, internal::RatioDiffDollars, investing::ByDcaPeriod, market::lookback, price};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn compute(
|
||||
@@ -25,7 +23,7 @@ impl Vecs {
|
||||
.iter_mut_with_days()
|
||||
.zip(lookback.price_past.iter_with_days())
|
||||
{
|
||||
returns.compute_binary::<Dollars, Dollars, RatioDiffDollarsBps32>(
|
||||
returns.compute_binary::<Dollars, Dollars, RatioDiffDollars<PartsPerMillionSigned64>>(
|
||||
starting_lengths.height,
|
||||
&prices.spot.usd.height,
|
||||
&lookback_price.usd.height,
|
||||
@@ -37,13 +35,13 @@ impl Vecs {
|
||||
let price_return_dca = ByDcaPeriod::from_lookback(&self.periods);
|
||||
for (cagr, returns, days) in self.cagr.zip_mut_with_period(&price_return_dca) {
|
||||
let years = days as f64 / 365.0;
|
||||
cagr.bps.height.compute_transform(
|
||||
cagr.raw.height.compute_transform(
|
||||
starting_lengths.height,
|
||||
&returns.bps.height,
|
||||
&returns.raw.height,
|
||||
|(h, r, ..)| {
|
||||
let ratio = f64::from(r);
|
||||
let v = (ratio + 1.0).powf(1.0 / years) - 1.0;
|
||||
(h, BasisPointsSigned32::from(v))
|
||||
(h, PartsPerMillionSigned64::from(v))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::BasisPointsSigned32;
|
||||
use brk_types::PartsPerMillionSigned64;
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub periods: ByLookbackPeriod<PercentPerBlock<BasisPointsSigned32, M>>,
|
||||
pub cagr: ByDcaCagr<PercentPerBlock<BasisPointsSigned32, M>>,
|
||||
pub periods: ByLookbackPeriod<PercentPerBlock<PartsPerMillionSigned64, M>>,
|
||||
pub cagr: ByDcaCagr<PercentPerBlock<PartsPerMillionSigned64, M>>,
|
||||
pub sd_24h: Windows<StdDevPerBlock<M>>,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::Dollars;
|
||||
use brk_types::{Dollars, PartsPerMillion32};
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::{
|
||||
@@ -9,7 +9,7 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
blocks,
|
||||
internal::{RatioDollarsBp32, WindowsTo1m},
|
||||
internal::{RatioDollars, WindowsTo1m},
|
||||
price,
|
||||
};
|
||||
|
||||
@@ -62,8 +62,8 @@ impl Vecs {
|
||||
}
|
||||
|
||||
self.pi_cycle
|
||||
.bps
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
.raw
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion32>>(
|
||||
starting_height,
|
||||
&moving_average.sma._111d.usd.height,
|
||||
&moving_average.sma._350d_x2.usd.height,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{BasisPoints16, Height, StoredF32};
|
||||
use brk_types::{Height, PartsPerMillion32, StoredF32};
|
||||
use vecdb::{Exit, ReadableVec};
|
||||
|
||||
use super::RsiChain;
|
||||
@@ -47,60 +47,60 @@ pub(super) fn compute(
|
||||
exit,
|
||||
)?;
|
||||
|
||||
chain.rsi.bps.height.compute_transform2(
|
||||
chain.rsi.raw.height.compute_transform2(
|
||||
starting_height,
|
||||
&chain.average_gain.height,
|
||||
&chain.average_loss.height,
|
||||
|(h, g, l, ..)| {
|
||||
let sum = *g + *l;
|
||||
let rsi = if sum == 0.0 { 0.5 } else { *g / sum };
|
||||
(h, BasisPoints16::from(rsi as f64))
|
||||
(h, PartsPerMillion32::from(rsi as f64))
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
chain.rsi_min.bps.height.compute_rolling_min_from_starts(
|
||||
chain.rsi_min.raw.height.compute_rolling_min_from_starts(
|
||||
starting_height,
|
||||
ws_rma,
|
||||
&chain.rsi.bps.height,
|
||||
&chain.rsi.raw.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
chain.rsi_max.bps.height.compute_rolling_max_from_starts(
|
||||
chain.rsi_max.raw.height.compute_rolling_max_from_starts(
|
||||
starting_height,
|
||||
ws_rma,
|
||||
&chain.rsi.bps.height,
|
||||
&chain.rsi.raw.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
chain.stoch_rsi.bps.height.compute_transform3(
|
||||
chain.stoch_rsi.raw.height.compute_transform3(
|
||||
starting_height,
|
||||
&chain.rsi.bps.height,
|
||||
&chain.rsi_min.bps.height,
|
||||
&chain.rsi_max.bps.height,
|
||||
&chain.rsi.raw.height,
|
||||
&chain.rsi_min.raw.height,
|
||||
&chain.rsi_max.raw.height,
|
||||
|(h, r, mn, mx, ..)| {
|
||||
let range = f64::from(*mx) - f64::from(*mn);
|
||||
let stoch = if range == 0.0 {
|
||||
BasisPoints16::ZERO
|
||||
PartsPerMillion32::ZERO
|
||||
} else {
|
||||
BasisPoints16::from((f64::from(*r) - f64::from(*mn)) / range)
|
||||
PartsPerMillion32::from((f64::from(*r) - f64::from(*mn)) / range)
|
||||
};
|
||||
(h, stoch)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
chain.stoch_rsi_k.bps.height.compute_rolling_average(
|
||||
chain.stoch_rsi_k.raw.height.compute_rolling_average(
|
||||
starting_height,
|
||||
ws_sma,
|
||||
&chain.stoch_rsi.bps.height,
|
||||
&chain.stoch_rsi.raw.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
chain.stoch_rsi_d.bps.height.compute_rolling_average(
|
||||
chain.stoch_rsi_d.raw.height.compute_rolling_average(
|
||||
starting_height,
|
||||
ws_sma,
|
||||
&chain.stoch_rsi_k.bps.height,
|
||||
&chain.stoch_rsi_k.raw.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, BasisPoints32, StoredF32};
|
||||
use brk_types::{PartsPerMillion32, StoredF32};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{PerBlock, PercentPerBlock, RatioPerBlock, WindowsTo1m};
|
||||
@@ -14,15 +14,15 @@ pub struct RsiChain<M: StorageMode = Rw> {
|
||||
pub average_gain: PerBlock<StoredF32, M>,
|
||||
#[traversable(hidden)]
|
||||
pub average_loss: PerBlock<StoredF32, M>,
|
||||
pub rsi: PercentPerBlock<BasisPoints16, M>,
|
||||
pub rsi: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(hidden)]
|
||||
pub rsi_min: PercentPerBlock<BasisPoints16, M>,
|
||||
pub rsi_min: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(hidden)]
|
||||
pub rsi_max: PercentPerBlock<BasisPoints16, M>,
|
||||
pub rsi_max: PercentPerBlock<PartsPerMillion32, M>,
|
||||
#[traversable(hidden)]
|
||||
pub stoch_rsi: PercentPerBlock<BasisPoints16, M>,
|
||||
pub stoch_rsi_k: PercentPerBlock<BasisPoints16, M>,
|
||||
pub stoch_rsi_d: PercentPerBlock<BasisPoints16, M>,
|
||||
pub stoch_rsi: PercentPerBlock<PartsPerMillion32, M>,
|
||||
pub stoch_rsi_k: PercentPerBlock<PartsPerMillion32, M>,
|
||||
pub stoch_rsi_d: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -38,7 +38,7 @@ pub struct MacdChain<M: StorageMode = Rw> {
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub rsi: WindowsTo1m<RsiChain<M>>,
|
||||
|
||||
pub pi_cycle: RatioPerBlock<BasisPoints32, M>,
|
||||
pub pi_cycle: RatioPerBlock<PartsPerMillion32, M>,
|
||||
|
||||
pub macd: WindowsTo1m<MacdChain<M>>,
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{Dollars, Height, Sats, StoredF32, StoredF64};
|
||||
use brk_types::{Dollars, Height, PartsPerMillionSigned64, Sats, StoredF32, StoredF64};
|
||||
use vecdb::{Exit, ReadableVec};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
blocks::{self, ONE_TERA_HASH, TARGET_BLOCKS_PER_DAY_F64},
|
||||
internal::RatioDiffF32Bps32,
|
||||
internal::RatioDiffF32,
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -103,7 +103,7 @@ impl Vecs {
|
||||
|
||||
self.price
|
||||
.rebound
|
||||
.compute_binary::<StoredF32, StoredF32, RatioDiffF32Bps32>(
|
||||
.compute_binary::<StoredF32, StoredF32, RatioDiffF32<PartsPerMillionSigned64>>(
|
||||
starting_height,
|
||||
&self.price.phs.height,
|
||||
&self.price.phs_min.height,
|
||||
@@ -112,7 +112,7 @@ impl Vecs {
|
||||
|
||||
self.value
|
||||
.rebound
|
||||
.compute_binary::<StoredF32, StoredF32, RatioDiffF32Bps32>(
|
||||
.compute_binary::<StoredF32, StoredF32, RatioDiffF32<PartsPerMillionSigned64>>(
|
||||
starting_height,
|
||||
&self.value.phs.height,
|
||||
&self.value.phs_min.height,
|
||||
|
||||
@@ -77,7 +77,7 @@ impl Vecs {
|
||||
rebound: PercentPerBlock::forced_import(
|
||||
db,
|
||||
"hash_price_rebound",
|
||||
version + v4,
|
||||
version + v5,
|
||||
indexes,
|
||||
)?,
|
||||
},
|
||||
@@ -89,7 +89,7 @@ impl Vecs {
|
||||
rebound: PercentPerBlock::forced_import(
|
||||
db,
|
||||
"hash_value_rebound",
|
||||
version + v4,
|
||||
version + v5,
|
||||
indexes,
|
||||
)?,
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned16, BasisPointsSigned32, StoredF32, StoredF64};
|
||||
use brk_types::{PartsPerMillionSigned32, PartsPerMillionSigned64, StoredF32, StoredF64};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{LazyPerBlock, PerBlock, PercentPerBlock};
|
||||
@@ -18,7 +18,7 @@ pub struct HashPriceValueVecs<M: StorageMode = Rw> {
|
||||
pub ths_min: PerBlock<StoredF32, M>,
|
||||
pub phs: LazyPerBlock<StoredF32>,
|
||||
pub phs_min: LazyPerBlock<StoredF32>,
|
||||
pub rebound: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub rebound: PercentPerBlock<PartsPerMillionSigned64, M>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -26,7 +26,7 @@ pub struct RateVecs<M: StorageMode = Rw> {
|
||||
pub base: PerBlock<StoredF64, M>,
|
||||
pub sma: HashRateSmaVecs<M>,
|
||||
pub ath: PerBlock<StoredF64, M>,
|
||||
pub drawdown: PercentPerBlock<BasisPointsSigned16, M>,
|
||||
pub drawdown: PercentPerBlock<PartsPerMillionSigned32, M>,
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{CheckedSub, Dollars, Halving, Sats};
|
||||
use brk_types::{
|
||||
CheckedSub, Dollars, Halving, PartsPerMillion32, PartsPerMillion64, Sats,
|
||||
};
|
||||
use vecdb::{Exit, ReadableVec, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
blocks, indexes,
|
||||
internal::{RatioDollarsBp32, RatioSatsBp16},
|
||||
internal::{RatioDollars, RatioSats},
|
||||
price, transactions,
|
||||
};
|
||||
|
||||
@@ -109,7 +111,7 @@ impl Vecs {
|
||||
self.unclaimed.compute(prices, starting_height, exit)?;
|
||||
|
||||
self.fee_dominance
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16, _, _, _, _>(
|
||||
.compute_binary::<Sats, Sats, RatioSats<PartsPerMillion32>, _, _, _, _>(
|
||||
starting_height,
|
||||
&self.fees.cumulative.sats.height,
|
||||
&self.coinbase.cumulative.sats.height,
|
||||
@@ -119,7 +121,7 @@ impl Vecs {
|
||||
)?;
|
||||
|
||||
self.fee_to_subsidy_ratio
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32, _, _>(
|
||||
.compute_binary::<Dollars, Dollars, RatioDollars<PartsPerMillion64>, _, _>(
|
||||
starting_height,
|
||||
self.coinbase.sum.as_array().map(|w| &w.usd.height),
|
||||
self.fees.sum.as_array().map(|w| &w.usd.height),
|
||||
|
||||
@@ -6,7 +6,7 @@ use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
LazyPercentCumulativeRolling, OneMinusBp16, PercentCumulativeRolling, RatioRollingWindows,
|
||||
LazyPercentCumulativeRolling, OneMinusPpm, PercentCumulativeRolling, RatioRollingWindows,
|
||||
ValuePerBlockCumulative, ValuePerBlockCumulativeRolling, ValuePerBlockFull, WindowStartVec,
|
||||
Windows,
|
||||
},
|
||||
@@ -22,7 +22,7 @@ impl Vecs {
|
||||
let fee_dominance =
|
||||
PercentCumulativeRolling::forced_import(db, "fee_dominance", version, indexes)?;
|
||||
|
||||
let subsidy_dominance = LazyPercentCumulativeRolling::from_source::<OneMinusBp16>(
|
||||
let subsidy_dominance = LazyPercentCumulativeRolling::from_source::<OneMinusPpm>(
|
||||
"subsidy_dominance",
|
||||
version,
|
||||
&fee_dominance,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, BasisPoints32, Height, Sats};
|
||||
use brk_types::{Height, PartsPerMillion32, PartsPerMillion64, Sats};
|
||||
use vecdb::{EagerVec, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{
|
||||
@@ -15,9 +15,9 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub output_volume: M::Stored<EagerVec<PcoVec<Height, Sats>>>,
|
||||
pub unclaimed: ValuePerBlockCumulative<M>,
|
||||
#[traversable(wrap = "fees", rename = "dominance")]
|
||||
pub fee_dominance: PercentCumulativeRolling<BasisPoints16, M>,
|
||||
pub fee_dominance: PercentCumulativeRolling<PartsPerMillion32, M>,
|
||||
#[traversable(wrap = "subsidy", rename = "dominance")]
|
||||
pub subsidy_dominance: LazyPercentCumulativeRolling<BasisPoints16>,
|
||||
pub subsidy_dominance: LazyPercentCumulativeRolling<PartsPerMillion32>,
|
||||
#[traversable(wrap = "fees", rename = "to_subsidy_ratio")]
|
||||
pub fee_to_subsidy_ratio: RatioRollingWindows<BasisPoints32, M>,
|
||||
pub fee_to_subsidy_ratio: RatioRollingWindows<PartsPerMillion64, M>,
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{BasisPoints16, Height, OpReturnKind, StoredU64, VSize};
|
||||
use brk_types::{Height, OpReturnKind, PartsPerMillion32, StoredU64, VSize};
|
||||
use vecdb::{AnyVec, Exit, ReadableVec, VecIndex};
|
||||
|
||||
use super::{Breakdown, Vecs, vecs::Totals};
|
||||
use crate::{
|
||||
blocks,
|
||||
internal::{PercentPerBlock, RatioU64Bp16},
|
||||
internal::{PercentPerBlock, RatioU64},
|
||||
};
|
||||
|
||||
const KIND_COUNT: usize = OpReturnKind::Unknown as usize + 1;
|
||||
@@ -192,12 +192,17 @@ fn compute_breakdown_data_shares(
|
||||
|
||||
fn compute_data_share(
|
||||
max_from: Height,
|
||||
target: &mut PercentPerBlock<BasisPoints16>,
|
||||
target: &mut PercentPerBlock<PartsPerMillion32>,
|
||||
data: &impl ReadableVec<Height, StoredU64>,
|
||||
block_size: &impl ReadableVec<Height, StoredU64>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
target.compute_binary::<StoredU64, StoredU64, RatioU64Bp16>(max_from, data, block_size, exit)
|
||||
target.compute_binary::<StoredU64, StoredU64, RatioU64<PartsPerMillion32>>(
|
||||
max_from,
|
||||
data,
|
||||
block_size,
|
||||
exit,
|
||||
)
|
||||
}
|
||||
|
||||
fn finalize_transaction(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Height, StoredU64, VSize, Version};
|
||||
use brk_types::{Height, PartsPerMillion32, StoredU64, VSize, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Database, Exit, Rw, StorageMode, WritableVec};
|
||||
|
||||
@@ -111,7 +111,7 @@ pub struct Total<M: StorageMode = Rw> {
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
pub metrics: TotalMetrics<M>,
|
||||
pub chain_share: PercentPerBlock<BasisPoints16, M>,
|
||||
pub chain_share: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
impl Total {
|
||||
@@ -203,8 +203,8 @@ pub struct Breakdown<M: StorageMode = Rw> {
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
pub metrics: Metrics<M>,
|
||||
pub data_share: PercentPerBlock<BasisPoints16, M>,
|
||||
pub chain_share: PercentPerBlock<BasisPoints16, M>,
|
||||
pub data_share: PercentPerBlock<PartsPerMillion32, M>,
|
||||
pub chain_share: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
impl Breakdown {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_cohort::ByType;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, StoredU64};
|
||||
use brk_types::{PartsPerMillion32, StoredU64};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use super::WithOutputTypes;
|
||||
@@ -10,7 +10,7 @@ use crate::internal::{PerBlockCumulativeRolling, PercentCumulativeRolling};
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub output_count: WithOutputTypes<PerBlockCumulativeRolling<StoredU64, StoredU64, M>>,
|
||||
pub spendable_output_count: PerBlockCumulativeRolling<StoredU64, StoredU64, M>,
|
||||
pub output_share: ByType<PercentCumulativeRolling<BasisPoints16, M>>,
|
||||
pub output_share: ByType<PercentCumulativeRolling<PartsPerMillion32, M>>,
|
||||
pub tx_count: WithOutputTypes<PerBlockCumulativeRolling<StoredU64, StoredU64, M>>,
|
||||
pub tx_share: ByType<PercentCumulativeRolling<BasisPoints16, M>>,
|
||||
pub tx_share: ByType<PercentCumulativeRolling<PartsPerMillion32, M>>,
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Height, PoolSlug, StoredU64};
|
||||
use brk_types::{Height, PartsPerMillion32, PoolSlug, StoredU64};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{BinaryTransform, Database, Exit, ReadableVec, Rw, StorageMode, Version};
|
||||
|
||||
use crate::{
|
||||
blocks, indexes,
|
||||
internal::{
|
||||
MaskSats, PercentRollingWindows, RatioU64Bp16, ValuePerBlockCumulativeRolling,
|
||||
MaskSats, PercentRollingWindows, RatioU64, ValuePerBlockCumulativeRolling,
|
||||
WindowStartVec, Windows,
|
||||
},
|
||||
mining, price,
|
||||
@@ -25,7 +25,7 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
|
||||
pub rewards: ValuePerBlockCumulativeRolling<M>,
|
||||
#[traversable(rename = "dominance")]
|
||||
pub dominance_rolling: PercentRollingWindows<BasisPoints16, M>,
|
||||
pub dominance_rolling: PercentRollingWindows<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -79,7 +79,7 @@ impl Vecs {
|
||||
.into_iter()
|
||||
.zip(blocks.count.total.sum.as_array()),
|
||||
) {
|
||||
dom.compute_binary::<StoredU64, StoredU64, RatioU64Bp16>(
|
||||
dom.compute_binary::<StoredU64, StoredU64, RatioU64<PartsPerMillion32>>(
|
||||
starting_height,
|
||||
&mined.height,
|
||||
&total.height,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, Height, PoolSlug, StoredU32, StoredU64};
|
||||
use brk_types::{Height, PartsPerMillion32, PoolSlug, StoredU32, StoredU64};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, Version};
|
||||
|
||||
use crate::{
|
||||
blocks, indexes,
|
||||
internal::{PerBlockCumulativeRolling, PercentPerBlock, RatioU64Bp16, WindowStartVec, Windows},
|
||||
internal::{PerBlockCumulativeRolling, PercentPerBlock, RatioU64, WindowStartVec, Windows},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -15,7 +15,7 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
slug: PoolSlug,
|
||||
|
||||
pub blocks_mined: PerBlockCumulativeRolling<StoredU32, StoredU64, M>,
|
||||
pub dominance: PercentPerBlock<BasisPoints16, M>,
|
||||
pub dominance: PercentPerBlock<PartsPerMillion32, M>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -74,7 +74,7 @@ impl Vecs {
|
||||
})?;
|
||||
|
||||
self.dominance
|
||||
.compute_binary::<StoredU64, StoredU64, RatioU64Bp16>(
|
||||
.compute_binary::<StoredU64, StoredU64, RatioU64<PartsPerMillion32>>(
|
||||
starting_height,
|
||||
&self.blocks_mined.cumulative.height,
|
||||
&blocks.count.total.cumulative.height,
|
||||
|
||||
@@ -35,7 +35,7 @@ impl Vecs {
|
||||
// i.e. the lookback points to block 0 or 1 in the genesis era.
|
||||
let circulating_supply = &distribution.utxo_cohorts.all.metrics.supply.total.sats;
|
||||
self.inflation_rate
|
||||
.bps
|
||||
.raw
|
||||
.height
|
||||
.compute_rolling_from_window_starts(
|
||||
starting_height,
|
||||
@@ -61,16 +61,16 @@ impl Vecs {
|
||||
let diff_arr = self.market_minus_realized_cap_growth_rate.0.as_mut_array();
|
||||
|
||||
let rcr_rates = [
|
||||
&all_realized.cap.delta.rate._24h.bps.height,
|
||||
&all_realized.cap.delta.rate._1w.bps.height,
|
||||
&all_realized.cap.delta.rate._1m.bps.height,
|
||||
&all_realized.cap.delta.rate._1y.bps.height,
|
||||
&all_realized.cap.delta.rate._24h.raw.height,
|
||||
&all_realized.cap.delta.rate._1w.raw.height,
|
||||
&all_realized.cap.delta.rate._1m.raw.height,
|
||||
&all_realized.cap.delta.rate._1y.raw.height,
|
||||
];
|
||||
|
||||
for i in 0..4 {
|
||||
diff_arr[i].height.compute_subtract(
|
||||
starting_height,
|
||||
&mcr_arr[i].bps.height,
|
||||
&mcr_arr[i].raw.height,
|
||||
rcr_rates[i],
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -38,7 +38,7 @@ impl Vecs {
|
||||
|
||||
// Inflation rate
|
||||
let inflation_rate =
|
||||
PercentPerBlock::forced_import(&db, "inflation_rate", version + Version::ONE, indexes)?;
|
||||
PercentPerBlock::forced_import(&db, "inflation_rate", version + Version::TWO, indexes)?;
|
||||
|
||||
// Velocity
|
||||
let velocity = super::velocity::Vecs::forced_import(&db, version, indexes)?;
|
||||
@@ -50,7 +50,7 @@ impl Vecs {
|
||||
// Market cap delta (change + rate across 4 windows)
|
||||
let market_cap_delta = LazyRollingDeltasFiatFromHeight::new(
|
||||
"market_cap_delta",
|
||||
version + Version::new(3),
|
||||
version + Version::new(4),
|
||||
&market_cap.cents.height,
|
||||
cached_starts,
|
||||
indexes,
|
||||
@@ -59,7 +59,7 @@ impl Vecs {
|
||||
let market_minus_realized_cap_growth_rate = RollingWindows::forced_import(
|
||||
&db,
|
||||
"market_minus_realized_cap_growth_rate",
|
||||
version + Version::TWO,
|
||||
version + Version::new(3),
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Cents, CentsSigned};
|
||||
use brk_types::{Cents, CentsSigned, PartsPerMillionSigned64};
|
||||
use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
use super::{burned, velocity};
|
||||
@@ -15,11 +15,12 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
|
||||
pub circulating: LazyValuePerBlock,
|
||||
pub burned: burned::Vecs<M>,
|
||||
pub inflation_rate: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
pub inflation_rate: PercentPerBlock<PartsPerMillionSigned64, M>,
|
||||
pub velocity: velocity::Vecs<M>,
|
||||
pub market_cap: LazyFiatPerBlock<Cents>,
|
||||
#[traversable(wrap = "market_cap", rename = "delta")]
|
||||
pub market_cap_delta: LazyRollingDeltasFiatFromHeight<Cents, CentsSigned, BasisPointsSigned32>,
|
||||
pub market_minus_realized_cap_growth_rate: RollingWindows<BasisPointsSigned32, M>,
|
||||
pub market_cap_delta:
|
||||
LazyRollingDeltasFiatFromHeight<Cents, CentsSigned, PartsPerMillionSigned64>,
|
||||
pub market_minus_realized_cap_growth_rate: RollingWindows<PartsPerMillionSigned64, M>,
|
||||
pub hodled_or_lost: LazyValuePerBlock,
|
||||
}
|
||||
|
||||
@@ -16,4 +16,3 @@ brk_types = { workspace = true }
|
||||
byteview = { workspace = true }
|
||||
fjall = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
@@ -19,7 +19,6 @@ use brk_types::{Height, Version};
|
||||
use byteview::ByteView;
|
||||
use fjall::{Database, Keyspace, KeyspaceCreateOptions, config::*};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use tracing::info;
|
||||
|
||||
mod any;
|
||||
mod item;
|
||||
@@ -229,7 +228,6 @@ where
|
||||
for<'a> ByteView: From<&'a K> + From<&'a V>,
|
||||
{
|
||||
self.export_meta_if_needed(height)?;
|
||||
self.report_db_reads();
|
||||
|
||||
let puts = mem::take(&mut self.puts);
|
||||
let dels = mem::take(&mut self.dels);
|
||||
@@ -304,13 +302,6 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn report_db_reads(&self) {
|
||||
let reads = self.db_reads.swap(0, Relaxed);
|
||||
if reads != 0 {
|
||||
info!(store = self.name, reads, "Store DB reads");
|
||||
}
|
||||
}
|
||||
|
||||
fn ingest<'a>(
|
||||
keyspace: &Keyspace,
|
||||
puts: impl Iterator<Item = (&'a K, &'a V)>,
|
||||
@@ -386,7 +377,6 @@ where
|
||||
|
||||
fn commit(&mut self, height: Height) -> Result<()> {
|
||||
self.export_meta_if_needed(height)?;
|
||||
self.report_db_reads();
|
||||
|
||||
let puts = mem::take(&mut self.puts);
|
||||
let dels = mem::take(&mut self.dels);
|
||||
|
||||
@@ -11,6 +11,6 @@ repository.workspace = true
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "2.0"
|
||||
syn = "3.0"
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0.106"
|
||||
proc-macro2 = "1.0.107"
|
||||
|
||||
@@ -163,7 +163,7 @@ fn type_contains_ident(ty: &Type, ident: &syn::Ident) -> bool {
|
||||
matches!(arg, syn::GenericArgument::Type(inner) if type_contains_ident(inner, ident))
|
||||
}),
|
||||
syn::PathArguments::Parenthesized(args) => {
|
||||
args.inputs.iter().any(|inner| type_contains_ident(inner, ident))
|
||||
args.inputs.iter().any(|inner| type_contains_ident(&inner.ty, ident))
|
||||
|| matches!(&args.output, syn::ReturnType::Type(_, inner) if type_contains_ident(inner, ident))
|
||||
}
|
||||
syn::PathArguments::None => false,
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
use std::ops::{Add, AddAssign, Div, Sub};
|
||||
|
||||
use derive_more::Deref;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{CheckedSub, Formattable, Pco, unlikely};
|
||||
|
||||
use super::StoredF32;
|
||||
|
||||
/// Unsigned basis points stored as u16.
|
||||
/// 1 bp = 0.0001. Range: 0–6.5535.
|
||||
/// Use for bounded 0–1 ratios (dominance, adoption, liveliness, etc.).
|
||||
/// `u16::MAX` is reserved as a NaN sentinel.
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Default,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Pco,
|
||||
JsonSchema,
|
||||
)]
|
||||
pub struct BasisPoints16(u16);
|
||||
|
||||
impl BasisPoints16 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const ONE: Self = Self(10000);
|
||||
/// NaN sentinel — uses u16::MAX which is outside the practical range.
|
||||
pub const NAN: Self = Self(u16::MAX);
|
||||
|
||||
#[inline]
|
||||
pub const fn new(value: u16) -> Self {
|
||||
debug_assert!(value != u16::MAX, "u16::MAX is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn inner(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_nan(self) -> bool {
|
||||
self.0 == u16::MAX
|
||||
}
|
||||
|
||||
/// Convert to f32: divide by 10000. Returns NaN for sentinel value.
|
||||
#[inline]
|
||||
pub fn to_f32(self) -> f32 {
|
||||
if unlikely(self.0 == u16::MAX) {
|
||||
f32::NAN
|
||||
} else {
|
||||
self.0 as f32 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for BasisPoints16 {
|
||||
#[inline]
|
||||
fn from(value: usize) -> Self {
|
||||
debug_assert!(
|
||||
value < u16::MAX as usize,
|
||||
"usize out of BasisPoints16 range: {value}"
|
||||
);
|
||||
Self(value as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for BasisPoints16 {
|
||||
#[inline]
|
||||
fn from(value: u16) -> Self {
|
||||
debug_assert!(value != u16::MAX, "u16::MAX is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPoints16> for u16 {
|
||||
#[inline]
|
||||
fn from(value: BasisPoints16) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from f32: multiply by 10000 and round.
|
||||
/// Input is in ratio form (e.g., 0.4523 for 45.23%).
|
||||
/// NaN/Inf → NaN sentinel.
|
||||
impl From<f32> for BasisPoints16 {
|
||||
#[inline]
|
||||
fn from(value: f32) -> Self {
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 10000.0).round().clamp(0.0, u16::MAX as f32 - 1.0);
|
||||
Self(scaled as u16)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from f64: multiply by 10000 and round.
|
||||
/// Input is in ratio form (e.g., 0.4523 for 45.23%).
|
||||
/// NaN/Inf → NaN sentinel.
|
||||
impl From<f64> for BasisPoints16 {
|
||||
#[inline]
|
||||
fn from(value: f64) -> Self {
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 10000.0).round().clamp(0.0, u16::MAX as f64 - 1.0);
|
||||
Self(scaled as u16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPoints16> for f64 {
|
||||
#[inline]
|
||||
fn from(value: BasisPoints16) -> Self {
|
||||
if unlikely(value.0 == u16::MAX) {
|
||||
f64::NAN
|
||||
} else {
|
||||
value.0 as f64 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPoints16> for StoredF32 {
|
||||
#[inline]
|
||||
fn from(value: BasisPoints16) -> Self {
|
||||
StoredF32::from(value.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for BasisPoints16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
if unlikely(self.0 == u16::MAX || rhs.0 == u16::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for BasisPoints16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
if unlikely(self.0 == u16::MAX || rhs.0 == u16::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for BasisPoints16 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for BasisPoints16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
if unlikely(self.0 == u16::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
debug_assert!(rhs <= u16::MAX as usize, "divisor out of u16 range: {rhs}");
|
||||
Self(self.0 / rhs as u16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for BasisPoints16 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
if unlikely(self.0 == u16::MAX || rhs.0 == u16::MAX) {
|
||||
Some(Self::NAN)
|
||||
} else {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BasisPoints16 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut buf = itoa::Buffer::new();
|
||||
let str = buf.format(self.0);
|
||||
f.write_str(str)
|
||||
}
|
||||
}
|
||||
|
||||
impl Formattable for BasisPoints16 {
|
||||
#[inline(always)]
|
||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||
let mut b = itoa::Buffer::new();
|
||||
buf.extend_from_slice(b.format(self.0).as_bytes());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fmt_json(&self, buf: &mut Vec<u8>) {
|
||||
if unlikely(self.0 == u16::MAX) {
|
||||
buf.extend_from_slice(b"null");
|
||||
} else {
|
||||
self.write_to(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
use std::ops::{Add, AddAssign, Div, Sub, SubAssign};
|
||||
|
||||
use derive_more::Deref;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{CheckedSub, Formattable, Pco, unlikely};
|
||||
|
||||
use super::StoredF32;
|
||||
|
||||
/// Signed basis points stored as i16.
|
||||
/// 1 bp = 0.0001. Range: -3.2767 to +3.2767.
|
||||
/// Use for signed bounded ratios (NUPL, net PnL ratios, etc.).
|
||||
/// `i16::MIN` is reserved as a NaN sentinel.
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Default,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Pco,
|
||||
JsonSchema,
|
||||
)]
|
||||
pub struct BasisPointsSigned16(i16);
|
||||
|
||||
impl BasisPointsSigned16 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
/// NaN sentinel — uses i16::MIN which is outside the documented range.
|
||||
pub const NAN: Self = Self(i16::MIN);
|
||||
|
||||
#[inline]
|
||||
pub const fn new(value: i16) -> Self {
|
||||
debug_assert!(value != i16::MIN, "i16::MIN is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn inner(self) -> i16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_nan(self) -> bool {
|
||||
self.0 == i16::MIN
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_negative(self) -> bool {
|
||||
self.0 < 0 && self.0 != i16::MIN
|
||||
}
|
||||
|
||||
/// Convert to f32: divide by 10000. Returns NaN for sentinel value.
|
||||
#[inline]
|
||||
pub fn to_f32(self) -> f32 {
|
||||
if unlikely(self.0 == i16::MIN) {
|
||||
f32::NAN
|
||||
} else {
|
||||
self.0 as f32 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn from(value: usize) -> Self {
|
||||
debug_assert!(
|
||||
value <= i16::MAX as usize,
|
||||
"usize out of BasisPointsSigned16 range: {value}"
|
||||
);
|
||||
Self(value as i16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i16> for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn from(value: i16) -> Self {
|
||||
debug_assert!(value != i16::MIN, "i16::MIN is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPointsSigned16> for i16 {
|
||||
#[inline]
|
||||
fn from(value: BasisPointsSigned16) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from float: multiply by 10000 and round.
|
||||
/// Input is in ratio form (e.g., -0.4523 for -45.23%).
|
||||
/// NaN/Inf → NaN sentinel.
|
||||
impl From<f64> for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn from(value: f64) -> Self {
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 10000.0)
|
||||
.round()
|
||||
.clamp(i16::MIN as f64 + 1.0, i16::MAX as f64);
|
||||
Self(scaled as i16)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPointsSigned16> for f64 {
|
||||
#[inline]
|
||||
fn from(value: BasisPointsSigned16) -> Self {
|
||||
if unlikely(value.0 == i16::MIN) {
|
||||
f64::NAN
|
||||
} else {
|
||||
value.0 as f64 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPointsSigned16> for StoredF32 {
|
||||
#[inline]
|
||||
fn from(value: BasisPointsSigned16) -> Self {
|
||||
StoredF32::from(value.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for BasisPointsSigned16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
if unlikely(self.0 == i16::MIN || rhs.0 == i16::MIN) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for BasisPointsSigned16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
if unlikely(self.0 == i16::MIN || rhs.0 == i16::MIN) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for BasisPointsSigned16 {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for BasisPointsSigned16 {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
if unlikely(self.0 == i16::MIN) {
|
||||
Self::NAN
|
||||
} else {
|
||||
debug_assert!(rhs <= i16::MAX as usize, "divisor out of i16 range: {rhs}");
|
||||
Self(self.0 / rhs as i16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for BasisPointsSigned16 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
if unlikely(self.0 == i16::MIN || rhs.0 == i16::MIN) {
|
||||
Some(Self::NAN)
|
||||
} else {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BasisPointsSigned16 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut buf = itoa::Buffer::new();
|
||||
let str = buf.format(self.0);
|
||||
f.write_str(str)
|
||||
}
|
||||
}
|
||||
|
||||
impl Formattable for BasisPointsSigned16 {
|
||||
#[inline(always)]
|
||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||
let mut b = itoa::Buffer::new();
|
||||
buf.extend_from_slice(b.format(self.0).as_bytes());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fmt_json(&self, buf: &mut Vec<u8>) {
|
||||
if unlikely(self.0 == i16::MIN) {
|
||||
buf.extend_from_slice(b"null");
|
||||
} else {
|
||||
self.write_to(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,6 @@ mod addr_mempool_stats;
|
||||
mod addr_stats;
|
||||
mod addr_validation;
|
||||
mod age;
|
||||
mod basis_points_16;
|
||||
mod basis_points_32;
|
||||
mod basis_points_signed_16;
|
||||
mod basis_points_signed_32;
|
||||
mod bitcoin;
|
||||
mod blk_metadata;
|
||||
mod blk_position;
|
||||
@@ -122,6 +118,10 @@ mod p2wpkh_bytes;
|
||||
mod p2wsh_addr_index;
|
||||
mod p2wsh_bytes;
|
||||
mod pagination;
|
||||
mod parts_per_million_32;
|
||||
mod parts_per_million_64;
|
||||
mod parts_per_million_signed_32;
|
||||
mod parts_per_million_signed_64;
|
||||
mod percentile;
|
||||
mod pool;
|
||||
mod pool_detail;
|
||||
@@ -213,10 +213,6 @@ pub use addr_mempool_stats::*;
|
||||
pub use addr_stats::*;
|
||||
pub use addr_validation::*;
|
||||
pub use age::*;
|
||||
pub use basis_points_16::*;
|
||||
pub use basis_points_32::*;
|
||||
pub use basis_points_signed_16::*;
|
||||
pub use basis_points_signed_32::*;
|
||||
pub use bitcoin::*;
|
||||
pub use blk_metadata::*;
|
||||
pub use blk_position::*;
|
||||
@@ -321,6 +317,10 @@ pub use p2wpkh_bytes::*;
|
||||
pub use p2wsh_addr_index::*;
|
||||
pub use p2wsh_bytes::*;
|
||||
pub use pagination::*;
|
||||
pub use parts_per_million_32::*;
|
||||
pub use parts_per_million_64::*;
|
||||
pub use parts_per_million_signed_32::*;
|
||||
pub use parts_per_million_signed_64::*;
|
||||
pub use percentile::*;
|
||||
pub use pool::*;
|
||||
pub use pool_detail::*;
|
||||
|
||||
+84
-58
@@ -1,4 +1,4 @@
|
||||
use std::ops::{Add, AddAssign, Div};
|
||||
use std::ops::{Add, AddAssign, Div, Sub};
|
||||
|
||||
use derive_more::Deref;
|
||||
use schemars::JsonSchema;
|
||||
@@ -7,9 +7,9 @@ use vecdb::{CheckedSub, Formattable, Pco, unlikely};
|
||||
|
||||
use super::StoredF32;
|
||||
|
||||
/// Unsigned basis points stored as u32.
|
||||
/// 1 bp = 0.0001. Range: 0–429,496.7295.
|
||||
/// Use for unbounded unsigned ratios (MVRV, NVT, SOPR, etc.).
|
||||
/// Unsigned parts per million stored as u32.
|
||||
/// One unit is 0.000001. Range: 0–4,294.967294.
|
||||
/// Use for precise bounded ratios and percentages.
|
||||
/// `u32::MAX` is reserved as a NaN sentinel.
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -27,11 +27,11 @@ use super::StoredF32;
|
||||
Pco,
|
||||
JsonSchema,
|
||||
)]
|
||||
pub struct BasisPoints32(u32);
|
||||
pub struct PartsPerMillion32(u32);
|
||||
|
||||
impl BasisPoints32 {
|
||||
impl PartsPerMillion32 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
/// NaN sentinel — uses u32::MAX which is outside the practical range.
|
||||
pub const ONE: Self = Self(1_000_000);
|
||||
pub const NAN: Self = Self(u32::MAX);
|
||||
|
||||
#[inline]
|
||||
@@ -50,29 +50,28 @@ impl BasisPoints32 {
|
||||
self.0 == u32::MAX
|
||||
}
|
||||
|
||||
/// Convert to f32: divide by 10000. Returns NaN for sentinel value.
|
||||
#[inline]
|
||||
pub fn to_f32(self) -> f32 {
|
||||
if unlikely(self.0 == u32::MAX) {
|
||||
f32::NAN
|
||||
} else {
|
||||
self.0 as f32 / 10000.0
|
||||
self.0 as f32 / 1_000_000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for BasisPoints32 {
|
||||
impl From<usize> for PartsPerMillion32 {
|
||||
#[inline]
|
||||
fn from(value: usize) -> Self {
|
||||
debug_assert!(
|
||||
value < u32::MAX as usize,
|
||||
"usize out of BasisPoints32 range: {value}"
|
||||
"usize out of PartsPerMillion32 range: {value}"
|
||||
);
|
||||
Self(value as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for BasisPoints32 {
|
||||
impl From<u32> for PartsPerMillion32 {
|
||||
#[inline]
|
||||
fn from(value: u32) -> Self {
|
||||
debug_assert!(value != u32::MAX, "u32::MAX is reserved as NaN sentinel");
|
||||
@@ -80,39 +79,14 @@ impl From<u32> for BasisPoints32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPoints32> for u32 {
|
||||
impl From<PartsPerMillion32> for u32 {
|
||||
#[inline]
|
||||
fn from(value: BasisPoints32) -> Self {
|
||||
fn from(value: PartsPerMillion32) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from float: multiply by 10000 and round.
|
||||
/// Input is in ratio form (e.g., 2.5 for MVRV of 2.5).
|
||||
/// NaN/Inf → NaN sentinel.
|
||||
impl From<f64> for BasisPoints32 {
|
||||
#[inline]
|
||||
fn from(value: f64) -> Self {
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 10000.0).round().clamp(0.0, u32::MAX as f64 - 1.0);
|
||||
Self(scaled as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPoints32> for f64 {
|
||||
#[inline]
|
||||
fn from(value: BasisPoints32) -> Self {
|
||||
if unlikely(value.0 == u32::MAX) {
|
||||
f64::NAN
|
||||
} else {
|
||||
value.0 as f64 / 10000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for BasisPoints32 {
|
||||
impl From<f32> for PartsPerMillion32 {
|
||||
#[inline]
|
||||
fn from(value: f32) -> Self {
|
||||
if unlikely(!value.is_finite()) {
|
||||
@@ -122,33 +96,54 @@ impl From<f32> for BasisPoints32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF32> for BasisPoints32 {
|
||||
impl From<StoredF32> for PartsPerMillion32 {
|
||||
#[inline]
|
||||
fn from(value: StoredF32) -> Self {
|
||||
Self::from(f64::from(*value))
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPoints32> for f32 {
|
||||
impl From<f64> for PartsPerMillion32 {
|
||||
#[inline]
|
||||
fn from(value: BasisPoints32) -> Self {
|
||||
fn from(value: f64) -> Self {
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 1_000_000.0)
|
||||
.round()
|
||||
.clamp(0.0, u32::MAX as f64 - 1.0);
|
||||
Self(scaled as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PartsPerMillion32> for f64 {
|
||||
#[inline]
|
||||
fn from(value: PartsPerMillion32) -> Self {
|
||||
if unlikely(value.0 == u32::MAX) {
|
||||
f32::NAN
|
||||
f64::NAN
|
||||
} else {
|
||||
value.0 as f32 / 10000.0
|
||||
value.0 as f64 / 1_000_000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BasisPoints32> for StoredF32 {
|
||||
impl From<PartsPerMillion32> for f32 {
|
||||
#[inline]
|
||||
fn from(value: BasisPoints32) -> Self {
|
||||
fn from(value: PartsPerMillion32) -> Self {
|
||||
value.to_f32()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PartsPerMillion32> for StoredF32 {
|
||||
#[inline]
|
||||
fn from(value: PartsPerMillion32) -> Self {
|
||||
StoredF32::from(value.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for BasisPoints32 {
|
||||
impl Add for PartsPerMillion32 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
if unlikely(self.0 == u32::MAX || rhs.0 == u32::MAX) {
|
||||
@@ -159,15 +154,29 @@ impl Add for BasisPoints32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for BasisPoints32 {
|
||||
impl Sub for PartsPerMillion32 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
if unlikely(self.0 == u32::MAX || rhs.0 == u32::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for PartsPerMillion32 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for BasisPoints32 {
|
||||
impl Div<usize> for PartsPerMillion32 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
if unlikely(self.0 == u32::MAX) {
|
||||
@@ -179,7 +188,7 @@ impl Div<usize> for BasisPoints32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for BasisPoints32 {
|
||||
impl CheckedSub for PartsPerMillion32 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
if unlikely(self.0 == u32::MAX || rhs.0 == u32::MAX) {
|
||||
Some(Self::NAN)
|
||||
@@ -189,19 +198,18 @@ impl CheckedSub for BasisPoints32 {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BasisPoints32 {
|
||||
impl std::fmt::Display for PartsPerMillion32 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut buf = itoa::Buffer::new();
|
||||
let str = buf.format(self.0);
|
||||
f.write_str(str)
|
||||
f.write_str(buf.format(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Formattable for BasisPoints32 {
|
||||
impl Formattable for PartsPerMillion32 {
|
||||
#[inline(always)]
|
||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||
let mut b = itoa::Buffer::new();
|
||||
buf.extend_from_slice(b.format(self.0).as_bytes());
|
||||
let mut value = itoa::Buffer::new();
|
||||
buf.extend_from_slice(value.format(self.0).as_bytes());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -213,3 +221,21 @@ impl Formattable for BasisPoints32 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conversions_and_sentinels() {
|
||||
assert_eq!(PartsPerMillion32::from(0.123_456_6).inner(), 123_457);
|
||||
assert_eq!(f64::from(PartsPerMillion32::ONE), 1.0);
|
||||
assert_eq!(PartsPerMillion32::from(-1.0), PartsPerMillion32::ZERO);
|
||||
assert_eq!(PartsPerMillion32::from(f64::MAX).inner(), u32::MAX - 1);
|
||||
assert!(PartsPerMillion32::from(f64::NAN).is_nan());
|
||||
|
||||
let mut json = Vec::new();
|
||||
PartsPerMillion32::NAN.fmt_json(&mut json);
|
||||
assert_eq!(json, b"null");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
use std::ops::{Add, AddAssign, Div, Sub};
|
||||
|
||||
use derive_more::Deref;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{CheckedSub, Formattable, Pco, unlikely};
|
||||
|
||||
use super::StoredF32;
|
||||
|
||||
/// Unsigned parts per million stored as u64.
|
||||
/// One unit is 0.000001. Range: 0–18,446,744,073,709.551614.
|
||||
/// Use for precise wide-range ratios.
|
||||
/// `u64::MAX` is reserved as a NaN sentinel.
|
||||
#[derive(
|
||||
Debug,
|
||||
Deref,
|
||||
Clone,
|
||||
Default,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Pco,
|
||||
JsonSchema,
|
||||
)]
|
||||
pub struct PartsPerMillion64(u64);
|
||||
|
||||
impl PartsPerMillion64 {
|
||||
pub const ZERO: Self = Self(0);
|
||||
pub const ONE: Self = Self(1_000_000);
|
||||
pub const NAN: Self = Self(u64::MAX);
|
||||
|
||||
#[inline]
|
||||
pub const fn new(value: u64) -> Self {
|
||||
debug_assert!(value != u64::MAX, "u64::MAX is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub const fn inner(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_nan(self) -> bool {
|
||||
self.0 == u64::MAX
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_f32(self) -> f32 {
|
||||
if unlikely(self.0 == u64::MAX) {
|
||||
f32::NAN
|
||||
} else {
|
||||
self.0 as f32 / 1_000_000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for PartsPerMillion64 {
|
||||
#[inline]
|
||||
fn from(value: usize) -> Self {
|
||||
debug_assert!(
|
||||
value < u64::MAX as usize,
|
||||
"usize out of PartsPerMillion64 range: {value}"
|
||||
);
|
||||
Self(value as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for PartsPerMillion64 {
|
||||
#[inline]
|
||||
fn from(value: u64) -> Self {
|
||||
debug_assert!(value != u64::MAX, "u64::MAX is reserved as NaN sentinel");
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PartsPerMillion64> for u64 {
|
||||
#[inline]
|
||||
fn from(value: PartsPerMillion64) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for PartsPerMillion64 {
|
||||
#[inline]
|
||||
fn from(value: f32) -> Self {
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
Self::from(value as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredF32> for PartsPerMillion64 {
|
||||
#[inline]
|
||||
fn from(value: StoredF32) -> Self {
|
||||
Self::from(*value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for PartsPerMillion64 {
|
||||
#[inline]
|
||||
fn from(value: f64) -> Self {
|
||||
if unlikely(!value.is_finite()) {
|
||||
return Self::NAN;
|
||||
}
|
||||
let scaled = (value * 1_000_000.0).round();
|
||||
if scaled <= 0.0 {
|
||||
Self::ZERO
|
||||
} else if scaled >= u64::MAX as f64 {
|
||||
Self(u64::MAX - 1)
|
||||
} else {
|
||||
Self(scaled as u64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PartsPerMillion64> for f64 {
|
||||
#[inline]
|
||||
fn from(value: PartsPerMillion64) -> Self {
|
||||
if unlikely(value.0 == u64::MAX) {
|
||||
f64::NAN
|
||||
} else {
|
||||
value.0 as f64 / 1_000_000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PartsPerMillion64> for f32 {
|
||||
#[inline]
|
||||
fn from(value: PartsPerMillion64) -> Self {
|
||||
value.to_f32()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PartsPerMillion64> for StoredF32 {
|
||||
#[inline]
|
||||
fn from(value: PartsPerMillion64) -> Self {
|
||||
StoredF32::from(value.to_f32())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for PartsPerMillion64 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
if unlikely(self.0 == u64::MAX || rhs.0 == u64::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for PartsPerMillion64 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
if unlikely(self.0 == u64::MAX || rhs.0 == u64::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for PartsPerMillion64 {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for PartsPerMillion64 {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
if unlikely(self.0 == u64::MAX) {
|
||||
Self::NAN
|
||||
} else {
|
||||
debug_assert!(rhs <= u64::MAX as usize, "divisor out of u64 range: {rhs}");
|
||||
Self(self.0 / rhs as u64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CheckedSub for PartsPerMillion64 {
|
||||
fn checked_sub(self, rhs: Self) -> Option<Self> {
|
||||
if unlikely(self.0 == u64::MAX || rhs.0 == u64::MAX) {
|
||||
Some(Self::NAN)
|
||||
} else {
|
||||
self.0.checked_sub(rhs.0).map(Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PartsPerMillion64 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut buf = itoa::Buffer::new();
|
||||
f.write_str(buf.format(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Formattable for PartsPerMillion64 {
|
||||
#[inline(always)]
|
||||
fn write_to(&self, buf: &mut Vec<u8>) {
|
||||
let mut value = itoa::Buffer::new();
|
||||
buf.extend_from_slice(value.format(self.0).as_bytes());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn fmt_json(&self, buf: &mut Vec<u8>) {
|
||||
if unlikely(self.0 == u64::MAX) {
|
||||
buf.extend_from_slice(b"null");
|
||||
} else {
|
||||
self.write_to(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conversions_and_sentinels() {
|
||||
assert_eq!(PartsPerMillion64::from(0.123_456_6).inner(), 123_457);
|
||||
assert_eq!(f64::from(PartsPerMillion64::ONE), 1.0);
|
||||
assert_eq!(PartsPerMillion64::from(-1.0), PartsPerMillion64::ZERO);
|
||||
assert_eq!(PartsPerMillion64::from(f64::MAX).inner(), u64::MAX - 1);
|
||||
assert!(PartsPerMillion64::from(f64::INFINITY).is_nan());
|
||||
|
||||
let mut json = Vec::new();
|
||||
PartsPerMillion64::NAN.fmt_json(&mut json);
|
||||
assert_eq!(json, b"null");
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user