mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-08 14:11:56 -07:00
global: snapshot
This commit is contained in:
Generated
+16
-22
@@ -2045,9 +2045,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.14"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
|
||||
checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -2201,9 +2201,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
|
||||
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
@@ -2546,8 +2546,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rawdb"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "912a9c6f76a5f141057139d510b969b082ff74f39a72a1c27178d8e1eeec95dc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
@@ -2916,9 +2914,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.0.4"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
|
||||
checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
@@ -3182,9 +3180,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.0.7+spec-1.1.0"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd28d57d8a6f6e458bc0b8784f8fdcc4b99a437936056fa122cb234f18656a96"
|
||||
checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
@@ -3197,27 +3195,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "1.0.1+spec-1.1.0"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9"
|
||||
checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.10+spec-1.1.0"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420"
|
||||
checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.7+spec-1.1.0"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d"
|
||||
checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed"
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
@@ -3352,9 +3350,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
checksum = "da36089a805484bcccfffe0739803392c8298778a2d2f09febf76fac5ad9025b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@@ -3440,8 +3438,6 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23"
|
||||
[[package]]
|
||||
name = "vecdb"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f89be182f86511ee28832cc04039d818564b88c63b14093fcf1871c732c0dd"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
@@ -3463,8 +3459,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vecdb_derive"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42915a5ca404d941e3e6d024f794403c481e5aeb96b1867d12d1f1e972d1433f"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
|
||||
+2
-2
@@ -87,8 +87,8 @@ tower-http = { version = "0.6.8", features = ["catch-panic", "compression-br", "
|
||||
tower-layer = "0.3"
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
ureq = { version = "3.3.0", features = ["json"] }
|
||||
vecdb = { version = "0.7.2", features = ["derive", "serde_json", "pco", "schemars"] }
|
||||
# vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] }
|
||||
# vecdb = { version = "0.7.2", features = ["derive", "serde_json", "pco", "schemars"] }
|
||||
vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] }
|
||||
|
||||
[workspace.metadata.release]
|
||||
shared-version = true
|
||||
|
||||
@@ -26,7 +26,7 @@ owo-colors = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
toml = "1.0.7"
|
||||
toml = "1.1.0"
|
||||
vecdb = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
|
||||
+289
-239
@@ -1247,7 +1247,7 @@ impl GrossInvestedInvestorLossNetNuplProfitSentimentPattern2 {
|
||||
pub struct BpsCentsPercentilesRatioSatsSmaStdUsdPattern {
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
pub cents: SeriesPattern1<Cents>,
|
||||
pub percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub ratio: SeriesPattern1<StoredF32>,
|
||||
pub sats: SeriesPattern1<SatsFract>,
|
||||
pub sma: _1m1w1y2y4yAllPattern,
|
||||
@@ -1255,6 +1255,34 @@ pub struct BpsCentsPercentilesRatioSatsSmaStdUsdPattern {
|
||||
pub usd: SeriesPattern1<Dollars>,
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern {
|
||||
pub pct0_5: BpsPriceRatioPattern,
|
||||
pub pct1: BpsPriceRatioPattern,
|
||||
pub pct2: BpsPriceRatioPattern,
|
||||
pub pct5: BpsPriceRatioPattern,
|
||||
pub pct95: BpsPriceRatioPattern,
|
||||
pub pct98: BpsPriceRatioPattern,
|
||||
pub pct99: BpsPriceRatioPattern,
|
||||
pub pct99_5: BpsPriceRatioPattern,
|
||||
}
|
||||
|
||||
impl Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern {
|
||||
/// Create a new pattern node with accumulated series name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
pct0_5: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct0_5".to_string()),
|
||||
pct1: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct1".to_string()),
|
||||
pct2: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct2".to_string()),
|
||||
pct5: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct5".to_string()),
|
||||
pct95: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct95".to_string()),
|
||||
pct98: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct98".to_string()),
|
||||
pct99: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct99".to_string()),
|
||||
pct99_5: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct99_5".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _10y2y3y4y5y6y8yPattern {
|
||||
pub _10y: BpsPercentRatioPattern,
|
||||
@@ -1487,7 +1515,7 @@ impl AverageBlockCumulativeInSumPattern {
|
||||
pub struct BpsCentsPercentilesRatioSatsUsdPattern {
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
pub cents: SeriesPattern1<Cents>,
|
||||
pub percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub ratio: SeriesPattern1<StoredF32>,
|
||||
pub sats: SeriesPattern1<SatsFract>,
|
||||
pub usd: SeriesPattern1<Dollars>,
|
||||
@@ -1499,7 +1527,7 @@ impl BpsCentsPercentilesRatioSatsUsdPattern {
|
||||
Self {
|
||||
bps: SeriesPattern1::new(client.clone(), _m(&acc, "ratio_bps")),
|
||||
cents: SeriesPattern1::new(client.clone(), _m(&acc, "cents")),
|
||||
percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), acc.clone()),
|
||||
percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), acc.clone()),
|
||||
ratio: SeriesPattern1::new(client.clone(), _m(&acc, "ratio")),
|
||||
sats: SeriesPattern1::new(client.clone(), _m(&acc, "sats")),
|
||||
usd: SeriesPattern1::new(client.clone(), acc.clone()),
|
||||
@@ -1603,30 +1631,6 @@ impl DeltaHalfInToTotalPattern2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct Pct1Pct2Pct5Pct95Pct98Pct99Pattern {
|
||||
pub pct1: BpsPriceRatioPattern,
|
||||
pub pct2: BpsPriceRatioPattern,
|
||||
pub pct5: BpsPriceRatioPattern,
|
||||
pub pct95: BpsPriceRatioPattern,
|
||||
pub pct98: BpsPriceRatioPattern,
|
||||
pub pct99: BpsPriceRatioPattern,
|
||||
}
|
||||
|
||||
impl Pct1Pct2Pct5Pct95Pct98Pct99Pattern {
|
||||
/// Create a new pattern node with accumulated series name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
pct1: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct1".to_string()),
|
||||
pct2: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct2".to_string()),
|
||||
pct5: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct5".to_string()),
|
||||
pct95: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct95".to_string()),
|
||||
pct98: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct98".to_string()),
|
||||
pct99: BpsPriceRatioPattern::new(client.clone(), acc.clone(), "pct99".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _1m1w1y24hBlockPattern {
|
||||
pub _1m: SeriesPattern1<StoredF32>,
|
||||
@@ -3126,6 +3130,7 @@ pub struct SeriesTree {
|
||||
pub constants: SeriesTree_Constants,
|
||||
pub indexes: SeriesTree_Indexes,
|
||||
pub indicators: SeriesTree_Indicators,
|
||||
pub investing: SeriesTree_Investing,
|
||||
pub market: SeriesTree_Market,
|
||||
pub pools: SeriesTree_Pools,
|
||||
pub prices: SeriesTree_Prices,
|
||||
@@ -3148,6 +3153,7 @@ impl SeriesTree {
|
||||
constants: SeriesTree_Constants::new(client.clone(), format!("{base_path}_constants")),
|
||||
indexes: SeriesTree_Indexes::new(client.clone(), format!("{base_path}_indexes")),
|
||||
indicators: SeriesTree_Indicators::new(client.clone(), format!("{base_path}_indicators")),
|
||||
investing: SeriesTree_Investing::new(client.clone(), format!("{base_path}_investing")),
|
||||
market: SeriesTree_Market::new(client.clone(), format!("{base_path}_market")),
|
||||
pools: SeriesTree_Pools::new(client.clone(), format!("{base_path}_pools")),
|
||||
prices: SeriesTree_Prices::new(client.clone(), format!("{base_path}_prices")),
|
||||
@@ -3215,17 +3221,13 @@ impl SeriesTree_Blocks_Difficulty {
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Blocks_Time {
|
||||
pub timestamp: SeriesPattern1<Timestamp>,
|
||||
pub date: SeriesPattern18<Date>,
|
||||
pub timestamp_monotonic: SeriesPattern18<Timestamp>,
|
||||
pub timestamp: SeriesPattern18<Timestamp>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Blocks_Time {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
timestamp: SeriesPattern1::new(client.clone(), "timestamp".to_string()),
|
||||
date: SeriesPattern18::new(client.clone(), "date".to_string()),
|
||||
timestamp_monotonic: SeriesPattern18::new(client.clone(), "timestamp_monotonic".to_string()),
|
||||
timestamp: SeriesPattern18::new(client.clone(), "timestamp".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4562,6 +4564,7 @@ pub struct SeriesTree_Indexes {
|
||||
pub tx_index: SeriesTree_Indexes_TxIndex,
|
||||
pub txin_index: SeriesTree_Indexes_TxinIndex,
|
||||
pub txout_index: SeriesTree_Indexes_TxoutIndex,
|
||||
pub timestamp: SeriesTree_Indexes_Timestamp,
|
||||
}
|
||||
|
||||
impl SeriesTree_Indexes {
|
||||
@@ -4587,6 +4590,7 @@ impl SeriesTree_Indexes {
|
||||
tx_index: SeriesTree_Indexes_TxIndex::new(client.clone(), format!("{base_path}_tx_index")),
|
||||
txin_index: SeriesTree_Indexes_TxinIndex::new(client.clone(), format!("{base_path}_txin_index")),
|
||||
txout_index: SeriesTree_Indexes_TxoutIndex::new(client.clone(), format!("{base_path}_txout_index")),
|
||||
timestamp: SeriesTree_Indexes_Timestamp::new(client.clone(), format!("{base_path}_timestamp")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5129,6 +5133,21 @@ impl SeriesTree_Indexes_TxoutIndex {
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Indexes_Timestamp {
|
||||
pub monotonic: SeriesPattern18<Timestamp>,
|
||||
pub resolutions: SeriesPattern2<Timestamp>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Indexes_Timestamp {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
monotonic: SeriesPattern18::new(client.clone(), "timestamp_monotonic".to_string()),
|
||||
resolutions: SeriesPattern2::new(client.clone(), "timestamp".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Indicators {
|
||||
pub puell_multiple: BpsRatioPattern2,
|
||||
@@ -5141,6 +5160,7 @@ pub struct SeriesTree_Indicators {
|
||||
pub dormancy: SeriesTree_Indicators_Dormancy,
|
||||
pub stock_to_flow: SeriesPattern1<StoredF32>,
|
||||
pub seller_exhaustion: SeriesPattern1<StoredF32>,
|
||||
pub thermometer: SeriesTree_Indicators_Thermometer,
|
||||
}
|
||||
|
||||
impl SeriesTree_Indicators {
|
||||
@@ -5156,6 +5176,7 @@ impl SeriesTree_Indicators {
|
||||
dormancy: SeriesTree_Indicators_Dormancy::new(client.clone(), format!("{base_path}_dormancy")),
|
||||
stock_to_flow: SeriesPattern1::new(client.clone(), "stock_to_flow".to_string()),
|
||||
seller_exhaustion: SeriesPattern1::new(client.clone(), "seller_exhaustion".to_string()),
|
||||
thermometer: SeriesTree_Indicators_Thermometer::new(client.clone(), format!("{base_path}_thermometer")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5175,6 +5196,234 @@ impl SeriesTree_Indicators_Dormancy {
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Indicators_Thermometer {
|
||||
pub pct0_5: CentsSatsUsdPattern,
|
||||
pub pct1: CentsSatsUsdPattern,
|
||||
pub pct2: CentsSatsUsdPattern,
|
||||
pub pct5: CentsSatsUsdPattern,
|
||||
pub pct95: CentsSatsUsdPattern,
|
||||
pub pct98: CentsSatsUsdPattern,
|
||||
pub pct99: CentsSatsUsdPattern,
|
||||
pub pct99_5: CentsSatsUsdPattern,
|
||||
pub zone: SeriesPattern1<StoredI8>,
|
||||
pub score: SeriesPattern1<StoredI8>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Indicators_Thermometer {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
pct0_5: CentsSatsUsdPattern::new(client.clone(), "thermometer_pct0_5".to_string()),
|
||||
pct1: CentsSatsUsdPattern::new(client.clone(), "thermometer_pct01".to_string()),
|
||||
pct2: CentsSatsUsdPattern::new(client.clone(), "thermometer_pct02".to_string()),
|
||||
pct5: CentsSatsUsdPattern::new(client.clone(), "thermometer_pct05".to_string()),
|
||||
pct95: CentsSatsUsdPattern::new(client.clone(), "thermometer_pct95".to_string()),
|
||||
pct98: CentsSatsUsdPattern::new(client.clone(), "thermometer_pct98".to_string()),
|
||||
pct99: CentsSatsUsdPattern::new(client.clone(), "thermometer_pct99".to_string()),
|
||||
pct99_5: CentsSatsUsdPattern::new(client.clone(), "thermometer_pct99_5".to_string()),
|
||||
zone: SeriesPattern1::new(client.clone(), "thermometer_zone".to_string()),
|
||||
score: SeriesPattern1::new(client.clone(), "thermometer_score".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Investing {
|
||||
pub sats_per_day: SeriesPattern18<Sats>,
|
||||
pub period: SeriesTree_Investing_Period,
|
||||
pub class: SeriesTree_Investing_Class,
|
||||
}
|
||||
|
||||
impl SeriesTree_Investing {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sats_per_day: SeriesPattern18::new(client.clone(), "dca_sats_per_day".to_string()),
|
||||
period: SeriesTree_Investing_Period::new(client.clone(), format!("{base_path}_period")),
|
||||
class: SeriesTree_Investing_Class::new(client.clone(), format!("{base_path}_class")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Investing_Period {
|
||||
pub stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3,
|
||||
pub cost_basis: SeriesTree_Investing_Period_CostBasis,
|
||||
pub return_: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2,
|
||||
pub cagr: _10y2y3y4y5y6y8yPattern,
|
||||
pub lump_sum_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3,
|
||||
pub lump_sum_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2,
|
||||
}
|
||||
|
||||
impl SeriesTree_Investing_Period {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3::new(client.clone(), "dca_stack".to_string()),
|
||||
cost_basis: SeriesTree_Investing_Period_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")),
|
||||
return_: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2::new(client.clone(), "dca_return".to_string()),
|
||||
cagr: _10y2y3y4y5y6y8yPattern::new(client.clone(), "dca_cagr".to_string()),
|
||||
lump_sum_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3::new(client.clone(), "lump_sum_stack".to_string()),
|
||||
lump_sum_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2::new(client.clone(), "lump_sum_return".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Investing_Period_CostBasis {
|
||||
pub _1w: CentsSatsUsdPattern,
|
||||
pub _1m: CentsSatsUsdPattern,
|
||||
pub _3m: CentsSatsUsdPattern,
|
||||
pub _6m: CentsSatsUsdPattern,
|
||||
pub _1y: CentsSatsUsdPattern,
|
||||
pub _2y: CentsSatsUsdPattern,
|
||||
pub _3y: CentsSatsUsdPattern,
|
||||
pub _4y: CentsSatsUsdPattern,
|
||||
pub _5y: CentsSatsUsdPattern,
|
||||
pub _6y: CentsSatsUsdPattern,
|
||||
pub _8y: CentsSatsUsdPattern,
|
||||
pub _10y: CentsSatsUsdPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Investing_Period_CostBasis {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
_1w: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_1w".to_string()),
|
||||
_1m: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_1m".to_string()),
|
||||
_3m: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_3m".to_string()),
|
||||
_6m: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_6m".to_string()),
|
||||
_1y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_1y".to_string()),
|
||||
_2y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_2y".to_string()),
|
||||
_3y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_3y".to_string()),
|
||||
_4y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_4y".to_string()),
|
||||
_5y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_5y".to_string()),
|
||||
_6y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_6y".to_string()),
|
||||
_8y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_8y".to_string()),
|
||||
_10y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_10y".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Investing_Class {
|
||||
pub stack: SeriesTree_Investing_Class_Stack,
|
||||
pub cost_basis: SeriesTree_Investing_Class_CostBasis,
|
||||
pub return_: SeriesTree_Investing_Class_Return,
|
||||
}
|
||||
|
||||
impl SeriesTree_Investing_Class {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
stack: SeriesTree_Investing_Class_Stack::new(client.clone(), format!("{base_path}_stack")),
|
||||
cost_basis: SeriesTree_Investing_Class_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")),
|
||||
return_: SeriesTree_Investing_Class_Return::new(client.clone(), format!("{base_path}_return")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Investing_Class_Stack {
|
||||
pub from_2015: BtcCentsSatsUsdPattern3,
|
||||
pub from_2016: BtcCentsSatsUsdPattern3,
|
||||
pub from_2017: BtcCentsSatsUsdPattern3,
|
||||
pub from_2018: BtcCentsSatsUsdPattern3,
|
||||
pub from_2019: BtcCentsSatsUsdPattern3,
|
||||
pub from_2020: BtcCentsSatsUsdPattern3,
|
||||
pub from_2021: BtcCentsSatsUsdPattern3,
|
||||
pub from_2022: BtcCentsSatsUsdPattern3,
|
||||
pub from_2023: BtcCentsSatsUsdPattern3,
|
||||
pub from_2024: BtcCentsSatsUsdPattern3,
|
||||
pub from_2025: BtcCentsSatsUsdPattern3,
|
||||
pub from_2026: BtcCentsSatsUsdPattern3,
|
||||
}
|
||||
|
||||
impl SeriesTree_Investing_Class_Stack {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
from_2015: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2015".to_string()),
|
||||
from_2016: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2016".to_string()),
|
||||
from_2017: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2017".to_string()),
|
||||
from_2018: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2018".to_string()),
|
||||
from_2019: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2019".to_string()),
|
||||
from_2020: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2020".to_string()),
|
||||
from_2021: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2021".to_string()),
|
||||
from_2022: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2022".to_string()),
|
||||
from_2023: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2023".to_string()),
|
||||
from_2024: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2024".to_string()),
|
||||
from_2025: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2025".to_string()),
|
||||
from_2026: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2026".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Investing_Class_CostBasis {
|
||||
pub from_2015: CentsSatsUsdPattern,
|
||||
pub from_2016: CentsSatsUsdPattern,
|
||||
pub from_2017: CentsSatsUsdPattern,
|
||||
pub from_2018: CentsSatsUsdPattern,
|
||||
pub from_2019: CentsSatsUsdPattern,
|
||||
pub from_2020: CentsSatsUsdPattern,
|
||||
pub from_2021: CentsSatsUsdPattern,
|
||||
pub from_2022: CentsSatsUsdPattern,
|
||||
pub from_2023: CentsSatsUsdPattern,
|
||||
pub from_2024: CentsSatsUsdPattern,
|
||||
pub from_2025: CentsSatsUsdPattern,
|
||||
pub from_2026: CentsSatsUsdPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Investing_Class_CostBasis {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
from_2015: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2015".to_string()),
|
||||
from_2016: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2016".to_string()),
|
||||
from_2017: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2017".to_string()),
|
||||
from_2018: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2018".to_string()),
|
||||
from_2019: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2019".to_string()),
|
||||
from_2020: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2020".to_string()),
|
||||
from_2021: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2021".to_string()),
|
||||
from_2022: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2022".to_string()),
|
||||
from_2023: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2023".to_string()),
|
||||
from_2024: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2024".to_string()),
|
||||
from_2025: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2025".to_string()),
|
||||
from_2026: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2026".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Investing_Class_Return {
|
||||
pub from_2015: BpsPercentRatioPattern,
|
||||
pub from_2016: BpsPercentRatioPattern,
|
||||
pub from_2017: BpsPercentRatioPattern,
|
||||
pub from_2018: BpsPercentRatioPattern,
|
||||
pub from_2019: BpsPercentRatioPattern,
|
||||
pub from_2020: BpsPercentRatioPattern,
|
||||
pub from_2021: BpsPercentRatioPattern,
|
||||
pub from_2022: BpsPercentRatioPattern,
|
||||
pub from_2023: BpsPercentRatioPattern,
|
||||
pub from_2024: BpsPercentRatioPattern,
|
||||
pub from_2025: BpsPercentRatioPattern,
|
||||
pub from_2026: BpsPercentRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Investing_Class_Return {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
from_2015: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2015".to_string()),
|
||||
from_2016: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2016".to_string()),
|
||||
from_2017: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2017".to_string()),
|
||||
from_2018: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2018".to_string()),
|
||||
from_2019: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2019".to_string()),
|
||||
from_2020: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2020".to_string()),
|
||||
from_2021: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2021".to_string()),
|
||||
from_2022: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2022".to_string()),
|
||||
from_2023: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2023".to_string()),
|
||||
from_2024: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2024".to_string()),
|
||||
from_2025: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2025".to_string()),
|
||||
from_2026: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2026".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market {
|
||||
pub ath: SeriesTree_Market_Ath,
|
||||
@@ -5183,7 +5432,6 @@ pub struct SeriesTree_Market {
|
||||
pub volatility: _1m1w1y24hPattern<StoredF32>,
|
||||
pub range: SeriesTree_Market_Range,
|
||||
pub moving_average: SeriesTree_Market_MovingAverage,
|
||||
pub dca: SeriesTree_Market_Dca,
|
||||
pub technical: SeriesTree_Market_Technical,
|
||||
}
|
||||
|
||||
@@ -5196,7 +5444,6 @@ impl SeriesTree_Market {
|
||||
volatility: _1m1w1y24hPattern::new(client.clone(), "price_volatility".to_string()),
|
||||
range: SeriesTree_Market_Range::new(client.clone(), format!("{base_path}_range")),
|
||||
moving_average: SeriesTree_Market_MovingAverage::new(client.clone(), format!("{base_path}_moving_average")),
|
||||
dca: SeriesTree_Market_Dca::new(client.clone(), format!("{base_path}_dca")),
|
||||
technical: SeriesTree_Market_Technical::new(client.clone(), format!("{base_path}_technical")),
|
||||
}
|
||||
}
|
||||
@@ -5565,203 +5812,6 @@ impl SeriesTree_Market_MovingAverage_Ema {
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market_Dca {
|
||||
pub sats_per_day: SeriesPattern18<Sats>,
|
||||
pub period: SeriesTree_Market_Dca_Period,
|
||||
pub class: SeriesTree_Market_Dca_Class,
|
||||
}
|
||||
|
||||
impl SeriesTree_Market_Dca {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
sats_per_day: SeriesPattern18::new(client.clone(), "dca_sats_per_day".to_string()),
|
||||
period: SeriesTree_Market_Dca_Period::new(client.clone(), format!("{base_path}_period")),
|
||||
class: SeriesTree_Market_Dca_Class::new(client.clone(), format!("{base_path}_class")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market_Dca_Period {
|
||||
pub stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3,
|
||||
pub cost_basis: SeriesTree_Market_Dca_Period_CostBasis,
|
||||
pub return_: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2,
|
||||
pub cagr: _10y2y3y4y5y6y8yPattern,
|
||||
pub lump_sum_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3,
|
||||
pub lump_sum_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2,
|
||||
}
|
||||
|
||||
impl SeriesTree_Market_Dca_Period {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3::new(client.clone(), "dca_stack".to_string()),
|
||||
cost_basis: SeriesTree_Market_Dca_Period_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")),
|
||||
return_: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2::new(client.clone(), "dca_return".to_string()),
|
||||
cagr: _10y2y3y4y5y6y8yPattern::new(client.clone(), "dca_cagr".to_string()),
|
||||
lump_sum_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3::new(client.clone(), "lump_sum_stack".to_string()),
|
||||
lump_sum_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2::new(client.clone(), "lump_sum_return".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market_Dca_Period_CostBasis {
|
||||
pub _1w: CentsSatsUsdPattern,
|
||||
pub _1m: CentsSatsUsdPattern,
|
||||
pub _3m: CentsSatsUsdPattern,
|
||||
pub _6m: CentsSatsUsdPattern,
|
||||
pub _1y: CentsSatsUsdPattern,
|
||||
pub _2y: CentsSatsUsdPattern,
|
||||
pub _3y: CentsSatsUsdPattern,
|
||||
pub _4y: CentsSatsUsdPattern,
|
||||
pub _5y: CentsSatsUsdPattern,
|
||||
pub _6y: CentsSatsUsdPattern,
|
||||
pub _8y: CentsSatsUsdPattern,
|
||||
pub _10y: CentsSatsUsdPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Market_Dca_Period_CostBasis {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
_1w: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_1w".to_string()),
|
||||
_1m: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_1m".to_string()),
|
||||
_3m: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_3m".to_string()),
|
||||
_6m: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_6m".to_string()),
|
||||
_1y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_1y".to_string()),
|
||||
_2y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_2y".to_string()),
|
||||
_3y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_3y".to_string()),
|
||||
_4y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_4y".to_string()),
|
||||
_5y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_5y".to_string()),
|
||||
_6y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_6y".to_string()),
|
||||
_8y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_8y".to_string()),
|
||||
_10y: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_10y".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market_Dca_Class {
|
||||
pub stack: SeriesTree_Market_Dca_Class_Stack,
|
||||
pub cost_basis: SeriesTree_Market_Dca_Class_CostBasis,
|
||||
pub return_: SeriesTree_Market_Dca_Class_Return,
|
||||
}
|
||||
|
||||
impl SeriesTree_Market_Dca_Class {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
stack: SeriesTree_Market_Dca_Class_Stack::new(client.clone(), format!("{base_path}_stack")),
|
||||
cost_basis: SeriesTree_Market_Dca_Class_CostBasis::new(client.clone(), format!("{base_path}_cost_basis")),
|
||||
return_: SeriesTree_Market_Dca_Class_Return::new(client.clone(), format!("{base_path}_return")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market_Dca_Class_Stack {
|
||||
pub from_2015: BtcCentsSatsUsdPattern3,
|
||||
pub from_2016: BtcCentsSatsUsdPattern3,
|
||||
pub from_2017: BtcCentsSatsUsdPattern3,
|
||||
pub from_2018: BtcCentsSatsUsdPattern3,
|
||||
pub from_2019: BtcCentsSatsUsdPattern3,
|
||||
pub from_2020: BtcCentsSatsUsdPattern3,
|
||||
pub from_2021: BtcCentsSatsUsdPattern3,
|
||||
pub from_2022: BtcCentsSatsUsdPattern3,
|
||||
pub from_2023: BtcCentsSatsUsdPattern3,
|
||||
pub from_2024: BtcCentsSatsUsdPattern3,
|
||||
pub from_2025: BtcCentsSatsUsdPattern3,
|
||||
pub from_2026: BtcCentsSatsUsdPattern3,
|
||||
}
|
||||
|
||||
impl SeriesTree_Market_Dca_Class_Stack {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
from_2015: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2015".to_string()),
|
||||
from_2016: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2016".to_string()),
|
||||
from_2017: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2017".to_string()),
|
||||
from_2018: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2018".to_string()),
|
||||
from_2019: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2019".to_string()),
|
||||
from_2020: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2020".to_string()),
|
||||
from_2021: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2021".to_string()),
|
||||
from_2022: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2022".to_string()),
|
||||
from_2023: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2023".to_string()),
|
||||
from_2024: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2024".to_string()),
|
||||
from_2025: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2025".to_string()),
|
||||
from_2026: BtcCentsSatsUsdPattern3::new(client.clone(), "dca_stack_from_2026".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market_Dca_Class_CostBasis {
|
||||
pub from_2015: CentsSatsUsdPattern,
|
||||
pub from_2016: CentsSatsUsdPattern,
|
||||
pub from_2017: CentsSatsUsdPattern,
|
||||
pub from_2018: CentsSatsUsdPattern,
|
||||
pub from_2019: CentsSatsUsdPattern,
|
||||
pub from_2020: CentsSatsUsdPattern,
|
||||
pub from_2021: CentsSatsUsdPattern,
|
||||
pub from_2022: CentsSatsUsdPattern,
|
||||
pub from_2023: CentsSatsUsdPattern,
|
||||
pub from_2024: CentsSatsUsdPattern,
|
||||
pub from_2025: CentsSatsUsdPattern,
|
||||
pub from_2026: CentsSatsUsdPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Market_Dca_Class_CostBasis {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
from_2015: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2015".to_string()),
|
||||
from_2016: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2016".to_string()),
|
||||
from_2017: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2017".to_string()),
|
||||
from_2018: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2018".to_string()),
|
||||
from_2019: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2019".to_string()),
|
||||
from_2020: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2020".to_string()),
|
||||
from_2021: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2021".to_string()),
|
||||
from_2022: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2022".to_string()),
|
||||
from_2023: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2023".to_string()),
|
||||
from_2024: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2024".to_string()),
|
||||
from_2025: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2025".to_string()),
|
||||
from_2026: CentsSatsUsdPattern::new(client.clone(), "dca_cost_basis_from_2026".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market_Dca_Class_Return {
|
||||
pub from_2015: BpsPercentRatioPattern,
|
||||
pub from_2016: BpsPercentRatioPattern,
|
||||
pub from_2017: BpsPercentRatioPattern,
|
||||
pub from_2018: BpsPercentRatioPattern,
|
||||
pub from_2019: BpsPercentRatioPattern,
|
||||
pub from_2020: BpsPercentRatioPattern,
|
||||
pub from_2021: BpsPercentRatioPattern,
|
||||
pub from_2022: BpsPercentRatioPattern,
|
||||
pub from_2023: BpsPercentRatioPattern,
|
||||
pub from_2024: BpsPercentRatioPattern,
|
||||
pub from_2025: BpsPercentRatioPattern,
|
||||
pub from_2026: BpsPercentRatioPattern,
|
||||
}
|
||||
|
||||
impl SeriesTree_Market_Dca_Class_Return {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
from_2015: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2015".to_string()),
|
||||
from_2016: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2016".to_string()),
|
||||
from_2017: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2017".to_string()),
|
||||
from_2018: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2018".to_string()),
|
||||
from_2019: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2019".to_string()),
|
||||
from_2020: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2020".to_string()),
|
||||
from_2021: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2021".to_string()),
|
||||
from_2022: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2022".to_string()),
|
||||
from_2023: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2023".to_string()),
|
||||
from_2024: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2024".to_string()),
|
||||
from_2025: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2025".to_string()),
|
||||
from_2026: BpsPercentRatioPattern::new(client.clone(), "dca_return_from_2026".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Market_Technical {
|
||||
pub rsi: SeriesTree_Market_Technical_Rsi,
|
||||
@@ -6527,7 +6577,7 @@ pub struct SeriesTree_Cohorts_Utxo_All_Realized_Price {
|
||||
pub sats: SeriesPattern1<SatsFract>,
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
pub ratio: SeriesPattern1<StoredF32>,
|
||||
pub percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub sma: _1m1w1y2y4yAllPattern,
|
||||
pub std_dev: SeriesTree_Cohorts_Utxo_All_Realized_Price_StdDev,
|
||||
}
|
||||
@@ -6540,7 +6590,7 @@ impl SeriesTree_Cohorts_Utxo_All_Realized_Price {
|
||||
sats: SeriesPattern1::new(client.clone(), "realized_price_sats".to_string()),
|
||||
bps: SeriesPattern1::new(client.clone(), "realized_price_ratio_bps".to_string()),
|
||||
ratio: SeriesPattern1::new(client.clone(), "realized_price_ratio".to_string()),
|
||||
percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), "realized_price".to_string()),
|
||||
percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), "realized_price".to_string()),
|
||||
sma: _1m1w1y2y4yAllPattern::new(client.clone(), "realized_price_ratio_sma".to_string()),
|
||||
std_dev: SeriesTree_Cohorts_Utxo_All_Realized_Price_StdDev::new(client.clone(), format!("{base_path}_std_dev")),
|
||||
}
|
||||
@@ -6957,7 +7007,7 @@ pub struct SeriesTree_Cohorts_Utxo_Sth_Realized_Price {
|
||||
pub sats: SeriesPattern1<SatsFract>,
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
pub ratio: SeriesPattern1<StoredF32>,
|
||||
pub percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub sma: _1m1w1y2y4yAllPattern,
|
||||
pub std_dev: SeriesTree_Cohorts_Utxo_Sth_Realized_Price_StdDev,
|
||||
}
|
||||
@@ -6970,7 +7020,7 @@ impl SeriesTree_Cohorts_Utxo_Sth_Realized_Price {
|
||||
sats: SeriesPattern1::new(client.clone(), "sth_realized_price_sats".to_string()),
|
||||
bps: SeriesPattern1::new(client.clone(), "sth_realized_price_ratio_bps".to_string()),
|
||||
ratio: SeriesPattern1::new(client.clone(), "sth_realized_price_ratio".to_string()),
|
||||
percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), "sth_realized_price".to_string()),
|
||||
percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), "sth_realized_price".to_string()),
|
||||
sma: _1m1w1y2y4yAllPattern::new(client.clone(), "sth_realized_price_ratio_sma".to_string()),
|
||||
std_dev: SeriesTree_Cohorts_Utxo_Sth_Realized_Price_StdDev::new(client.clone(), format!("{base_path}_std_dev")),
|
||||
}
|
||||
@@ -7225,7 +7275,7 @@ pub struct SeriesTree_Cohorts_Utxo_Lth_Realized_Price {
|
||||
pub sats: SeriesPattern1<SatsFract>,
|
||||
pub bps: SeriesPattern1<BasisPoints32>,
|
||||
pub ratio: SeriesPattern1<StoredF32>,
|
||||
pub percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern,
|
||||
pub sma: _1m1w1y2y4yAllPattern,
|
||||
pub std_dev: SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev,
|
||||
}
|
||||
@@ -7238,7 +7288,7 @@ impl SeriesTree_Cohorts_Utxo_Lth_Realized_Price {
|
||||
sats: SeriesPattern1::new(client.clone(), "lth_realized_price_sats".to_string()),
|
||||
bps: SeriesPattern1::new(client.clone(), "lth_realized_price_ratio_bps".to_string()),
|
||||
ratio: SeriesPattern1::new(client.clone(), "lth_realized_price_ratio".to_string()),
|
||||
percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), "lth_realized_price".to_string()),
|
||||
percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern::new(client.clone(), "lth_realized_price".to_string()),
|
||||
sma: _1m1w1y2y4yAllPattern::new(client.clone(), "lth_realized_price_ratio_sma".to_string()),
|
||||
std_dev: SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev::new(client.clone(), format!("{base_path}_std_dev")),
|
||||
}
|
||||
@@ -8145,7 +8195,7 @@ pub struct BrkClient {
|
||||
|
||||
impl BrkClient {
|
||||
/// Client version.
|
||||
pub const VERSION: &'static str = "v0.1.9";
|
||||
pub const VERSION: &'static str = "v0.2.2";
|
||||
|
||||
/// Create a new client with the given base URL.
|
||||
pub fn new(base_url: impl Into<String>) -> Self {
|
||||
|
||||
@@ -17,12 +17,10 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
// Sequential: time → lookback (dependency chain)
|
||||
self.time
|
||||
.timestamp
|
||||
.compute(indexer, indexes, starting_indexes, exit)?;
|
||||
self.lookback
|
||||
.compute(&self.time, starting_indexes, exit)?;
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
// lookback depends on indexes.timestamp.monotonic
|
||||
self.lookback.compute(indexes, starting_indexes, exit)?;
|
||||
|
||||
// Parallel: remaining sub-modules are independent of each other.
|
||||
// size depends on lookback (already computed above).
|
||||
@@ -52,8 +50,11 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
CountVecs, DifficultyVecs, HalvingVecs, IntervalVecs, LookbackVecs, SizeVecs, TimeVecs, Vecs,
|
||||
CountVecs, DifficultyVecs, HalvingVecs, IntervalVecs, LookbackVecs, SizeVecs, Vecs,
|
||||
WeightVecs,
|
||||
};
|
||||
|
||||
@@ -30,7 +30,6 @@ impl Vecs {
|
||||
let interval = IntervalVecs::forced_import(&db, version, indexes, cached_starts)?;
|
||||
let size = SizeVecs::forced_import(&db, version, indexes, cached_starts)?;
|
||||
let weight = WeightVecs::forced_import(&db, version, indexes, cached_starts, &size)?;
|
||||
let time = TimeVecs::forced_import(&db, version, indexes)?;
|
||||
let difficulty = DifficultyVecs::forced_import(&db, version, indexer, indexes)?;
|
||||
let halving = HalvingVecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
@@ -41,7 +40,6 @@ impl Vecs {
|
||||
interval,
|
||||
size,
|
||||
weight,
|
||||
time,
|
||||
difficulty,
|
||||
halving,
|
||||
};
|
||||
|
||||
@@ -3,9 +3,10 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Indexes, Timestamp, Version};
|
||||
use vecdb::{AnyVec, CachedVec, Cursor, Database, EagerVec, Exit, ImportableVec, PcoVec, ReadableVec, Rw, StorageMode, VecIndex};
|
||||
|
||||
use crate::internal::{CachedWindowStarts, Windows, WindowStarts};
|
||||
|
||||
use super::time;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{CachedWindowStarts, Windows, WindowStarts},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
@@ -178,71 +179,71 @@ impl Vecs {
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
time: &time::Vecs,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.compute_rolling_start_hours(time, starting_indexes, exit, 1, |s| {
|
||||
self.compute_rolling_start_hours(indexes, starting_indexes, exit, 1, |s| {
|
||||
&mut s._1h
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 1, |s| &mut s._24h)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 3, |s| &mut s._3d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 7, |s| &mut s._1w)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 8, |s| &mut s._8d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 9, |s| &mut s._9d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 12, |s| &mut s._12d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 13, |s| &mut s._13d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 14, |s| &mut s._2w)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 21, |s| &mut s._21d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 26, |s| &mut s._26d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 30, |s| &mut s._1m)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 34, |s| &mut s._34d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 55, |s| &mut s._55d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 60, |s| &mut s._2m)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 63, |s| &mut s._9w)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 84, |s| &mut s._12w)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 89, |s| &mut s._89d)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 90, |s| &mut s._3m)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 98, |s| &mut s._14w)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 111, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 1, |s| &mut s._24h)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 3, |s| &mut s._3d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 7, |s| &mut s._1w)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 8, |s| &mut s._8d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 9, |s| &mut s._9d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 12, |s| &mut s._12d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 13, |s| &mut s._13d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 14, |s| &mut s._2w)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 21, |s| &mut s._21d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 26, |s| &mut s._26d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 30, |s| &mut s._1m)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 34, |s| &mut s._34d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 55, |s| &mut s._55d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 60, |s| &mut s._2m)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 63, |s| &mut s._9w)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 84, |s| &mut s._12w)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 89, |s| &mut s._89d)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 90, |s| &mut s._3m)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 98, |s| &mut s._14w)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 111, |s| {
|
||||
&mut s._111d
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 144, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 144, |s| {
|
||||
&mut s._144d
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 180, |s| &mut s._6m)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 182, |s| &mut s._26w)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 200, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 180, |s| &mut s._6m)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 182, |s| &mut s._26w)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 200, |s| {
|
||||
&mut s._200d
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 270, |s| &mut s._9m)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 350, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 270, |s| &mut s._9m)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 350, |s| {
|
||||
&mut s._350d
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 360, |s| &mut s._12m)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 365, |s| &mut s._1y)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 420, |s| &mut s._14m)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 730, |s| &mut s._2y)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 780, |s| &mut s._26m)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 1095, |s| &mut s._3y)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 1400, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 360, |s| &mut s._12m)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 365, |s| &mut s._1y)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 420, |s| &mut s._14m)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 730, |s| &mut s._2y)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 780, |s| &mut s._26m)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 1095, |s| &mut s._3y)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 1400, |s| {
|
||||
&mut s._200w
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 1460, |s| &mut s._4y)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 1825, |s| &mut s._5y)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 2190, |s| &mut s._6y)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 2920, |s| &mut s._8y)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 3285, |s| &mut s._9y)?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 3650, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 1460, |s| &mut s._4y)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 1825, |s| &mut s._5y)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 2190, |s| &mut s._6y)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 2920, |s| &mut s._8y)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 3285, |s| &mut s._9y)?;
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 3650, |s| {
|
||||
&mut s._10y
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 4380, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 4380, |s| {
|
||||
&mut s._12y
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 5110, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 5110, |s| {
|
||||
&mut s._14y
|
||||
})?;
|
||||
self.compute_rolling_start(time, starting_indexes, exit, 9490, |s| {
|
||||
self.compute_rolling_start(indexes, starting_indexes, exit, 9490, |s| {
|
||||
&mut s._26y
|
||||
})?;
|
||||
|
||||
@@ -251,7 +252,7 @@ impl Vecs {
|
||||
|
||||
fn compute_rolling_start<F>(
|
||||
&mut self,
|
||||
time: &time::Vecs,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
days: usize,
|
||||
@@ -260,14 +261,14 @@ impl Vecs {
|
||||
where
|
||||
F: FnOnce(&mut Self) -> &mut EagerVec<PcoVec<Height, Height>>,
|
||||
{
|
||||
self.compute_rolling_start_inner(time, starting_indexes, exit, get_field, |t, prev_ts| {
|
||||
self.compute_rolling_start_inner(indexes, starting_indexes, exit, get_field, |t, prev_ts| {
|
||||
t.difference_in_days_between(prev_ts) >= days
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_rolling_start_hours<F>(
|
||||
&mut self,
|
||||
time: &time::Vecs,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
hours: usize,
|
||||
@@ -276,14 +277,14 @@ impl Vecs {
|
||||
where
|
||||
F: FnOnce(&mut Self) -> &mut EagerVec<PcoVec<Height, Height>>,
|
||||
{
|
||||
self.compute_rolling_start_inner(time, starting_indexes, exit, get_field, |t, prev_ts| {
|
||||
self.compute_rolling_start_inner(indexes, starting_indexes, exit, get_field, |t, prev_ts| {
|
||||
t.difference_in_hours_between(prev_ts) >= hours
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_rolling_start_inner<F, D>(
|
||||
&mut self,
|
||||
time: &time::Vecs,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
get_field: F,
|
||||
@@ -300,12 +301,12 @@ impl Vecs {
|
||||
} else {
|
||||
Height::ZERO
|
||||
};
|
||||
let mut cursor = Cursor::new(&time.timestamp_monotonic);
|
||||
let mut cursor = Cursor::new(&indexes.timestamp.monotonic);
|
||||
cursor.advance(prev.to_usize());
|
||||
let mut prev_ts = cursor.next().unwrap();
|
||||
Ok(field.compute_transform(
|
||||
starting_indexes.height,
|
||||
&time.timestamp_monotonic,
|
||||
&indexes.timestamp.monotonic,
|
||||
|(h, t, ..)| {
|
||||
while expired(t, prev_ts) {
|
||||
prev.increment();
|
||||
|
||||
@@ -4,7 +4,6 @@ pub mod halving;
|
||||
pub mod interval;
|
||||
pub mod lookback;
|
||||
pub mod size;
|
||||
pub mod time;
|
||||
pub mod weight;
|
||||
|
||||
mod compute;
|
||||
@@ -19,7 +18,6 @@ pub use halving::Vecs as HalvingVecs;
|
||||
pub use interval::Vecs as IntervalVecs;
|
||||
pub use lookback::Vecs as LookbackVecs;
|
||||
pub use size::Vecs as SizeVecs;
|
||||
pub use time::Vecs as TimeVecs;
|
||||
pub use weight::Vecs as WeightVecs;
|
||||
|
||||
pub const DB_NAME: &str = "blocks";
|
||||
@@ -37,7 +35,7 @@ pub(crate) const ONE_TERA_HASH: f64 = 1_000_000_000_000.0;
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
#[traversable(skip)]
|
||||
pub(crate) db: Database,
|
||||
pub db: Database,
|
||||
|
||||
pub count: CountVecs<M>,
|
||||
pub lookback: LookbackVecs<M>,
|
||||
@@ -46,7 +44,6 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub size: SizeVecs<M>,
|
||||
#[traversable(flatten)]
|
||||
pub weight: WeightVecs<M>,
|
||||
pub time: TimeVecs<M>,
|
||||
pub difficulty: DifficultyVecs<M>,
|
||||
pub halving: HalvingVecs<M>,
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use vecdb::{Exit, ReadableVec};
|
||||
|
||||
use super::Vecs;
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
starting_height: brk_types::Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let mut prev_timestamp_monotonic = None;
|
||||
self.timestamp_monotonic.compute_transform(
|
||||
starting_height,
|
||||
&indexer.vecs.blocks.timestamp,
|
||||
|(h, timestamp, this)| {
|
||||
if prev_timestamp_monotonic.is_none()
|
||||
&& let Some(prev_h) = h.decremented()
|
||||
{
|
||||
prev_timestamp_monotonic.replace(this.collect_one(prev_h).unwrap());
|
||||
}
|
||||
let timestamp_monotonic =
|
||||
prev_timestamp_monotonic.map_or(timestamp, |prev_d| prev_d.max(timestamp));
|
||||
prev_timestamp_monotonic.replace(timestamp_monotonic);
|
||||
(h, timestamp_monotonic)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{Date, Height, Version};
|
||||
use vecdb::{Database, EagerVec, ImportableVec, LazyVecFrom1, ReadableCloneableVec};
|
||||
|
||||
use super::{TimestampIndexes, Vecs};
|
||||
use crate::indexes;
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let timestamp_monotonic = EagerVec::forced_import(db, "timestamp_monotonic", version)?;
|
||||
|
||||
Ok(Self {
|
||||
date: LazyVecFrom1::init(
|
||||
"date",
|
||||
version,
|
||||
timestamp_monotonic.read_only_boxed_clone(),
|
||||
|_height: Height, timestamp| Date::from(timestamp),
|
||||
),
|
||||
timestamp_monotonic,
|
||||
timestamp: TimestampIndexes::forced_import(db, version, indexes)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TimestampIndexes {
|
||||
fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
|
||||
macro_rules! period {
|
||||
($field:ident) => {
|
||||
LazyVecFrom1::init(
|
||||
"timestamp",
|
||||
version,
|
||||
indexes.$field.first_height.read_only_boxed_clone(),
|
||||
|idx, _: Height| idx.to_timestamp(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! epoch {
|
||||
($field:ident) => {
|
||||
ImportableVec::forced_import(db, "timestamp", version)?
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Self(crate::internal::PerResolution {
|
||||
minute10: period!(minute10),
|
||||
minute30: period!(minute30),
|
||||
hour1: period!(hour1),
|
||||
hour4: period!(hour4),
|
||||
hour12: period!(hour12),
|
||||
day1: period!(day1),
|
||||
day3: period!(day3),
|
||||
week1: period!(week1),
|
||||
month1: period!(month1),
|
||||
month3: period!(month3),
|
||||
month6: period!(month6),
|
||||
year1: period!(year1),
|
||||
year10: period!(year10),
|
||||
halving: epoch!(halving),
|
||||
epoch: epoch!(difficulty),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
mod compute;
|
||||
mod import;
|
||||
mod vecs;
|
||||
|
||||
pub use vecs::{TimestampIndexes, Vecs};
|
||||
@@ -1,80 +0,0 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
Date, Day1, Day3, Epoch, Halving, Height, Hour1, Hour4, Hour12, Indexes,
|
||||
Minute10, Minute30, Month1, Month3, Month6, Timestamp, Week1, Year1, Year10,
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{EagerVec, Exit, LazyVecFrom1, PcoVec, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{indexes, internal::PerResolution};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub date: LazyVecFrom1<Height, Date, Height, Timestamp>,
|
||||
pub timestamp_monotonic: M::Stored<EagerVec<PcoVec<Height, Timestamp>>>,
|
||||
pub timestamp: TimestampIndexes<M>,
|
||||
}
|
||||
|
||||
/// Per-period timestamp indexes.
|
||||
///
|
||||
/// Time-based periods (minute10–year10) are lazy: `idx.to_timestamp()` is a pure
|
||||
/// function of the index, so no storage or decompression is needed.
|
||||
/// Epoch-based periods (halving, difficulty) are eager: their timestamps
|
||||
/// come from block data via `compute_indirect_sequential`.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct TimestampIndexes<M: StorageMode = Rw>(
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub PerResolution<
|
||||
LazyVecFrom1<Minute10, Timestamp, Minute10, Height>,
|
||||
LazyVecFrom1<Minute30, Timestamp, Minute30, Height>,
|
||||
LazyVecFrom1<Hour1, Timestamp, Hour1, Height>,
|
||||
LazyVecFrom1<Hour4, Timestamp, Hour4, Height>,
|
||||
LazyVecFrom1<Hour12, Timestamp, Hour12, Height>,
|
||||
LazyVecFrom1<Day1, Timestamp, Day1, Height>,
|
||||
LazyVecFrom1<Day3, Timestamp, Day3, Height>,
|
||||
LazyVecFrom1<Week1, Timestamp, Week1, Height>,
|
||||
LazyVecFrom1<Month1, Timestamp, Month1, Height>,
|
||||
LazyVecFrom1<Month3, Timestamp, Month3, Height>,
|
||||
LazyVecFrom1<Month6, Timestamp, Month6, Height>,
|
||||
LazyVecFrom1<Year1, Timestamp, Year1, Height>,
|
||||
LazyVecFrom1<Year10, Timestamp, Year10, Height>,
|
||||
M::Stored<EagerVec<PcoVec<Halving, Timestamp>>>,
|
||||
M::Stored<EagerVec<PcoVec<Epoch, Timestamp>>>,
|
||||
>,
|
||||
);
|
||||
|
||||
impl TimestampIndexes {
|
||||
/// Compute epoch timestamps via indirect lookup from block timestamps.
|
||||
/// Time-based periods are lazy (idx.to_timestamp()) and need no compute.
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
indexer: &brk_indexer::Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let prev_height = starting_indexes.height.decremented().unwrap_or_default();
|
||||
self.halving.compute_indirect_sequential(
|
||||
indexes
|
||||
.height
|
||||
.halving
|
||||
.collect_one(prev_height)
|
||||
.unwrap_or_default(),
|
||||
&indexes.halving.first_height,
|
||||
&indexer.vecs.blocks.timestamp,
|
||||
exit,
|
||||
)?;
|
||||
self.epoch.compute_indirect_sequential(
|
||||
indexes
|
||||
.height
|
||||
.epoch
|
||||
.collect_one(prev_height)
|
||||
.unwrap_or_default(),
|
||||
&indexes.epoch.first_height,
|
||||
&indexer.vecs.blocks.timestamp,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ impl Vecs {
|
||||
distribution: &distribution::Vecs,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
// Activity computes first (liveliness, vaultedness, etc.)
|
||||
self.activity
|
||||
.compute(starting_indexes, distribution, exit)?;
|
||||
@@ -80,8 +82,11 @@ impl Vecs {
|
||||
r3?;
|
||||
r4?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +227,8 @@ impl Vecs {
|
||||
starting_indexes: &mut Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
// 1. Find minimum height we have data for across stateful vecs
|
||||
let current_height = Height::from(self.supply_state.len());
|
||||
let min_stateful = self.min_stateful_len();
|
||||
@@ -300,7 +302,7 @@ impl Vecs {
|
||||
.cents
|
||||
.height
|
||||
.len()
|
||||
.min(blocks.time.timestamp_monotonic.len());
|
||||
.min(indexes.timestamp.monotonic.len());
|
||||
let cache_current_len = self.caches.prices.len();
|
||||
if cache_target_len < cache_current_len {
|
||||
self.caches.prices.truncate(cache_target_len);
|
||||
@@ -312,9 +314,9 @@ impl Vecs {
|
||||
.cents
|
||||
.height
|
||||
.collect_range_at(cache_current_len, cache_target_len);
|
||||
let new_timestamps = blocks
|
||||
.time
|
||||
.timestamp_monotonic
|
||||
let new_timestamps = indexes
|
||||
.timestamp
|
||||
.monotonic
|
||||
.collect_range_at(cache_current_len, cache_target_len);
|
||||
self.caches.prices.extend(new_prices);
|
||||
self.caches.timestamps.extend(new_timestamps);
|
||||
@@ -499,8 +501,11 @@ impl Vecs {
|
||||
self.addr_cohorts
|
||||
.compute_rest_part2(prices, starting_indexes, &all_utxo_count, exit)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ mod minute30;
|
||||
mod month1;
|
||||
mod month3;
|
||||
mod month6;
|
||||
pub mod timestamp;
|
||||
mod tx_index;
|
||||
mod txin_index;
|
||||
mod txout_index;
|
||||
@@ -31,13 +32,11 @@ use brk_types::{
|
||||
};
|
||||
use vecdb::{CachedVec, Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
blocks,
|
||||
internal::db_utils::{finalize_db, open_db},
|
||||
};
|
||||
use crate::internal::db_utils::{finalize_db, open_db};
|
||||
|
||||
pub use cached_mappings::CachedMappings;
|
||||
pub use addr::Vecs as AddrVecs;
|
||||
pub use timestamp::Timestamps;
|
||||
pub use cached_mappings::CachedMappings;
|
||||
pub use day1::Vecs as Day1Vecs;
|
||||
pub use day3::Vecs as Day3Vecs;
|
||||
pub use epoch::Vecs as EpochVecs;
|
||||
@@ -85,6 +84,7 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub tx_index: TxIndexVecs<M>,
|
||||
pub txin_index: TxInIndexVecs,
|
||||
pub txout_index: TxOutIndexVecs,
|
||||
pub timestamp: Timestamps<M>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -136,6 +136,11 @@ impl Vecs {
|
||||
epoch_identity: CachedVec::new(&epoch.identity),
|
||||
};
|
||||
|
||||
let timestamp = Timestamps::forced_import_from_locals(
|
||||
&db, version, &minute10, &minute30, &hour1, &hour4, &hour12, &day1, &day3, &week1,
|
||||
&month1, &month3, &month6, &year1, &year10,
|
||||
)?;
|
||||
|
||||
let this = Self {
|
||||
cached_mappings,
|
||||
addr,
|
||||
@@ -158,6 +163,7 @@ impl Vecs {
|
||||
tx_index,
|
||||
txin_index,
|
||||
txout_index,
|
||||
timestamp,
|
||||
db,
|
||||
};
|
||||
|
||||
@@ -168,36 +174,24 @@ impl Vecs {
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
blocks: &mut blocks::Vecs,
|
||||
starting_indexes: Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<Indexes> {
|
||||
blocks
|
||||
.time
|
||||
.compute(indexer, starting_indexes.height, exit)?;
|
||||
let indexes = self.compute_(indexer, &blocks.time, starting_indexes, exit)?;
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
Ok(indexes)
|
||||
}
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
// timestamp_monotonic must be computed first — other mappings read it
|
||||
self.timestamp
|
||||
.compute_monotonic(indexer, starting_indexes.height, exit)?;
|
||||
|
||||
fn compute_(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
blocks_time: &blocks::time::Vecs,
|
||||
starting_indexes: Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<Indexes> {
|
||||
self.compute_tx_indexes(indexer, &starting_indexes, exit)?;
|
||||
self.compute_height_indexes(indexer, &starting_indexes, exit)?;
|
||||
|
||||
let prev_height = starting_indexes.height.decremented().unwrap_or_default();
|
||||
|
||||
self.compute_timestamp_mappings(blocks_time, &starting_indexes, exit)?;
|
||||
self.compute_timestamp_mappings(&starting_indexes, exit)?;
|
||||
|
||||
let starting_day1 = self.compute_calendar_mappings(
|
||||
indexer,
|
||||
blocks_time,
|
||||
&starting_indexes,
|
||||
prev_height,
|
||||
exit,
|
||||
@@ -205,13 +199,26 @@ impl Vecs {
|
||||
|
||||
self.compute_period_vecs(
|
||||
indexer,
|
||||
blocks_time,
|
||||
&starting_indexes,
|
||||
prev_height,
|
||||
starting_day1,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.timestamp.compute_per_resolution(
|
||||
indexer,
|
||||
&self.height,
|
||||
&self.halving,
|
||||
&self.epoch,
|
||||
&starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(starting_indexes)
|
||||
}
|
||||
|
||||
@@ -266,7 +273,6 @@ impl Vecs {
|
||||
|
||||
fn compute_timestamp_mappings(
|
||||
&mut self,
|
||||
blocks_time: &blocks::time::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
@@ -274,7 +280,7 @@ impl Vecs {
|
||||
($field:ident, $period:ty) => {
|
||||
self.height.$field.compute_transform(
|
||||
starting_indexes.height,
|
||||
&blocks_time.timestamp_monotonic,
|
||||
&self.timestamp.monotonic,
|
||||
|(h, ts, _)| (h, <$period>::from_timestamp(ts)),
|
||||
exit,
|
||||
)?;
|
||||
@@ -294,7 +300,6 @@ impl Vecs {
|
||||
fn compute_calendar_mappings(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
blocks_time: &blocks::time::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
prev_height: Height,
|
||||
exit: &Exit,
|
||||
@@ -307,8 +312,8 @@ impl Vecs {
|
||||
|
||||
self.height.day1.compute_transform(
|
||||
starting_indexes.height,
|
||||
&blocks_time.date,
|
||||
|(h, d, ..)| (h, Day1::try_from(d).unwrap()),
|
||||
&self.timestamp.monotonic,
|
||||
|(h, ts, ..)| (h, Day1::try_from(Date::from(ts)).unwrap()),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -318,7 +323,7 @@ impl Vecs {
|
||||
starting_day1
|
||||
};
|
||||
|
||||
self.compute_epoch(indexer, blocks_time, starting_indexes, prev_height, exit)?;
|
||||
self.compute_epoch(indexer, starting_indexes, prev_height, exit)?;
|
||||
|
||||
self.height.week1.compute_transform(
|
||||
starting_indexes.height,
|
||||
@@ -363,7 +368,6 @@ impl Vecs {
|
||||
fn compute_epoch(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
blocks_time: &blocks::time::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
prev_height: Height,
|
||||
exit: &Exit,
|
||||
@@ -389,14 +393,12 @@ impl Vecs {
|
||||
&self.epoch.first_height,
|
||||
exit,
|
||||
)?;
|
||||
self.epoch
|
||||
.height_count
|
||||
.compute_count_from_indexes(
|
||||
starting_difficulty,
|
||||
&self.epoch.first_height,
|
||||
&blocks_time.date,
|
||||
exit,
|
||||
)?;
|
||||
self.epoch.height_count.compute_count_from_indexes(
|
||||
starting_difficulty,
|
||||
&self.epoch.first_height,
|
||||
&self.timestamp.monotonic,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let starting_halving = self
|
||||
.height
|
||||
@@ -426,7 +428,6 @@ impl Vecs {
|
||||
fn compute_period_vecs(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
blocks_time: &blocks::time::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
prev_height: Height,
|
||||
starting_day1: Day1,
|
||||
@@ -478,7 +479,7 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let date = &blocks_time.date;
|
||||
let ts = &self.timestamp.monotonic;
|
||||
|
||||
macro_rules! dated_period {
|
||||
($period:ident) => {{
|
||||
@@ -500,7 +501,7 @@ impl Vecs {
|
||||
self.$period.date.compute_transform(
|
||||
start,
|
||||
&self.$period.first_height,
|
||||
|(idx, first_h, _)| (idx, date.collect_one(first_h).unwrap()),
|
||||
|(idx, first_h, _)| (idx, Date::from(ts.collect_one(first_h).unwrap())),
|
||||
exit,
|
||||
)?;
|
||||
}};
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
Day1, Day3, Epoch, Halving, Height, Hour1, Hour4, Hour12, Indexes, Minute10, Minute30, Month1,
|
||||
Month3, Month6, Timestamp, Week1, Year1, Year10,
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{
|
||||
Database, EagerVec, Exit, ImportableVec, LazyVecFrom1, PcoVec, ReadableCloneableVec,
|
||||
ReadableVec, Rw, StorageMode, Version,
|
||||
};
|
||||
|
||||
use crate::internal::PerResolution;
|
||||
|
||||
/// Timestamps: monotonic height→timestamp + per-period timestamp lookups.
|
||||
///
|
||||
/// Time-based periods (minute10–year10) are lazy: `idx.to_timestamp()` is a pure
|
||||
/// function of the index, so no storage or decompression is needed.
|
||||
/// Epoch-based periods (halving, difficulty) are eager: their timestamps
|
||||
/// come from block data via `compute_indirect_sequential`.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
pub struct Timestamps<M: StorageMode = Rw> {
|
||||
pub monotonic: M::Stored<EagerVec<PcoVec<Height, Timestamp>>>,
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub resolutions: PerResolution<
|
||||
LazyVecFrom1<Minute10, Timestamp, Minute10, Height>,
|
||||
LazyVecFrom1<Minute30, Timestamp, Minute30, Height>,
|
||||
LazyVecFrom1<Hour1, Timestamp, Hour1, Height>,
|
||||
LazyVecFrom1<Hour4, Timestamp, Hour4, Height>,
|
||||
LazyVecFrom1<Hour12, Timestamp, Hour12, Height>,
|
||||
LazyVecFrom1<Day1, Timestamp, Day1, Height>,
|
||||
LazyVecFrom1<Day3, Timestamp, Day3, Height>,
|
||||
LazyVecFrom1<Week1, Timestamp, Week1, Height>,
|
||||
LazyVecFrom1<Month1, Timestamp, Month1, Height>,
|
||||
LazyVecFrom1<Month3, Timestamp, Month3, Height>,
|
||||
LazyVecFrom1<Month6, Timestamp, Month6, Height>,
|
||||
LazyVecFrom1<Year1, Timestamp, Year1, Height>,
|
||||
LazyVecFrom1<Year10, Timestamp, Year10, Height>,
|
||||
M::Stored<EagerVec<PcoVec<Halving, Timestamp>>>,
|
||||
M::Stored<EagerVec<PcoVec<Epoch, Timestamp>>>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl Timestamps {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn forced_import_from_locals(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
minute10: &super::Minute10Vecs,
|
||||
minute30: &super::Minute30Vecs,
|
||||
hour1: &super::Hour1Vecs,
|
||||
hour4: &super::Hour4Vecs,
|
||||
hour12: &super::Hour12Vecs,
|
||||
day1: &super::Day1Vecs,
|
||||
day3: &super::Day3Vecs,
|
||||
week1: &super::Week1Vecs,
|
||||
month1: &super::Month1Vecs,
|
||||
month3: &super::Month3Vecs,
|
||||
month6: &super::Month6Vecs,
|
||||
year1: &super::Year1Vecs,
|
||||
year10: &super::Year10Vecs,
|
||||
) -> Result<Self> {
|
||||
let monotonic = EagerVec::forced_import(db, "timestamp_monotonic", version)?;
|
||||
|
||||
macro_rules! period {
|
||||
($field:ident) => {
|
||||
LazyVecFrom1::init(
|
||||
"timestamp",
|
||||
version,
|
||||
$field.first_height.read_only_boxed_clone(),
|
||||
|idx, _: Height| idx.to_timestamp(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
monotonic,
|
||||
resolutions: PerResolution {
|
||||
minute10: period!(minute10),
|
||||
minute30: period!(minute30),
|
||||
hour1: period!(hour1),
|
||||
hour4: period!(hour4),
|
||||
hour12: period!(hour12),
|
||||
day1: period!(day1),
|
||||
day3: period!(day3),
|
||||
week1: period!(week1),
|
||||
month1: period!(month1),
|
||||
month3: period!(month3),
|
||||
month6: period!(month6),
|
||||
year1: period!(year1),
|
||||
year10: period!(year10),
|
||||
halving: ImportableVec::forced_import(db, "timestamp", version)?,
|
||||
epoch: ImportableVec::forced_import(db, "timestamp", version)?,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute_monotonic(
|
||||
&mut self,
|
||||
indexer: &brk_indexer::Indexer,
|
||||
starting_height: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let mut prev = None;
|
||||
self.monotonic.compute_transform(
|
||||
starting_height,
|
||||
&indexer.vecs.blocks.timestamp,
|
||||
|(h, timestamp, this)| {
|
||||
if prev.is_none()
|
||||
&& let Some(prev_h) = h.decremented()
|
||||
{
|
||||
prev.replace(this.collect_one(prev_h).unwrap());
|
||||
}
|
||||
let monotonic = prev.map_or(timestamp, |p| p.max(timestamp));
|
||||
prev.replace(monotonic);
|
||||
(h, monotonic)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn compute_per_resolution(
|
||||
&mut self,
|
||||
indexer: &brk_indexer::Indexer,
|
||||
height: &super::HeightVecs,
|
||||
halving_vecs: &super::HalvingVecs,
|
||||
epoch_vecs: &super::EpochVecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let prev_height = starting_indexes.height.decremented().unwrap_or_default();
|
||||
self.resolutions.halving.compute_indirect_sequential(
|
||||
height.halving.collect_one(prev_height).unwrap_or_default(),
|
||||
&halving_vecs.first_height,
|
||||
&indexer.vecs.blocks.timestamp,
|
||||
exit,
|
||||
)?;
|
||||
self.resolutions.epoch.compute_indirect_sequential(
|
||||
height.epoch.collect_one(prev_height).unwrap_or_default(),
|
||||
&epoch_vecs.first_height,
|
||||
&indexer.vecs.blocks.timestamp,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
// Puell Multiple: daily_subsidy_usd / sma_365d_subsidy_usd
|
||||
self.puell_multiple
|
||||
.bps
|
||||
@@ -199,8 +201,11 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::path::Path;
|
||||
use brk_error::Result;
|
||||
use brk_types::Version;
|
||||
|
||||
use super::Vecs;
|
||||
use super::{Vecs, thermometer::Thermometer};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{PerBlock, PercentPerBlock, RatioPerBlock, db_utils::{finalize_db, open_db}},
|
||||
@@ -38,6 +38,8 @@ impl Vecs {
|
||||
let seller_exhaustion =
|
||||
PerBlock::forced_import(&db, "seller_exhaustion", v, indexes)?;
|
||||
|
||||
let thermometer = Thermometer::forced_import(&db, v, indexes)?;
|
||||
|
||||
let this = Self {
|
||||
db,
|
||||
puell_multiple,
|
||||
@@ -50,6 +52,7 @@ impl Vecs {
|
||||
dormancy,
|
||||
stock_to_flow,
|
||||
seller_exhaustion,
|
||||
thermometer,
|
||||
};
|
||||
finalize_db(&this.db, &this)?;
|
||||
Ok(this)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mod compute;
|
||||
mod gini;
|
||||
mod import;
|
||||
pub mod thermometer;
|
||||
mod vecs;
|
||||
|
||||
pub use vecs::Vecs;
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Cents, Height, Indexes, StoredI8, Version};
|
||||
use vecdb::{AnyVec, Database, EagerVec, Exit, PcoVec, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{
|
||||
cointime,
|
||||
distribution,
|
||||
indexes,
|
||||
internal::{PerBlock, Price, RatioPerBlockPercentiles},
|
||||
prices,
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Thermometer<M: StorageMode = Rw> {
|
||||
pub pct0_5: Price<PerBlock<Cents, M>>,
|
||||
pub pct1: Price<PerBlock<Cents, M>>,
|
||||
pub pct2: Price<PerBlock<Cents, M>>,
|
||||
pub pct5: Price<PerBlock<Cents, M>>,
|
||||
pub pct95: Price<PerBlock<Cents, M>>,
|
||||
pub pct98: Price<PerBlock<Cents, M>>,
|
||||
pub pct99: Price<PerBlock<Cents, M>>,
|
||||
pub pct99_5: Price<PerBlock<Cents, M>>,
|
||||
pub zone: PerBlock<StoredI8, M>,
|
||||
pub score: PerBlock<StoredI8, M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::new(2);
|
||||
|
||||
impl Thermometer {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
Ok(Self {
|
||||
pct0_5: Price::forced_import(db, "thermometer_pct0_5", v, indexes)?,
|
||||
pct1: Price::forced_import(db, "thermometer_pct01", v, indexes)?,
|
||||
pct2: Price::forced_import(db, "thermometer_pct02", v, indexes)?,
|
||||
pct5: Price::forced_import(db, "thermometer_pct05", v, indexes)?,
|
||||
pct95: Price::forced_import(db, "thermometer_pct95", v, indexes)?,
|
||||
pct98: Price::forced_import(db, "thermometer_pct98", v, indexes)?,
|
||||
pct99: Price::forced_import(db, "thermometer_pct99", v, indexes)?,
|
||||
pct99_5: Price::forced_import(db, "thermometer_pct99_5", v, indexes)?,
|
||||
zone: PerBlock::forced_import(db, "thermometer_zone", v, indexes)?,
|
||||
score: PerBlock::forced_import(db, "thermometer_score", v, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
distribution: &distribution::Vecs,
|
||||
cointime: &cointime::Vecs,
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let realized = &distribution.utxo_cohorts.all.metrics.realized;
|
||||
let ct = &cointime.prices;
|
||||
|
||||
let sth_realized = &distribution.utxo_cohorts.sth.metrics.realized;
|
||||
let lth_realized = &distribution.utxo_cohorts.lth.metrics.realized;
|
||||
|
||||
let models: [&RatioPerBlockPercentiles; 10] = [
|
||||
&realized.price_ratio_percentiles,
|
||||
&realized.investor.price.percentiles,
|
||||
&sth_realized.price_ratio_percentiles,
|
||||
&sth_realized.investor.price.percentiles,
|
||||
<h_realized.price_ratio_percentiles,
|
||||
<h_realized.investor.price.percentiles,
|
||||
&ct.vaulted.percentiles,
|
||||
&ct.active.percentiles,
|
||||
&ct.true_market_mean.percentiles,
|
||||
&ct.cointime.percentiles,
|
||||
];
|
||||
|
||||
macro_rules! sources {
|
||||
($pct:ident) => {
|
||||
models.each_ref().map(|m| &m.$pct.price.cents.height)
|
||||
};
|
||||
}
|
||||
|
||||
// Lower percentiles: max across all models (tightest lower bound)
|
||||
self.pct0_5.cents.height.compute_max_of_others(starting_indexes.height, &sources!(pct0_5), exit)?;
|
||||
self.pct1.cents.height.compute_max_of_others(starting_indexes.height, &sources!(pct1), exit)?;
|
||||
self.pct2.cents.height.compute_max_of_others(starting_indexes.height, &sources!(pct2), exit)?;
|
||||
self.pct5.cents.height.compute_max_of_others(starting_indexes.height, &sources!(pct5), exit)?;
|
||||
|
||||
// Upper percentiles: min across all models (tightest upper bound)
|
||||
self.pct95.cents.height.compute_min_of_others(starting_indexes.height, &sources!(pct95), exit)?;
|
||||
self.pct98.cents.height.compute_min_of_others(starting_indexes.height, &sources!(pct98), exit)?;
|
||||
self.pct99.cents.height.compute_min_of_others(starting_indexes.height, &sources!(pct99), exit)?;
|
||||
self.pct99_5.cents.height.compute_min_of_others(starting_indexes.height, &sources!(pct99_5), exit)?;
|
||||
|
||||
let spot = &prices.spot.cents.height;
|
||||
|
||||
// Zone: spot vs own envelope bands (-4 to +4)
|
||||
self.compute_zone(spot, starting_indexes, exit)?;
|
||||
|
||||
// Temperature: per-model band crossings (-40 to +40)
|
||||
self.compute_score(&models, spot, starting_indexes, exit)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compute_zone(
|
||||
&mut self,
|
||||
spot: &EagerVec<PcoVec<Height, Cents>>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let bands: [&_; 8] = [
|
||||
&self.pct0_5.cents.height,
|
||||
&self.pct1.cents.height,
|
||||
&self.pct2.cents.height,
|
||||
&self.pct5.cents.height,
|
||||
&self.pct95.cents.height,
|
||||
&self.pct98.cents.height,
|
||||
&self.pct99.cents.height,
|
||||
&self.pct99_5.cents.height,
|
||||
];
|
||||
|
||||
let dep_version: Version = bands.iter().map(|b| b.version()).sum::<Version>() + spot.version();
|
||||
|
||||
self.zone.height.validate_computed_version_or_reset(dep_version)?;
|
||||
self.zone.height.truncate_if_needed(starting_indexes.height)?;
|
||||
|
||||
self.zone.height.repeat_until_complete(exit, |vec| {
|
||||
let skip = vec.len();
|
||||
let source_end = bands.iter().map(|b| b.len()).min().unwrap().min(spot.len());
|
||||
let end = vec.batch_end(source_end);
|
||||
|
||||
if skip >= end {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let spot_batch = spot.collect_range_at(skip, end);
|
||||
let b: [Vec<Cents>; 8] = bands.each_ref().map(|v| v.collect_range_at(skip, end));
|
||||
|
||||
for j in 0..(end - skip) {
|
||||
let price = spot_batch[j];
|
||||
let mut score: i8 = 0;
|
||||
|
||||
if price < b[3][j] { score -= 1; }
|
||||
if price < b[2][j] { score -= 1; }
|
||||
if price < b[1][j] { score -= 1; }
|
||||
if price < b[0][j] { score -= 1; }
|
||||
if price > b[4][j] { score += 1; }
|
||||
if price > b[5][j] { score += 1; }
|
||||
if price > b[6][j] { score += 1; }
|
||||
if price > b[7][j] { score += 1; }
|
||||
|
||||
vec.push(StoredI8::new(score));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compute_score(
|
||||
&mut self,
|
||||
models: &[&RatioPerBlockPercentiles; 10],
|
||||
spot: &EagerVec<PcoVec<Height, Cents>>,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let dep_version: Version = models
|
||||
.iter()
|
||||
.map(|p| {
|
||||
p.pct0_5.price.cents.height.version()
|
||||
+ p.pct1.price.cents.height.version()
|
||||
+ p.pct2.price.cents.height.version()
|
||||
+ p.pct5.price.cents.height.version()
|
||||
+ p.pct95.price.cents.height.version()
|
||||
+ p.pct98.price.cents.height.version()
|
||||
+ p.pct99.price.cents.height.version()
|
||||
+ p.pct99_5.price.cents.height.version()
|
||||
})
|
||||
.sum::<Version>()
|
||||
+ spot.version();
|
||||
|
||||
self.score.height.validate_computed_version_or_reset(dep_version)?;
|
||||
self.score.height.truncate_if_needed(starting_indexes.height)?;
|
||||
|
||||
self.score.height.repeat_until_complete(exit, |vec| {
|
||||
let skip = vec.len();
|
||||
let source_end = models
|
||||
.iter()
|
||||
.flat_map(|p| {
|
||||
[
|
||||
p.pct0_5.price.cents.height.len(),
|
||||
p.pct1.price.cents.height.len(),
|
||||
p.pct2.price.cents.height.len(),
|
||||
p.pct5.price.cents.height.len(),
|
||||
p.pct95.price.cents.height.len(),
|
||||
p.pct98.price.cents.height.len(),
|
||||
p.pct99.price.cents.height.len(),
|
||||
p.pct99_5.price.cents.height.len(),
|
||||
]
|
||||
})
|
||||
.min()
|
||||
.unwrap()
|
||||
.min(spot.len());
|
||||
let end = vec.batch_end(source_end);
|
||||
|
||||
if skip >= end {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let spot_batch = spot.collect_range_at(skip, end);
|
||||
|
||||
let bands: Vec<[Vec<Cents>; 8]> = models
|
||||
.iter()
|
||||
.map(|p| {
|
||||
[
|
||||
p.pct0_5.price.cents.height.collect_range_at(skip, end),
|
||||
p.pct1.price.cents.height.collect_range_at(skip, end),
|
||||
p.pct2.price.cents.height.collect_range_at(skip, end),
|
||||
p.pct5.price.cents.height.collect_range_at(skip, end),
|
||||
p.pct95.price.cents.height.collect_range_at(skip, end),
|
||||
p.pct98.price.cents.height.collect_range_at(skip, end),
|
||||
p.pct99.price.cents.height.collect_range_at(skip, end),
|
||||
p.pct99_5.price.cents.height.collect_range_at(skip, end),
|
||||
]
|
||||
})
|
||||
.collect();
|
||||
|
||||
for j in 0..(end - skip) {
|
||||
let price = spot_batch[j];
|
||||
let mut total: i8 = 0;
|
||||
|
||||
for model in &bands {
|
||||
if price < model[3][j] { total -= 1; }
|
||||
if price < model[2][j] { total -= 1; }
|
||||
if price < model[1][j] { total -= 1; }
|
||||
if price < model[0][j] { total -= 1; }
|
||||
if price > model[4][j] { total += 1; }
|
||||
if price > model[5][j] { total += 1; }
|
||||
if price > model[6][j] { total += 1; }
|
||||
if price > model[7][j] { total += 1; }
|
||||
}
|
||||
|
||||
vec.push(StoredI8::new(total));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, BasisPoints32, StoredF32};
|
||||
use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
use super::thermometer::Thermometer;
|
||||
use crate::internal::{PerBlock, PercentPerBlock, RatioPerBlock};
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -24,4 +25,5 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub dormancy: DormancyVecs<M>,
|
||||
pub stock_to_flow: PerBlock<StoredF32, M>,
|
||||
pub seller_exhaustion: PerBlock<StoredF32, M>,
|
||||
pub thermometer: Thermometer<M>,
|
||||
}
|
||||
|
||||
@@ -15,13 +15,18 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
self.spent
|
||||
.compute(indexer, starting_indexes, exit)?;
|
||||
self.count
|
||||
.compute(indexer, indexes, blocks, starting_indexes, exit)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,20 +71,20 @@ impl ExpandingPercentiles {
|
||||
self.tree.add(Self::to_bucket(value), &1);
|
||||
}
|
||||
|
||||
/// Compute 6 percentiles in one call via kth. O(6 × log N) but with
|
||||
/// shared tree traversal across all 6 targets for better cache locality.
|
||||
/// 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; 6], out: &mut [u32; 6]) {
|
||||
pub fn quantiles(&self, qs: &[f64; 8], out: &mut [u32; 8]) {
|
||||
if self.count == 0 {
|
||||
out.iter_mut().for_each(|o| *o = 0);
|
||||
return;
|
||||
}
|
||||
let mut targets = [0u32; 6];
|
||||
let mut targets = [0u32; 8];
|
||||
for (i, &q) in qs.iter().enumerate() {
|
||||
let k = ((q * self.count as f64).ceil() as u32).clamp(1, self.count);
|
||||
targets[i] = k - 1; // 0-indexed
|
||||
}
|
||||
let mut buckets = [0usize; 6];
|
||||
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;
|
||||
@@ -97,8 +97,8 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
fn quantile(ep: &ExpandingPercentiles, q: f64) -> u32 {
|
||||
let mut out = [0u32; 6];
|
||||
ep.quantiles(&[q, q, q, q, q, q], &mut out);
|
||||
let mut out = [0u32; 8];
|
||||
ep.quantiles(&[q, q, q, q, q, q, q, q], &mut out);
|
||||
out[0]
|
||||
}
|
||||
|
||||
|
||||
@@ -22,18 +22,20 @@ pub struct RatioBand<M: StorageMode = Rw> {
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct RatioPerBlockPercentiles<M: StorageMode = Rw> {
|
||||
pub pct99_5: RatioBand<M>,
|
||||
pub pct99: RatioBand<M>,
|
||||
pub pct98: RatioBand<M>,
|
||||
pub pct95: RatioBand<M>,
|
||||
pub pct5: RatioBand<M>,
|
||||
pub pct2: RatioBand<M>,
|
||||
pub pct1: RatioBand<M>,
|
||||
pub pct0_5: RatioBand<M>,
|
||||
|
||||
#[traversable(skip)]
|
||||
expanding_pct: ExpandingPercentiles,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::new(5);
|
||||
const VERSION: Version = Version::new(6);
|
||||
|
||||
/// First height included in ratio percentile computation (first halving).
|
||||
/// Earlier blocks lack meaningful market data and pollute the distribution.
|
||||
@@ -70,12 +72,14 @@ impl RatioPerBlockPercentiles {
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
pct99_5: import_band!("pct99_5"),
|
||||
pct99: import_band!("pct99"),
|
||||
pct98: import_band!("pct98"),
|
||||
pct95: import_band!("pct95"),
|
||||
pct5: import_band!("pct5"),
|
||||
pct2: import_band!("pct2"),
|
||||
pct1: import_band!("pct1"),
|
||||
pct0_5: import_band!("pct0_5"),
|
||||
expanding_pct: ExpandingPercentiles::default(),
|
||||
})
|
||||
}
|
||||
@@ -114,16 +118,18 @@ impl RatioPerBlockPercentiles {
|
||||
}
|
||||
|
||||
let new_ratios = ratio_source.collect_range_at(start, ratio_len);
|
||||
let mut pct_vecs: [&mut EagerVec<PcoVec<Height, BasisPoints32>>; 6] = [
|
||||
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,
|
||||
];
|
||||
const PCTS: [f64; 6] = [0.01, 0.02, 0.05, 0.95, 0.98, 0.99];
|
||||
let mut out = [0u32; 6];
|
||||
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];
|
||||
|
||||
for vec in pct_vecs.iter_mut() {
|
||||
vec.truncate_if_needed_at(start)?;
|
||||
@@ -160,12 +166,14 @@ impl RatioPerBlockPercentiles {
|
||||
};
|
||||
}
|
||||
|
||||
compute_band!(pct99_5);
|
||||
compute_band!(pct99);
|
||||
compute_band!(pct98);
|
||||
compute_band!(pct95);
|
||||
compute_band!(pct5);
|
||||
compute_band!(pct2);
|
||||
compute_band!(pct1);
|
||||
compute_band!(pct0_5);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -174,12 +182,14 @@ impl RatioPerBlockPercentiles {
|
||||
&mut self,
|
||||
) -> impl Iterator<Item = &mut EagerVec<PcoVec<Height, BasisPoints32>>> {
|
||||
[
|
||||
&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,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
+22
@@ -1,5 +1,7 @@
|
||||
use brk_traversable::Traversable;
|
||||
|
||||
use crate::market::lookback::ByLookbackPeriod;
|
||||
|
||||
/// DCA period identifiers with their day counts
|
||||
pub const DCA_PERIOD_DAYS: ByDcaPeriod<u32> = ByDcaPeriod {
|
||||
_1w: 7,
|
||||
@@ -173,6 +175,26 @@ impl<T> ByDcaPeriod<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ByDcaPeriod<&T> {
|
||||
/// Get the DCA-matching subset from lookback (excludes 24h)
|
||||
pub(crate) fn from_lookback(lookback: &ByLookbackPeriod<T>) -> ByDcaPeriod<&T> {
|
||||
ByDcaPeriod {
|
||||
_1w: &lookback._1w,
|
||||
_1m: &lookback._1m,
|
||||
_3m: &lookback._3m,
|
||||
_6m: &lookback._6m,
|
||||
_1y: &lookback._1y,
|
||||
_2y: &lookback._2y,
|
||||
_3y: &lookback._3y,
|
||||
_4y: &lookback._4y,
|
||||
_5y: &lookback._5y,
|
||||
_6y: &lookback._6y,
|
||||
_8y: &lookback._8y,
|
||||
_10y: &lookback._10y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic wrapper for DCA CAGR data (periods >= 2 years)
|
||||
#[derive(Clone, Default, Traversable)]
|
||||
pub struct ByDcaCagr<T> {
|
||||
+20
-28
@@ -2,8 +2,8 @@ use brk_error::Result;
|
||||
use brk_types::{BasisPointsSigned32, Bitcoin, Cents, Date, Day1, Dollars, Indexes, Sats};
|
||||
use vecdb::{AnyVec, Exit, ReadableOptionVec, ReadableVec, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{blocks, indexes, internal::RatioDiffCentsBps32, market::lookback, prices};
|
||||
use super::{ByDcaPeriod, Vecs};
|
||||
use crate::{blocks, indexes, internal::RatioDiffCentsBps32, market, prices};
|
||||
|
||||
const DCA_AMOUNT: Dollars = Dollars::mint(100.0);
|
||||
|
||||
@@ -13,10 +13,12 @@ impl Vecs {
|
||||
indexes: &indexes::Vecs,
|
||||
prices: &prices::Vecs,
|
||||
blocks: &blocks::Vecs,
|
||||
lookback: &lookback::Vecs,
|
||||
lookback: &market::lookback::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
let h2d = &indexes.height.day1;
|
||||
let close = &prices.split.close.usd.day1;
|
||||
|
||||
@@ -71,17 +73,12 @@ impl Vecs {
|
||||
self.period.cost_basis.zip_mut_with_days(&self.period.stack)
|
||||
{
|
||||
let days = days as usize;
|
||||
let start = average_price.cents.height.len().min(starting_height);
|
||||
let stack_data = stack
|
||||
.sats
|
||||
.height
|
||||
.collect_range_at(start, stack.sats.height.len());
|
||||
average_price.cents.height.compute_transform(
|
||||
average_price.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
h2d,
|
||||
|(h, di, _)| {
|
||||
&stack.sats.height,
|
||||
|(h, di, stack_sats, ..)| {
|
||||
let di_usize = di.to_usize();
|
||||
let stack_sats = stack_data[h.to_usize() - start];
|
||||
let avg = if di_usize > first_price_di {
|
||||
let num_days = days.min(di_usize + 1 - first_price_di);
|
||||
Cents::from(DCA_AMOUNT * num_days / Bitcoin::from(stack_sats))
|
||||
@@ -125,21 +122,16 @@ impl Vecs {
|
||||
}
|
||||
|
||||
// Lump sum by period - stack
|
||||
let lookback_dca = lookback.price_past.as_dca_period();
|
||||
let lookback_dca = ByDcaPeriod::from_lookback(&lookback.price_past);
|
||||
for (stack, lookback_price, days) in
|
||||
self.period.lump_sum_stack.zip_mut_with_days(&lookback_dca)
|
||||
{
|
||||
let total_invested = DCA_AMOUNT * days as usize;
|
||||
let ls_start = stack.sats.height.len().min(starting_height);
|
||||
let lookback_data = lookback_price
|
||||
.cents
|
||||
.height
|
||||
.collect_range_at(ls_start, lookback_price.cents.height.len());
|
||||
stack.sats.height.compute_transform(
|
||||
stack.sats.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
h2d,
|
||||
|(h, _di, _)| {
|
||||
let lp = lookback_data[h.to_usize() - ls_start];
|
||||
&lookback_price.cents.height,
|
||||
|(h, _di, lp, ..)| {
|
||||
let sats = if lp == Cents::ZERO {
|
||||
Sats::ZERO
|
||||
} else {
|
||||
@@ -238,20 +230,15 @@ impl Vecs {
|
||||
.zip(start_days)
|
||||
{
|
||||
let from_usize = from.to_usize();
|
||||
let cls_start = average_price.cents.height.len().min(starting_height);
|
||||
let stack_data = stack
|
||||
.sats
|
||||
.height
|
||||
.collect_range_at(cls_start, stack.sats.height.len());
|
||||
average_price.cents.height.compute_transform(
|
||||
average_price.cents.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
h2d,
|
||||
|(h, di, _)| {
|
||||
&stack.sats.height,
|
||||
|(h, di, stack_sats, ..)| {
|
||||
let di_usize = di.to_usize();
|
||||
if di_usize < from_usize {
|
||||
return (h, Cents::ZERO);
|
||||
}
|
||||
let stack_sats = stack_data[h.to_usize() - cls_start];
|
||||
let num_days = di_usize + 1 - from_usize;
|
||||
let avg = Cents::from(DCA_AMOUNT * num_days / Bitcoin::from(stack_sats));
|
||||
(h, avg)
|
||||
@@ -275,6 +262,11 @@ impl Vecs {
|
||||
)?;
|
||||
}
|
||||
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+26
-16
@@ -1,43 +1,50 @@
|
||||
use std::path::Path;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_types::Version;
|
||||
use vecdb::{Database, ImportableVec};
|
||||
use vecdb::ImportableVec;
|
||||
|
||||
use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod, Vecs};
|
||||
use super::vecs::{ClassVecs, PeriodVecs};
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{AmountPerBlock, PercentPerBlock, Price},
|
||||
internal::{
|
||||
db_utils::{finalize_db, open_db},
|
||||
AmountPerBlock, PercentPerBlock, Price,
|
||||
},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
parent_path: &Path,
|
||||
parent_version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let db = open_db(parent_path, super::DB_NAME, 50_000)?;
|
||||
let version = parent_version;
|
||||
let stack = ByDcaPeriod::try_new(|name, _days| {
|
||||
AmountPerBlock::forced_import(db, &format!("dca_stack_{name}"), version, indexes)
|
||||
AmountPerBlock::forced_import(&db, &format!("dca_stack_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let cost_basis = ByDcaPeriod::try_new(|name, _days| {
|
||||
Price::forced_import(db, &format!("dca_cost_basis_{name}"), version, indexes)
|
||||
Price::forced_import(&db, &format!("dca_cost_basis_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let r#return = ByDcaPeriod::try_new(|name, _days| {
|
||||
PercentPerBlock::forced_import(db, &format!("dca_return_{name}"), version, indexes)
|
||||
PercentPerBlock::forced_import(&db, &format!("dca_return_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let cagr = ByDcaCagr::try_new(|name, _days| {
|
||||
PercentPerBlock::forced_import(db, &format!("dca_cagr_{name}"), version, indexes)
|
||||
PercentPerBlock::forced_import(&db, &format!("dca_cagr_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let lump_sum_stack = ByDcaPeriod::try_new(|name, _days| {
|
||||
AmountPerBlock::forced_import(db, &format!("lump_sum_stack_{name}"), version, indexes)
|
||||
AmountPerBlock::forced_import(&db, &format!("lump_sum_stack_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let lump_sum_return = ByDcaPeriod::try_new(|name, _days| {
|
||||
PercentPerBlock::forced_import(
|
||||
db,
|
||||
&db,
|
||||
&format!("lump_sum_return_{name}"),
|
||||
version,
|
||||
indexes,
|
||||
@@ -45,19 +52,19 @@ impl Vecs {
|
||||
})?;
|
||||
|
||||
let class_stack = ByDcaClass::try_new(|name, _year, _day1| {
|
||||
AmountPerBlock::forced_import(db, &format!("dca_stack_{name}"), version, indexes)
|
||||
AmountPerBlock::forced_import(&db, &format!("dca_stack_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let class_cost_basis = ByDcaClass::try_new(|name, _year, _day1| {
|
||||
Price::forced_import(db, &format!("dca_cost_basis_{name}"), version, indexes)
|
||||
Price::forced_import(&db, &format!("dca_cost_basis_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
let class_return = ByDcaClass::try_new(|name, _year, _day1| {
|
||||
PercentPerBlock::forced_import(db, &format!("dca_return_{name}"), version, indexes)
|
||||
PercentPerBlock::forced_import(&db, &format!("dca_return_{name}"), version, indexes)
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
sats_per_day: ImportableVec::forced_import(db, "dca_sats_per_day", version)?,
|
||||
let this = Self {
|
||||
sats_per_day: ImportableVec::forced_import(&db, "dca_sats_per_day", version)?,
|
||||
period: PeriodVecs {
|
||||
stack,
|
||||
cost_basis,
|
||||
@@ -71,6 +78,9 @@ impl Vecs {
|
||||
cost_basis: class_cost_basis,
|
||||
r#return: class_return,
|
||||
},
|
||||
})
|
||||
db,
|
||||
};
|
||||
finalize_db(&this.db, &this)?;
|
||||
Ok(this)
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,5 @@ mod vecs;
|
||||
pub use by_class::*;
|
||||
pub use by_period::*;
|
||||
pub use vecs::Vecs;
|
||||
|
||||
pub const DB_NAME: &str = "investing";
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Cents, Height, Sats};
|
||||
use vecdb::{EagerVec, PcoVec, Rw, StorageMode};
|
||||
use vecdb::{Database, EagerVec, PcoVec, Rw, StorageMode};
|
||||
|
||||
use super::{ByDcaCagr, ByDcaClass, ByDcaPeriod};
|
||||
use crate::internal::{AmountPerBlock, PerBlock, PercentPerBlock, Price};
|
||||
@@ -24,6 +24,8 @@ pub struct ClassVecs<M: StorageMode = Rw> {
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
#[traversable(skip)]
|
||||
pub(crate) db: Database,
|
||||
pub sats_per_day: M::Stored<EagerVec<PcoVec<Height, Sats>>>,
|
||||
pub period: PeriodVecs<M>,
|
||||
pub class: ClassVecs<M>,
|
||||
@@ -18,6 +18,7 @@ mod indicators;
|
||||
pub mod indexes;
|
||||
mod inputs;
|
||||
mod internal;
|
||||
mod investing;
|
||||
mod market;
|
||||
mod mining;
|
||||
mod outputs;
|
||||
@@ -39,6 +40,7 @@ pub struct Computer<M: StorageMode = Rw> {
|
||||
pub constants: Box<constants::Vecs>,
|
||||
pub indexes: Box<indexes::Vecs<M>>,
|
||||
pub indicators: Box<indicators::Vecs<M>>,
|
||||
pub investing: Box<investing::Vecs<M>>,
|
||||
pub market: Box<market::Vecs<M>>,
|
||||
pub pools: Box<pools::Vecs<M>>,
|
||||
pub prices: Box<prices::Vecs<M>>,
|
||||
@@ -180,8 +182,8 @@ impl Computer {
|
||||
|
||||
// Market, indicators, and distribution are independent; import in parallel.
|
||||
// Supply depends on distribution so it runs after.
|
||||
let (distribution, market, indicators) =
|
||||
timed("Imported distribution/market/indicators", || {
|
||||
let (distribution, market, indicators, investing) =
|
||||
timed("Imported distribution/market/indicators/investing", || {
|
||||
thread::scope(|s| -> Result<_> {
|
||||
let market_handle = big_thread().spawn_scoped(s, || -> Result<_> {
|
||||
Ok(Box::new(market::Vecs::forced_import(
|
||||
@@ -199,6 +201,14 @@ impl Computer {
|
||||
)?))
|
||||
})?;
|
||||
|
||||
let investing_handle = big_thread().spawn_scoped(s, || -> Result<_> {
|
||||
Ok(Box::new(investing::Vecs::forced_import(
|
||||
&computed_path,
|
||||
VERSION,
|
||||
&indexes,
|
||||
)?))
|
||||
})?;
|
||||
|
||||
let distribution = Box::new(distribution::Vecs::forced_import(
|
||||
&computed_path,
|
||||
VERSION,
|
||||
@@ -208,7 +218,8 @@ impl Computer {
|
||||
|
||||
let market = market_handle.join().unwrap()?;
|
||||
let indicators = indicators_handle.join().unwrap()?;
|
||||
Ok((distribution, market, indicators))
|
||||
let investing = investing_handle.join().unwrap()?;
|
||||
Ok((distribution, market, indicators, investing))
|
||||
})
|
||||
})?;
|
||||
|
||||
@@ -232,6 +243,7 @@ impl Computer {
|
||||
scripts,
|
||||
constants,
|
||||
indicators,
|
||||
investing,
|
||||
market,
|
||||
distribution,
|
||||
supply,
|
||||
@@ -260,6 +272,7 @@ impl Computer {
|
||||
cointime::DB_NAME,
|
||||
indicators::DB_NAME,
|
||||
indexes::DB_NAME,
|
||||
investing::DB_NAME,
|
||||
market::DB_NAME,
|
||||
pools::DB_NAME,
|
||||
prices::DB_NAME,
|
||||
@@ -305,7 +318,7 @@ impl Computer {
|
||||
|
||||
let mut starting_indexes = timed("Computed indexes", || {
|
||||
self.indexes
|
||||
.compute(indexer, &mut self.blocks, starting_indexes, exit)
|
||||
.compute(indexer, starting_indexes, exit)
|
||||
})?;
|
||||
|
||||
thread::scope(|scope| -> Result<()> {
|
||||
@@ -339,8 +352,8 @@ impl Computer {
|
||||
let market = scope.spawn(|| {
|
||||
timed("Computed market", || {
|
||||
self.market.compute(
|
||||
&self.indexes,
|
||||
&self.prices,
|
||||
&self.indexes,
|
||||
&self.blocks,
|
||||
&starting_indexes,
|
||||
exit,
|
||||
@@ -422,6 +435,19 @@ impl Computer {
|
||||
})
|
||||
});
|
||||
|
||||
let investing = scope.spawn(|| {
|
||||
timed("Computed investing", || {
|
||||
self.investing.compute(
|
||||
&self.indexes,
|
||||
&self.prices,
|
||||
&self.blocks,
|
||||
&self.market.lookback,
|
||||
&starting_indexes_clone,
|
||||
exit,
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
timed("Computed distribution", || {
|
||||
self.distribution.compute(
|
||||
indexer,
|
||||
@@ -437,6 +463,7 @@ impl Computer {
|
||||
})?;
|
||||
|
||||
pools.join().unwrap()?;
|
||||
investing.join().unwrap()?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -485,6 +512,14 @@ impl Computer {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.indicators.thermometer.compute(
|
||||
&self.distribution,
|
||||
&self.cointime,
|
||||
&self.prices,
|
||||
&starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
info!("Total compute time: {:?}", compute_start.elapsed());
|
||||
Ok(())
|
||||
}
|
||||
@@ -517,7 +552,7 @@ macro_rules! impl_iter_named {
|
||||
}
|
||||
|
||||
impl_iter_named!(blocks, mining, transactions, scripts, positions, cointime,
|
||||
constants, indicators, indexes, market, pools, prices, distribution, supply, inputs, outputs);
|
||||
constants, indicators, indexes, investing, market, pools, prices, distribution, supply, inputs, outputs);
|
||||
|
||||
fn timed<T>(label: &str, f: impl FnOnce() -> T) -> T {
|
||||
let start = Instant::now();
|
||||
|
||||
@@ -3,13 +3,13 @@ use brk_types::{Indexes, StoredF32, Timestamp};
|
||||
use vecdb::{Exit, ReadableVec, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{blocks, prices};
|
||||
use crate::{indexes, prices};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
blocks: &blocks::Vecs,
|
||||
indexes: &indexes::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
@@ -24,7 +24,7 @@ impl Vecs {
|
||||
starting_indexes.height,
|
||||
&self.high.cents.height,
|
||||
&prices.spot.cents.height,
|
||||
&blocks.time.timestamp_monotonic,
|
||||
&indexes.timestamp.monotonic,
|
||||
|(i, ath, price, ts, slf)| {
|
||||
if ath_ts.is_none() {
|
||||
let idx = i.to_usize();
|
||||
|
||||
@@ -9,17 +9,19 @@ use super::Vecs;
|
||||
impl Vecs {
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
prices: &prices::Vecs,
|
||||
indexes: &indexes::Vecs,
|
||||
blocks: &blocks::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
// Phase 1: Independent sub-modules in parallel
|
||||
let (r1, r2) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| self.ath.compute(prices, blocks, starting_indexes, exit),
|
||||
|| self.ath.compute(prices, indexes, starting_indexes, exit),
|
||||
|| self.lookback.compute(blocks, prices, starting_indexes, exit),
|
||||
)
|
||||
},
|
||||
@@ -39,24 +41,8 @@ impl Vecs {
|
||||
r2.1?;
|
||||
|
||||
// Phase 2: Depend on lookback
|
||||
let (r3, r4) = rayon::join(
|
||||
|| {
|
||||
self.returns
|
||||
.compute(prices, blocks, &self.lookback, starting_indexes, exit)
|
||||
},
|
||||
|| {
|
||||
self.dca.compute(
|
||||
indexes,
|
||||
prices,
|
||||
blocks,
|
||||
&self.lookback,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)
|
||||
},
|
||||
);
|
||||
r3?;
|
||||
r4?;
|
||||
self.returns
|
||||
.compute(prices, blocks, &self.lookback, starting_indexes, exit)?;
|
||||
|
||||
// Phase 3: Depends on returns, moving_average
|
||||
self.technical.compute(
|
||||
@@ -68,8 +54,11 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
AthVecs, DcaVecs, TechnicalVecs, LookbackVecs, MovingAverageVecs, RangeVecs, ReturnsVecs,
|
||||
AthVecs, TechnicalVecs, LookbackVecs, MovingAverageVecs, RangeVecs, ReturnsVecs,
|
||||
Vecs, VolatilityVecs,
|
||||
};
|
||||
|
||||
@@ -28,7 +28,6 @@ impl Vecs {
|
||||
let volatility = VolatilityVecs::forced_import(version, &returns)?;
|
||||
let range = RangeVecs::forced_import(&db, version, indexes)?;
|
||||
let moving_average = MovingAverageVecs::forced_import(&db, version, indexes)?;
|
||||
let dca = DcaVecs::forced_import(&db, version, indexes)?;
|
||||
let technical = TechnicalVecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
let this = Self {
|
||||
@@ -39,7 +38,6 @@ impl Vecs {
|
||||
volatility,
|
||||
range,
|
||||
moving_average,
|
||||
dca,
|
||||
technical,
|
||||
};
|
||||
finalize_db(&this.db, &this)?;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use brk_traversable::Traversable;
|
||||
|
||||
use crate::market::dca::ByDcaPeriod;
|
||||
|
||||
/// Lookback period days (includes 24h, unlike DCA)
|
||||
pub const LOOKBACK_PERIOD_DAYS: ByLookbackPeriod<u32> = ByLookbackPeriod {
|
||||
_24h: 1,
|
||||
@@ -117,22 +115,4 @@ impl<T> ByLookbackPeriod<T> {
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
/// Get the DCA-matching subset (excludes 24h)
|
||||
pub(crate) fn as_dca_period(&self) -> ByDcaPeriod<&T> {
|
||||
ByDcaPeriod {
|
||||
_1w: &self._1w,
|
||||
_1m: &self._1m,
|
||||
_3m: &self._3m,
|
||||
_6m: &self._6m,
|
||||
_1y: &self._1y,
|
||||
_2y: &self._2y,
|
||||
_3y: &self._3y,
|
||||
_4y: &self._4y,
|
||||
_5y: &self._5y,
|
||||
_6y: &self._6y,
|
||||
_8y: &self._8y,
|
||||
_10y: &self._10y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
pub mod ath;
|
||||
mod compute;
|
||||
pub mod dca;
|
||||
mod import;
|
||||
pub mod technical;
|
||||
pub mod lookback;
|
||||
@@ -13,7 +12,6 @@ use brk_traversable::Traversable;
|
||||
use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
pub use ath::Vecs as AthVecs;
|
||||
pub use dca::Vecs as DcaVecs;
|
||||
pub use technical::Vecs as TechnicalVecs;
|
||||
pub use lookback::Vecs as LookbackVecs;
|
||||
pub use moving_average::Vecs as MovingAverageVecs;
|
||||
@@ -32,6 +30,5 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub volatility: VolatilityVecs,
|
||||
pub range: RangeVecs<M>,
|
||||
pub moving_average: MovingAverageVecs<M>,
|
||||
pub dca: DcaVecs<M>,
|
||||
pub technical: TechnicalVecs<M>,
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use brk_types::{BasisPointsSigned32, Dollars, Indexes};
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{blocks, internal::RatioDiffDollarsBps32, market::lookback, prices};
|
||||
use crate::{blocks, internal::RatioDiffDollarsBps32, investing::ByDcaPeriod, market::lookback, prices};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn compute(
|
||||
@@ -29,7 +29,7 @@ impl Vecs {
|
||||
}
|
||||
|
||||
// CAGR computed from returns at height level (2y+ periods only)
|
||||
let price_return_dca = self.periods.as_dca_period();
|
||||
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(
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{StdDevPerBlock, PercentPerBlock, Windows},
|
||||
market::dca::ByDcaCagr,
|
||||
investing::ByDcaCagr,
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
|
||||
@@ -4,7 +4,8 @@ use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
internal::{PercentPerBlock, StdDevPerBlock, Windows},
|
||||
market::{dca::ByDcaCagr, lookback::ByLookbackPeriod},
|
||||
investing::ByDcaCagr,
|
||||
market::lookback::ByLookbackPeriod,
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
|
||||
@@ -18,6 +18,8 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
// Block rewards (coinbase, subsidy, fee_dominance, etc.)
|
||||
self.rewards.compute(
|
||||
indexer,
|
||||
@@ -39,8 +41,11 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
self.count.compute(
|
||||
indexer,
|
||||
indexes,
|
||||
@@ -27,10 +29,13 @@ impl Vecs {
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
let _lock = self
|
||||
let lock = self
|
||||
.spent
|
||||
.compute(indexer, inputs, starting_indexes, exit)?;
|
||||
self.db.compact()?;
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = lock;
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ use crate::inputs;
|
||||
const HEIGHT_BATCH: u32 = 10_000;
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn compute<'a>(
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
inputs: &inputs::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
exit: &'a Exit,
|
||||
) -> Result<ExitGuard<'a>> {
|
||||
exit: &Exit,
|
||||
) -> Result<ExitGuard> {
|
||||
let target_height = indexer.vecs.blocks.blockhash.len();
|
||||
if target_height == 0 {
|
||||
return Ok(exit.lock());
|
||||
|
||||
@@ -86,6 +86,8 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
self.compute_pool(indexer, indexes, starting_indexes, exit)?;
|
||||
|
||||
self.major.par_iter_mut().try_for_each(|(_, vecs)| {
|
||||
@@ -103,8 +105,11 @@ impl Vecs {
|
||||
vecs.compute(starting_indexes, &self.pool, blocks, exit)
|
||||
})?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -45,9 +45,14 @@ impl Vecs {
|
||||
reader: &Reader,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
self.compute_(indexer, starting_indexes, reader, exit)?;
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
self.compute_prices(indexer, starting_indexes, exit)?;
|
||||
self.split.open.cents.compute_first(
|
||||
starting_indexes,
|
||||
@@ -47,8 +49,11 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db().compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ pub const DB_NAME: &str = "prices";
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
#[traversable(skip)]
|
||||
pub(crate) db: Database,
|
||||
pub db: Database,
|
||||
|
||||
pub split: SplitByUnit<M>,
|
||||
pub ohlc: OhlcByUnit<M>,
|
||||
@@ -183,7 +183,4 @@ impl Vecs {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn db(&self) -> &Database {
|
||||
&self.db
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,18 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
self.count.compute(indexer, starting_indexes, exit)?;
|
||||
|
||||
self.value
|
||||
.compute(indexer, prices, starting_indexes, exit)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
// 1. Compute burned/unspendable supply
|
||||
self.burned.compute(
|
||||
scripts,
|
||||
@@ -76,8 +78,11 @@ impl Vecs {
|
||||
)?;
|
||||
}
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.db.sync_bg_tasks()?;
|
||||
|
||||
let (r1, (r2, r3)) = rayon::join(
|
||||
|| {
|
||||
self.count
|
||||
@@ -57,8 +59,11 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
let exit = exit.clone();
|
||||
self.db.run_bg(move |db| {
|
||||
let _lock = exit.lock();
|
||||
db.compact()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use brk_error::Result;
|
||||
use brk_iterator::Blocks;
|
||||
use brk_rpc::Client;
|
||||
use brk_types::Height;
|
||||
use fjall::PersistMode;
|
||||
use tracing::{debug, info};
|
||||
use vecdb::{Exit, ReadOnlyClone, ReadableVec, Ro, Rw, StorageMode};
|
||||
mod constants;
|
||||
@@ -107,6 +108,8 @@ impl Indexer {
|
||||
exit: &Exit,
|
||||
check_collisions: bool,
|
||||
) -> Result<Indexes> {
|
||||
self.vecs.db.sync_bg_tasks()?;
|
||||
|
||||
debug!("Starting indexing...");
|
||||
|
||||
let last_blockhash = self.vecs.blocks.blockhash.collect_last();
|
||||
@@ -248,11 +251,32 @@ impl Indexer {
|
||||
|
||||
drop(readers);
|
||||
|
||||
if !is_export_height(indexes.height) {
|
||||
export(stores, vecs, indexes.height)?;
|
||||
}
|
||||
let lock = exit.lock();
|
||||
let tasks = self.stores.take_all_pending_ingests(indexes.height)?;
|
||||
self.vecs.stamped_write(indexes.height)?;
|
||||
let fjall_db = self.stores.db.clone();
|
||||
|
||||
self.vecs.compact()?;
|
||||
self.vecs.db.run_bg(move |db| {
|
||||
let _lock = lock;
|
||||
|
||||
if !tasks.is_empty() {
|
||||
let i = Instant::now();
|
||||
for task in tasks {
|
||||
task().map_err(vecdb::RawDBError::other)?;
|
||||
}
|
||||
info!("Stores committed in {:?}", i.elapsed());
|
||||
|
||||
let i = Instant::now();
|
||||
fjall_db
|
||||
.persist(PersistMode::SyncData)
|
||||
.map_err(vecdb::RawDBError::other)?;
|
||||
info!("Stores persisted in {:?}", i.elapsed());
|
||||
}
|
||||
|
||||
db.flush()?;
|
||||
db.compact()?;
|
||||
Ok(())
|
||||
});
|
||||
|
||||
Ok(starting_indexes)
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ use brk_cohort::ByAddrType;
|
||||
use brk_error::Result;
|
||||
use brk_store::{AnyStore, Kind, Mode, Store};
|
||||
use brk_types::{
|
||||
AddrHash, AddrIndexOutPoint, AddrIndexTxIndex, BlockHashPrefix, Height, OutPoint,
|
||||
OutputType, StoredString, TxIndex, TxOutIndex, TxidPrefix, TypeIndex, Unit, Version, Vout,
|
||||
AddrHash, AddrIndexOutPoint, AddrIndexTxIndex, BlockHashPrefix, Height, OutPoint, OutputType,
|
||||
StoredString, TxIndex, TxOutIndex, TxidPrefix, TypeIndex, Unit, Version, Vout,
|
||||
};
|
||||
use fjall::{Database, PersistMode};
|
||||
use rayon::prelude::*;
|
||||
@@ -24,8 +24,7 @@ pub struct Stores {
|
||||
|
||||
pub addr_type_to_addr_hash_to_addr_index: ByAddrType<Store<AddrHash, TypeIndex>>,
|
||||
pub addr_type_to_addr_index_and_tx_index: ByAddrType<Store<AddrIndexTxIndex, Unit>>,
|
||||
pub addr_type_to_addr_index_and_unspent_outpoint:
|
||||
ByAddrType<Store<AddrIndexOutPoint, Unit>>,
|
||||
pub addr_type_to_addr_index_and_unspent_outpoint: ByAddrType<Store<AddrIndexOutPoint, Unit>>,
|
||||
pub blockhash_prefix_to_height: Store<BlockHashPrefix, Height>,
|
||||
pub height_to_coinbase_tag: Store<Height, StoredString>,
|
||||
pub txid_prefix_to_tx_index: Store<TxidPrefix, TxIndex>,
|
||||
@@ -194,6 +193,39 @@ impl Stores {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Takes all pending puts/dels from every store and returns closures
|
||||
/// that can ingest them on a background thread.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn take_all_pending_ingests(
|
||||
&mut self,
|
||||
height: Height,
|
||||
) -> Result<Vec<Box<dyn FnOnce() -> Result<()> + Send>>> {
|
||||
let h = height;
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
macro_rules! take {
|
||||
($store:expr) => {
|
||||
tasks.extend($store.take_pending_ingest(h)?);
|
||||
};
|
||||
}
|
||||
|
||||
take!(self.blockhash_prefix_to_height);
|
||||
take!(self.height_to_coinbase_tag);
|
||||
take!(self.txid_prefix_to_tx_index);
|
||||
|
||||
for store in self.addr_type_to_addr_hash_to_addr_index.values_mut() {
|
||||
take!(store);
|
||||
}
|
||||
for store in self.addr_type_to_addr_index_and_tx_index.values_mut() {
|
||||
take!(store);
|
||||
}
|
||||
for store in self.addr_type_to_addr_index_and_unspent_outpoint.values_mut() {
|
||||
take!(store);
|
||||
}
|
||||
|
||||
Ok(tasks)
|
||||
}
|
||||
|
||||
pub fn rollback_if_needed(
|
||||
&mut self,
|
||||
vecs: &mut Vecs,
|
||||
@@ -368,11 +400,7 @@ impl Stores {
|
||||
let addr_type = output_type;
|
||||
let addr_index = type_index;
|
||||
|
||||
addr_index_tx_index_to_remove.insert((
|
||||
addr_type,
|
||||
addr_index,
|
||||
spending_tx_index,
|
||||
));
|
||||
addr_index_tx_index_to_remove.insert((addr_type, addr_index, spending_tx_index));
|
||||
|
||||
self.addr_type_to_addr_index_and_unspent_outpoint
|
||||
.get_mut_unwrap(addr_type)
|
||||
|
||||
@@ -30,7 +30,7 @@ use crate::Indexes;
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
#[traversable(skip)]
|
||||
db: Database,
|
||||
pub db: Database,
|
||||
pub blocks: BlocksVecs<M>,
|
||||
#[traversable(wrap = "transactions", rename = "raw")]
|
||||
pub transactions: TransactionsVecs<M>,
|
||||
@@ -121,8 +121,7 @@ impl Vecs {
|
||||
}
|
||||
|
||||
pub fn flush(&mut self, height: Height) -> Result<()> {
|
||||
self.par_iter_mut_any_stored_vec()
|
||||
.try_for_each(|vec| vec.stamped_write(Stamp::from(height)))?;
|
||||
self.stamped_write(height)?;
|
||||
self.db.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -137,6 +136,12 @@ impl Vecs {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn stamped_write(&mut self, height: Height) -> Result<()> {
|
||||
self.par_iter_mut_any_stored_vec()
|
||||
.try_for_each(|vec| vec.stamped_write(Stamp::from(height)))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compact(&self) -> Result<()> {
|
||||
self.db.compact()?;
|
||||
Ok(())
|
||||
@@ -168,7 +173,4 @@ impl Vecs {
|
||||
.chain(self.scripts.par_iter_mut_any())
|
||||
}
|
||||
|
||||
pub fn db(&self) -> &Database {
|
||||
&self.db
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ impl<'a> Day1Iter<'a> {
|
||||
.to_usize()
|
||||
.saturating_sub(self.start_di.to_usize())
|
||||
+ 1;
|
||||
let timestamps = &self.computer.blocks.time.timestamp.day1;
|
||||
let timestamps = &self.computer.indexes.timestamp.day1;
|
||||
let heights = &self.computer.indexes.day1.first_height;
|
||||
|
||||
let mut entries = Vec::with_capacity(total / self.step + 1);
|
||||
|
||||
@@ -45,8 +45,7 @@ impl Query {
|
||||
|
||||
// Get timestamps using difficulty_to_timestamp for epoch start
|
||||
let epoch_start_timestamp = computer
|
||||
.blocks
|
||||
.time
|
||||
.indexes
|
||||
.timestamp
|
||||
.epoch
|
||||
.collect_one(current_epoch)
|
||||
|
||||
@@ -22,7 +22,7 @@ pub fn iter_difficulty_epochs(
|
||||
.unwrap_or_default();
|
||||
|
||||
let epoch_to_height = &computer.indexes.epoch.first_height;
|
||||
let epoch_to_timestamp = &computer.blocks.time.timestamp.epoch;
|
||||
let epoch_to_timestamp = &computer.indexes.timestamp.epoch;
|
||||
let epoch_to_difficulty = &computer.blocks.difficulty.value.epoch;
|
||||
|
||||
let mut results = Vec::with_capacity(end_epoch.to_usize() - start_epoch.to_usize() + 1);
|
||||
|
||||
@@ -56,7 +56,7 @@ impl Query {
|
||||
let step = (total_days / 200).max(1); // Max ~200 data points
|
||||
|
||||
let hashrate_vec = &computer.mining.hashrate.rate.base.day1;
|
||||
let timestamp_vec = &computer.blocks.time.timestamp.day1;
|
||||
let timestamp_vec = &computer.indexes.timestamp.day1;
|
||||
|
||||
let mut hashrates = Vec::with_capacity(total_days / step + 1);
|
||||
let mut di = start_day1.to_usize();
|
||||
|
||||
@@ -373,7 +373,7 @@ impl Query {
|
||||
// Slow path: rebuild from computer's precomputed monotonic timestamps
|
||||
let mut map = HEIGHT_BY_MONOTONIC_TIMESTAMP.write();
|
||||
if map.len() <= current_height {
|
||||
*map = RangeMap::from(self.computer().blocks.time.timestamp_monotonic.collect());
|
||||
*map = RangeMap::from(self.computer().indexes.timestamp.monotonic.collect());
|
||||
}
|
||||
map.ceil(ts).map(usize::from).unwrap_or(current_height)
|
||||
}
|
||||
|
||||
@@ -206,6 +206,34 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes buffered puts/dels and returns a closure that ingests them into the keyspace.
|
||||
/// The store is left with empty buffers, ready for the next batch.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn take_pending_ingest(
|
||||
&mut self,
|
||||
height: Height,
|
||||
) -> Result<Option<Box<dyn FnOnce() -> Result<()> + Send>>>
|
||||
where
|
||||
K: Send + 'static,
|
||||
V: Send + 'static,
|
||||
for<'a> ByteView: From<&'a K> + From<&'a V>,
|
||||
{
|
||||
self.export_meta_if_needed(height)?;
|
||||
|
||||
let puts = mem::take(&mut self.puts);
|
||||
let dels = mem::take(&mut self.dels);
|
||||
|
||||
if puts.is_empty() && dels.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let keyspace = self.keyspace.clone();
|
||||
|
||||
Ok(Some(Box::new(move || {
|
||||
Self::ingest(&keyspace, puts.iter(), dels.iter())
|
||||
})))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> impl Iterator<Item = (K, V)> {
|
||||
self.keyspace
|
||||
|
||||
+237
-199
@@ -1973,7 +1973,7 @@ function createGrossInvestedInvestorLossNetNuplProfitSentimentPattern2(client, a
|
||||
* @typedef {Object} BpsCentsPercentilesRatioSatsSmaStdUsdPattern
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
* @property {SeriesPattern1<Cents>} cents
|
||||
* @property {Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {SeriesPattern1<StoredF32>} ratio
|
||||
* @property {SeriesPattern1<SatsFract>} sats
|
||||
* @property {_1m1w1y2y4yAllPattern} sma
|
||||
@@ -1981,6 +1981,37 @@ function createGrossInvestedInvestorLossNetNuplProfitSentimentPattern2(client, a
|
||||
* @property {SeriesPattern1<Dollars>} usd
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern
|
||||
* @property {BpsPriceRatioPattern} pct05
|
||||
* @property {BpsPriceRatioPattern} pct1
|
||||
* @property {BpsPriceRatioPattern} pct2
|
||||
* @property {BpsPriceRatioPattern} pct5
|
||||
* @property {BpsPriceRatioPattern} pct95
|
||||
* @property {BpsPriceRatioPattern} pct98
|
||||
* @property {BpsPriceRatioPattern} pct99
|
||||
* @property {BpsPriceRatioPattern} pct995
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated series name
|
||||
* @returns {Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern}
|
||||
*/
|
||||
function createPct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, acc) {
|
||||
return {
|
||||
pct05: createBpsPriceRatioPattern(client, acc, 'pct0_5'),
|
||||
pct1: createBpsPriceRatioPattern(client, acc, 'pct1'),
|
||||
pct2: createBpsPriceRatioPattern(client, acc, 'pct2'),
|
||||
pct5: createBpsPriceRatioPattern(client, acc, 'pct5'),
|
||||
pct95: createBpsPriceRatioPattern(client, acc, 'pct95'),
|
||||
pct98: createBpsPriceRatioPattern(client, acc, 'pct98'),
|
||||
pct99: createBpsPriceRatioPattern(client, acc, 'pct99'),
|
||||
pct995: createBpsPriceRatioPattern(client, acc, 'pct99_5'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _10y2y3y4y5y6y8yPattern
|
||||
* @property {BpsPercentRatioPattern} _10y
|
||||
@@ -2242,7 +2273,7 @@ function createAverageBlockCumulativeInSumPattern(client, acc) {
|
||||
* @typedef {Object} BpsCentsPercentilesRatioSatsUsdPattern
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
* @property {SeriesPattern1<Cents>} cents
|
||||
* @property {Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {SeriesPattern1<StoredF32>} ratio
|
||||
* @property {SeriesPattern1<SatsFract>} sats
|
||||
* @property {SeriesPattern1<Dollars>} usd
|
||||
@@ -2258,7 +2289,7 @@ function createBpsCentsPercentilesRatioSatsUsdPattern(client, acc) {
|
||||
return {
|
||||
bps: createSeriesPattern1(client, _m(acc, 'ratio_bps')),
|
||||
cents: createSeriesPattern1(client, _m(acc, 'cents')),
|
||||
percentiles: createPct1Pct2Pct5Pct95Pct98Pct99Pattern(client, acc),
|
||||
percentiles: createPct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, acc),
|
||||
ratio: createSeriesPattern1(client, _m(acc, 'ratio')),
|
||||
sats: createSeriesPattern1(client, _m(acc, 'sats')),
|
||||
usd: createSeriesPattern1(client, acc),
|
||||
@@ -2373,33 +2404,6 @@ function createDeltaHalfInToTotalPattern2(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Pct1Pct2Pct5Pct95Pct98Pct99Pattern
|
||||
* @property {BpsPriceRatioPattern} pct1
|
||||
* @property {BpsPriceRatioPattern} pct2
|
||||
* @property {BpsPriceRatioPattern} pct5
|
||||
* @property {BpsPriceRatioPattern} pct95
|
||||
* @property {BpsPriceRatioPattern} pct98
|
||||
* @property {BpsPriceRatioPattern} pct99
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a Pct1Pct2Pct5Pct95Pct98Pct99Pattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated series name
|
||||
* @returns {Pct1Pct2Pct5Pct95Pct98Pct99Pattern}
|
||||
*/
|
||||
function createPct1Pct2Pct5Pct95Pct98Pct99Pattern(client, acc) {
|
||||
return {
|
||||
pct1: createBpsPriceRatioPattern(client, acc, 'pct1'),
|
||||
pct2: createBpsPriceRatioPattern(client, acc, 'pct2'),
|
||||
pct5: createBpsPriceRatioPattern(client, acc, 'pct5'),
|
||||
pct95: createBpsPriceRatioPattern(client, acc, 'pct95'),
|
||||
pct98: createBpsPriceRatioPattern(client, acc, 'pct98'),
|
||||
pct99: createBpsPriceRatioPattern(client, acc, 'pct99'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _1m1w1y24hBlockPattern
|
||||
* @property {SeriesPattern1<StoredF32>} _1m
|
||||
@@ -4146,6 +4150,7 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesTree_Constants} constants
|
||||
* @property {SeriesTree_Indexes} indexes
|
||||
* @property {SeriesTree_Indicators} indicators
|
||||
* @property {SeriesTree_Investing} investing
|
||||
* @property {SeriesTree_Market} market
|
||||
* @property {SeriesTree_Pools} pools
|
||||
* @property {SeriesTree_Prices} prices
|
||||
@@ -4180,9 +4185,7 @@ function createTransferPattern(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Blocks_Time
|
||||
* @property {SeriesPattern1<Timestamp>} timestamp
|
||||
* @property {SeriesPattern18<Date>} date
|
||||
* @property {SeriesPattern18<Timestamp>} timestampMonotonic
|
||||
* @property {SeriesPattern18<Timestamp>} timestamp
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -4769,6 +4772,7 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesTree_Indexes_TxIndex} txIndex
|
||||
* @property {SeriesTree_Indexes_TxinIndex} txinIndex
|
||||
* @property {SeriesTree_Indexes_TxoutIndex} txoutIndex
|
||||
* @property {SeriesTree_Indexes_Timestamp} timestamp
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -4992,6 +4996,12 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesPattern21<TxOutIndex>} identity
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Indexes_Timestamp
|
||||
* @property {SeriesPattern18<Timestamp>} monotonic
|
||||
* @property {SeriesPattern2<Timestamp>} resolutions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Indicators
|
||||
* @property {BpsRatioPattern2} puellMultiple
|
||||
@@ -5004,6 +5014,7 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesTree_Indicators_Dormancy} dormancy
|
||||
* @property {SeriesPattern1<StoredF32>} stockToFlow
|
||||
* @property {SeriesPattern1<StoredF32>} sellerExhaustion
|
||||
* @property {SeriesTree_Indicators_Thermometer} thermometer
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -5012,6 +5023,108 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesPattern1<StoredF32>} flow
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Indicators_Thermometer
|
||||
* @property {CentsSatsUsdPattern} pct05
|
||||
* @property {CentsSatsUsdPattern} pct1
|
||||
* @property {CentsSatsUsdPattern} pct2
|
||||
* @property {CentsSatsUsdPattern} pct5
|
||||
* @property {CentsSatsUsdPattern} pct95
|
||||
* @property {CentsSatsUsdPattern} pct98
|
||||
* @property {CentsSatsUsdPattern} pct99
|
||||
* @property {CentsSatsUsdPattern} pct995
|
||||
* @property {SeriesPattern1<StoredI8>} zone
|
||||
* @property {SeriesPattern1<StoredI8>} score
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Investing
|
||||
* @property {SeriesPattern18<Sats>} satsPerDay
|
||||
* @property {SeriesTree_Investing_Period} period
|
||||
* @property {SeriesTree_Investing_Class} class
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Investing_Period
|
||||
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern3} stack
|
||||
* @property {SeriesTree_Investing_Period_CostBasis} costBasis
|
||||
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern2} return
|
||||
* @property {_10y2y3y4y5y6y8yPattern} cagr
|
||||
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern3} lumpSumStack
|
||||
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern2} lumpSumReturn
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Investing_Period_CostBasis
|
||||
* @property {CentsSatsUsdPattern} _1w
|
||||
* @property {CentsSatsUsdPattern} _1m
|
||||
* @property {CentsSatsUsdPattern} _3m
|
||||
* @property {CentsSatsUsdPattern} _6m
|
||||
* @property {CentsSatsUsdPattern} _1y
|
||||
* @property {CentsSatsUsdPattern} _2y
|
||||
* @property {CentsSatsUsdPattern} _3y
|
||||
* @property {CentsSatsUsdPattern} _4y
|
||||
* @property {CentsSatsUsdPattern} _5y
|
||||
* @property {CentsSatsUsdPattern} _6y
|
||||
* @property {CentsSatsUsdPattern} _8y
|
||||
* @property {CentsSatsUsdPattern} _10y
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Investing_Class
|
||||
* @property {SeriesTree_Investing_Class_Stack} stack
|
||||
* @property {SeriesTree_Investing_Class_CostBasis} costBasis
|
||||
* @property {SeriesTree_Investing_Class_Return} return
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Investing_Class_Stack
|
||||
* @property {BtcCentsSatsUsdPattern3} from2015
|
||||
* @property {BtcCentsSatsUsdPattern3} from2016
|
||||
* @property {BtcCentsSatsUsdPattern3} from2017
|
||||
* @property {BtcCentsSatsUsdPattern3} from2018
|
||||
* @property {BtcCentsSatsUsdPattern3} from2019
|
||||
* @property {BtcCentsSatsUsdPattern3} from2020
|
||||
* @property {BtcCentsSatsUsdPattern3} from2021
|
||||
* @property {BtcCentsSatsUsdPattern3} from2022
|
||||
* @property {BtcCentsSatsUsdPattern3} from2023
|
||||
* @property {BtcCentsSatsUsdPattern3} from2024
|
||||
* @property {BtcCentsSatsUsdPattern3} from2025
|
||||
* @property {BtcCentsSatsUsdPattern3} from2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Investing_Class_CostBasis
|
||||
* @property {CentsSatsUsdPattern} from2015
|
||||
* @property {CentsSatsUsdPattern} from2016
|
||||
* @property {CentsSatsUsdPattern} from2017
|
||||
* @property {CentsSatsUsdPattern} from2018
|
||||
* @property {CentsSatsUsdPattern} from2019
|
||||
* @property {CentsSatsUsdPattern} from2020
|
||||
* @property {CentsSatsUsdPattern} from2021
|
||||
* @property {CentsSatsUsdPattern} from2022
|
||||
* @property {CentsSatsUsdPattern} from2023
|
||||
* @property {CentsSatsUsdPattern} from2024
|
||||
* @property {CentsSatsUsdPattern} from2025
|
||||
* @property {CentsSatsUsdPattern} from2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Investing_Class_Return
|
||||
* @property {BpsPercentRatioPattern} from2015
|
||||
* @property {BpsPercentRatioPattern} from2016
|
||||
* @property {BpsPercentRatioPattern} from2017
|
||||
* @property {BpsPercentRatioPattern} from2018
|
||||
* @property {BpsPercentRatioPattern} from2019
|
||||
* @property {BpsPercentRatioPattern} from2020
|
||||
* @property {BpsPercentRatioPattern} from2021
|
||||
* @property {BpsPercentRatioPattern} from2022
|
||||
* @property {BpsPercentRatioPattern} from2023
|
||||
* @property {BpsPercentRatioPattern} from2024
|
||||
* @property {BpsPercentRatioPattern} from2025
|
||||
* @property {BpsPercentRatioPattern} from2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market
|
||||
* @property {SeriesTree_Market_Ath} ath
|
||||
@@ -5020,7 +5133,6 @@ function createTransferPattern(client, acc) {
|
||||
* @property {_1m1w1y24hPattern<StoredF32>} volatility
|
||||
* @property {SeriesTree_Market_Range} range
|
||||
* @property {SeriesTree_Market_MovingAverage} movingAverage
|
||||
* @property {SeriesTree_Market_Dca} dca
|
||||
* @property {SeriesTree_Market_Technical} technical
|
||||
*/
|
||||
|
||||
@@ -5183,94 +5295,6 @@ function createTransferPattern(client, acc) {
|
||||
* @property {BpsCentsRatioSatsUsdPattern} _4y
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market_Dca
|
||||
* @property {SeriesPattern18<Sats>} satsPerDay
|
||||
* @property {SeriesTree_Market_Dca_Period} period
|
||||
* @property {SeriesTree_Market_Dca_Class} class
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market_Dca_Period
|
||||
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern3} stack
|
||||
* @property {SeriesTree_Market_Dca_Period_CostBasis} costBasis
|
||||
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern2} return
|
||||
* @property {_10y2y3y4y5y6y8yPattern} cagr
|
||||
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern3} lumpSumStack
|
||||
* @property {_10y1m1w1y2y3m3y4y5y6m6y8yPattern2} lumpSumReturn
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market_Dca_Period_CostBasis
|
||||
* @property {CentsSatsUsdPattern} _1w
|
||||
* @property {CentsSatsUsdPattern} _1m
|
||||
* @property {CentsSatsUsdPattern} _3m
|
||||
* @property {CentsSatsUsdPattern} _6m
|
||||
* @property {CentsSatsUsdPattern} _1y
|
||||
* @property {CentsSatsUsdPattern} _2y
|
||||
* @property {CentsSatsUsdPattern} _3y
|
||||
* @property {CentsSatsUsdPattern} _4y
|
||||
* @property {CentsSatsUsdPattern} _5y
|
||||
* @property {CentsSatsUsdPattern} _6y
|
||||
* @property {CentsSatsUsdPattern} _8y
|
||||
* @property {CentsSatsUsdPattern} _10y
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market_Dca_Class
|
||||
* @property {SeriesTree_Market_Dca_Class_Stack} stack
|
||||
* @property {SeriesTree_Market_Dca_Class_CostBasis} costBasis
|
||||
* @property {SeriesTree_Market_Dca_Class_Return} return
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market_Dca_Class_Stack
|
||||
* @property {BtcCentsSatsUsdPattern3} from2015
|
||||
* @property {BtcCentsSatsUsdPattern3} from2016
|
||||
* @property {BtcCentsSatsUsdPattern3} from2017
|
||||
* @property {BtcCentsSatsUsdPattern3} from2018
|
||||
* @property {BtcCentsSatsUsdPattern3} from2019
|
||||
* @property {BtcCentsSatsUsdPattern3} from2020
|
||||
* @property {BtcCentsSatsUsdPattern3} from2021
|
||||
* @property {BtcCentsSatsUsdPattern3} from2022
|
||||
* @property {BtcCentsSatsUsdPattern3} from2023
|
||||
* @property {BtcCentsSatsUsdPattern3} from2024
|
||||
* @property {BtcCentsSatsUsdPattern3} from2025
|
||||
* @property {BtcCentsSatsUsdPattern3} from2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market_Dca_Class_CostBasis
|
||||
* @property {CentsSatsUsdPattern} from2015
|
||||
* @property {CentsSatsUsdPattern} from2016
|
||||
* @property {CentsSatsUsdPattern} from2017
|
||||
* @property {CentsSatsUsdPattern} from2018
|
||||
* @property {CentsSatsUsdPattern} from2019
|
||||
* @property {CentsSatsUsdPattern} from2020
|
||||
* @property {CentsSatsUsdPattern} from2021
|
||||
* @property {CentsSatsUsdPattern} from2022
|
||||
* @property {CentsSatsUsdPattern} from2023
|
||||
* @property {CentsSatsUsdPattern} from2024
|
||||
* @property {CentsSatsUsdPattern} from2025
|
||||
* @property {CentsSatsUsdPattern} from2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market_Dca_Class_Return
|
||||
* @property {BpsPercentRatioPattern} from2015
|
||||
* @property {BpsPercentRatioPattern} from2016
|
||||
* @property {BpsPercentRatioPattern} from2017
|
||||
* @property {BpsPercentRatioPattern} from2018
|
||||
* @property {BpsPercentRatioPattern} from2019
|
||||
* @property {BpsPercentRatioPattern} from2020
|
||||
* @property {BpsPercentRatioPattern} from2021
|
||||
* @property {BpsPercentRatioPattern} from2022
|
||||
* @property {BpsPercentRatioPattern} from2023
|
||||
* @property {BpsPercentRatioPattern} from2024
|
||||
* @property {BpsPercentRatioPattern} from2025
|
||||
* @property {BpsPercentRatioPattern} from2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SeriesTree_Market_Technical
|
||||
* @property {SeriesTree_Market_Technical_Rsi} rsi
|
||||
@@ -5624,7 +5648,7 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesPattern1<SatsFract>} sats
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
* @property {SeriesPattern1<StoredF32>} ratio
|
||||
* @property {Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {_1m1w1y2y4yAllPattern} sma
|
||||
* @property {SeriesTree_Cohorts_Utxo_All_Realized_Price_StdDev} stdDev
|
||||
*/
|
||||
@@ -5815,7 +5839,7 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesPattern1<SatsFract>} sats
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
* @property {SeriesPattern1<StoredF32>} ratio
|
||||
* @property {Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {_1m1w1y2y4yAllPattern} sma
|
||||
* @property {SeriesTree_Cohorts_Utxo_Sth_Realized_Price_StdDev} stdDev
|
||||
*/
|
||||
@@ -5937,7 +5961,7 @@ function createTransferPattern(client, acc) {
|
||||
* @property {SeriesPattern1<SatsFract>} sats
|
||||
* @property {SeriesPattern1<BasisPoints32>} bps
|
||||
* @property {SeriesPattern1<StoredF32>} ratio
|
||||
* @property {Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern} percentiles
|
||||
* @property {_1m1w1y2y4yAllPattern} sma
|
||||
* @property {SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev} stdDev
|
||||
*/
|
||||
@@ -7557,9 +7581,7 @@ class BrkClient extends BrkClientBase {
|
||||
daysToRetarget: createSeriesPattern1(this, 'days_to_retarget'),
|
||||
},
|
||||
time: {
|
||||
timestamp: createSeriesPattern1(this, 'timestamp'),
|
||||
date: createSeriesPattern18(this, 'date'),
|
||||
timestampMonotonic: createSeriesPattern18(this, 'timestamp_monotonic'),
|
||||
timestamp: createSeriesPattern18(this, 'timestamp'),
|
||||
},
|
||||
size: {
|
||||
base: createSeriesPattern18(this, 'total_size'),
|
||||
@@ -8101,6 +8123,10 @@ class BrkClient extends BrkClientBase {
|
||||
txoutIndex: {
|
||||
identity: createSeriesPattern21(this, 'txout_index'),
|
||||
},
|
||||
timestamp: {
|
||||
monotonic: createSeriesPattern18(this, 'timestamp_monotonic'),
|
||||
resolutions: createSeriesPattern2(this, 'timestamp'),
|
||||
},
|
||||
},
|
||||
indicators: {
|
||||
puellMultiple: createBpsRatioPattern2(this, 'puell_multiple'),
|
||||
@@ -8116,6 +8142,86 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
stockToFlow: createSeriesPattern1(this, 'stock_to_flow'),
|
||||
sellerExhaustion: createSeriesPattern1(this, 'seller_exhaustion'),
|
||||
thermometer: {
|
||||
pct05: createCentsSatsUsdPattern(this, 'thermometer_pct0_5'),
|
||||
pct1: createCentsSatsUsdPattern(this, 'thermometer_pct01'),
|
||||
pct2: createCentsSatsUsdPattern(this, 'thermometer_pct02'),
|
||||
pct5: createCentsSatsUsdPattern(this, 'thermometer_pct05'),
|
||||
pct95: createCentsSatsUsdPattern(this, 'thermometer_pct95'),
|
||||
pct98: createCentsSatsUsdPattern(this, 'thermometer_pct98'),
|
||||
pct99: createCentsSatsUsdPattern(this, 'thermometer_pct99'),
|
||||
pct995: createCentsSatsUsdPattern(this, 'thermometer_pct99_5'),
|
||||
zone: createSeriesPattern1(this, 'thermometer_zone'),
|
||||
score: createSeriesPattern1(this, 'thermometer_score'),
|
||||
},
|
||||
},
|
||||
investing: {
|
||||
satsPerDay: createSeriesPattern18(this, 'dca_sats_per_day'),
|
||||
period: {
|
||||
stack: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(this, 'dca_stack'),
|
||||
costBasis: {
|
||||
_1w: createCentsSatsUsdPattern(this, 'dca_cost_basis_1w'),
|
||||
_1m: createCentsSatsUsdPattern(this, 'dca_cost_basis_1m'),
|
||||
_3m: createCentsSatsUsdPattern(this, 'dca_cost_basis_3m'),
|
||||
_6m: createCentsSatsUsdPattern(this, 'dca_cost_basis_6m'),
|
||||
_1y: createCentsSatsUsdPattern(this, 'dca_cost_basis_1y'),
|
||||
_2y: createCentsSatsUsdPattern(this, 'dca_cost_basis_2y'),
|
||||
_3y: createCentsSatsUsdPattern(this, 'dca_cost_basis_3y'),
|
||||
_4y: createCentsSatsUsdPattern(this, 'dca_cost_basis_4y'),
|
||||
_5y: createCentsSatsUsdPattern(this, 'dca_cost_basis_5y'),
|
||||
_6y: createCentsSatsUsdPattern(this, 'dca_cost_basis_6y'),
|
||||
_8y: createCentsSatsUsdPattern(this, 'dca_cost_basis_8y'),
|
||||
_10y: createCentsSatsUsdPattern(this, 'dca_cost_basis_10y'),
|
||||
},
|
||||
return: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern2(this, 'dca_return'),
|
||||
cagr: create_10y2y3y4y5y6y8yPattern(this, 'dca_cagr'),
|
||||
lumpSumStack: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(this, 'lump_sum_stack'),
|
||||
lumpSumReturn: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern2(this, 'lump_sum_return'),
|
||||
},
|
||||
class: {
|
||||
stack: {
|
||||
from2015: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2015'),
|
||||
from2016: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2016'),
|
||||
from2017: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2017'),
|
||||
from2018: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2018'),
|
||||
from2019: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2019'),
|
||||
from2020: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2020'),
|
||||
from2021: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2021'),
|
||||
from2022: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2022'),
|
||||
from2023: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2023'),
|
||||
from2024: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2024'),
|
||||
from2025: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2025'),
|
||||
from2026: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2026'),
|
||||
},
|
||||
costBasis: {
|
||||
from2015: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2015'),
|
||||
from2016: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2016'),
|
||||
from2017: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2017'),
|
||||
from2018: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2018'),
|
||||
from2019: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2019'),
|
||||
from2020: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2020'),
|
||||
from2021: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2021'),
|
||||
from2022: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2022'),
|
||||
from2023: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2023'),
|
||||
from2024: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2024'),
|
||||
from2025: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2025'),
|
||||
from2026: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2026'),
|
||||
},
|
||||
return: {
|
||||
from2015: createBpsPercentRatioPattern(this, 'dca_return_from_2015'),
|
||||
from2016: createBpsPercentRatioPattern(this, 'dca_return_from_2016'),
|
||||
from2017: createBpsPercentRatioPattern(this, 'dca_return_from_2017'),
|
||||
from2018: createBpsPercentRatioPattern(this, 'dca_return_from_2018'),
|
||||
from2019: createBpsPercentRatioPattern(this, 'dca_return_from_2019'),
|
||||
from2020: createBpsPercentRatioPattern(this, 'dca_return_from_2020'),
|
||||
from2021: createBpsPercentRatioPattern(this, 'dca_return_from_2021'),
|
||||
from2022: createBpsPercentRatioPattern(this, 'dca_return_from_2022'),
|
||||
from2023: createBpsPercentRatioPattern(this, 'dca_return_from_2023'),
|
||||
from2024: createBpsPercentRatioPattern(this, 'dca_return_from_2024'),
|
||||
from2025: createBpsPercentRatioPattern(this, 'dca_return_from_2025'),
|
||||
from2026: createBpsPercentRatioPattern(this, 'dca_return_from_2026'),
|
||||
},
|
||||
},
|
||||
},
|
||||
market: {
|
||||
ath: {
|
||||
@@ -8238,74 +8344,6 @@ class BrkClient extends BrkClientBase {
|
||||
_4y: createBpsCentsRatioSatsUsdPattern(this, 'price_ema_4y'),
|
||||
},
|
||||
},
|
||||
dca: {
|
||||
satsPerDay: createSeriesPattern18(this, 'dca_sats_per_day'),
|
||||
period: {
|
||||
stack: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(this, 'dca_stack'),
|
||||
costBasis: {
|
||||
_1w: createCentsSatsUsdPattern(this, 'dca_cost_basis_1w'),
|
||||
_1m: createCentsSatsUsdPattern(this, 'dca_cost_basis_1m'),
|
||||
_3m: createCentsSatsUsdPattern(this, 'dca_cost_basis_3m'),
|
||||
_6m: createCentsSatsUsdPattern(this, 'dca_cost_basis_6m'),
|
||||
_1y: createCentsSatsUsdPattern(this, 'dca_cost_basis_1y'),
|
||||
_2y: createCentsSatsUsdPattern(this, 'dca_cost_basis_2y'),
|
||||
_3y: createCentsSatsUsdPattern(this, 'dca_cost_basis_3y'),
|
||||
_4y: createCentsSatsUsdPattern(this, 'dca_cost_basis_4y'),
|
||||
_5y: createCentsSatsUsdPattern(this, 'dca_cost_basis_5y'),
|
||||
_6y: createCentsSatsUsdPattern(this, 'dca_cost_basis_6y'),
|
||||
_8y: createCentsSatsUsdPattern(this, 'dca_cost_basis_8y'),
|
||||
_10y: createCentsSatsUsdPattern(this, 'dca_cost_basis_10y'),
|
||||
},
|
||||
return: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern2(this, 'dca_return'),
|
||||
cagr: create_10y2y3y4y5y6y8yPattern(this, 'dca_cagr'),
|
||||
lumpSumStack: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern3(this, 'lump_sum_stack'),
|
||||
lumpSumReturn: create_10y1m1w1y2y3m3y4y5y6m6y8yPattern2(this, 'lump_sum_return'),
|
||||
},
|
||||
class: {
|
||||
stack: {
|
||||
from2015: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2015'),
|
||||
from2016: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2016'),
|
||||
from2017: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2017'),
|
||||
from2018: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2018'),
|
||||
from2019: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2019'),
|
||||
from2020: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2020'),
|
||||
from2021: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2021'),
|
||||
from2022: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2022'),
|
||||
from2023: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2023'),
|
||||
from2024: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2024'),
|
||||
from2025: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2025'),
|
||||
from2026: createBtcCentsSatsUsdPattern3(this, 'dca_stack_from_2026'),
|
||||
},
|
||||
costBasis: {
|
||||
from2015: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2015'),
|
||||
from2016: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2016'),
|
||||
from2017: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2017'),
|
||||
from2018: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2018'),
|
||||
from2019: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2019'),
|
||||
from2020: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2020'),
|
||||
from2021: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2021'),
|
||||
from2022: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2022'),
|
||||
from2023: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2023'),
|
||||
from2024: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2024'),
|
||||
from2025: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2025'),
|
||||
from2026: createCentsSatsUsdPattern(this, 'dca_cost_basis_from_2026'),
|
||||
},
|
||||
return: {
|
||||
from2015: createBpsPercentRatioPattern(this, 'dca_return_from_2015'),
|
||||
from2016: createBpsPercentRatioPattern(this, 'dca_return_from_2016'),
|
||||
from2017: createBpsPercentRatioPattern(this, 'dca_return_from_2017'),
|
||||
from2018: createBpsPercentRatioPattern(this, 'dca_return_from_2018'),
|
||||
from2019: createBpsPercentRatioPattern(this, 'dca_return_from_2019'),
|
||||
from2020: createBpsPercentRatioPattern(this, 'dca_return_from_2020'),
|
||||
from2021: createBpsPercentRatioPattern(this, 'dca_return_from_2021'),
|
||||
from2022: createBpsPercentRatioPattern(this, 'dca_return_from_2022'),
|
||||
from2023: createBpsPercentRatioPattern(this, 'dca_return_from_2023'),
|
||||
from2024: createBpsPercentRatioPattern(this, 'dca_return_from_2024'),
|
||||
from2025: createBpsPercentRatioPattern(this, 'dca_return_from_2025'),
|
||||
from2026: createBpsPercentRatioPattern(this, 'dca_return_from_2026'),
|
||||
},
|
||||
},
|
||||
},
|
||||
technical: {
|
||||
rsi: {
|
||||
_24h: createRsiStochPattern(this, 'rsi', '24h'),
|
||||
@@ -8569,7 +8607,7 @@ class BrkClient extends BrkClientBase {
|
||||
sats: createSeriesPattern1(this, 'realized_price_sats'),
|
||||
bps: createSeriesPattern1(this, 'realized_price_ratio_bps'),
|
||||
ratio: createSeriesPattern1(this, 'realized_price_ratio'),
|
||||
percentiles: createPct1Pct2Pct5Pct95Pct98Pct99Pattern(this, 'realized_price'),
|
||||
percentiles: createPct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(this, 'realized_price'),
|
||||
sma: create_1m1w1y2y4yAllPattern(this, 'realized_price_ratio_sma'),
|
||||
stdDev: {
|
||||
all: {
|
||||
@@ -8713,7 +8751,7 @@ class BrkClient extends BrkClientBase {
|
||||
sats: createSeriesPattern1(this, 'sth_realized_price_sats'),
|
||||
bps: createSeriesPattern1(this, 'sth_realized_price_ratio_bps'),
|
||||
ratio: createSeriesPattern1(this, 'sth_realized_price_ratio'),
|
||||
percentiles: createPct1Pct2Pct5Pct95Pct98Pct99Pattern(this, 'sth_realized_price'),
|
||||
percentiles: createPct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(this, 'sth_realized_price'),
|
||||
sma: create_1m1w1y2y4yAllPattern(this, 'sth_realized_price_ratio_sma'),
|
||||
stdDev: {
|
||||
all: {
|
||||
@@ -8812,7 +8850,7 @@ class BrkClient extends BrkClientBase {
|
||||
sats: createSeriesPattern1(this, 'lth_realized_price_sats'),
|
||||
bps: createSeriesPattern1(this, 'lth_realized_price_ratio_bps'),
|
||||
ratio: createSeriesPattern1(this, 'lth_realized_price_ratio'),
|
||||
percentiles: createPct1Pct2Pct5Pct95Pct98Pct99Pattern(this, 'lth_realized_price'),
|
||||
percentiles: createPct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(this, 'lth_realized_price'),
|
||||
sma: create_1m1w1y2y4yAllPattern(this, 'lth_realized_price_ratio_sma'),
|
||||
stdDev: {
|
||||
all: {
|
||||
|
||||
@@ -238,6 +238,7 @@ export class QuickMatch {
|
||||
*/
|
||||
_rank(indices, minScore, qwords, sep, limit) {
|
||||
const { items, _scores: scores } = this;
|
||||
/** @type {[number[], number[], number[]]} */
|
||||
const buckets = [[], [], []]; // ps=0, ps=1, ps=2
|
||||
|
||||
for (let i = 0; i < indices.length; i++) {
|
||||
@@ -2306,6 +2306,20 @@ class BpsCentsPercentilesRatioSatsSmaStdUsdPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
pass
|
||||
|
||||
class Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.pct0_5: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct0_5')
|
||||
self.pct1: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct1')
|
||||
self.pct2: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct2')
|
||||
self.pct5: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct5')
|
||||
self.pct95: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct95')
|
||||
self.pct98: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct98')
|
||||
self.pct99: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct99')
|
||||
self.pct99_5: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct99_5')
|
||||
|
||||
class _10y2y3y4y5y6y8yPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2427,7 +2441,7 @@ class BpsCentsPercentilesRatioSatsUsdPattern:
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.bps: SeriesPattern1[BasisPoints32] = SeriesPattern1(client, _m(acc, 'ratio_bps'))
|
||||
self.cents: SeriesPattern1[Cents] = SeriesPattern1(client, _m(acc, 'cents'))
|
||||
self.percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, acc)
|
||||
self.percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, acc)
|
||||
self.ratio: SeriesPattern1[StoredF32] = SeriesPattern1(client, _m(acc, 'ratio'))
|
||||
self.sats: SeriesPattern1[SatsFract] = SeriesPattern1(client, _m(acc, 'sats'))
|
||||
self.usd: SeriesPattern1[Dollars] = SeriesPattern1(client, acc)
|
||||
@@ -2480,18 +2494,6 @@ class DeltaHalfInToTotalPattern2:
|
||||
self.to_circulating: BpsPercentRatioPattern3 = BpsPercentRatioPattern3(client, _m(acc, 'to_circulating'))
|
||||
self.total: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, acc)
|
||||
|
||||
class Pct1Pct2Pct5Pct95Pct98Pct99Pattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated series name."""
|
||||
self.pct1: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct1')
|
||||
self.pct2: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct2')
|
||||
self.pct5: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct5')
|
||||
self.pct95: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct95')
|
||||
self.pct98: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct98')
|
||||
self.pct99: BpsPriceRatioPattern = BpsPriceRatioPattern(client, acc, 'pct99')
|
||||
|
||||
class _1m1w1y24hBlockPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -3251,9 +3253,7 @@ class SeriesTree_Blocks_Time:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.timestamp: SeriesPattern1[Timestamp] = SeriesPattern1(client, 'timestamp')
|
||||
self.date: SeriesPattern18[Date] = SeriesPattern18(client, 'date')
|
||||
self.timestamp_monotonic: SeriesPattern18[Timestamp] = SeriesPattern18(client, 'timestamp_monotonic')
|
||||
self.timestamp: SeriesPattern18[Timestamp] = SeriesPattern18(client, 'timestamp')
|
||||
|
||||
class SeriesTree_Blocks_Size:
|
||||
"""Series tree node."""
|
||||
@@ -4149,6 +4149,13 @@ class SeriesTree_Indexes_TxoutIndex:
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.identity: SeriesPattern21[TxOutIndex] = SeriesPattern21(client, 'txout_index')
|
||||
|
||||
class SeriesTree_Indexes_Timestamp:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.monotonic: SeriesPattern18[Timestamp] = SeriesPattern18(client, 'timestamp_monotonic')
|
||||
self.resolutions: SeriesPattern2[Timestamp] = SeriesPattern2(client, 'timestamp')
|
||||
|
||||
class SeriesTree_Indexes:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -4173,6 +4180,7 @@ class SeriesTree_Indexes:
|
||||
self.tx_index: SeriesTree_Indexes_TxIndex = SeriesTree_Indexes_TxIndex(client)
|
||||
self.txin_index: SeriesTree_Indexes_TxinIndex = SeriesTree_Indexes_TxinIndex(client)
|
||||
self.txout_index: SeriesTree_Indexes_TxoutIndex = SeriesTree_Indexes_TxoutIndex(client)
|
||||
self.timestamp: SeriesTree_Indexes_Timestamp = SeriesTree_Indexes_Timestamp(client)
|
||||
|
||||
class SeriesTree_Indicators_Dormancy:
|
||||
"""Series tree node."""
|
||||
@@ -4181,6 +4189,21 @@ class SeriesTree_Indicators_Dormancy:
|
||||
self.supply_adjusted: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'dormancy_supply_adjusted')
|
||||
self.flow: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'dormancy_flow')
|
||||
|
||||
class SeriesTree_Indicators_Thermometer:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.pct0_5: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'thermometer_pct0_5')
|
||||
self.pct1: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'thermometer_pct01')
|
||||
self.pct2: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'thermometer_pct02')
|
||||
self.pct5: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'thermometer_pct05')
|
||||
self.pct95: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'thermometer_pct95')
|
||||
self.pct98: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'thermometer_pct98')
|
||||
self.pct99: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'thermometer_pct99')
|
||||
self.pct99_5: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'thermometer_pct99_5')
|
||||
self.zone: SeriesPattern1[StoredI8] = SeriesPattern1(client, 'thermometer_zone')
|
||||
self.score: SeriesPattern1[StoredI8] = SeriesPattern1(client, 'thermometer_score')
|
||||
|
||||
class SeriesTree_Indicators:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -4195,6 +4218,102 @@ class SeriesTree_Indicators:
|
||||
self.dormancy: SeriesTree_Indicators_Dormancy = SeriesTree_Indicators_Dormancy(client)
|
||||
self.stock_to_flow: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'stock_to_flow')
|
||||
self.seller_exhaustion: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'seller_exhaustion')
|
||||
self.thermometer: SeriesTree_Indicators_Thermometer = SeriesTree_Indicators_Thermometer(client)
|
||||
|
||||
class SeriesTree_Investing_Period_CostBasis:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self._1w: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_1w')
|
||||
self._1m: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_1m')
|
||||
self._3m: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_3m')
|
||||
self._6m: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_6m')
|
||||
self._1y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_1y')
|
||||
self._2y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_2y')
|
||||
self._3y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_3y')
|
||||
self._4y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_4y')
|
||||
self._5y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_5y')
|
||||
self._6y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_6y')
|
||||
self._8y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_8y')
|
||||
self._10y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_10y')
|
||||
|
||||
class SeriesTree_Investing_Period:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3 = _10y1m1w1y2y3m3y4y5y6m6y8yPattern3(client, 'dca_stack')
|
||||
self.cost_basis: SeriesTree_Investing_Period_CostBasis = SeriesTree_Investing_Period_CostBasis(client)
|
||||
self.return_: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2 = _10y1m1w1y2y3m3y4y5y6m6y8yPattern2(client, 'dca_return')
|
||||
self.cagr: _10y2y3y4y5y6y8yPattern = _10y2y3y4y5y6y8yPattern(client, 'dca_cagr')
|
||||
self.lump_sum_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3 = _10y1m1w1y2y3m3y4y5y6m6y8yPattern3(client, 'lump_sum_stack')
|
||||
self.lump_sum_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2 = _10y1m1w1y2y3m3y4y5y6m6y8yPattern2(client, 'lump_sum_return')
|
||||
|
||||
class SeriesTree_Investing_Class_Stack:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.from_2015: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2015')
|
||||
self.from_2016: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2016')
|
||||
self.from_2017: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2017')
|
||||
self.from_2018: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2018')
|
||||
self.from_2019: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2019')
|
||||
self.from_2020: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2020')
|
||||
self.from_2021: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2021')
|
||||
self.from_2022: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2022')
|
||||
self.from_2023: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2023')
|
||||
self.from_2024: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2024')
|
||||
self.from_2025: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2025')
|
||||
self.from_2026: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2026')
|
||||
|
||||
class SeriesTree_Investing_Class_CostBasis:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.from_2015: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2015')
|
||||
self.from_2016: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2016')
|
||||
self.from_2017: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2017')
|
||||
self.from_2018: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2018')
|
||||
self.from_2019: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2019')
|
||||
self.from_2020: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2020')
|
||||
self.from_2021: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2021')
|
||||
self.from_2022: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2022')
|
||||
self.from_2023: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2023')
|
||||
self.from_2024: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2024')
|
||||
self.from_2025: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2025')
|
||||
self.from_2026: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2026')
|
||||
|
||||
class SeriesTree_Investing_Class_Return:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.from_2015: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2015')
|
||||
self.from_2016: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2016')
|
||||
self.from_2017: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2017')
|
||||
self.from_2018: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2018')
|
||||
self.from_2019: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2019')
|
||||
self.from_2020: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2020')
|
||||
self.from_2021: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2021')
|
||||
self.from_2022: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2022')
|
||||
self.from_2023: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2023')
|
||||
self.from_2024: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2024')
|
||||
self.from_2025: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2025')
|
||||
self.from_2026: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2026')
|
||||
|
||||
class SeriesTree_Investing_Class:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.stack: SeriesTree_Investing_Class_Stack = SeriesTree_Investing_Class_Stack(client)
|
||||
self.cost_basis: SeriesTree_Investing_Class_CostBasis = SeriesTree_Investing_Class_CostBasis(client)
|
||||
self.return_: SeriesTree_Investing_Class_Return = SeriesTree_Investing_Class_Return(client)
|
||||
|
||||
class SeriesTree_Investing:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.sats_per_day: SeriesPattern18[Sats] = SeriesPattern18(client, 'dca_sats_per_day')
|
||||
self.period: SeriesTree_Investing_Period = SeriesTree_Investing_Period(client)
|
||||
self.class_: SeriesTree_Investing_Class = SeriesTree_Investing_Class(client)
|
||||
|
||||
class SeriesTree_Market_Ath:
|
||||
"""Series tree node."""
|
||||
@@ -4370,101 +4489,6 @@ class SeriesTree_Market_MovingAverage:
|
||||
self.sma: SeriesTree_Market_MovingAverage_Sma = SeriesTree_Market_MovingAverage_Sma(client)
|
||||
self.ema: SeriesTree_Market_MovingAverage_Ema = SeriesTree_Market_MovingAverage_Ema(client)
|
||||
|
||||
class SeriesTree_Market_Dca_Period_CostBasis:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self._1w: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_1w')
|
||||
self._1m: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_1m')
|
||||
self._3m: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_3m')
|
||||
self._6m: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_6m')
|
||||
self._1y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_1y')
|
||||
self._2y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_2y')
|
||||
self._3y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_3y')
|
||||
self._4y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_4y')
|
||||
self._5y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_5y')
|
||||
self._6y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_6y')
|
||||
self._8y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_8y')
|
||||
self._10y: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_10y')
|
||||
|
||||
class SeriesTree_Market_Dca_Period:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3 = _10y1m1w1y2y3m3y4y5y6m6y8yPattern3(client, 'dca_stack')
|
||||
self.cost_basis: SeriesTree_Market_Dca_Period_CostBasis = SeriesTree_Market_Dca_Period_CostBasis(client)
|
||||
self.return_: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2 = _10y1m1w1y2y3m3y4y5y6m6y8yPattern2(client, 'dca_return')
|
||||
self.cagr: _10y2y3y4y5y6y8yPattern = _10y2y3y4y5y6y8yPattern(client, 'dca_cagr')
|
||||
self.lump_sum_stack: _10y1m1w1y2y3m3y4y5y6m6y8yPattern3 = _10y1m1w1y2y3m3y4y5y6m6y8yPattern3(client, 'lump_sum_stack')
|
||||
self.lump_sum_return: _10y1m1w1y2y3m3y4y5y6m6y8yPattern2 = _10y1m1w1y2y3m3y4y5y6m6y8yPattern2(client, 'lump_sum_return')
|
||||
|
||||
class SeriesTree_Market_Dca_Class_Stack:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.from_2015: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2015')
|
||||
self.from_2016: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2016')
|
||||
self.from_2017: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2017')
|
||||
self.from_2018: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2018')
|
||||
self.from_2019: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2019')
|
||||
self.from_2020: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2020')
|
||||
self.from_2021: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2021')
|
||||
self.from_2022: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2022')
|
||||
self.from_2023: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2023')
|
||||
self.from_2024: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2024')
|
||||
self.from_2025: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2025')
|
||||
self.from_2026: BtcCentsSatsUsdPattern3 = BtcCentsSatsUsdPattern3(client, 'dca_stack_from_2026')
|
||||
|
||||
class SeriesTree_Market_Dca_Class_CostBasis:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.from_2015: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2015')
|
||||
self.from_2016: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2016')
|
||||
self.from_2017: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2017')
|
||||
self.from_2018: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2018')
|
||||
self.from_2019: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2019')
|
||||
self.from_2020: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2020')
|
||||
self.from_2021: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2021')
|
||||
self.from_2022: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2022')
|
||||
self.from_2023: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2023')
|
||||
self.from_2024: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2024')
|
||||
self.from_2025: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2025')
|
||||
self.from_2026: CentsSatsUsdPattern = CentsSatsUsdPattern(client, 'dca_cost_basis_from_2026')
|
||||
|
||||
class SeriesTree_Market_Dca_Class_Return:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.from_2015: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2015')
|
||||
self.from_2016: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2016')
|
||||
self.from_2017: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2017')
|
||||
self.from_2018: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2018')
|
||||
self.from_2019: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2019')
|
||||
self.from_2020: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2020')
|
||||
self.from_2021: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2021')
|
||||
self.from_2022: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2022')
|
||||
self.from_2023: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2023')
|
||||
self.from_2024: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2024')
|
||||
self.from_2025: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2025')
|
||||
self.from_2026: BpsPercentRatioPattern = BpsPercentRatioPattern(client, 'dca_return_from_2026')
|
||||
|
||||
class SeriesTree_Market_Dca_Class:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.stack: SeriesTree_Market_Dca_Class_Stack = SeriesTree_Market_Dca_Class_Stack(client)
|
||||
self.cost_basis: SeriesTree_Market_Dca_Class_CostBasis = SeriesTree_Market_Dca_Class_CostBasis(client)
|
||||
self.return_: SeriesTree_Market_Dca_Class_Return = SeriesTree_Market_Dca_Class_Return(client)
|
||||
|
||||
class SeriesTree_Market_Dca:
|
||||
"""Series tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.sats_per_day: SeriesPattern18[Sats] = SeriesPattern18(client, 'dca_sats_per_day')
|
||||
self.period: SeriesTree_Market_Dca_Period = SeriesTree_Market_Dca_Period(client)
|
||||
self.class_: SeriesTree_Market_Dca_Class = SeriesTree_Market_Dca_Class(client)
|
||||
|
||||
class SeriesTree_Market_Technical_Rsi:
|
||||
"""Series tree node."""
|
||||
|
||||
@@ -4529,7 +4553,6 @@ class SeriesTree_Market:
|
||||
self.volatility: _1m1w1y24hPattern[StoredF32] = _1m1w1y24hPattern(client, 'price_volatility')
|
||||
self.range: SeriesTree_Market_Range = SeriesTree_Market_Range(client)
|
||||
self.moving_average: SeriesTree_Market_MovingAverage = SeriesTree_Market_MovingAverage(client)
|
||||
self.dca: SeriesTree_Market_Dca = SeriesTree_Market_Dca(client)
|
||||
self.technical: SeriesTree_Market_Technical = SeriesTree_Market_Technical(client)
|
||||
|
||||
class SeriesTree_Pools_Major:
|
||||
@@ -4890,7 +4913,7 @@ class SeriesTree_Cohorts_Utxo_All_Realized_Price:
|
||||
self.sats: SeriesPattern1[SatsFract] = SeriesPattern1(client, 'realized_price_sats')
|
||||
self.bps: SeriesPattern1[BasisPoints32] = SeriesPattern1(client, 'realized_price_ratio_bps')
|
||||
self.ratio: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'realized_price_ratio')
|
||||
self.percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, 'realized_price')
|
||||
self.percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, 'realized_price')
|
||||
self.sma: _1m1w1y2y4yAllPattern = _1m1w1y2y4yAllPattern(client, 'realized_price_ratio_sma')
|
||||
self.std_dev: SeriesTree_Cohorts_Utxo_All_Realized_Price_StdDev = SeriesTree_Cohorts_Utxo_All_Realized_Price_StdDev(client)
|
||||
|
||||
@@ -5097,7 +5120,7 @@ class SeriesTree_Cohorts_Utxo_Sth_Realized_Price:
|
||||
self.sats: SeriesPattern1[SatsFract] = SeriesPattern1(client, 'sth_realized_price_sats')
|
||||
self.bps: SeriesPattern1[BasisPoints32] = SeriesPattern1(client, 'sth_realized_price_ratio_bps')
|
||||
self.ratio: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'sth_realized_price_ratio')
|
||||
self.percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, 'sth_realized_price')
|
||||
self.percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, 'sth_realized_price')
|
||||
self.sma: _1m1w1y2y4yAllPattern = _1m1w1y2y4yAllPattern(client, 'sth_realized_price_ratio_sma')
|
||||
self.std_dev: SeriesTree_Cohorts_Utxo_Sth_Realized_Price_StdDev = SeriesTree_Cohorts_Utxo_Sth_Realized_Price_StdDev(client)
|
||||
|
||||
@@ -5227,7 +5250,7 @@ class SeriesTree_Cohorts_Utxo_Lth_Realized_Price:
|
||||
self.sats: SeriesPattern1[SatsFract] = SeriesPattern1(client, 'lth_realized_price_sats')
|
||||
self.bps: SeriesPattern1[BasisPoints32] = SeriesPattern1(client, 'lth_realized_price_ratio_bps')
|
||||
self.ratio: SeriesPattern1[StoredF32] = SeriesPattern1(client, 'lth_realized_price_ratio')
|
||||
self.percentiles: Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, 'lth_realized_price')
|
||||
self.percentiles: Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern = Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern(client, 'lth_realized_price')
|
||||
self.sma: _1m1w1y2y4yAllPattern = _1m1w1y2y4yAllPattern(client, 'lth_realized_price_ratio_sma')
|
||||
self.std_dev: SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev = SeriesTree_Cohorts_Utxo_Lth_Realized_Price_StdDev(client)
|
||||
|
||||
@@ -5646,6 +5669,7 @@ class SeriesTree:
|
||||
self.constants: SeriesTree_Constants = SeriesTree_Constants(client)
|
||||
self.indexes: SeriesTree_Indexes = SeriesTree_Indexes(client)
|
||||
self.indicators: SeriesTree_Indicators = SeriesTree_Indicators(client)
|
||||
self.investing: SeriesTree_Investing = SeriesTree_Investing(client)
|
||||
self.market: SeriesTree_Market = SeriesTree_Market(client)
|
||||
self.pools: SeriesTree_Pools = SeriesTree_Pools(client)
|
||||
self.prices: SeriesTree_Prices = SeriesTree_Prices(client)
|
||||
|
||||
+163
-16
@@ -9,7 +9,7 @@ import {
|
||||
import { createLegend } from "./legend.js";
|
||||
import { capture } from "./capture.js";
|
||||
import { colors } from "../utils/colors.js";
|
||||
import { createRadios, createSelect } from "../utils/dom.js";
|
||||
import { createRadios, createSelect, getElementById } from "../utils/dom.js";
|
||||
import { createPersistedValue } from "../utils/persisted.js";
|
||||
import { onChange as onThemeChange } from "../utils/theme.js";
|
||||
import { throttle, debounce } from "../utils/timing.js";
|
||||
@@ -74,6 +74,71 @@ const lineWidth = /** @type {1} */ (/** @type {unknown} */ (1.5));
|
||||
|
||||
const MAX_SIZE = 10_000;
|
||||
|
||||
/** @typedef {{ label: string, index: IndexLabel, from: number }} RangePreset */
|
||||
|
||||
/** @returns {RangePreset[]} */
|
||||
function getRangePresets() {
|
||||
const nowSec = Math.floor(Date.now() / 1000);
|
||||
const now = new Date();
|
||||
const y = now.getUTCFullYear();
|
||||
const m = now.getUTCMonth();
|
||||
const d = now.getUTCDate();
|
||||
/** @param {number} n */
|
||||
const monthsAgo = (n) => Math.floor(Date.UTC(y, m - n, d) / 1000);
|
||||
|
||||
/** @type {RangePreset[]} */
|
||||
const presets = [
|
||||
{
|
||||
label: "1w",
|
||||
index: /** @type {IndexLabel} */ ("30mn"),
|
||||
from: nowSec - 7 * 86_400,
|
||||
},
|
||||
{
|
||||
label: "1m",
|
||||
index: /** @type {IndexLabel} */ ("1h"),
|
||||
from: monthsAgo(1),
|
||||
},
|
||||
{
|
||||
label: "3m",
|
||||
index: /** @type {IndexLabel} */ ("4h"),
|
||||
from: monthsAgo(3),
|
||||
},
|
||||
{
|
||||
label: "6m",
|
||||
index: /** @type {IndexLabel} */ ("12h"),
|
||||
from: monthsAgo(6),
|
||||
},
|
||||
{
|
||||
label: "1y",
|
||||
index: /** @type {IndexLabel} */ ("1d"),
|
||||
from: monthsAgo(12),
|
||||
},
|
||||
{
|
||||
label: "4y",
|
||||
index: /** @type {IndexLabel} */ ("3d"),
|
||||
from: monthsAgo(48),
|
||||
},
|
||||
];
|
||||
|
||||
// Insert ytd at the right position
|
||||
const ytdFrom = Math.floor(Date.UTC(y, 0, 1) / 1000);
|
||||
const ri = presets.findIndex((e) => e.from <= ytdFrom);
|
||||
const insertAt = ri === -1 ? presets.length : ri;
|
||||
presets.splice(insertAt, 0, {
|
||||
label: "ytd",
|
||||
index: presets[ri === -1 ? presets.length - 1 : ri].index,
|
||||
from: ytdFrom,
|
||||
});
|
||||
|
||||
presets.push({
|
||||
label: "all",
|
||||
index: /** @type {IndexLabel} */ ("1w"),
|
||||
from: -Infinity,
|
||||
});
|
||||
|
||||
return presets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {HTMLElement} args.parent
|
||||
@@ -89,8 +154,8 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
/** @param {ChartableIndex} idx */
|
||||
const getTimeEndpoint = (idx) =>
|
||||
idx === "height"
|
||||
? brk.series.blocks.time.timestampMonotonic.by[idx]
|
||||
: brk.series.blocks.time.timestamp.by[idx];
|
||||
? brk.series.indexes.timestamp.monotonic.by[idx]
|
||||
: brk.series.indexes.timestamp.resolutions.by[idx];
|
||||
|
||||
const index = {
|
||||
/** @type {Set<(index: ChartableIndex) => void>} */
|
||||
@@ -204,10 +269,6 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
enableResize: false,
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
vertLines: { visible: false },
|
||||
horzLines: { visible: false },
|
||||
},
|
||||
rightPriceScale: {
|
||||
borderVisible: false,
|
||||
},
|
||||
@@ -290,6 +351,8 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
const defaultColor = colors.default();
|
||||
const offColor = colors.gray();
|
||||
const borderColor = colors.border();
|
||||
const offBorderColor = colors.offBorder();
|
||||
console.log(borderColor);
|
||||
ichart.applyOptions({
|
||||
layout: {
|
||||
textColor: offColor,
|
||||
@@ -307,6 +370,14 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
labelBackgroundColor: defaultColor,
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
horzLines: {
|
||||
color: offBorderColor,
|
||||
},
|
||||
vertLines: {
|
||||
color: offBorderColor,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
applyColors();
|
||||
@@ -402,8 +473,9 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
const pane = ichart.panes().at(paneIndex);
|
||||
if (!pane) return;
|
||||
if (this.isAllHidden(paneIndex)) {
|
||||
const collapsedHeight = paneIndex === 0 ? 32 : 64;
|
||||
const chartHeight = ichart.chartElement().clientHeight;
|
||||
pane.setStretchFactor(chartHeight > 0 ? 48 / (chartHeight - 48) : 0);
|
||||
pane.setStretchFactor(chartHeight > 0 ? collapsedHeight / (chartHeight - collapsedHeight) : 0);
|
||||
} else {
|
||||
pane.setStretchFactor(1);
|
||||
}
|
||||
@@ -885,6 +957,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color | [Color, Color]} [args.color] - Single color or [positive, negative] colors
|
||||
* @param {(value: number) => Color} [args.colorFn]
|
||||
* @param {number} [args.paneIndex]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {HistogramSeriesPartialOptions} [args.options]
|
||||
@@ -894,6 +967,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
name,
|
||||
key,
|
||||
color = colors.bi.p1,
|
||||
colorFn,
|
||||
order,
|
||||
unit,
|
||||
paneIndex = 0,
|
||||
@@ -930,7 +1004,17 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
});
|
||||
},
|
||||
setData: (data) => {
|
||||
if (isDualColor) {
|
||||
if (colorFn) {
|
||||
iseries.setData(
|
||||
data.map((d) => ({
|
||||
...d,
|
||||
color:
|
||||
"value" in d
|
||||
? (colorFn(d.value) ?? (() => "transparent"))()
|
||||
: "transparent",
|
||||
})),
|
||||
);
|
||||
} else if (isDualColor) {
|
||||
iseries.setData(
|
||||
data.map((d) => ({
|
||||
...d,
|
||||
@@ -957,6 +1041,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color} args.color
|
||||
* @param {(value: number) => Color} [args.colorFn]
|
||||
* @param {number} [args.paneIndex]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {LineSeriesPartialOptions} [args.options]
|
||||
@@ -967,6 +1052,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
key,
|
||||
order,
|
||||
color,
|
||||
colorFn,
|
||||
unit,
|
||||
paneIndex = 0,
|
||||
defaultActive,
|
||||
@@ -999,7 +1085,18 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
color: color.highlight(highlighted),
|
||||
});
|
||||
},
|
||||
setData: (data) => iseries.setData(data),
|
||||
setData: (data) => {
|
||||
if (colorFn) {
|
||||
iseries.setData(
|
||||
data.map((d) => ({
|
||||
...d,
|
||||
color: "value" in d ? (colorFn(d.value) ?? color)() : color(),
|
||||
})),
|
||||
);
|
||||
} else {
|
||||
iseries.setData(data);
|
||||
}
|
||||
},
|
||||
update: (data) => iseries.update(data),
|
||||
getData: () => iseries.data(),
|
||||
onRemove: () => ichart.removeSeries(iseries),
|
||||
@@ -1373,7 +1470,11 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
break;
|
||||
case "Histogram":
|
||||
pane.series.push(
|
||||
serieses.addHistogram({ ...common, color: blueprint.color }),
|
||||
serieses.addHistogram({
|
||||
...common,
|
||||
color: blueprint.color,
|
||||
colorFn: blueprint.colorFn,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case "Candlestick":
|
||||
@@ -1414,6 +1515,7 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
serieses.addLine({
|
||||
...common,
|
||||
color: blueprint.color ?? defaultColor,
|
||||
colorFn: blueprint.colorFn,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -1443,9 +1545,35 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
/** @type {HTMLElement | null} */
|
||||
let indexField = null;
|
||||
|
||||
const lastTd = ichart
|
||||
.chartElement()
|
||||
.querySelector("table > tr:last-child > td:last-child");
|
||||
/** @param {RangePreset} preset */
|
||||
function applyPreset(preset) {
|
||||
preferredIndex = preset.index;
|
||||
/** @type {HTMLSelectElement} */ (getElementById("index")).value =
|
||||
preset.index;
|
||||
index.name.set(preset.index);
|
||||
|
||||
const targetGen = generation;
|
||||
const waitAndApply = () => {
|
||||
if (generation !== targetGen) return;
|
||||
if (!initialLoadComplete) {
|
||||
requestAnimationFrame(waitAndApply);
|
||||
return;
|
||||
}
|
||||
const data = blueprints.panes[0].series[0]?.getData();
|
||||
if (!data?.length) return;
|
||||
const from = isFinite(preset.from)
|
||||
? (data.findIndex(
|
||||
(d) => /** @type {number} */ (d.time) >= preset.from,
|
||||
) ?? 0)
|
||||
: 0;
|
||||
const padding = Math.round((data.length - from) * 0.025);
|
||||
ichart.timeScale().setVisibleLogicalRange({
|
||||
from: from - padding,
|
||||
to: data.length + padding,
|
||||
});
|
||||
};
|
||||
requestAnimationFrame(waitAndApply);
|
||||
}
|
||||
|
||||
const chart = {
|
||||
get panes() {
|
||||
@@ -1464,7 +1592,13 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
index.name.set(currentValue);
|
||||
}
|
||||
|
||||
indexField = createSelect({
|
||||
indexField = window.document.createElement("div");
|
||||
indexField.classList.add("index-bar");
|
||||
|
||||
const scroller = window.document.createElement("div");
|
||||
indexField.append(scroller);
|
||||
|
||||
const selectField = createSelect({
|
||||
initialValue: currentValue,
|
||||
onChange: (v) => {
|
||||
preferredIndex = v;
|
||||
@@ -1474,7 +1608,20 @@ export function createChart({ parent, brk, fitContent }) {
|
||||
groups,
|
||||
id: "index",
|
||||
});
|
||||
if (lastTd) lastTd.append(indexField);
|
||||
scroller.append(selectField);
|
||||
|
||||
const sep = window.document.createElement("span");
|
||||
sep.textContent = "|";
|
||||
scroller.append(sep);
|
||||
|
||||
for (const preset of getRangePresets()) {
|
||||
const btn = window.document.createElement("button");
|
||||
btn.textContent = preset.label;
|
||||
btn.addEventListener("click", () => applyPreset(preset));
|
||||
scroller.append(btn);
|
||||
}
|
||||
|
||||
chartEl.append(indexField);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,19 +69,19 @@ const ALL_YEARS = /** @type {const} */ ([...YEARS_2020S, ...YEARS_2010S]);
|
||||
|
||||
/**
|
||||
* Build DCA class entry from year
|
||||
* @param {MarketDca} dca
|
||||
* @param {Investing} investing
|
||||
* @param {DcaYear} year
|
||||
* @param {number} i
|
||||
* @returns {BaseEntryItem}
|
||||
*/
|
||||
function buildYearEntry(dca, year, i) {
|
||||
function buildYearEntry(investing, year, i) {
|
||||
const key = /** @type {DcaYearKey} */ (`from${year}`);
|
||||
return {
|
||||
name: `${year}`,
|
||||
color: colors.at(i, ALL_YEARS.length),
|
||||
costBasis: dca.class.costBasis[key],
|
||||
returns: dca.class.return[key],
|
||||
stack: dca.class.stack[key],
|
||||
costBasis: investing.class.costBasis[key],
|
||||
returns: investing.class.return[key],
|
||||
stack: investing.class.stack[key],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,16 +90,16 @@ function buildYearEntry(dca, year, i) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
export function createInvestingSection() {
|
||||
const { market } = brk.series;
|
||||
const { dca, lookback, returns } = market;
|
||||
const { market, investing } = brk.series;
|
||||
const { lookback, returns } = market;
|
||||
|
||||
return {
|
||||
name: "Investing",
|
||||
tree: [
|
||||
createDcaVsLumpSumSection({ dca, lookback, returns }),
|
||||
createDcaByPeriodSection({ dca, returns }),
|
||||
createLumpSumByPeriodSection({ dca, lookback, returns }),
|
||||
createDcaByStartYearSection({ dca }),
|
||||
createDcaVsLumpSumSection({ investing, lookback, returns }),
|
||||
createDcaByPeriodSection({ investing, returns }),
|
||||
createLumpSumByPeriodSection({ investing, lookback, returns }),
|
||||
createDcaByStartYearSection({ investing }),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -270,15 +270,15 @@ function createLongSingleEntry(item) {
|
||||
/**
|
||||
* Create DCA vs Lump Sum section
|
||||
* @param {Object} args
|
||||
* @param {Market["dca"]} args.dca
|
||||
* @param {Investing} args.investing
|
||||
* @param {Market["lookback"]} args.lookback
|
||||
* @param {Market["returns"]} args.returns
|
||||
*/
|
||||
export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
|
||||
export function createDcaVsLumpSumSection({ investing, lookback, returns }) {
|
||||
/** @param {AllPeriodKey} key */
|
||||
const topPane = (key) => [
|
||||
price({
|
||||
series: dca.period.costBasis[key],
|
||||
series: investing.period.costBasis[key],
|
||||
name: "DCA",
|
||||
color: colors.profit,
|
||||
}),
|
||||
@@ -299,11 +299,11 @@ export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
|
||||
top: topPane(key),
|
||||
bottom: [
|
||||
...percentRatioBaseline({
|
||||
pattern: dca.period.return[key],
|
||||
pattern: investing.period.return[key],
|
||||
name: "DCA",
|
||||
}),
|
||||
...percentRatioBaseline({
|
||||
pattern: dca.period.lumpSumReturn[key],
|
||||
pattern: investing.period.lumpSumReturn[key],
|
||||
name: "Lump Sum",
|
||||
color: colors.bi.p2,
|
||||
}),
|
||||
@@ -317,7 +317,7 @@ export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
|
||||
top: topPane(key),
|
||||
bottom: [
|
||||
...percentRatioBaseline({
|
||||
pattern: dca.period.cagr[key],
|
||||
pattern: investing.period.cagr[key],
|
||||
name: "DCA",
|
||||
}),
|
||||
...percentRatioBaseline({
|
||||
@@ -335,12 +335,12 @@ export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
|
||||
top: topPane(key),
|
||||
bottom: [
|
||||
...satsBtcUsd({
|
||||
pattern: dca.period.stack[key],
|
||||
pattern: investing.period.stack[key],
|
||||
name: "DCA",
|
||||
color: colors.profit,
|
||||
}),
|
||||
...satsBtcUsd({
|
||||
pattern: dca.period.lumpSumStack[key],
|
||||
pattern: investing.period.lumpSumStack[key],
|
||||
name: "Lump Sum",
|
||||
color: colors.bitcoin,
|
||||
}),
|
||||
@@ -395,11 +395,11 @@ export function createDcaVsLumpSumSection({ dca, lookback, returns }) {
|
||||
/**
|
||||
* Create period-based section (DCA or Lump Sum)
|
||||
* @param {Object} args
|
||||
* @param {Market["dca"]} args.dca
|
||||
* @param {Investing} args.investing
|
||||
* @param {Market["lookback"]} [args.lookback]
|
||||
* @param {Market["returns"]} args.returns
|
||||
*/
|
||||
function createPeriodSection({ dca, lookback, returns }) {
|
||||
function createPeriodSection({ investing, lookback, returns }) {
|
||||
const isLumpSum = !!lookback;
|
||||
const suffix = isLumpSum ? "Lump Sum" : "DCA";
|
||||
|
||||
@@ -409,20 +409,20 @@ function createPeriodSection({ dca, lookback, returns }) {
|
||||
const buildBaseEntry = (key, i) => ({
|
||||
name: periodName(key),
|
||||
color: colors.at(i, allPeriods.length),
|
||||
costBasis: isLumpSum ? lookback[key] : dca.period.costBasis[key],
|
||||
costBasis: isLumpSum ? lookback[key] : investing.period.costBasis[key],
|
||||
returns: isLumpSum
|
||||
? dca.period.lumpSumReturn[key]
|
||||
: dca.period.return[key],
|
||||
? investing.period.lumpSumReturn[key]
|
||||
: investing.period.return[key],
|
||||
stack: isLumpSum
|
||||
? dca.period.lumpSumStack[key]
|
||||
: dca.period.stack[key],
|
||||
? investing.period.lumpSumStack[key]
|
||||
: investing.period.stack[key],
|
||||
});
|
||||
|
||||
/** @param {LongPeriodKey} key @param {number} i @returns {LongEntryItem} */
|
||||
const buildLongEntry = (key, i) =>
|
||||
withCagr(
|
||||
buildBaseEntry(key, i),
|
||||
isLumpSum ? returns.cagr[key] : dca.period.cagr[key],
|
||||
isLumpSum ? returns.cagr[key] : investing.period.cagr[key],
|
||||
);
|
||||
|
||||
/** @param {BaseEntryItem} entry */
|
||||
@@ -471,30 +471,30 @@ function createPeriodSection({ dca, lookback, returns }) {
|
||||
/**
|
||||
* Create DCA by Period section
|
||||
* @param {Object} args
|
||||
* @param {Market["dca"]} args.dca
|
||||
* @param {Investing} args.investing
|
||||
* @param {Market["returns"]} args.returns
|
||||
*/
|
||||
export function createDcaByPeriodSection({ dca, returns }) {
|
||||
return createPeriodSection({ dca, returns });
|
||||
export function createDcaByPeriodSection({ investing, returns }) {
|
||||
return createPeriodSection({ investing, returns });
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Lump Sum by Period section
|
||||
* @param {Object} args
|
||||
* @param {Market["dca"]} args.dca
|
||||
* @param {Investing} args.investing
|
||||
* @param {Market["lookback"]} args.lookback
|
||||
* @param {Market["returns"]} args.returns
|
||||
*/
|
||||
export function createLumpSumByPeriodSection({ dca, lookback, returns }) {
|
||||
return createPeriodSection({ dca, lookback, returns });
|
||||
export function createLumpSumByPeriodSection({ investing, lookback, returns }) {
|
||||
return createPeriodSection({ investing, lookback, returns });
|
||||
}
|
||||
|
||||
/**
|
||||
* Create DCA by Start Year section
|
||||
* @param {Object} args
|
||||
* @param {Market["dca"]} args.dca
|
||||
* @param {Investing} args.investing
|
||||
*/
|
||||
export function createDcaByStartYearSection({ dca }) {
|
||||
export function createDcaByStartYearSection({ investing }) {
|
||||
/** @param {string} name @param {string} title @param {BaseEntryItem[]} entries */
|
||||
const createDecadeGroup = (name, title, entries) => ({
|
||||
name,
|
||||
@@ -511,10 +511,10 @@ export function createDcaByStartYearSection({ dca }) {
|
||||
});
|
||||
|
||||
const entries2020s = YEARS_2020S.map((year, i) =>
|
||||
buildYearEntry(dca, year, i),
|
||||
buildYearEntry(investing, year, i),
|
||||
);
|
||||
const entries2010s = YEARS_2010S.map((year, i) =>
|
||||
buildYearEntry(dca, year, YEARS_2020S.length + i),
|
||||
buildYearEntry(investing, year, YEARS_2020S.length + i),
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
ROLLING_WINDOWS,
|
||||
ROLLING_WINDOWS_TO_1M,
|
||||
} from "./series.js";
|
||||
import { simplePriceRatioTree } from "./shared.js";
|
||||
import { simplePriceRatioTree, percentileBands, priceBands } from "./shared.js";
|
||||
import { periodIdToName } from "./utils.js";
|
||||
|
||||
/**
|
||||
@@ -165,7 +165,10 @@ function returnsSubSectionWithCagr(name, periods) {
|
||||
...periods.map((p) => ({
|
||||
name: periodIdToName(p.id, true),
|
||||
title: `${periodIdToName(p.id, true)} Total Price Returns`,
|
||||
bottom: percentRatioBaseline({ pattern: p.returns, name: "Return" }),
|
||||
bottom: percentRatioBaseline({
|
||||
pattern: p.returns,
|
||||
name: "Return",
|
||||
}),
|
||||
})),
|
||||
],
|
||||
},
|
||||
@@ -1084,6 +1087,46 @@ export function createMarketSection() {
|
||||
color: colors.loss,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Thermometer",
|
||||
tree: [
|
||||
{
|
||||
name: "Bands",
|
||||
title: "Thermometer",
|
||||
top: priceBands(percentileBands(indicators.thermometer), { defaultActive: true }),
|
||||
},
|
||||
{
|
||||
name: "Score",
|
||||
title: "Thermometer",
|
||||
top: priceBands(percentileBands(indicators.thermometer)),
|
||||
bottom: [
|
||||
histogram({
|
||||
series: indicators.thermometer.zone,
|
||||
name: "Zone",
|
||||
unit: Unit.count,
|
||||
colorFn: (v) => /** @type {const} */ ([
|
||||
colors.ratioPct._0_5,
|
||||
colors.ratioPct._1,
|
||||
colors.ratioPct._2,
|
||||
colors.ratioPct._5,
|
||||
colors.transparent,
|
||||
colors.ratioPct._95,
|
||||
colors.ratioPct._98,
|
||||
colors.ratioPct._99,
|
||||
colors.ratioPct._99_5,
|
||||
])[v + 4],
|
||||
}),
|
||||
baseline({
|
||||
series: indicators.thermometer.score,
|
||||
name: "Score",
|
||||
unit: Unit.count,
|
||||
color: [colors.ratioPct._99, colors.ratioPct._1],
|
||||
defaultActive: false,
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -147,6 +147,7 @@ function percentileSeries({ pattern, unit, title = "" }) {
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {LineStyle} [args.style]
|
||||
* @param {Color} [args.color]
|
||||
* @param {(value: number) => Color} [args.colorFn]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {LineSeriesPartialOptions} [args.options]
|
||||
* @returns {FetchedLineSeriesBlueprint}
|
||||
@@ -157,6 +158,7 @@ export function line({
|
||||
key,
|
||||
style,
|
||||
color,
|
||||
colorFn,
|
||||
defaultActive,
|
||||
unit,
|
||||
options,
|
||||
@@ -166,6 +168,7 @@ export function line({
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
colorFn,
|
||||
unit,
|
||||
defaultActive,
|
||||
options: {
|
||||
@@ -370,6 +373,7 @@ export function dotsBaseline({
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color | [Color, Color]} [args.color]
|
||||
* @param {(value: number) => Color} [args.colorFn]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {HistogramSeriesPartialOptions} [args.options]
|
||||
* @returns {FetchedHistogramSeriesBlueprint}
|
||||
@@ -379,6 +383,7 @@ export function histogram({
|
||||
name,
|
||||
key,
|
||||
color,
|
||||
colorFn,
|
||||
defaultActive,
|
||||
unit,
|
||||
options,
|
||||
@@ -389,6 +394,7 @@ export function histogram({
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
colorFn,
|
||||
unit,
|
||||
defaultActive,
|
||||
options,
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
/** Shared helpers for options */
|
||||
|
||||
import { Unit } from "../utils/units.js";
|
||||
import { ROLLING_WINDOWS, line, baseline, price, sumsAndAveragesCumulativeWith } from "./series.js";
|
||||
import {
|
||||
ROLLING_WINDOWS,
|
||||
line,
|
||||
baseline,
|
||||
price,
|
||||
sumsAndAveragesCumulativeWith,
|
||||
} from "./series.js";
|
||||
import { priceLine, priceLines } from "./constants.js";
|
||||
import { colors } from "../utils/colors.js";
|
||||
|
||||
@@ -270,11 +276,19 @@ export function simplePriceRatioTree({ pattern, title, legend, color }) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {InvestorPercentilesPattern} p
|
||||
* @param {(entry: InvestorPercentileEntry) => T} extract
|
||||
* @param {{ pct95: AnyPricePattern, pct5: AnyPricePattern, pct98: AnyPricePattern, pct2: AnyPricePattern, pct99: AnyPricePattern, pct1: AnyPricePattern, pct995: AnyPricePattern, pct05: AnyPricePattern }} p
|
||||
*/
|
||||
function percentileBands(p, extract) {
|
||||
export function percentileBands(p) {
|
||||
return percentileBandsWith(p, (e) => e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @template E
|
||||
* @template T
|
||||
* @param {{ pct95: E, pct5: E, pct98: E, pct2: E, pct99: E, pct1: E, pct995: E, pct05: E }} p
|
||||
* @param {(entry: E) => T} extract
|
||||
*/
|
||||
export function percentileBandsWith(p, extract) {
|
||||
return [
|
||||
{ name: "P95", prop: extract(p.pct95), color: colors.ratioPct._95 },
|
||||
{ name: "P5", prop: extract(p.pct5), color: colors.ratioPct._5 },
|
||||
@@ -282,20 +296,38 @@ function percentileBands(p, extract) {
|
||||
{ name: "P2", prop: extract(p.pct2), color: colors.ratioPct._2 },
|
||||
{ name: "P99", prop: extract(p.pct99), color: colors.ratioPct._99 },
|
||||
{ name: "P1", prop: extract(p.pct1), color: colors.ratioPct._1 },
|
||||
{ name: "P99.5", prop: extract(p.pct995), color: colors.ratioPct._99_5 },
|
||||
{ name: "P0.5", prop: extract(p.pct05), color: colors.ratioPct._0_5 },
|
||||
];
|
||||
}
|
||||
|
||||
/** @param {{ name: string, prop: AnyPricePattern, color: Color }[]} bands */
|
||||
function priceBands(bands) {
|
||||
/**
|
||||
* @param {{ name: string, prop: AnyPricePattern, color: Color }[]} bands
|
||||
* @param {{ defaultActive?: boolean }} [opts]
|
||||
*/
|
||||
export function priceBands(bands, opts) {
|
||||
return bands.map(({ name, prop, color }) =>
|
||||
price({ series: prop, name, color, defaultActive: false, options: { lineStyle: 1 } }),
|
||||
price({
|
||||
series: prop,
|
||||
name,
|
||||
color,
|
||||
defaultActive: opts?.defaultActive ?? false,
|
||||
options: { lineStyle: 1 },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {{ name: string, prop: AnySeriesPattern, color: Color }[]} bands */
|
||||
function ratioBands(bands) {
|
||||
return bands.map(({ name, prop, color }) =>
|
||||
line({ series: prop, name, color, defaultActive: false, unit: Unit.ratio, options: { lineStyle: 1 } }),
|
||||
line({
|
||||
series: prop,
|
||||
name,
|
||||
color,
|
||||
defaultActive: false,
|
||||
unit: Unit.ratio,
|
||||
options: { lineStyle: 1 },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -319,8 +351,8 @@ export function priceRatioPercentilesTree({
|
||||
priceReferences,
|
||||
}) {
|
||||
const p = pattern.percentiles;
|
||||
const pctUsd = percentileBands(p, (e) => e.price);
|
||||
const pctRatio = percentileBands(p, (e) => e.ratio);
|
||||
const pctUsd = percentileBandsWith(p, (e) => e.price);
|
||||
const pctRatio = percentileBandsWith(p, (e) => e.ratio);
|
||||
return [
|
||||
{
|
||||
name: "Price",
|
||||
@@ -500,7 +532,11 @@ export function ratioSmas(ratio) {
|
||||
{ name: "1y SMA", series: ratio.sma._1y.ratio },
|
||||
{ name: "2y SMA", series: ratio.sma._2y.ratio },
|
||||
{ name: "4y SMA", series: ratio.sma._4y.ratio },
|
||||
{ name: "All Time SMA", series: ratio.sma.all.ratio, color: colors.time.all },
|
||||
{
|
||||
name: "All Time SMA",
|
||||
series: ratio.sma.all.ratio,
|
||||
color: colors.time.all,
|
||||
},
|
||||
].map((s, i, arr) => ({ color: colors.at(i, arr.length), ...s }));
|
||||
}
|
||||
|
||||
@@ -543,7 +579,14 @@ export function ratioBottomSeries(ratio) {
|
||||
* @param {string} [args.legend]
|
||||
* @returns {PartialChartOption}
|
||||
*/
|
||||
export function createRatioChart({ title, pricePattern, ratio, color, name, legend }) {
|
||||
export function createRatioChart({
|
||||
title,
|
||||
pricePattern,
|
||||
ratio,
|
||||
color,
|
||||
name,
|
||||
legend,
|
||||
}) {
|
||||
return {
|
||||
name: name ?? "Ratio",
|
||||
title: title(name ?? "Ratio"),
|
||||
@@ -727,7 +770,7 @@ export function createPriceRatioCharts({
|
||||
priceReferences,
|
||||
}) {
|
||||
const titleFn = formatCohortTitle(context);
|
||||
const pctUsd = percentileBands(ratio.percentiles, (e) => e.price);
|
||||
const pctUsd = percentileBandsWith(ratio.percentiles, (e) => e.price);
|
||||
return [
|
||||
{
|
||||
name: "Price",
|
||||
@@ -775,20 +818,39 @@ export function createPriceRatioCharts({
|
||||
* @param {Unit} args.unit
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
export function groupedWindowsCumulative({ list, all, title, metricTitle, getWindowSeries, getCumulativeSeries, seriesFn, unit }) {
|
||||
export function groupedWindowsCumulative({
|
||||
list,
|
||||
all,
|
||||
title,
|
||||
metricTitle,
|
||||
getWindowSeries,
|
||||
getCumulativeSeries,
|
||||
seriesFn,
|
||||
unit,
|
||||
}) {
|
||||
return [
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`${w.title} ${metricTitle}`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
seriesFn({ series: getWindowSeries(c, w.key), name: c.name, color: c.color, unit }),
|
||||
seriesFn({
|
||||
series: getWindowSeries(c, w.key),
|
||||
name: c.name,
|
||||
color: c.color,
|
||||
unit,
|
||||
}),
|
||||
),
|
||||
})),
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: title(`Cumulative ${metricTitle}`),
|
||||
bottom: mapCohortsWithAll(list, all, (c) =>
|
||||
seriesFn({ series: getCumulativeSeries(c), name: c.name, color: c.color, unit }),
|
||||
seriesFn({
|
||||
series: getCumulativeSeries(c),
|
||||
name: c.name,
|
||||
color: c.color,
|
||||
unit,
|
||||
}),
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -807,9 +869,21 @@ export function groupedWindowsCumulative({ list, all, title, metricTitle, getWin
|
||||
* @param {(args: { series: AnySeriesPattern, name: string, color: Color, unit: Unit }) => AnyFetchedSeriesBlueprint} [args.seriesFn]
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
export function groupedWindowsCumulativeUsd({ list, all, title, metricTitle, getMetric, seriesFn = line }) {
|
||||
export function groupedWindowsCumulativeUsd({
|
||||
list,
|
||||
all,
|
||||
title,
|
||||
metricTitle,
|
||||
getMetric,
|
||||
seriesFn = line,
|
||||
}) {
|
||||
return groupedWindowsCumulative({
|
||||
list, all, title, metricTitle, seriesFn, unit: Unit.usd,
|
||||
list,
|
||||
all,
|
||||
title,
|
||||
metricTitle,
|
||||
seriesFn,
|
||||
unit: Unit.usd,
|
||||
getWindowSeries: (c, key) => getMetric(c).sum[key].usd,
|
||||
getCumulativeSeries: (c) => getMetric(c).cumulative.usd,
|
||||
});
|
||||
@@ -827,20 +901,34 @@ export function groupedWindowsCumulativeUsd({ list, all, title, metricTitle, get
|
||||
* @param {(c: T | A) => { sum: Record<string, AnyValuePattern>, cumulative: AnyValuePattern }} args.getMetric
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
export function groupedWindowsCumulativeSatsBtcUsd({ list, all, title, metricTitle, getMetric }) {
|
||||
export function groupedWindowsCumulativeSatsBtcUsd({
|
||||
list,
|
||||
all,
|
||||
title,
|
||||
metricTitle,
|
||||
getMetric,
|
||||
}) {
|
||||
return [
|
||||
...ROLLING_WINDOWS.map((w) => ({
|
||||
name: w.name,
|
||||
title: title(`${w.title} ${metricTitle}`),
|
||||
bottom: flatMapCohortsWithAll(list, all, (c) =>
|
||||
satsBtcUsd({ pattern: getMetric(c).sum[w.key], name: c.name, color: c.color }),
|
||||
satsBtcUsd({
|
||||
pattern: getMetric(c).sum[w.key],
|
||||
name: c.name,
|
||||
color: c.color,
|
||||
}),
|
||||
),
|
||||
})),
|
||||
{
|
||||
name: "Cumulative",
|
||||
title: title(`Cumulative ${metricTitle}`),
|
||||
bottom: flatMapCohortsWithAll(list, all, (c) =>
|
||||
satsBtcUsd({ pattern: getMetric(c).cumulative, name: c.name, color: c.color }),
|
||||
satsBtcUsd({
|
||||
pattern: getMetric(c).cumulative,
|
||||
name: c.name,
|
||||
color: c.color,
|
||||
}),
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
* @typedef {Object} LineSeriesBlueprintSpecific
|
||||
* @property {"Line"} [type]
|
||||
* @property {Color} [color]
|
||||
* @property {(value: number) => Color} [colorFn]
|
||||
* @property {LineSeriesPartialOptions} [options]
|
||||
* @typedef {BaseSeriesBlueprint & LineSeriesBlueprintSpecific} LineSeriesBlueprint
|
||||
*
|
||||
* @typedef {Object} HistogramSeriesBlueprintSpecific
|
||||
* @property {"Histogram"} type
|
||||
* @property {Color | [Color, Color]} [color] - Single color or [positive, negative] colors (defaults to green/red)
|
||||
* @property {(value: number) => Color} [colorFn]
|
||||
* @property {HistogramSeriesPartialOptions} [options]
|
||||
* @typedef {BaseSeriesBlueprint & HistogramSeriesBlueprintSpecific} HistogramSeriesBlueprint
|
||||
*
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
searchLabelElement,
|
||||
searchResultsElement,
|
||||
} from "../utils/elements.js";
|
||||
import { QuickMatch } from "../modules/quickmatch-js/0.4.0/src/index.js";
|
||||
import { QuickMatch } from "../modules/quickmatch-js/0.4.1/src/index.js";
|
||||
|
||||
/**
|
||||
* @param {Options} options
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
* Tree branch types
|
||||
* @typedef {Brk.SeriesTree_Market} Market
|
||||
* @typedef {Brk.SeriesTree_Market_MovingAverage} MarketMovingAverage
|
||||
* @typedef {Brk.SeriesTree_Market_Dca} MarketDca
|
||||
* @typedef {Brk.SeriesTree_Investing} Investing
|
||||
* @typedef {Brk._10y2y3y4y5y6y8yPattern} PeriodCagrPattern
|
||||
* @typedef {FullStatsPattern} AnyFullStatsPattern
|
||||
*
|
||||
@@ -243,7 +243,7 @@
|
||||
* @typedef {Brk.AbsoluteRatePattern2} FiatDeltaPattern
|
||||
*
|
||||
* Investor price percentiles (pct1/2/5/95/98/99)
|
||||
* @typedef {Brk.Pct1Pct2Pct5Pct95Pct98Pct99Pattern} InvestorPercentilesPattern
|
||||
* @typedef {Brk.Pct0Pct1Pct2Pct5Pct95Pct98Pct99Pattern} InvestorPercentilesPattern
|
||||
* @typedef {Brk.BpsPriceRatioPattern} InvestorPercentileEntry
|
||||
*
|
||||
* Generic tree node type for walking
|
||||
|
||||
@@ -124,9 +124,11 @@ function seq(keys) {
|
||||
}
|
||||
|
||||
export const colors = {
|
||||
transparent: createColor(() => "transparent"),
|
||||
default: createColor(() => getLightDarkValue("--color")),
|
||||
gray: createColor(() => getColor("gray")),
|
||||
border: createColor(() => getLightDarkValue("--border-color")),
|
||||
offBorder: createColor(() => getLightDarkValue("--off-border-color")),
|
||||
|
||||
// Directional
|
||||
profit: palette.green,
|
||||
@@ -214,12 +216,14 @@ export const colors = {
|
||||
|
||||
// Ratio percentile bands (extreme values)
|
||||
ratioPct: {
|
||||
_99: palette.rose,
|
||||
_98: palette.pink,
|
||||
_95: palette.fuchsia,
|
||||
_5: palette.teal,
|
||||
_99_5: palette.red,
|
||||
_99: palette.orange,
|
||||
_98: palette.amber,
|
||||
_95: palette.yellow,
|
||||
_5: palette.cyan,
|
||||
_2: palette.sky,
|
||||
_1: palette.indigo,
|
||||
_1: palette.blue,
|
||||
_0_5: palette.indigo,
|
||||
},
|
||||
|
||||
// Standard deviation bands (warm = positive, cool = negative)
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
label,
|
||||
select {
|
||||
margin: -0.5rem;
|
||||
padding: 0.5rem;
|
||||
margin: -0.375rem;
|
||||
padding: 0.375rem;
|
||||
}
|
||||
|
||||
select {
|
||||
@@ -67,7 +67,7 @@
|
||||
overflow-x: auto;
|
||||
scrollbar-width: thin;
|
||||
padding: 0 var(--main-padding);
|
||||
padding-top: 0.278rem;
|
||||
padding-top: 0.375rem;
|
||||
padding-bottom: 0.75rem;
|
||||
> * {
|
||||
pointer-events: auto;
|
||||
@@ -210,6 +210,7 @@
|
||||
display: inline-flex;
|
||||
font-size: var(--font-size-xs);
|
||||
align-items: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
tr:not(:last-child) > td:last-child > .field {
|
||||
@@ -217,7 +218,6 @@
|
||||
right: 0;
|
||||
gap: 0.375rem;
|
||||
background-color: var(--background-color);
|
||||
text-transform: uppercase;
|
||||
padding-left: 0.625rem;
|
||||
padding-top: 0.35rem;
|
||||
padding-bottom: 0.125rem;
|
||||
@@ -237,8 +237,74 @@
|
||||
}
|
||||
}
|
||||
|
||||
tr:last-child > td:last-child > .field {
|
||||
bottom: 2.125rem;
|
||||
.index-bar {
|
||||
position: absolute;
|
||||
bottom: 1.8rem;
|
||||
left: calc(var(--main-padding) * -1);
|
||||
right: 50px;
|
||||
z-index: 20;
|
||||
font-size: var(--font-size-xs);
|
||||
line-height: var(--line-height-xs);
|
||||
text-transform: uppercase;
|
||||
pointer-events: none;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: var(--main-padding);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&::before {
|
||||
left: 0;
|
||||
background-image: linear-gradient(
|
||||
to left,
|
||||
transparent,
|
||||
var(--background-color)
|
||||
);
|
||||
}
|
||||
|
||||
&::after {
|
||||
right: 0;
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
var(--background-color)
|
||||
);
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: thin;
|
||||
padding: 0 var(--main-padding);
|
||||
padding-top: 0.375rem;
|
||||
padding-bottom: 0.375rem;
|
||||
|
||||
> * {
|
||||
pointer-events: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
> span {
|
||||
padding: 0 0.75rem;
|
||||
}
|
||||
|
||||
button {
|
||||
color: var(--off-color);
|
||||
padding: 0.375rem;
|
||||
margin: -0.375rem 0rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button.capture {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
|
||||
/*--white: oklch(90% 0 0);*/
|
||||
--white: oklch(93.3% 0.006 75);
|
||||
/*oklch(0.9333 0.0059 59.65)*/
|
||||
--light-gray: oklch(85% 0.01 75);
|
||||
--gray: oklch(60% 0.01 44);
|
||||
--dark-gray: oklch(25% 0.006 90);
|
||||
--black: oklch(16.5% 0.006 90);
|
||||
--white: oklch(95% 0 0);
|
||||
--dark-white: oklch(92.5% 0 0);
|
||||
--light-gray: oklch(90% 0 0);
|
||||
--gray: oklch(55% 0 0);
|
||||
--dark-gray: oklch(20% 0 0);
|
||||
--light-black: oklch(17.5% 0 0);
|
||||
--black: oklch(15% 0 0);
|
||||
/*oklch(0.2038 0.0076 196.57)*/
|
||||
--red: oklch(0.607 0.241 26.328);
|
||||
--orange: oklch(67.64% 0.191 44.41);
|
||||
@@ -31,6 +31,7 @@
|
||||
--color: light-dark(var(--black), var(--white));
|
||||
--off-color: var(--gray);
|
||||
--border-color: light-dark(var(--light-gray), var(--dark-gray));
|
||||
--off-border-color: light-dark(var(--dark-white), var(--light-black));
|
||||
|
||||
--font-size-xs: 0.75rem;
|
||||
--line-height-xs: calc(1 / 0.75);
|
||||
|
||||
Reference in New Issue
Block a user