Compare commits

...

5 Commits

Author SHA1 Message Date
nym21 c87b1c133c release: v0.0.65 2025-06-17 22:30:32 +02:00
nym21 9b275ecdae web: fix hang when candles fetched are slightly diff than before 2025-06-17 22:30:11 +02:00
nym21 49d66a133e release: v0.0.64 2025-06-17 18:49:17 +02:00
nym21 c559f26d0e global: add a bunch of realized datasets + charts 2025-06-17 18:47:04 +02:00
nym21 bbe9f1bad2 global: 4y zscore + 200d sma + mayer's multiple 2025-06-17 10:01:49 +02:00
20 changed files with 2647 additions and 792 deletions
Generated
+15 -15
View File
@@ -443,7 +443,7 @@ dependencies = [
[[package]]
name = "brk"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"brk_bundler",
"brk_cli",
@@ -463,7 +463,7 @@ dependencies = [
[[package]]
name = "brk_bundler"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"brk_rolldown",
"log",
@@ -474,7 +474,7 @@ dependencies = [
[[package]]
name = "brk_cli"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"bitcoincore-rpc",
"brk_computer",
@@ -499,7 +499,7 @@ dependencies = [
[[package]]
name = "brk_computer"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -520,7 +520,7 @@ dependencies = [
[[package]]
name = "brk_core"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"bincode",
"bitcoin",
@@ -541,7 +541,7 @@ dependencies = [
[[package]]
name = "brk_exit"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"brk_logger",
"ctrlc",
@@ -550,7 +550,7 @@ dependencies = [
[[package]]
name = "brk_fetcher"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"brk_core",
"brk_logger",
@@ -563,7 +563,7 @@ dependencies = [
[[package]]
name = "brk_indexer"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -581,7 +581,7 @@ dependencies = [
[[package]]
name = "brk_logger"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"color-eyre",
"env_logger",
@@ -591,7 +591,7 @@ dependencies = [
[[package]]
name = "brk_parser"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -606,7 +606,7 @@ dependencies = [
[[package]]
name = "brk_query"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"brk_computer",
"brk_core",
@@ -929,7 +929,7 @@ dependencies = [
[[package]]
name = "brk_server"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"axum",
"bitcoincore-rpc",
@@ -959,7 +959,7 @@ dependencies = [
[[package]]
name = "brk_state"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"bincode",
"brk_core",
@@ -973,7 +973,7 @@ dependencies = [
[[package]]
name = "brk_store"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"arc-swap",
"brk_core",
@@ -995,7 +995,7 @@ dependencies = [
[[package]]
name = "brk_vec"
version = "0.0.63"
version = "0.0.65"
dependencies = [
"arc-swap",
"brk_core",
+15 -15
View File
@@ -4,7 +4,7 @@ members = ["crates/*"]
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
package.license = "MIT"
package.edition = "2024"
package.version = "0.0.63"
package.version = "0.0.65"
package.homepage = "https://bitcoinresearchkit.org"
package.repository = "https://github.com/bitcoinresearchkit/brk"
@@ -22,20 +22,20 @@ axum = "0.8.4"
bincode = { version = "2.0.1", features = ["serde"] }
bitcoin = { version = "0.32.6", features = ["serde"] }
bitcoincore-rpc = "0.19.0"
brk_bundler = { version = "0.0.63", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.63", path = "crates/brk_cli" }
brk_computer = { version = "0.0.63", path = "crates/brk_computer" }
brk_core = { version = "0.0.63", path = "crates/brk_core" }
brk_exit = { version = "0.0.63", path = "crates/brk_exit" }
brk_fetcher = { version = "0.0.63", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.63", path = "crates/brk_indexer" }
brk_logger = { version = "0.0.63", path = "crates/brk_logger" }
brk_parser = { version = "0.0.63", path = "crates/brk_parser" }
brk_query = { version = "0.0.63", path = "crates/brk_query" }
brk_server = { version = "0.0.63", path = "crates/brk_server" }
brk_state = { version = "0.0.63", path = "crates/brk_state" }
brk_store = { version = "0.0.63", path = "crates/brk_store" }
brk_vec = { version = "0.0.63", path = "crates/brk_vec" }
brk_bundler = { version = "0.0.65", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.65", path = "crates/brk_cli" }
brk_computer = { version = "0.0.65", path = "crates/brk_computer" }
brk_core = { version = "0.0.65", path = "crates/brk_core" }
brk_exit = { version = "0.0.65", path = "crates/brk_exit" }
brk_fetcher = { version = "0.0.65", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.65", path = "crates/brk_indexer" }
brk_logger = { version = "0.0.65", path = "crates/brk_logger" }
brk_parser = { version = "0.0.65", path = "crates/brk_parser" }
brk_query = { version = "0.0.65", path = "crates/brk_query" }
brk_server = { version = "0.0.65", path = "crates/brk_server" }
brk_state = { version = "0.0.65", path = "crates/brk_state" }
brk_store = { version = "0.0.65", path = "crates/brk_store" }
brk_vec = { version = "0.0.65", path = "crates/brk_vec" }
byteview = "=0.6.1"
clap = { version = "4.5.40", features = ["string"] }
clap_derive = "4.5.40"
+2 -1
View File
@@ -52,7 +52,8 @@ pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> i
if let Some(start) = entry.find("main") {
if let Some(end) = entry.find(".js") {
let main_hashed = &entry[start..end];
contents = contents.replace("/scripts/main.js", &format!("/scripts/{main_hashed}.js"));
contents =
contents.replace("/scripts/main.js", &format!("/scripts/{main_hashed}.js"));
}
}
}
@@ -130,7 +130,11 @@ where
Box::new(
EagerVec::forced_import(
path,
&maybe_suffix("sum"),
&(if !options.last {
name.to_string()
} else {
maybe_suffix("sum")
}),
version + VERSION + Version::ZERO,
format,
)
@@ -24,8 +24,10 @@ pub struct ComputedRatioVecsFromDateIndex {
pub ratio_1w_sma: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_1m_sma: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_1y_sma: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_4y_sma: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_1y_sma_momentum_oscillator: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_standard_deviation: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_sd: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_4y_sd: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p99_9: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p99_5: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_p99: ComputedVecsFromDateIndex<StoredF32>,
@@ -51,6 +53,7 @@ pub struct ComputedRatioVecsFromDateIndex {
pub ratio_m2sd_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_m3sd_as_price: ComputedVecsFromDateIndex<Dollars>,
pub ratio_zscore: ComputedVecsFromDateIndex<StoredF32>,
pub ratio_4y_zscore: ComputedVecsFromDateIndex<StoredF32>,
}
const VERSION: Version = Version::ZERO;
@@ -116,6 +119,14 @@ impl ComputedRatioVecsFromDateIndex {
format,
options,
)?,
ratio_4y_sma: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_4y_sma"),
true,
version + VERSION + Version::ZERO,
format,
options,
)?,
ratio_1y_sma_momentum_oscillator: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_1y_sma_momentum_oscillator"),
@@ -124,9 +135,17 @@ impl ComputedRatioVecsFromDateIndex {
format,
options,
)?,
ratio_standard_deviation: ComputedVecsFromDateIndex::forced_import(
ratio_sd: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_standard_deviation"),
&format!("{name}_ratio_sd"),
true,
version + VERSION + Version::ZERO,
format,
options,
)?,
ratio_4y_sd: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_4y_sd"),
true,
version + VERSION + Version::ZERO,
format,
@@ -332,6 +351,14 @@ impl ComputedRatioVecsFromDateIndex {
format,
options,
)?,
ratio_4y_zscore: ComputedVecsFromDateIndex::forced_import(
path,
&format!("{name}_ratio_4y_zscore"),
true,
version + VERSION + Version::ZERO,
format,
options,
)?,
})
}
@@ -476,6 +503,22 @@ impl ComputedRatioVecsFromDateIndex {
},
)?;
self.ratio_4y_sma.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_sma_(
starting_indexes.dateindex,
self.ratio.dateindex.as_ref().unwrap(),
4 * 365,
exit,
Some(min_ratio_date),
)
},
)?;
self.ratio_1y_sma_momentum_oscillator.compute_all(
indexer,
indexes,
@@ -528,6 +571,8 @@ impl ComputedRatioVecsFromDateIndex {
let mut sma_iter = self.ratio_sma.dateindex.as_ref().unwrap().into_iter();
let mut _4y_sma_iter = self.ratio_4y_sma.dateindex.as_ref().unwrap().into_iter();
let nan = StoredF32::from(f32::NAN);
self.ratio
.dateindex
@@ -566,7 +611,12 @@ impl ComputedRatioVecsFromDateIndex {
.as_mut()
.unwrap()
.forced_push_at(index, nan, exit)?;
self.ratio_standard_deviation
self.ratio_sd
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, nan, exit)?;
self.ratio_4y_sd
.dateindex
.as_mut()
.unwrap()
@@ -645,12 +695,26 @@ impl ComputedRatioVecsFromDateIndex {
.sqrt(),
);
self.ratio_standard_deviation
self.ratio_sd
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, sd, exit)?;
let _4y_avg = _4y_sma_iter.unwrap_get_inner(index);
let _4y_sd = StoredF32::from(
(sorted.iter().map(|v| (**v - *_4y_avg).powi(2)).sum::<f32>()
/ (index.unwrap_to_usize() + 1) as f32)
.sqrt(),
);
self.ratio_4y_sd
.dateindex
.as_mut()
.unwrap()
.forced_push_at(index, _4y_sd, exit)?;
self.ratio_p1sd.dateindex.as_mut().unwrap().forced_push_at(
index,
avg + sd,
@@ -726,7 +790,13 @@ impl ComputedRatioVecsFromDateIndex {
exit,
None as Option<&EagerVec<_, _>>,
)?;
self.ratio_standard_deviation.compute_rest(
self.ratio_sd.compute_rest(
indexes,
starting_indexes,
exit,
None as Option<&EagerVec<_, _>>,
)?;
self.ratio_4y_sd.compute_rest(
indexes,
starting_indexes,
exit,
@@ -1007,21 +1077,27 @@ impl ComputedRatioVecsFromDateIndex {
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
let mut sma_iter = self.ratio_sma.dateindex.as_ref().unwrap().into_iter();
let mut sd_iter = self
.ratio_standard_deviation
.dateindex
.as_ref()
.unwrap()
.into_iter();
vec.compute_transform(
vec.compute_zscore(
starting_indexes.dateindex,
self.ratio.dateindex.as_ref().unwrap(),
|(i, ratio, ..)| {
let sma = sma_iter.unwrap_get_inner(i);
let sd = sd_iter.unwrap_get_inner(i);
(i, (ratio - sma) / sd)
},
self.ratio_sma.dateindex.as_ref().unwrap(),
self.ratio_sd.dateindex.as_ref().unwrap(),
exit,
)
},
)?;
self.ratio_4y_zscore.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
vec.compute_zscore(
starting_indexes.dateindex,
self.ratio.dateindex.as_ref().unwrap(),
self.ratio_4y_sma.dateindex.as_ref().unwrap(),
self.ratio_4y_sd.dateindex.as_ref().unwrap(),
exit,
)
},
@@ -1032,7 +1108,8 @@ impl ComputedRatioVecsFromDateIndex {
fn mut_ratio_vecs(&mut self) -> Vec<&mut EagerVec<DateIndex, StoredF32>> {
vec![
self.ratio_standard_deviation.dateindex.as_mut().unwrap(),
self.ratio_sd.dateindex.as_mut().unwrap(),
self.ratio_4y_sd.dateindex.as_mut().unwrap(),
self.ratio_p99_9.dateindex.as_mut().unwrap(),
self.ratio_p99_5.dateindex.as_mut().unwrap(),
self.ratio_p99.dateindex.as_mut().unwrap(),
@@ -1056,8 +1133,10 @@ impl ComputedRatioVecsFromDateIndex {
self.ratio_1w_sma.vecs(),
self.ratio_1m_sma.vecs(),
self.ratio_1y_sma.vecs(),
self.ratio_4y_sma.vecs(),
self.ratio_1y_sma_momentum_oscillator.vecs(),
self.ratio_standard_deviation.vecs(),
self.ratio_sd.vecs(),
self.ratio_4y_sd.vecs(),
self.ratio_p99_9.vecs(),
self.ratio_p99_5.vecs(),
self.ratio_p99.vecs(),
@@ -1083,6 +1162,7 @@ impl ComputedRatioVecsFromDateIndex {
self.ratio_m2sd_as_price.vecs(),
self.ratio_m3sd_as_price.vecs(),
self.ratio_zscore.vecs(),
self.ratio_4y_zscore.vecs(),
]
.into_iter()
.flatten()
+78 -1
View File
@@ -36,11 +36,15 @@ pub struct Vecs {
pub indexes_to_55d_sma: ComputedRatioVecsFromDateIndex,
pub indexes_to_89d_sma: ComputedRatioVecsFromDateIndex,
pub indexes_to_144d_sma: ComputedRatioVecsFromDateIndex,
pub indexes_to_200d_sma: ComputedRatioVecsFromDateIndex,
pub indexes_to_1y_sma: ComputedRatioVecsFromDateIndex,
pub indexes_to_2y_sma: ComputedRatioVecsFromDateIndex,
pub indexes_to_200w_sma: ComputedRatioVecsFromDateIndex,
pub indexes_to_4y_sma: ComputedRatioVecsFromDateIndex,
pub indexes_to_200d_sma_x2_4: ComputedVecsFromDateIndex<Dollars>,
pub indexes_to_200d_sma_x0_8: ComputedVecsFromDateIndex<Dollars>,
pub price_1d_ago: ComputedVecsFromDateIndex<Dollars>,
pub price_1w_ago: ComputedVecsFromDateIndex<Dollars>,
pub price_1m_ago: ComputedVecsFromDateIndex<Dollars>,
@@ -306,6 +310,14 @@ impl Vecs {
format,
StorableVecGeneatorOptions::default().add_last(),
)?,
indexes_to_200d_sma: ComputedRatioVecsFromDateIndex::forced_import(
path,
"200d_sma",
true,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
)?,
indexes_to_1y_sma: ComputedRatioVecsFromDateIndex::forced_import(
path,
"1y_sma",
@@ -1215,6 +1227,23 @@ impl Vecs {
format,
StorableVecGeneatorOptions::default().add_last(),
)?,
indexes_to_200d_sma_x2_4: ComputedVecsFromDateIndex::forced_import(
path,
"200d_sma_x2_4",
true,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
)?,
indexes_to_200d_sma_x0_8: ComputedVecsFromDateIndex::forced_import(
path,
"200d_sma_x0_8",
true,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
)?,
})
}
@@ -1771,6 +1800,7 @@ impl Vecs {
(&mut self.indexes_to_55d_sma, 55),
(&mut self.indexes_to_89d_sma, 89),
(&mut self.indexes_to_144d_sma, 144),
(&mut self.indexes_to_200d_sma, 200),
(&mut self.indexes_to_1y_sma, 365),
(&mut self.indexes_to_2y_sma, 2 * 365),
(&mut self.indexes_to_200w_sma, 200 * 7),
@@ -1797,7 +1827,51 @@ impl Vecs {
});
});
Ok(())
})
})?;
self.indexes_to_200d_sma_x0_8.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.indexes_to_200d_sma
.price
.as_ref()
.unwrap()
.dateindex
.as_ref()
.unwrap(),
|(i, v, ..)| (i, v * 0.8),
exit,
)
},
)?;
self.indexes_to_200d_sma_x2_4.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_transform(
starting_indexes.dateindex,
self.indexes_to_200d_sma
.price
.as_ref()
.unwrap()
.dateindex
.as_ref()
.unwrap(),
|(i, v, ..)| (i, v * 2.4),
exit,
)
},
)?;
Ok(())
}
pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> {
@@ -1817,10 +1891,13 @@ impl Vecs {
self.indexes_to_55d_sma.vecs(),
self.indexes_to_89d_sma.vecs(),
self.indexes_to_144d_sma.vecs(),
self.indexes_to_200d_sma.vecs(),
self.indexes_to_1y_sma.vecs(),
self.indexes_to_2y_sma.vecs(),
self.indexes_to_200w_sma.vecs(),
self.indexes_to_4y_sma.vecs(),
self.indexes_to_200d_sma_x0_8.vecs(),
self.indexes_to_200d_sma_x2_4.vecs(),
self.price_1d_ago.vecs(),
self.price_1w_ago.vecs(),
self.price_1m_ago.vecs(),
+208 -20
View File
@@ -57,7 +57,7 @@ pub struct Vecs {
pub indexes_to_coinblocks_destroyed: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_coindays_destroyed: ComputedVecsFromHeight<StoredF64>,
pub dateindex_to_adjusted_spent_output_profit_ratio: Option<EagerVec<DateIndex, StoredF32>>,
pub dateindex_to_realized_cap_30d_change: Option<EagerVec<DateIndex, Dollars>>,
pub indexes_to_realized_cap_30d_change: Option<ComputedVecsFromDateIndex<Dollars>>,
pub dateindex_to_sell_side_risk_ratio: Option<EagerVec<DateIndex, StoredF32>>,
pub dateindex_to_spent_output_profit_ratio: Option<EagerVec<DateIndex, StoredF32>>,
pub indexes_to_adjusted_value_created: Option<ComputedVecsFromHeight<Dollars>>,
@@ -89,6 +89,10 @@ pub struct Vecs {
Option<EagerVec<Height, StoredF32>>,
pub indexes_to_net_unrealized_profit_and_loss_relative_to_market_cap:
Option<ComputedVecsFromDateIndex<StoredF32>>,
pub indexes_to_realized_profit_relative_to_realized_cap:
Option<ComputedVecsFromHeight<StoredF32>>,
pub indexes_to_realized_loss_relative_to_realized_cap:
Option<ComputedVecsFromHeight<StoredF32>>,
pub indexes_to_net_realized_profit_and_loss_relative_to_realized_cap:
Option<ComputedVecsFromHeight<StoredF32>>,
pub height_to_supply_even_value: Option<ComputedHeightValueVecs>,
@@ -117,6 +121,12 @@ pub struct Vecs {
Option<ComputedVecsFromDateIndex<StoredF64>>,
pub indexes_to_supply_in_profit_relative_to_circulating_supply:
Option<ComputedVecsFromDateIndex<StoredF64>>,
pub indexes_to_cumulative_net_realized_profit_and_loss_30d_change:
Option<ComputedVecsFromDateIndex<Dollars>>,
pub indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_realized_cap:
Option<ComputedVecsFromDateIndex<StoredF32>>,
pub indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_market_cap:
Option<ComputedVecsFromDateIndex<StoredF32>>,
}
impl Vecs {
@@ -432,7 +442,9 @@ impl Vecs {
false,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_sum(),
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
)
.unwrap()
}),
@@ -452,7 +464,9 @@ impl Vecs {
false,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_sum(),
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
)
.unwrap()
}),
@@ -463,7 +477,7 @@ impl Vecs {
true,
version + VERSION + Version::ONE,
format,
StorableVecGeneatorOptions::default().add_sum(),
StorableVecGeneatorOptions::default().add_sum().add_cumulative(),
)
.unwrap()
}),
@@ -558,12 +572,14 @@ impl Vecs {
)
.unwrap()
}),
dateindex_to_realized_cap_30d_change: compute_dollars.then(|| {
EagerVec::forced_import(
indexes_to_realized_cap_30d_change: compute_dollars.then(|| {
ComputedVecsFromDateIndex::forced_import(
path,
&suffix("realized_cap_30d_change"),
true,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_last(),
)
.unwrap()
}),
@@ -574,7 +590,9 @@ impl Vecs {
true,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_sum(),
StorableVecGeneatorOptions::default()
.add_sum()
.add_cumulative(),
)
.unwrap()
}),
@@ -686,15 +704,37 @@ impl Vecs {
.unwrap()
},
),
indexes_to_realized_profit_relative_to_realized_cap: compute_dollars.then(|| {
ComputedVecsFromHeight::forced_import(
path,
&suffix("realized_profit_relative_to_realized_cap"),
true,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_sum(),
)
.unwrap()
}),
indexes_to_realized_loss_relative_to_realized_cap: compute_dollars.then(|| {
ComputedVecsFromHeight::forced_import(
path,
&suffix("realized_loss_relative_to_realized_cap"),
true,
version + VERSION + Version::ZERO,
format,
StorableVecGeneatorOptions::default().add_sum(),
)
.unwrap()
}),
indexes_to_net_realized_profit_and_loss_relative_to_realized_cap: compute_dollars.then(
|| {
ComputedVecsFromHeight::forced_import(
path,
&suffix("net_realized_profit_and_loss_relative_to_realized_cap"),
true,
version + VERSION + Version::ZERO,
version + VERSION + Version::ONE,
format,
StorableVecGeneatorOptions::default().add_last(),
StorableVecGeneatorOptions::default().add_sum(),
)
.unwrap()
},
@@ -903,6 +943,39 @@ impl Vecs {
format,
StorableVecGeneatorOptions::default().add_sum(),
)?,
indexes_to_cumulative_net_realized_profit_and_loss_30d_change: compute_dollars.then(|| {
ComputedVecsFromDateIndex::forced_import(
path,
&format!("cumulative_{}", suffix("net_realized_profit_and_loss_30d_change")),
true,
version + VERSION + Version::new(3),
format,
StorableVecGeneatorOptions::default().add_last()
)
.unwrap()
}),
indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_realized_cap: compute_dollars.then(|| {
ComputedVecsFromDateIndex::forced_import(
path,
&format!("cumulative_{}", suffix("net_realized_profit_and_loss_30d_change_relative_to_realized_cap")),
true,
version + VERSION + Version::new(3),
format,
StorableVecGeneatorOptions::default().add_last()
)
.unwrap()
}),
indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_market_cap: compute_dollars.then(|| {
ComputedVecsFromDateIndex::forced_import(
path,
&format!("cumulative_{}", suffix("net_realized_profit_and_loss_30d_change_relative_to_market_cap")),
true,
version + VERSION + Version::new(3),
format,
StorableVecGeneatorOptions::default().add_last()
)
.unwrap()
}),
})
}
@@ -1877,6 +1950,7 @@ impl Vecs {
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
exit: &Exit,
) -> color_eyre::Result<()> {
if let Some(v) = self
@@ -2021,18 +2095,26 @@ impl Vecs {
Some(self.height_to_adjusted_value_destroyed.as_ref().unwrap()),
)?;
self.dateindex_to_realized_cap_30d_change
self.indexes_to_realized_cap_30d_change
.as_mut()
.unwrap()
.compute_change(
starting_indexes.dateindex,
self.indexes_to_realized_cap
.as_ref()
.unwrap()
.dateindex
.unwrap_last(),
30,
.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
vec.compute_change(
starting_indexes.dateindex,
self.indexes_to_realized_cap
.as_ref()
.unwrap()
.dateindex
.unwrap_last(),
30,
exit,
)
},
)?;
self.indexes_to_net_realized_profit_and_loss
@@ -2280,6 +2362,42 @@ impl Vecs {
},
)?;
self.indexes_to_realized_profit_relative_to_realized_cap
.as_mut()
.unwrap()
.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
vec.compute_percentage(
starting_indexes.height,
self.height_to_realized_profit.as_ref().unwrap(),
*height_to_realized_cap.as_ref().unwrap(),
exit,
)
},
)?;
self.indexes_to_realized_loss_relative_to_realized_cap
.as_mut()
.unwrap()
.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|vec, _, _, starting_indexes, exit| {
vec.compute_percentage(
starting_indexes.height,
self.height_to_realized_loss.as_ref().unwrap(),
*height_to_realized_cap.as_ref().unwrap(),
exit,
)
},
)?;
self.indexes_to_net_realized_profit_and_loss_relative_to_realized_cap
.as_mut()
.unwrap()
@@ -2435,6 +2553,64 @@ impl Vecs {
},
)?;
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change
.as_mut()
.unwrap()
.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_change(
starting_indexes.dateindex,
self.indexes_to_net_realized_profit_and_loss
.as_ref()
.unwrap()
.dateindex
.unwrap_cumulative(),
30,
exit,
)
},
)?;
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_realized_cap.
as_mut()
.unwrap()
.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_percentage(
starting_indexes.dateindex,
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change.as_ref().unwrap().dateindex.as_ref().unwrap(),
*dateindex_to_realized_cap.as_ref().unwrap(),
exit,
)
},
)?;
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_market_cap.
as_mut()
.unwrap()
.compute_all(
indexer,
indexes,
starting_indexes,
exit,
|v, _, _, starting_indexes, exit| {
v.compute_percentage(
starting_indexes.dateindex,
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change.as_ref().unwrap().dateindex.as_ref().unwrap(),
market.indexes_to_marketcap.dateindex.as_ref().unwrap(),
exit,
)
},
)?;
if let Some(height_to_supply_even_relative_to_circulating_supply) = self
.height_to_supply_even_relative_to_circulating_supply
.as_mut()
@@ -2618,9 +2794,9 @@ impl Vecs {
self.indexes_to_adjusted_value_destroyed
.as_ref()
.map_or(vec![], |v| v.vecs()),
self.dateindex_to_realized_cap_30d_change
self.indexes_to_realized_cap_30d_change
.as_ref()
.map_or(vec![], |v| vec![v]),
.map_or(vec![], |v| v.vecs()),
self.indexes_to_net_realized_profit_and_loss
.as_ref()
.map_or(vec![], |v| v.vecs()),
@@ -2703,6 +2879,12 @@ impl Vecs {
self.indexes_to_net_unrealized_profit_and_loss_relative_to_market_cap
.as_ref()
.map_or(vec![], |v| v.vecs()),
self.indexes_to_realized_profit_relative_to_realized_cap
.as_ref()
.map_or(vec![], |v| v.vecs()),
self.indexes_to_realized_loss_relative_to_realized_cap
.as_ref()
.map_or(vec![], |v| v.vecs()),
self.indexes_to_net_realized_profit_and_loss_relative_to_realized_cap
.as_ref()
.map_or(vec![], |v| v.vecs()),
@@ -2756,6 +2938,12 @@ impl Vecs {
.map_or(vec![], |v| v.vecs()),
self.indexes_to_coinblocks_destroyed.vecs(),
self.indexes_to_coindays_destroyed.vecs(),
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change.as_ref()
.map_or(vec![], |v| v.vecs()),
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_realized_cap.as_ref()
.map_or(vec![], |v| v.vecs()),
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_market_cap.as_ref()
.map_or(vec![], |v| v.vecs()),
]
.into_iter()
.flatten()
+254 -249
View File
@@ -4,8 +4,8 @@ use brk_core::{DateIndex, Height, InputIndex, OutputIndex, OutputType, Result, S
use brk_exit::Exit;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, AnyVec, BaseVecIterator, CollectableVec, Computation, EagerVec, Format,
GenericStoredVec, StoredIndex, StoredVec, UnsafeSlice, VecIterator,
AnyCollectableVec, AnyVec, CollectableVec, Computation, EagerVec, Format, GenericStoredVec,
StoredIndex, StoredVec, UnsafeSlice, VecIterator,
};
use log::info;
use outputs::OutputCohorts;
@@ -1343,268 +1343,265 @@ impl Vecs {
.try_for_each(|(_, v)| v.state.price_to_amount.reset())?;
}
if starting_height == Height::from(height_to_date_fixed.len()) {
return Ok(());
}
if starting_height < Height::from(height_to_date_fixed.len()) {
starting_indexes.update_from_height(starting_height, indexes);
// ---
// INIT
// ---
separate_utxo_vecs
.par_iter_mut()
.for_each(|(_, v)| v.init(starting_height));
separate_utxo_vecs
.par_iter_mut()
.for_each(|(_, v)| v.init(starting_height));
let mut unspendable_supply = if let Some(prev_height) = starting_height.decremented() {
self.height_to_unspendable_supply
.into_iter()
.unwrap_get_inner(prev_height)
} else {
Sats::ZERO
};
let mut opreturn_supply = if let Some(prev_height) = starting_height.decremented() {
self.height_to_opreturn_supply
.into_iter()
.unwrap_get_inner(prev_height)
} else {
Sats::ZERO
};
let mut height = starting_height;
starting_indexes.update_from_height(height, indexes);
(height.unwrap_to_usize()..height_to_first_outputindex_iter.len())
.map(Height::from)
.try_for_each(|_height| -> color_eyre::Result<()> {
height = _height;
self.utxos_vecs
.as_mut_separate_vecs()
.iter_mut()
.for_each(|(_, v)| v.state.reset_single_iteration_values());
info!("Processing chain at {height}...");
let timestamp = height_to_timestamp_fixed_iter.unwrap_get_inner(height);
let price = height_to_close_iter
.as_mut()
.map(|i| *i.unwrap_get_inner(height));
let first_outputindex = height_to_first_outputindex_iter
.unwrap_get_inner(height)
.unwrap_to_usize();
let first_inputindex = height_to_first_inputindex_iter
.unwrap_get_inner(height)
.unwrap_to_usize();
let output_count = height_to_output_count_iter.unwrap_get_inner(height);
let input_count = height_to_input_count_iter.unwrap_get_inner(height);
let (mut height_to_sent, mut received) = thread::scope(|s| {
if chain_state_starting_height <= height {
s.spawn(|| {
self.utxos_vecs
.tick_tock_next_block(&chain_state, timestamp);
});
}
let sent_handle = s.spawn(|| {
// Skip coinbase
(first_inputindex + 1..first_inputindex + *input_count)
.into_par_iter()
.map(InputIndex::from)
.map(|inputindex| {
let outputindex = inputindex_to_outputindex
.get_or_read(inputindex, &inputindex_to_outputindex_mmap)
.unwrap()
.unwrap()
.into_inner();
let value = outputindex_to_value
.get_or_read(outputindex, &outputindex_to_value_mmap)
.unwrap()
.unwrap()
.into_inner();
let input_type = outputindex_to_outputtype
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
.unwrap()
.unwrap()
.into_inner();
// dbg!(input_type);
if input_type.is_unspendable() {
unreachable!()
}
let input_txindex = outputindex_to_txindex
.get_or_read(outputindex, &outputindex_to_txindex_mmap)
.unwrap()
.unwrap()
.into_inner();
let height = txindex_to_height
.get_or_read(input_txindex, &txindex_to_height_mmap)
.unwrap()
.unwrap()
.into_inner();
(height, value, input_type)
})
.fold(
BTreeMap::<Height, Transacted>::default,
|mut tree, (height, value, input_type)| {
tree.entry(height).or_default().iterate(value, input_type);
tree
},
)
.reduce(BTreeMap::<Height, Transacted>::default, |first, second| {
let (mut source, to_consume) = if first.len() > second.len() {
(first, second)
} else {
(second, first)
};
to_consume.into_iter().for_each(|(k, v)| {
*source.entry(k).or_default() += v;
});
source
})
});
let received_handle = s.spawn(|| {
(first_outputindex..first_outputindex + *output_count)
.into_par_iter()
.map(OutputIndex::from)
.map(|outputindex| {
let value = outputindex_to_value
.get_or_read(outputindex, &outputindex_to_value_mmap)
.unwrap()
.unwrap()
.into_inner();
let output_type = outputindex_to_outputtype
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
.unwrap()
.unwrap()
.into_inner();
(value, output_type)
})
.fold(
Transacted::default,
|mut transacted, (value, output_type)| {
transacted.iterate(value, output_type);
transacted
},
)
.reduce(Transacted::default, |acc, transacted| acc + transacted)
});
(sent_handle.join().unwrap(), received_handle.join().unwrap())
});
unspendable_supply += received
.by_type
.unspendable
.as_vec()
let mut unspendable_supply = if let Some(prev_height) = starting_height.decremented() {
self.height_to_unspendable_supply
.into_iter()
.map(|state| state.value)
.sum::<Sats>()
+ height_to_unclaimed_rewards_iter.unwrap_get_inner(height);
opreturn_supply += received.by_type.unspendable.opreturn.value;
if height == Height::new(0) {
received = Transacted::default();
unspendable_supply += Sats::FIFTY_BTC;
} else if height == Height::new(91_842) || height == Height::new(91_880) {
// Need to destroy invalid coinbases due to duplicate txids
if height == Height::new(91_842) {
height_to_sent.entry(Height::new(91_812)).or_default()
} else {
height_to_sent.entry(Height::new(91_722)).or_default()
}
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
};
if chain_state_starting_height <= height {
// Push current block state before processing sends and receives
chain_state.push(BlockState {
supply: received.spendable_supply.clone(),
price,
timestamp,
});
self.utxos_vecs.receive(received, height, price);
let unsafe_chain_state = UnsafeSlice::new(&mut chain_state);
height_to_sent.par_iter().for_each(|(height, sent)| unsafe {
(*unsafe_chain_state.get(height.unwrap_to_usize())).supply -=
&sent.spendable_supply;
});
self.utxos_vecs.send(height_to_sent, chain_state.as_slice());
} else {
dbg!(chain_state_starting_height, height);
panic!("temp, just making sure")
}
let mut separate_utxo_vecs = self.utxos_vecs.as_mut_separate_vecs();
separate_utxo_vecs
.iter_mut()
.try_for_each(|(_, v)| v.forced_pushed_at(height, exit))?;
self.height_to_unspendable_supply.forced_push_at(
height,
unspendable_supply,
exit,
)?;
.unwrap_get_inner(prev_height)
} else {
Sats::ZERO
};
let mut opreturn_supply = if let Some(prev_height) = starting_height.decremented() {
self.height_to_opreturn_supply
.forced_push_at(height, opreturn_supply, exit)?;
.into_iter()
.unwrap_get_inner(prev_height)
} else {
Sats::ZERO
};
let date = height_to_date_fixed_iter.unwrap_get_inner(height);
let dateindex = DateIndex::try_from(date).unwrap();
let date_first_height = dateindex_to_first_height_iter.unwrap_get_inner(dateindex);
let date_height_count = dateindex_to_height_count_iter.unwrap_get_inner(dateindex);
let is_date_last_height = date_first_height
+ Height::from(date_height_count).decremented().unwrap()
== height;
let date_price = dateindex_to_close_iter
.as_mut()
.map(|v| is_date_last_height.then(|| *v.unwrap_get_inner(dateindex)));
let mut height = starting_height;
separate_utxo_vecs.par_iter_mut().try_for_each(|(_, v)| {
v.compute_then_force_push_unrealized_states(
(height.unwrap_to_usize()..height_to_date_fixed.len())
.map(Height::from)
.try_for_each(|_height| -> color_eyre::Result<()> {
height = _height;
self.utxos_vecs
.as_mut_separate_vecs()
.iter_mut()
.for_each(|(_, v)| v.state.reset_single_iteration_values());
info!("Processing chain at {height}...");
let timestamp = height_to_timestamp_fixed_iter.unwrap_get_inner(height);
let price = height_to_close_iter
.as_mut()
.map(|i| *i.unwrap_get_inner(height));
let first_outputindex = height_to_first_outputindex_iter
.unwrap_get_inner(height)
.unwrap_to_usize();
let first_inputindex = height_to_first_inputindex_iter
.unwrap_get_inner(height)
.unwrap_to_usize();
let output_count = height_to_output_count_iter.unwrap_get_inner(height);
let input_count = height_to_input_count_iter.unwrap_get_inner(height);
let (mut height_to_sent, mut received) = thread::scope(|s| {
if chain_state_starting_height <= height {
s.spawn(|| {
self.utxos_vecs
.tick_tock_next_block(&chain_state, timestamp);
});
}
let sent_handle = s.spawn(|| {
// Skip coinbase
(first_inputindex + 1..first_inputindex + *input_count)
.into_par_iter()
.map(InputIndex::from)
.map(|inputindex| {
let outputindex = inputindex_to_outputindex
.get_or_read(inputindex, &inputindex_to_outputindex_mmap)
.unwrap()
.unwrap()
.into_inner();
let value = outputindex_to_value
.get_or_read(outputindex, &outputindex_to_value_mmap)
.unwrap()
.unwrap()
.into_inner();
let input_type = outputindex_to_outputtype
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
.unwrap()
.unwrap()
.into_inner();
// dbg!(input_type);
if input_type.is_unspendable() {
unreachable!()
}
let input_txindex = outputindex_to_txindex
.get_or_read(outputindex, &outputindex_to_txindex_mmap)
.unwrap()
.unwrap()
.into_inner();
let height = txindex_to_height
.get_or_read(input_txindex, &txindex_to_height_mmap)
.unwrap()
.unwrap()
.into_inner();
(height, value, input_type)
})
.fold(
BTreeMap::<Height, Transacted>::default,
|mut tree, (height, value, input_type)| {
tree.entry(height).or_default().iterate(value, input_type);
tree
},
)
.reduce(BTreeMap::<Height, Transacted>::default, |first, second| {
let (mut source, to_consume) = if first.len() > second.len() {
(first, second)
} else {
(second, first)
};
to_consume.into_iter().for_each(|(k, v)| {
*source.entry(k).or_default() += v;
});
source
})
});
let received_handle = s.spawn(|| {
(first_outputindex..first_outputindex + *output_count)
.into_par_iter()
.map(OutputIndex::from)
.map(|outputindex| {
let value = outputindex_to_value
.get_or_read(outputindex, &outputindex_to_value_mmap)
.unwrap()
.unwrap()
.into_inner();
let output_type = outputindex_to_outputtype
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
.unwrap()
.unwrap()
.into_inner();
(value, output_type)
})
.fold(
Transacted::default,
|mut transacted, (value, output_type)| {
transacted.iterate(value, output_type);
transacted
},
)
.reduce(Transacted::default, |acc, transacted| acc + transacted)
});
(sent_handle.join().unwrap(), received_handle.join().unwrap())
});
unspendable_supply += received
.by_type
.unspendable
.as_vec()
.into_iter()
.map(|state| state.value)
.sum::<Sats>()
+ height_to_unclaimed_rewards_iter.unwrap_get_inner(height);
opreturn_supply += received.by_type.unspendable.opreturn.value;
if height == Height::new(0) {
received = Transacted::default();
unspendable_supply += Sats::FIFTY_BTC;
} else if height == Height::new(91_842) || height == Height::new(91_880) {
// Need to destroy invalid coinbases due to duplicate txids
if height == Height::new(91_842) {
height_to_sent.entry(Height::new(91_812)).or_default()
} else {
height_to_sent.entry(Height::new(91_722)).or_default()
}
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
};
if chain_state_starting_height <= height {
// Push current block state before processing sends and receives
chain_state.push(BlockState {
supply: received.spendable_supply.clone(),
price,
timestamp,
});
self.utxos_vecs.receive(received, height, price);
let unsafe_chain_state = UnsafeSlice::new(&mut chain_state);
height_to_sent.par_iter().for_each(|(height, sent)| unsafe {
(*unsafe_chain_state.get(height.unwrap_to_usize())).supply -=
&sent.spendable_supply;
});
self.utxos_vecs.send(height_to_sent, chain_state.as_slice());
} else {
dbg!(chain_state_starting_height, height);
panic!("temp, just making sure")
}
let mut separate_utxo_vecs = self.utxos_vecs.as_mut_separate_vecs();
separate_utxo_vecs
.iter_mut()
.try_for_each(|(_, v)| v.forced_pushed_at(height, exit))?;
self.height_to_unspendable_supply.forced_push_at(
height,
price,
is_date_last_height.then_some(dateindex),
date_price,
unspendable_supply,
exit,
)
)?;
self.height_to_opreturn_supply
.forced_push_at(height, opreturn_supply, exit)?;
let date = height_to_date_fixed_iter.unwrap_get_inner(height);
let dateindex = DateIndex::try_from(date).unwrap();
let date_first_height =
dateindex_to_first_height_iter.unwrap_get_inner(dateindex);
let date_height_count =
dateindex_to_height_count_iter.unwrap_get_inner(dateindex);
let is_date_last_height = date_first_height
+ Height::from(date_height_count).decremented().unwrap()
== height;
let date_price = dateindex_to_close_iter
.as_mut()
.map(|v| is_date_last_height.then(|| *v.unwrap_get_inner(dateindex)));
separate_utxo_vecs.par_iter_mut().try_for_each(|(_, v)| {
v.compute_then_force_push_unrealized_states(
height,
price,
is_date_last_height.then_some(dateindex),
date_price,
exit,
)
})?;
if height != Height::ZERO && height.unwrap_to_usize() % 20_000 == 0 {
info!("Flushing...");
exit.block();
self.flush_states(height, &chain_state, exit)?;
exit.release();
}
Ok(())
})?;
if height != Height::ZERO && height.unwrap_to_usize() % 20_000 == 0 {
info!("Flushing...");
exit.block();
self.flush_states(height, &chain_state, exit)?;
exit.release();
}
exit.block();
Ok(())
})?;
info!("Flushing...");
exit.block();
self.flush_states(height, &chain_state, exit)?;
}
info!("Flushing...");
self.flush_states(height, &chain_state, exit)?;
info!("Computing overlaping...");
info!("Computing overlapping...");
self.utxos_vecs
.compute_overlaping_vecs(&starting_indexes, exit)?;
.compute_overlapping_vecs(&starting_indexes, exit)?;
info!("Computing rest part 1...");
@@ -1627,6 +1624,13 @@ impl Vecs {
.dateindex
.clone();
let height_to_realized_cap = self.utxos_vecs.all.1.height_to_realized_cap.clone();
let dateindex_to_realized_cap = self
.utxos_vecs
.all
.1
.indexes_to_realized_cap
.as_ref()
.map(|v| v.dateindex.unwrap_last().clone());
self.utxos_vecs
.as_mut_vecs()
@@ -1641,6 +1645,7 @@ impl Vecs {
&height_to_supply,
dateindex_to_supply.as_ref().unwrap(),
height_to_realized_cap.as_ref(),
dateindex_to_realized_cap.as_ref(),
exit,
)
})?;
@@ -14,7 +14,7 @@ pub trait OutputCohorts {
fn tick_tock_next_block(&mut self, chain_state: &[BlockState], timestamp: Timestamp);
fn send(&mut self, height_to_sent: BTreeMap<Height, Transacted>, chain_state: &[BlockState]);
fn receive(&mut self, received: Transacted, height: Height, price: Option<Dollars>);
fn compute_overlaping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
fn compute_overlapping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
}
impl OutputCohorts for Outputs<(OutputFilter, cohort::Vecs)> {
@@ -172,7 +172,7 @@ impl OutputCohorts for Outputs<(OutputFilter, cohort::Vecs)> {
});
}
fn compute_overlaping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
fn compute_overlapping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
let by_date_range = self.by_date_range.as_vec();
let by_size_range = self.by_size_range.as_vec();
+19 -5
View File
@@ -178,6 +178,17 @@ impl Mul<usize> for Close<Dollars> {
}
}
impl Mul<f64> for Dollars {
type Output = Dollars;
fn mul(self, rhs: f64) -> Self::Output {
if rhs.fract() != 0.0 {
Self::from(self.0 * rhs)
} else {
self * rhs as i64
}
}
}
impl Mul<Bitcoin> for Dollars {
type Output = Self;
fn mul(self, rhs: Bitcoin) -> Self::Output {
@@ -208,11 +219,14 @@ impl Mul<Sats> for Dollars {
impl Mul<StoredF32> for Dollars {
type Output = Self;
fn mul(self, rhs: StoredF32) -> Self::Output {
if rhs.fract() != 0.0 {
Self::from(self.0 * *rhs as f64)
} else {
self * *rhs as i64
}
self * *rhs as f64
}
}
impl Mul<StoredF64> for Dollars {
type Output = Self;
fn mul(self, rhs: StoredF64) -> Self::Output {
self * *rhs
}
}
+3 -1
View File
@@ -3,5 +3,7 @@ use log::info;
pub fn pause() {
info!("Press enter to continue...");
let mut buffer = String::new();
std::io::stdin().read_line(&mut buffer).expect("Failed to read line");
std::io::stdin()
.read_line(&mut buffer)
.expect("Failed to read line");
}
+8 -3
View File
@@ -28,9 +28,14 @@ impl<'a> VecTrees<'a> {
|| s.starts_with("cumulative_from")
}))
&& !(split.len() == 4
&& split
.get(1)
.is_some_and(|s| s == &"up" || s == &"start" || s.starts_with("from"))
&& split.get(1).is_some_and(|s| {
s == &"up"
|| s == &"start"
|| s.starts_with("from")
|| s == &"cumulative_up"
|| s == &"cumulative_start"
|| s.starts_with("cumulative_from")
})
&& split.get(2).is_some_and(|s| s.ends_with("relative")))
{
dbg!(&name, &split);
@@ -0,0 +1 @@
+1 -1
View File
@@ -70,7 +70,7 @@ impl<T> Outputs<T> {
.collect::<Vec<_>>()
}
pub fn as_mut_overlaping_vecs(&mut self) -> Vec<&mut T> {
pub fn as_mut_overlapping_vecs(&mut self) -> Vec<&mut T> {
[&mut self.all]
.into_iter()
.chain(self.by_term.as_mut_vec())
+26
View File
@@ -1015,6 +1015,32 @@ where
self.safe_flush(exit)
}
pub fn compute_zscore(
&mut self,
max_from: I,
ratio: &impl AnyIterableVec<I, StoredF32>,
sma: &impl AnyIterableVec<I, StoredF32>,
sd: &impl AnyIterableVec<I, StoredF32>,
exit: &Exit,
) -> Result<()>
where
T: From<StoredF32>,
{
let mut sma_iter = sma.iter();
let mut sd_iter = sd.iter();
self.compute_transform(
max_from,
ratio,
|(i, ratio, ..)| {
let sma = sma_iter.unwrap_get_inner(i);
let sd = sd_iter.unwrap_get_inner(i);
(i, T::from((ratio - sma) / sd))
},
exit,
)
}
}
impl EagerVec<DateIndex, Sats> {
@@ -400,13 +400,17 @@ function createChartElement({
({ _indexes, values }) => {
if (!_indexes?.length || !values?.length) return;
const consoleTimeLabel = `${vecId}-time`;
console.time(consoleTimeLabel);
const indexes = /** @type {number[]} */ (_indexes);
let length = Math.min(indexes.length, values.length);
// TODO: Don't create new Array if data already present, update instead
/** @type {LineData[] | CandlestickData[]} */
const data = new Array(length);
const data = /** @type {LineData[] | CandlestickData[]} */ (
Array.from({ length })
);
let prevTime = null;
let timeOffset = 0;
@@ -433,16 +437,18 @@ function createChartElement({
if (sameTime) {
console.log(data[offsetedI]);
}
const candles = /** @type {CandlestickData[]} */ (data);
let [open, high, low, close] = v;
candles[offsetedI] = {
data[offsetedI] = {
time,
open: sameTime ? candles[offsetedI].open : open,
// @ts-ignore
open: sameTime ? data[offsetedI].open : open,
high: sameTime
? Math.max(candles[offsetedI].high, high)
? // @ts-ignore
Math.max(data[offsetedI].high, high)
: high,
low: sameTime
? Math.min(candles[offsetedI].low, low)
? // @ts-ignore
Math.min(data[offsetedI].low, low)
: low,
close,
};
@@ -474,69 +480,12 @@ function createChartElement({
});
}
});
} else if (data.length) {
let i = 0;
// console.log(seriesData);
const first = seriesData[0];
} else {
const last = seriesData.at(-1);
if (!last) throw Error("Unreachable");
while (data[i].time < first.time) {
iseries.update(data[i], true);
i++;
}
// console.log(i);
let j = 0;
while (i < data.length) {
const dataI = data[i];
const iTime = dataI.time;
const seriesDataJ = /** @type {typeof dataI} */ (
seriesData[j]
);
const jTime = seriesDataJ.time;
if (iTime === jTime) {
const historicalUpdate = iTime < last.time;
if ("value" in dataI) {
if (
// @ts-ignore
dataI.value !== seriesDataJ.value &&
// @ts-ignore
(!isNaN(dataI.value) || !isNaN(seriesDataJ.value))
) {
// console.log(vecId);
iseries.update(dataI, historicalUpdate);
}
} else if (
// @ts-ignore
dataI.open !== seriesDataJ.open ||
// @ts-ignore
dataI.high !== seriesDataJ.high ||
// @ts-ignore
dataI.low !== seriesDataJ.low ||
// @ts-ignore
dataI.close !== seriesDataJ.close
) {
// console.log({
// vecId,
// dataI,
// i,
// data,
// j,
// seriesDataJ,
// seriesData,
// });
iseries.update(dataI, historicalUpdate);
}
i++;
j++;
} else if (iTime < jTime) {
iseries.update(dataI, true);
i++;
} else if (iTime > last.time) {
iseries.update(dataI);
i++;
} else if (iTime > jTime) {
j++;
for (let i = 0; i < data.length; i++) {
if (data[i].time >= last.time) {
iseries.update(data[i]);
}
}
}
@@ -546,6 +495,8 @@ function createChartElement({
index,
unit,
});
console.timeEnd(consoleTimeLabel);
}
);
} else {
+1
View File
@@ -396,6 +396,7 @@ export function init({
blueprints[unit]?.forEach((blueprint, order) => {
order += orderStart;
console.log(blueprint.key);
const indexes = /** @type {readonly number[]} */ (
vecIdToIndexes[blueprint.key]
);
+35 -36
View File
@@ -752,7 +752,8 @@ function createUtils() {
(id.includes("realized") &&
!id.includes("ratio") &&
!id.includes("relative-to")) ||
(id.endsWith("sma") && !id.includes("ratio")) ||
((id.endsWith("sma") || id.includes("sma-x")) &&
!id.includes("ratio")) ||
id === "ath")
) {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
@@ -838,7 +839,7 @@ function createUtils() {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
unit = "Bytes";
}
if ((!unit || thoroughUnitCheck) && id.endsWith("standard-deviation")) {
if ((!unit || thoroughUnitCheck) && id.endsWith("-sd")) {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
unit = "sd";
}
@@ -1264,12 +1265,6 @@ function createUtils() {
return 0;
return this.differenceBetween(date, new Date("2009-01-09"));
},
/**
* @param {Date} start
*/
getRangeUpToToday(start) {
return this.getRange(start, new Date());
},
/**
* @param {Date} start
* @param {Date} end
@@ -1578,7 +1573,9 @@ function createVecsResources(signals, utils) {
map.set(fetchedKey, {
loading: false,
at: null,
vec: signals.createSignal(/** @type {T[] | null} */ (null)),
vec: signals.createSignal(/** @type {T[] | null} */ (null), {
equals: false,
}),
});
return map;
});
@@ -2289,36 +2286,36 @@ function main() {
initSelected();
function initFolders() {
// async function scrollToSelected() {
// if (!options.selected()) throw "Selected should be set by now";
// const selectedId = options.selected().id;
async function scrollToSelected() {
if (!options.selected()) throw "Selected should be set by now";
const selectedId = options.selected().id;
// const path = options.selected().path;
const path = options.selected().path;
// let i = 0;
// while (i !== path.length) {
// try {
// const id = path[i];
// const details = /** @type {HTMLDetailsElement} */ (
// utils.dom.getElementById(id)
// );
// details.open = true;
// i++;
// } catch {
// await utils.next();
// }
// }
let i = 0;
while (i !== path.length) {
try {
const id = path[i];
const details = /** @type {HTMLDetailsElement} */ (
utils.dom.getElementById(id)
);
details.open = true;
i++;
} catch {
await utils.next();
}
}
// await utils.next();
// await utils.next();
await utils.next();
await utils.next();
// utils.dom
// .getElementById(`${selectedId}-nav-selector`)
// .scrollIntoView({
// behavior: "instant",
// block: "center",
// });
// }
utils.dom
.getElementById(`${selectedId}-nav-selector`)
.scrollIntoView({
behavior: "instant",
block: "center",
});
}
utils.dom.onFirstIntersection(elements.nav, () => {
options.treeElement.set(() => {
@@ -2328,7 +2325,9 @@ function main() {
return treeElement;
});
// setTimeout(scrollToSelected, 10);
if (localhost) {
setTimeout(scrollToSelected, 10);
}
});
}
initFolders();
+357 -78
View File
@@ -132,9 +132,6 @@ function createPartialOptions(colors) {
* @typedef {"cumulative-"} CumulativePrefix
* @typedef {StartsWith<CumulativePrefix>} CumulativeVecId
* @typedef {WithoutPrefix<CumulativeVecId, CumulativePrefix>} CumulativeVecIdBase
* @typedef {"-sum"} SumSuffix
* @typedef {EndsWith<SumSuffix>} VecIdSum
* @typedef {WithoutSuffix<VecIdSum, SumSuffix>} VecIdSumBase
* @typedef {"-average"} AverageSuffix
* @typedef {EndsWith<AverageSuffix>} VecIdAverage
* @typedef {WithoutSuffix<VecIdAverage, AverageSuffix>} VecIdAverageBase
@@ -162,15 +159,16 @@ function createPartialOptions(colors) {
*/
const averages = /** @type {const} */ ([
{ name: "1 Week", key: "1w", days: 7, color: colors.orange },
{ name: "8 Day", key: "8d", days: 8, color: colors.amber },
{ name: "13 Day", key: "13d", days: 13, color: colors.yellow },
{ name: "21 Day", key: "21d", days: 21, color: colors.lime },
{ name: "1 Month", key: "1m", days: 30, color: colors.green },
{ name: "34 Day", key: "34d", days: 34, color: colors.emerald },
{ name: "55 Day", key: "55d", days: 55, color: colors.teal },
{ name: "89 Day", key: "89d", days: 89, color: colors.cyan },
{ name: "144 Day", key: "144d", days: 144, color: colors.sky },
{ name: "1 Week", key: "1w", days: 7, color: colors.red },
{ name: "8 Day", key: "8d", days: 8, color: colors.orange },
{ name: "13 Day", key: "13d", days: 13, color: colors.amber },
{ name: "21 Day", key: "21d", days: 21, color: colors.yellow },
{ name: "1 Month", key: "1m", days: 30, color: colors.lime },
{ name: "34 Day", key: "34d", days: 34, color: colors.green },
{ name: "55 Day", key: "55d", days: 55, color: colors.emerald },
{ name: "89 Day", key: "89d", days: 89, color: colors.teal },
{ name: "144 Day", key: "144d", days: 144, color: colors.cyan },
{ name: "200 Day", key: "200d", days: 200, color: colors.sky },
{ name: "1 Year", key: "1y", days: 365, color: colors.blue },
{ name: "2 Year", key: "2y", days: 2 * 365, color: colors.indigo },
{ name: "200 Week", key: "200w", days: 200 * 7, color: colors.violet },
@@ -831,13 +829,13 @@ function createPartialOptions(colors) {
/**
* @param {Object} args
* @param {VecIdSumBase & CumulativeVecIdBase} args.concat
* @param {CumulativeVecIdBase} args.concat
* @param {string} [args.name]
*/
function createSumCumulativeSeries({ concat, name }) {
return /** @satisfies {AnyFetchedSeriesBlueprint[]} */ ([
{
key: `${concat}-sum`,
key: concat,
title: name ? `${name} Sum` : "Sum",
color: colors.orange,
},
@@ -902,7 +900,7 @@ function createPartialOptions(colors) {
}
/**
* @param {VecIdAverageBase & VecIdSumBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key
* @param {VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key
*/
function createAverageSumCumulativeMinMaxPercentilesSeries(key) {
return [
@@ -914,7 +912,7 @@ function createPartialOptions(colors) {
/**
* @param {Object} args
* @param {VecId & VecIdAverageBase & VecIdSumBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} args.key
* @param {VecId & VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} args.key
* @param {string} args.name
*/
function createBaseAverageSumCumulativeMinMaxPercentilesSeries({
@@ -932,7 +930,7 @@ function createPartialOptions(colors) {
/**
* @param {Object} args
* @param {VecId & VecIdSumBase & CumulativeVecIdBase} args.key
* @param {VecId & CumulativeVecIdBase} args.key
* @param {string} args.name
*/
function createBaseSumCumulativeSeries({ key, name }) {
@@ -1057,12 +1055,6 @@ function createPartialOptions(colors) {
},
},
}),
createBaseSeries({
key: `${key}-ratio-sma`,
name: "sma",
color: colors.yellow,
defaultActive: false,
}),
createBaseSeries({
key: `${key}-ratio-p1sd`,
name: "+1σ",
@@ -1153,6 +1145,18 @@ function createPartialOptions(colors) {
color: colors.rose,
defaultActive: false,
}),
createBaseSeries({
key: `${key}-ratio-4y-sma`,
name: "4y-sma",
color: colors.violet,
defaultActive: false,
}),
createBaseSeries({
key: `${key}-ratio-sma`,
name: "sma",
color: colors.yellow,
defaultActive: false,
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}-ratio-1y-sma-momentum-oscillator`,
title: "1Y Momentum",
@@ -1165,7 +1169,7 @@ function createPartialOptions(colors) {
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}-ratio-zscore`,
title: "Score",
title: "All time",
type: "Baseline",
options: {
createPriceLine: {
@@ -1173,6 +1177,17 @@ function createPartialOptions(colors) {
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}-ratio-4y-zscore`,
title: "4y",
type: "Baseline",
colors: [colors.yellow, colors.pink],
options: {
createPriceLine: {
value: 0,
},
},
}),
],
};
}
@@ -1434,19 +1449,170 @@ function createPartialOptions(colors) {
name: "Profit",
color: colors.green,
}),
createBaseSeries({
key: `cumulative-${fixKey(args.key)}realized-profit`,
name: "Cumulative Profit",
color: colors.green,
defaultActive: false,
}),
createBaseSeries({
key: `${fixKey(args.key)}realized-loss`,
name: "Loss",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `cumulative-${fixKey(args.key)}realized-loss`,
name: "Cumulative Loss",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${fixKey(args.key)}negative-realized-loss`,
name: "Negative Loss",
color: colors.red,
}),
createBaseSeries({
key: `cumulative-${fixKey(
args.key
)}negative-realized-loss`,
name: "Cumulative Negative Loss",
color: colors.red,
defaultActive: false,
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(
args.key
)}realized-profit-relative-to-realized-cap`,
title: "Profit",
color: colors.green,
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(
args.key
)}realized-loss-relative-to-realized-cap`,
title: "Loss",
color: colors.red,
options: {
createPriceLine: {
value: 0,
},
},
}),
],
},
{
name: "Net pnl",
title: `${args.title} Net Realized Profit And Loss`,
bottom: list.flatMap(({ color, name, key }) => [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(key)}net-realized-profit-and-loss`,
title: "Net",
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `cumulative-${fixKey(
key
)}net-realized-profit-and-loss`,
title: "Cumulative net",
defaultActive: false,
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `cumulative-${fixKey(
key
)}net-realized-profit-and-loss-30d-change`,
title: "cum net 30d change",
defaultActive: false,
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(
key
)}net-realized-profit-and-loss-relative-to-realized-cap`,
title: "Net",
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `cumulative-${fixKey(
key
)}net-realized-profit-and-loss-30d-change-relative-to-realized-cap`,
title: "cum net 30d change",
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `cumulative-${fixKey(
key
)}net-realized-profit-and-loss-30d-change-relative-to-market-cap`,
title: "cum net 30d change",
options: {
createPriceLine: {
value: 0,
},
},
}),
]),
},
{
name: "sopr",
title: `${args.title} Spent Output Profit Ratio`,
bottom: list.flatMap(({ color, name, key }) => [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(key)}spent-output-profit-ratio`,
title: "sopr",
options: {
createPriceLine: {
value: 1,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(key)}adjusted-spent-output-profit-ratio`,
title: "asopr",
colors: [colors.yellow, colors.pink],
options: {
createPriceLine: {
value: 1,
},
},
}),
]),
},
]
: [
{
@@ -1457,8 +1623,19 @@ function createPartialOptions(colors) {
return /** @type {const} */ ([
createBaseSeries({
key: `${key}realized-profit`,
name: useGroupName ? name : "Profit",
color: useGroupName ? color : colors.green,
name,
color,
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${key}realized-profit-relative-to-realized-cap`,
title: name,
color,
options: {
createPriceLine: {
value: 0,
},
},
}),
]);
}),
@@ -1471,75 +1648,151 @@ function createPartialOptions(colors) {
return /** @type {const} */ ([
createBaseSeries({
key: `${key}realized-loss`,
name: useGroupName ? name : "Loss",
color: useGroupName ? color : colors.red,
name,
color,
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${key}realized-loss-relative-to-realized-cap`,
title: name,
color,
options: {
createPriceLine: {
value: 0,
},
},
}),
]);
}),
},
]),
{
name: "Net pnl",
title: `${args.title} Net Realized Profit And Loss`,
bottom: list.flatMap(({ color, name, key }) => [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(key)}net-realized-profit-and-loss`,
title: useGroupName ? name : "Net",
color: useGroupName ? color : undefined,
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(
key
)}net-realized-profit-and-loss-relative-to-realized-cap`,
title: useGroupName ? name : "Net",
color: useGroupName ? color : undefined,
options: {
createPriceLine: {
value: 0,
},
},
}),
]),
},
...(!("list" in args)
? [
{
name: "sopr",
title: `${args.title} Spent Output Profit Ratio`,
name: "Net pnl",
title: `${args.title} Net Realized Profit And Loss`,
bottom: list.flatMap(({ color, name, key }) => [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(key)}spent-output-profit-ratio`,
title: useGroupName ? name : "sopr",
color: useGroupName ? color : undefined,
key: `${fixKey(key)}net-realized-profit-and-loss`,
title: name,
color,
options: {
createPriceLine: {
value: 1,
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(key)}adjusted-spent-output-profit-ratio`,
title: useGroupName ? name : "asopr",
color: useGroupName ? color : undefined,
key: `${fixKey(
key
)}net-realized-profit-and-loss-relative-to-realized-cap`,
title: name,
color,
options: {
createPriceLine: {
value: 1,
value: 0,
},
},
}),
]),
},
]
: [
{
name: "cumulative",
tree: [
{
name: "profit",
title: `Cumulative ${args.title} Realized Profit`,
bottom: list.flatMap(({ color, name, key: _key }) => {
const key = fixKey(_key);
return /** @type {const} */ ([
createBaseSeries({
key: `cumulative-${key}realized-profit`,
name,
color,
}),
]);
}),
},
{
name: "loss",
title: `Cumulative ${args.title} Realized Loss`,
bottom: list.flatMap(({ color, name, key: _key }) => {
const key = fixKey(_key);
return /** @type {const} */ ([
createBaseSeries({
key: `cumulative-${key}realized-loss`,
name,
color,
}),
]);
}),
},
{
name: "Net pnl",
title: `Cumulative ${args.title} Net Realized Profit And Loss`,
bottom: list.flatMap(({ color, name, key }) => [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `cumulative-${fixKey(
key
)}net-realized-profit-and-loss`,
title: name,
color,
defaultActive: false,
options: {
createPriceLine: {
value: 0,
},
},
}),
]),
},
{
name: "Net pnl 30d change",
title: `Cumulative ${args.title} Net Realized Profit And Loss 30 Day Change`,
bottom: list.flatMap(({ color, name, key }) => [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `cumulative-${fixKey(
key
)}net-realized-profit-and-loss-30d-change`,
title: name,
color,
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `cumulative-${fixKey(
key
)}net-realized-profit-and-loss-30d-change-relative-to-realized-cap`,
title: name,
color,
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `cumulative-${fixKey(
key
)}net-realized-profit-and-loss-30d-change-relative-to-market-cap`,
title: name,
color,
options: {
createPriceLine: {
value: 0,
},
},
}),
]),
},
],
},
{
name: "sopr",
tree: [
@@ -1550,8 +1803,8 @@ function createPartialOptions(colors) {
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(key)}spent-output-profit-ratio`,
title: useGroupName ? name : "sopr",
color: useGroupName ? color : undefined,
title: name,
color,
options: {
createPriceLine: {
value: 1,
@@ -1569,8 +1822,8 @@ function createPartialOptions(colors) {
key: `${fixKey(
key
)}adjusted-spent-output-profit-ratio`,
title: useGroupName ? name : "asopr",
color: useGroupName ? color : undefined,
title: name,
color,
options: {
createPriceLine: {
value: 1,
@@ -1904,6 +2157,32 @@ function createPartialOptions(colors) {
],
})),
},
{
name: "Indicators",
tree: [
{
name: "Mayer multiple",
title: "Mayer multiple",
top: [
createBaseSeries({
key: `200d-sma`,
name: "200d sma",
color: colors.yellow,
}),
createBaseSeries({
key: `200d-sma-x2-4`,
name: "200d sma x2.4",
color: colors.green,
}),
createBaseSeries({
key: `200d-sma-x0-8`,
name: "200d sma x0.8",
color: colors.red,
}),
],
},
],
},
],
},
{
@@ -2732,7 +3011,7 @@ function createPartialOptions(colors) {
bottom: [
createBaseSeries({ key: "opreturn-count", name: "Count" }),
createBaseSeries({
key: "opreturn-count-sum",
key: "opreturn-count",
name: "sum",
}),
createBaseSeries({
File diff suppressed because it is too large Load Diff