mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-08 06:01:57 -07:00
website: snapshot
This commit is contained in:
@@ -23,6 +23,7 @@ _*
|
||||
/heatmaps*
|
||||
/oracle*
|
||||
/playground
|
||||
/*.txt
|
||||
|
||||
# Logs
|
||||
*.log*
|
||||
|
||||
Generated
+6
-1
@@ -412,6 +412,7 @@ dependencies = [
|
||||
"brk_server",
|
||||
"brk_types",
|
||||
"lexopt",
|
||||
"owo-colors",
|
||||
"serde",
|
||||
"tokio",
|
||||
"toml",
|
||||
@@ -570,6 +571,7 @@ dependencies = [
|
||||
"brk_indexer",
|
||||
"brk_logger",
|
||||
"brk_types",
|
||||
"jiff",
|
||||
"memmap2",
|
||||
"plotters",
|
||||
"tracing",
|
||||
@@ -716,6 +718,7 @@ dependencies = [
|
||||
"brk_logger",
|
||||
"importmap",
|
||||
"include_dir",
|
||||
"serde",
|
||||
"tokio",
|
||||
"tower-http",
|
||||
"tower-layer",
|
||||
@@ -1749,7 +1752,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "importmap"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "689654b51e7a463f6d1009c18e784a43d287d82296b67f27411f01c38ab5adb7"
|
||||
dependencies = [
|
||||
"include_dir",
|
||||
"rapidhash",
|
||||
|
||||
@@ -68,6 +68,7 @@ derive_more = { version = "2.1.1", features = ["deref", "deref_mut"] }
|
||||
fjall = "3.0.1"
|
||||
jiff = { version = "0.2.18", features = ["perf-inline", "tz-system"], default-features = false }
|
||||
minreq = { version = "2.14.1", features = ["https", "json-using-serde"] }
|
||||
owo-colors = "4.2.3"
|
||||
parking_lot = "0.12.5"
|
||||
rayon = "1.11.0"
|
||||
rustc-hash = "2.1.1"
|
||||
|
||||
@@ -23,6 +23,7 @@ brk_rpc = { workspace = true }
|
||||
brk_server = { workspace = true }
|
||||
brk_types = { workspace = true }
|
||||
lexopt = "0.3"
|
||||
owo-colors = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
@@ -4,12 +4,14 @@ use std::{
|
||||
};
|
||||
|
||||
use brk_error::{Error, Result};
|
||||
use owo_colors::OwoColorize;
|
||||
use brk_fetcher::Fetcher;
|
||||
use brk_rpc::{Auth, Client};
|
||||
use brk_server::Website;
|
||||
use brk_types::Port;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
use crate::{default_brk_path, dot_brk_path, fix_user_path, website::WebsiteArg};
|
||||
use crate::{default_brk_path, dot_brk_path, fix_user_path};
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
@@ -20,7 +22,7 @@ pub struct Config {
|
||||
brkport: Option<Port>,
|
||||
|
||||
#[serde(default, deserialize_with = "default_on_error")]
|
||||
website: Option<WebsiteArg>,
|
||||
website: Option<Website>,
|
||||
|
||||
#[serde(default, deserialize_with = "default_on_error")]
|
||||
fetch: Option<bool>,
|
||||
@@ -45,9 +47,6 @@ pub struct Config {
|
||||
|
||||
#[serde(default, deserialize_with = "default_on_error")]
|
||||
rpcpassword: Option<String>,
|
||||
|
||||
#[serde(default, deserialize_with = "default_on_error")]
|
||||
check_collisions: Option<bool>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -95,9 +94,6 @@ impl Config {
|
||||
if let Some(v) = config_args.rpcpassword {
|
||||
config.rpcpassword = Some(v);
|
||||
}
|
||||
if let Some(v) = config_args.check_collisions {
|
||||
config.check_collisions = Some(v);
|
||||
}
|
||||
|
||||
config.check();
|
||||
|
||||
@@ -126,14 +122,23 @@ impl Config {
|
||||
Long("brkport") => config.brkport = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("website") => config.website = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("fetch") => config.fetch = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("bitcoindir") => config.bitcoindir = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("blocksdir") => config.blocksdir = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("rpcconnect") => config.rpcconnect = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("bitcoindir") => {
|
||||
config.bitcoindir = Some(parser.value().unwrap().parse().unwrap())
|
||||
}
|
||||
Long("blocksdir") => {
|
||||
config.blocksdir = Some(parser.value().unwrap().parse().unwrap())
|
||||
}
|
||||
Long("rpcconnect") => {
|
||||
config.rpcconnect = Some(parser.value().unwrap().parse().unwrap())
|
||||
}
|
||||
Long("rpcport") => config.rpcport = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("rpccookiefile") => config.rpccookiefile = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("rpccookiefile") => {
|
||||
config.rpccookiefile = Some(parser.value().unwrap().parse().unwrap())
|
||||
}
|
||||
Long("rpcuser") => config.rpcuser = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("rpcpassword") => config.rpcpassword = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("check-collisions") => config.check_collisions = Some(parser.value().unwrap().parse().unwrap()),
|
||||
Long("rpcpassword") => {
|
||||
config.rpcpassword = Some(parser.value().unwrap().parse().unwrap())
|
||||
}
|
||||
_ => {
|
||||
eprintln!("{}", arg.unexpected());
|
||||
std::process::exit(1);
|
||||
@@ -145,32 +150,31 @@ impl Config {
|
||||
}
|
||||
|
||||
fn print_help() {
|
||||
println!(
|
||||
"brk {}
|
||||
Bitcoin Research Kit
|
||||
let v = env!("CARGO_PKG_VERSION");
|
||||
|
||||
USAGE:
|
||||
brk [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
-h, --help Print help
|
||||
-V, --version Print version
|
||||
|
||||
--brkdir <PATH> Output directory [~/.brk]
|
||||
--brkport <PORT> Server port [3110]
|
||||
--website <BOOL|PATH> Website: true, false, or path [true]
|
||||
--fetch <BOOL> Fetch prices [true]
|
||||
|
||||
--bitcoindir <PATH> Bitcoin directory [~/.bitcoin, ~/Library/Application Support/Bitcoin]
|
||||
--blocksdir <PATH> Blocks directory [<bitcoindir>/blocks]
|
||||
|
||||
--rpcconnect <IP> RPC host [localhost]
|
||||
--rpcport <PORT> RPC port [8332]
|
||||
--rpccookiefile <PATH> RPC cookie file [<bitcoindir>/.cookie]
|
||||
--rpcuser <USERNAME> RPC username
|
||||
--rpcpassword <PASSWORD> RPC password",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
);
|
||||
println!("{} {}", "brk".bold(), v.bright_black());
|
||||
println!("Bitcoin Research Kit");
|
||||
println!();
|
||||
println!("{}", "USAGE:".bold());
|
||||
println!(" brk {}", "[OPTIONS]".bright_black());
|
||||
println!();
|
||||
println!("{}", "OPTIONS:".bold());
|
||||
println!(" -h, --help Print help");
|
||||
println!(" -V, --version Print version");
|
||||
println!();
|
||||
println!(" --brkdir {} Output directory {}", "<PATH>".bright_black(), "[~/.brk]".bright_black());
|
||||
println!(" --brkport {} Server port {}", "<PORT>".bright_black(), "[3110]".bright_black());
|
||||
println!(" --website {} Website: true, false, or path {}", "<BOOL|PATH>".bright_black(), "[true]".bright_black());
|
||||
println!(" --fetch {} Fetch prices {}", "<BOOL>".bright_black(), "[true]".bright_black());
|
||||
println!();
|
||||
println!(" --bitcoindir {} Bitcoin directory {}", "<PATH>".bright_black(), "[~/.bitcoin, ~/Library/...]".bright_black());
|
||||
println!(" --blocksdir {} Blocks directory {}", "<PATH>".bright_black(), "[<bitcoindir>/blocks]".bright_black());
|
||||
println!();
|
||||
println!(" --rpcconnect {} RPC host {}", "<IP>".bright_black(), "[localhost]".bright_black());
|
||||
println!(" --rpcport {} RPC port {}", "<PORT>".bright_black(), "[8332]".bright_black());
|
||||
println!(" --rpccookiefile {} RPC cookie file {}", "<PATH>".bright_black(), "[<bitcoindir>/.cookie]".bright_black());
|
||||
println!(" --rpcuser {} RPC username", "<USERNAME>".bright_black());
|
||||
println!(" --rpcpassword {} RPC password", "<PASSWORD>".bright_black());
|
||||
}
|
||||
|
||||
fn check(&self) {
|
||||
@@ -280,7 +284,7 @@ Finally, you can run the program with '-h' for help."
|
||||
)
|
||||
}
|
||||
|
||||
pub fn website(&self) -> WebsiteArg {
|
||||
pub fn website(&self) -> Website {
|
||||
self.website.clone().unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -297,9 +301,6 @@ Finally, you can run the program with '-h' for help."
|
||||
.then(|| Fetcher::import(Some(self.harsdir().as_path())).unwrap())
|
||||
}
|
||||
|
||||
pub fn check_collisions(&self) -> bool {
|
||||
self.check_collisions.is_some_and(|b| b)
|
||||
}
|
||||
}
|
||||
|
||||
fn default_on_error<'de, D, T>(deserializer: D) -> Result<T, D::Error>
|
||||
|
||||
@@ -14,15 +14,14 @@ use brk_iterator::Blocks;
|
||||
use brk_mempool::Mempool;
|
||||
use brk_query::AsyncQuery;
|
||||
use brk_reader::Reader;
|
||||
use brk_server::{Server, Website};
|
||||
use brk_server::Server;
|
||||
use tracing::info;
|
||||
use vecdb::Exit;
|
||||
|
||||
mod config;
|
||||
mod paths;
|
||||
mod website;
|
||||
|
||||
use crate::{config::Config, paths::*, website::WebsiteArg};
|
||||
use crate::{config::Config, paths::*};
|
||||
|
||||
pub fn main() -> anyhow::Result<()> {
|
||||
// Can't increase main thread's stack size, thus we need to use another thread
|
||||
@@ -80,11 +79,7 @@ pub fn run() -> anyhow::Result<()> {
|
||||
|
||||
let data_path = config.brkdir();
|
||||
|
||||
let website = match config.website() {
|
||||
WebsiteArg::Enabled(false) => Website::Disabled,
|
||||
WebsiteArg::Enabled(true) => Website::Default,
|
||||
WebsiteArg::Path(p) => Website::Filesystem(p),
|
||||
};
|
||||
let website = config.website();
|
||||
|
||||
let port = config.brkport();
|
||||
|
||||
@@ -111,7 +106,7 @@ pub fn run() -> anyhow::Result<()> {
|
||||
|
||||
info!("{} blocks found.", u32::from(last_height) + 1);
|
||||
|
||||
let starting_indexes = if config.check_collisions() {
|
||||
let starting_indexes = if cfg!(debug_assertions) {
|
||||
indexer.checked_index(&blocks, &client, &exit)?
|
||||
} else {
|
||||
indexer.index(&blocks, &client, &exit)?
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::paths::fix_user_path;
|
||||
|
||||
/// Website configuration:
|
||||
/// - `true` or omitted: serve embedded website
|
||||
/// - `false`: disable website serving
|
||||
/// - `"/path/to/website"`: serve custom website from path
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum WebsiteArg {
|
||||
Enabled(bool),
|
||||
Path(PathBuf),
|
||||
}
|
||||
|
||||
impl Default for WebsiteArg {
|
||||
fn default() -> Self {
|
||||
Self::Enabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for WebsiteArg {
|
||||
type Err = std::convert::Infallible;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s.to_lowercase().as_str() {
|
||||
"true" | "1" | "yes" | "on" => Self::Enabled(true),
|
||||
"false" | "0" | "no" | "off" => Self::Enabled(false),
|
||||
_ => Self::Path(fix_user_path(s)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::fs::File;
|
||||
use std::io::{BufWriter, Write};
|
||||
|
||||
use brk_client::{BrkClient, BrkClientOptions, Result};
|
||||
use brk_types::Dollars;
|
||||
|
||||
const CHUNK_SIZE: usize = 10_000;
|
||||
const END_HEIGHT: usize = 630_000;
|
||||
const OUTPUT_FILE: &str = "prices_avg.txt";
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let client = BrkClient::with_options(BrkClientOptions {
|
||||
base_url: "https://next.bitview.space".to_string(),
|
||||
timeout_secs: 60,
|
||||
});
|
||||
|
||||
let file = File::create(OUTPUT_FILE).map_err(|e| brk_client::BrkError {
|
||||
message: e.to_string(),
|
||||
})?;
|
||||
let mut writer = BufWriter::new(file);
|
||||
|
||||
for start in (0..END_HEIGHT).step_by(CHUNK_SIZE) {
|
||||
let end = (start + CHUNK_SIZE).min(END_HEIGHT);
|
||||
eprintln!("Fetching {start} to {end}...");
|
||||
|
||||
let ohlcs = client
|
||||
.metrics()
|
||||
.price
|
||||
.cents
|
||||
.ohlc
|
||||
.by
|
||||
.height()
|
||||
.range(start..end)
|
||||
.fetch()?;
|
||||
|
||||
for ohlc in ohlcs.data {
|
||||
let avg = (*ohlc.open + *ohlc.close) / 2;
|
||||
let avg = Dollars::from(avg);
|
||||
writeln!(writer, "{avg}").map_err(|e| brk_client::BrkError {
|
||||
message: e.to_string(),
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
writer.flush().map_err(|e| brk_client::BrkError {
|
||||
message: e.to_string(),
|
||||
})?;
|
||||
eprintln!("Done. Output in {OUTPUT_FILE}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+247
-231
@@ -1268,56 +1268,6 @@ impl Price111dSmaPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct PercentilesPattern {
|
||||
pub pct05: MetricPattern4<Dollars>,
|
||||
pub pct10: MetricPattern4<Dollars>,
|
||||
pub pct15: MetricPattern4<Dollars>,
|
||||
pub pct20: MetricPattern4<Dollars>,
|
||||
pub pct25: MetricPattern4<Dollars>,
|
||||
pub pct30: MetricPattern4<Dollars>,
|
||||
pub pct35: MetricPattern4<Dollars>,
|
||||
pub pct40: MetricPattern4<Dollars>,
|
||||
pub pct45: MetricPattern4<Dollars>,
|
||||
pub pct50: MetricPattern4<Dollars>,
|
||||
pub pct55: MetricPattern4<Dollars>,
|
||||
pub pct60: MetricPattern4<Dollars>,
|
||||
pub pct65: MetricPattern4<Dollars>,
|
||||
pub pct70: MetricPattern4<Dollars>,
|
||||
pub pct75: MetricPattern4<Dollars>,
|
||||
pub pct80: MetricPattern4<Dollars>,
|
||||
pub pct85: MetricPattern4<Dollars>,
|
||||
pub pct90: MetricPattern4<Dollars>,
|
||||
pub pct95: MetricPattern4<Dollars>,
|
||||
}
|
||||
|
||||
impl PercentilesPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
pct05: MetricPattern4::new(client.clone(), _m(&acc, "pct05")),
|
||||
pct10: MetricPattern4::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct15: MetricPattern4::new(client.clone(), _m(&acc, "pct15")),
|
||||
pct20: MetricPattern4::new(client.clone(), _m(&acc, "pct20")),
|
||||
pct25: MetricPattern4::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct30: MetricPattern4::new(client.clone(), _m(&acc, "pct30")),
|
||||
pct35: MetricPattern4::new(client.clone(), _m(&acc, "pct35")),
|
||||
pct40: MetricPattern4::new(client.clone(), _m(&acc, "pct40")),
|
||||
pct45: MetricPattern4::new(client.clone(), _m(&acc, "pct45")),
|
||||
pct50: MetricPattern4::new(client.clone(), _m(&acc, "pct50")),
|
||||
pct55: MetricPattern4::new(client.clone(), _m(&acc, "pct55")),
|
||||
pct60: MetricPattern4::new(client.clone(), _m(&acc, "pct60")),
|
||||
pct65: MetricPattern4::new(client.clone(), _m(&acc, "pct65")),
|
||||
pct70: MetricPattern4::new(client.clone(), _m(&acc, "pct70")),
|
||||
pct75: MetricPattern4::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct80: MetricPattern4::new(client.clone(), _m(&acc, "pct80")),
|
||||
pct85: MetricPattern4::new(client.clone(), _m(&acc, "pct85")),
|
||||
pct90: MetricPattern4::new(client.clone(), _m(&acc, "pct90")),
|
||||
pct95: MetricPattern4::new(client.clone(), _m(&acc, "pct95")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct ActivePriceRatioPattern {
|
||||
pub ratio: MetricPattern4<StoredF32>,
|
||||
@@ -1368,6 +1318,56 @@ impl ActivePriceRatioPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct PercentilesPattern {
|
||||
pub pct05: MetricPattern4<Dollars>,
|
||||
pub pct10: MetricPattern4<Dollars>,
|
||||
pub pct15: MetricPattern4<Dollars>,
|
||||
pub pct20: MetricPattern4<Dollars>,
|
||||
pub pct25: MetricPattern4<Dollars>,
|
||||
pub pct30: MetricPattern4<Dollars>,
|
||||
pub pct35: MetricPattern4<Dollars>,
|
||||
pub pct40: MetricPattern4<Dollars>,
|
||||
pub pct45: MetricPattern4<Dollars>,
|
||||
pub pct50: MetricPattern4<Dollars>,
|
||||
pub pct55: MetricPattern4<Dollars>,
|
||||
pub pct60: MetricPattern4<Dollars>,
|
||||
pub pct65: MetricPattern4<Dollars>,
|
||||
pub pct70: MetricPattern4<Dollars>,
|
||||
pub pct75: MetricPattern4<Dollars>,
|
||||
pub pct80: MetricPattern4<Dollars>,
|
||||
pub pct85: MetricPattern4<Dollars>,
|
||||
pub pct90: MetricPattern4<Dollars>,
|
||||
pub pct95: MetricPattern4<Dollars>,
|
||||
}
|
||||
|
||||
impl PercentilesPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
pct05: MetricPattern4::new(client.clone(), _m(&acc, "pct05")),
|
||||
pct10: MetricPattern4::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct15: MetricPattern4::new(client.clone(), _m(&acc, "pct15")),
|
||||
pct20: MetricPattern4::new(client.clone(), _m(&acc, "pct20")),
|
||||
pct25: MetricPattern4::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct30: MetricPattern4::new(client.clone(), _m(&acc, "pct30")),
|
||||
pct35: MetricPattern4::new(client.clone(), _m(&acc, "pct35")),
|
||||
pct40: MetricPattern4::new(client.clone(), _m(&acc, "pct40")),
|
||||
pct45: MetricPattern4::new(client.clone(), _m(&acc, "pct45")),
|
||||
pct50: MetricPattern4::new(client.clone(), _m(&acc, "pct50")),
|
||||
pct55: MetricPattern4::new(client.clone(), _m(&acc, "pct55")),
|
||||
pct60: MetricPattern4::new(client.clone(), _m(&acc, "pct60")),
|
||||
pct65: MetricPattern4::new(client.clone(), _m(&acc, "pct65")),
|
||||
pct70: MetricPattern4::new(client.clone(), _m(&acc, "pct70")),
|
||||
pct75: MetricPattern4::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct80: MetricPattern4::new(client.clone(), _m(&acc, "pct80")),
|
||||
pct85: MetricPattern4::new(client.clone(), _m(&acc, "pct85")),
|
||||
pct90: MetricPattern4::new(client.clone(), _m(&acc, "pct90")),
|
||||
pct95: MetricPattern4::new(client.clone(), _m(&acc, "pct95")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct RelativePattern5 {
|
||||
pub neg_unrealized_loss_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
@@ -1566,6 +1566,42 @@ impl<T: DeserializeOwned> PeriodAveragePricePattern<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct ClassAveragePricePattern<T> {
|
||||
pub _2015: MetricPattern4<T>,
|
||||
pub _2016: MetricPattern4<T>,
|
||||
pub _2017: MetricPattern4<T>,
|
||||
pub _2018: MetricPattern4<T>,
|
||||
pub _2019: MetricPattern4<T>,
|
||||
pub _2020: MetricPattern4<T>,
|
||||
pub _2021: MetricPattern4<T>,
|
||||
pub _2022: MetricPattern4<T>,
|
||||
pub _2023: MetricPattern4<T>,
|
||||
pub _2024: MetricPattern4<T>,
|
||||
pub _2025: MetricPattern4<T>,
|
||||
pub _2026: MetricPattern4<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> ClassAveragePricePattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
_2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_returns")),
|
||||
_2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_returns")),
|
||||
_2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_returns")),
|
||||
_2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_returns")),
|
||||
_2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_returns")),
|
||||
_2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_returns")),
|
||||
_2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_returns")),
|
||||
_2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_returns")),
|
||||
_2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_returns")),
|
||||
_2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_returns")),
|
||||
_2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_returns")),
|
||||
_2026: MetricPattern4::new(client.clone(), _m(&acc, "2026_returns")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BitcoinPattern {
|
||||
pub average: MetricPattern2<Bitcoin>,
|
||||
@@ -1600,40 +1636,6 @@ impl BitcoinPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct ClassAveragePricePattern<T> {
|
||||
pub _2015: MetricPattern4<T>,
|
||||
pub _2016: MetricPattern4<T>,
|
||||
pub _2017: MetricPattern4<T>,
|
||||
pub _2018: MetricPattern4<T>,
|
||||
pub _2019: MetricPattern4<T>,
|
||||
pub _2020: MetricPattern4<T>,
|
||||
pub _2021: MetricPattern4<T>,
|
||||
pub _2022: MetricPattern4<T>,
|
||||
pub _2023: MetricPattern4<T>,
|
||||
pub _2024: MetricPattern4<T>,
|
||||
pub _2025: MetricPattern4<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> ClassAveragePricePattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
_2015: MetricPattern4::new(client.clone(), _m(&acc, "2015_returns")),
|
||||
_2016: MetricPattern4::new(client.clone(), _m(&acc, "2016_returns")),
|
||||
_2017: MetricPattern4::new(client.clone(), _m(&acc, "2017_returns")),
|
||||
_2018: MetricPattern4::new(client.clone(), _m(&acc, "2018_returns")),
|
||||
_2019: MetricPattern4::new(client.clone(), _m(&acc, "2019_returns")),
|
||||
_2020: MetricPattern4::new(client.clone(), _m(&acc, "2020_returns")),
|
||||
_2021: MetricPattern4::new(client.clone(), _m(&acc, "2021_returns")),
|
||||
_2022: MetricPattern4::new(client.clone(), _m(&acc, "2022_returns")),
|
||||
_2023: MetricPattern4::new(client.clone(), _m(&acc, "2023_returns")),
|
||||
_2024: MetricPattern4::new(client.clone(), _m(&acc, "2024_returns")),
|
||||
_2025: MetricPattern4::new(client.clone(), _m(&acc, "2025_returns")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct DollarsPattern<T> {
|
||||
pub average: MetricPattern2<T>,
|
||||
@@ -1937,24 +1939,76 @@ impl _10yTo12yPattern {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _10yPattern {
|
||||
pub struct UnrealizedPattern {
|
||||
pub neg_unrealized_loss: MetricPattern1<Dollars>,
|
||||
pub net_unrealized_pnl: MetricPattern1<Dollars>,
|
||||
pub supply_in_loss: ActiveSupplyPattern,
|
||||
pub supply_in_profit: ActiveSupplyPattern,
|
||||
pub total_unrealized_pnl: MetricPattern1<Dollars>,
|
||||
pub unrealized_loss: MetricPattern1<Dollars>,
|
||||
pub unrealized_profit: MetricPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl UnrealizedPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
neg_unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")),
|
||||
net_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl")),
|
||||
supply_in_loss: ActiveSupplyPattern::new(client.clone(), _m(&acc, "supply_in_loss")),
|
||||
supply_in_profit: ActiveSupplyPattern::new(client.clone(), _m(&acc, "supply_in_profit")),
|
||||
total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_unrealized_pnl")),
|
||||
unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss")),
|
||||
unrealized_profit: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _0satsPattern2 {
|
||||
pub activity: ActivityPattern2,
|
||||
pub cost_basis: CostBasisPattern,
|
||||
pub outputs: OutputsPattern,
|
||||
pub realized: RealizedPattern4,
|
||||
pub relative: RelativePattern,
|
||||
pub realized: RealizedPattern,
|
||||
pub relative: RelativePattern4,
|
||||
pub supply: SupplyPattern2,
|
||||
pub unrealized: UnrealizedPattern,
|
||||
}
|
||||
|
||||
impl _10yPattern {
|
||||
impl _0satsPattern2 {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
activity: ActivityPattern2::new(client.clone(), acc.clone()),
|
||||
cost_basis: CostBasisPattern::new(client.clone(), acc.clone()),
|
||||
outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")),
|
||||
realized: RealizedPattern4::new(client.clone(), acc.clone()),
|
||||
realized: RealizedPattern::new(client.clone(), acc.clone()),
|
||||
relative: RelativePattern4::new(client.clone(), _m(&acc, "supply_in")),
|
||||
supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")),
|
||||
unrealized: UnrealizedPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _100btcPattern {
|
||||
pub activity: ActivityPattern2,
|
||||
pub cost_basis: CostBasisPattern,
|
||||
pub outputs: OutputsPattern,
|
||||
pub realized: RealizedPattern,
|
||||
pub relative: RelativePattern,
|
||||
pub supply: SupplyPattern2,
|
||||
pub unrealized: UnrealizedPattern,
|
||||
}
|
||||
|
||||
impl _100btcPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
activity: ActivityPattern2::new(client.clone(), acc.clone()),
|
||||
cost_basis: CostBasisPattern::new(client.clone(), acc.clone()),
|
||||
outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")),
|
||||
realized: RealizedPattern::new(client.clone(), acc.clone()),
|
||||
relative: RelativePattern::new(client.clone(), acc.clone()),
|
||||
supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")),
|
||||
unrealized: UnrealizedPattern::new(client.clone(), acc.clone()),
|
||||
@@ -1989,76 +2043,24 @@ impl PeriodCagrPattern {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _0satsPattern2 {
|
||||
pub struct _10yPattern {
|
||||
pub activity: ActivityPattern2,
|
||||
pub cost_basis: CostBasisPattern,
|
||||
pub outputs: OutputsPattern,
|
||||
pub realized: RealizedPattern,
|
||||
pub relative: RelativePattern4,
|
||||
pub supply: SupplyPattern2,
|
||||
pub unrealized: UnrealizedPattern,
|
||||
}
|
||||
|
||||
impl _0satsPattern2 {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
activity: ActivityPattern2::new(client.clone(), acc.clone()),
|
||||
cost_basis: CostBasisPattern::new(client.clone(), acc.clone()),
|
||||
outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")),
|
||||
realized: RealizedPattern::new(client.clone(), acc.clone()),
|
||||
relative: RelativePattern4::new(client.clone(), _m(&acc, "supply_in")),
|
||||
supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")),
|
||||
unrealized: UnrealizedPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct UnrealizedPattern {
|
||||
pub neg_unrealized_loss: MetricPattern1<Dollars>,
|
||||
pub net_unrealized_pnl: MetricPattern1<Dollars>,
|
||||
pub supply_in_loss: ActiveSupplyPattern,
|
||||
pub supply_in_profit: ActiveSupplyPattern,
|
||||
pub total_unrealized_pnl: MetricPattern1<Dollars>,
|
||||
pub unrealized_loss: MetricPattern1<Dollars>,
|
||||
pub unrealized_profit: MetricPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl UnrealizedPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
neg_unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss")),
|
||||
net_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl")),
|
||||
supply_in_loss: ActiveSupplyPattern::new(client.clone(), _m(&acc, "supply_in_loss")),
|
||||
supply_in_profit: ActiveSupplyPattern::new(client.clone(), _m(&acc, "supply_in_profit")),
|
||||
total_unrealized_pnl: MetricPattern1::new(client.clone(), _m(&acc, "total_unrealized_pnl")),
|
||||
unrealized_loss: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss")),
|
||||
unrealized_profit: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _100btcPattern {
|
||||
pub activity: ActivityPattern2,
|
||||
pub cost_basis: CostBasisPattern,
|
||||
pub outputs: OutputsPattern,
|
||||
pub realized: RealizedPattern,
|
||||
pub realized: RealizedPattern4,
|
||||
pub relative: RelativePattern,
|
||||
pub supply: SupplyPattern2,
|
||||
pub unrealized: UnrealizedPattern,
|
||||
}
|
||||
|
||||
impl _100btcPattern {
|
||||
impl _10yPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
activity: ActivityPattern2::new(client.clone(), acc.clone()),
|
||||
cost_basis: CostBasisPattern::new(client.clone(), acc.clone()),
|
||||
outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")),
|
||||
realized: RealizedPattern::new(client.clone(), acc.clone()),
|
||||
realized: RealizedPattern4::new(client.clone(), acc.clone()),
|
||||
relative: RelativePattern::new(client.clone(), acc.clone()),
|
||||
supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")),
|
||||
unrealized: UnrealizedPattern::new(client.clone(), acc.clone()),
|
||||
@@ -2108,6 +2110,24 @@ impl<T: DeserializeOwned> SplitPattern2<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct SegwitAdoptionPattern {
|
||||
pub base: MetricPattern11<StoredF32>,
|
||||
pub cumulative: MetricPattern2<StoredF32>,
|
||||
pub sum: MetricPattern2<StoredF32>,
|
||||
}
|
||||
|
||||
impl SegwitAdoptionPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
base: MetricPattern11::new(client.clone(), acc.clone()),
|
||||
cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")),
|
||||
sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct UnclaimedRewardsPattern {
|
||||
pub bitcoin: BitcoinPattern2<Bitcoin>,
|
||||
@@ -2144,24 +2164,6 @@ impl ActiveSupplyPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _2015Pattern {
|
||||
pub bitcoin: MetricPattern4<Bitcoin>,
|
||||
pub dollars: MetricPattern4<Dollars>,
|
||||
pub sats: MetricPattern4<Sats>,
|
||||
}
|
||||
|
||||
impl _2015Pattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
bitcoin: MetricPattern4::new(client.clone(), _m(&acc, "btc")),
|
||||
dollars: MetricPattern4::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: MetricPattern4::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CoinbasePattern2 {
|
||||
pub bitcoin: BlockCountPattern<Bitcoin>,
|
||||
@@ -2180,42 +2182,6 @@ impl CoinbasePattern2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct SegwitAdoptionPattern {
|
||||
pub base: MetricPattern11<StoredF32>,
|
||||
pub cumulative: MetricPattern2<StoredF32>,
|
||||
pub sum: MetricPattern2<StoredF32>,
|
||||
}
|
||||
|
||||
impl SegwitAdoptionPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
base: MetricPattern11::new(client.clone(), acc.clone()),
|
||||
cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")),
|
||||
sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CoinbasePattern {
|
||||
pub bitcoin: BitcoinPattern,
|
||||
pub dollars: DollarsPattern<Dollars>,
|
||||
pub sats: DollarsPattern<Sats>,
|
||||
}
|
||||
|
||||
impl CoinbasePattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
bitcoin: BitcoinPattern::new(client.clone(), _m(&acc, "btc")),
|
||||
dollars: DollarsPattern::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: DollarsPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CostBasisPattern2 {
|
||||
pub max: MetricPattern1<Dollars>,
|
||||
@@ -2234,6 +2200,42 @@ impl CostBasisPattern2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _2015Pattern {
|
||||
pub bitcoin: MetricPattern4<Bitcoin>,
|
||||
pub dollars: MetricPattern4<Dollars>,
|
||||
pub sats: MetricPattern4<Sats>,
|
||||
}
|
||||
|
||||
impl _2015Pattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
bitcoin: MetricPattern4::new(client.clone(), _m(&acc, "btc")),
|
||||
dollars: MetricPattern4::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: MetricPattern4::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CoinbasePattern {
|
||||
pub bitcoin: BitcoinPattern,
|
||||
pub dollars: DollarsPattern<Dollars>,
|
||||
pub sats: DollarsPattern<Sats>,
|
||||
}
|
||||
|
||||
impl CoinbasePattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
bitcoin: BitcoinPattern::new(client.clone(), _m(&acc, "btc")),
|
||||
dollars: DollarsPattern::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: DollarsPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct RelativePattern4 {
|
||||
pub supply_in_loss_rel_to_own_supply: MetricPattern1<StoredF64>,
|
||||
@@ -2250,22 +2252,6 @@ impl RelativePattern4 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CostBasisPattern {
|
||||
pub max: MetricPattern1<Dollars>,
|
||||
pub min: MetricPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl CostBasisPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")),
|
||||
min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _1dReturns1mSdPattern {
|
||||
pub sd: MetricPattern4<StoredF32>,
|
||||
@@ -2282,6 +2268,22 @@ impl _1dReturns1mSdPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CostBasisPattern {
|
||||
pub max: MetricPattern1<Dollars>,
|
||||
pub min: MetricPattern1<Dollars>,
|
||||
}
|
||||
|
||||
impl CostBasisPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
max: MetricPattern1::new(client.clone(), _m(&acc, "max_cost_basis")),
|
||||
min: MetricPattern1::new(client.clone(), _m(&acc, "min_cost_basis")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct SupplyPattern2 {
|
||||
pub halved: ActiveSupplyPattern,
|
||||
@@ -2298,22 +2300,6 @@ impl SupplyPattern2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BitcoinPattern2<T> {
|
||||
pub cumulative: MetricPattern2<T>,
|
||||
pub sum: MetricPattern1<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> BitcoinPattern2<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")),
|
||||
sum: MetricPattern1::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct SatsPattern<T> {
|
||||
pub ohlc: MetricPattern1<T>,
|
||||
@@ -2330,6 +2316,22 @@ impl<T: DeserializeOwned> SatsPattern<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BitcoinPattern2<T> {
|
||||
pub cumulative: MetricPattern2<T>,
|
||||
pub sum: MetricPattern1<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> BitcoinPattern2<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
cumulative: MetricPattern2::new(client.clone(), _m(&acc, "cumulative")),
|
||||
sum: MetricPattern1::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BlockCountPattern<T> {
|
||||
pub cumulative: MetricPattern1<T>,
|
||||
@@ -4238,6 +4240,7 @@ pub struct MetricsTree_Market_Dca_ClassAveragePrice {
|
||||
pub _2023: MetricPattern4<Dollars>,
|
||||
pub _2024: MetricPattern4<Dollars>,
|
||||
pub _2025: MetricPattern4<Dollars>,
|
||||
pub _2026: MetricPattern4<Dollars>,
|
||||
}
|
||||
|
||||
impl MetricsTree_Market_Dca_ClassAveragePrice {
|
||||
@@ -4254,6 +4257,7 @@ impl MetricsTree_Market_Dca_ClassAveragePrice {
|
||||
_2023: MetricPattern4::new(client.clone(), "dca_class_2023_average_price".to_string()),
|
||||
_2024: MetricPattern4::new(client.clone(), "dca_class_2024_average_price".to_string()),
|
||||
_2025: MetricPattern4::new(client.clone(), "dca_class_2025_average_price".to_string()),
|
||||
_2026: MetricPattern4::new(client.clone(), "dca_class_2026_average_price".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4271,6 +4275,7 @@ pub struct MetricsTree_Market_Dca_ClassStack {
|
||||
pub _2023: _2015Pattern,
|
||||
pub _2024: _2015Pattern,
|
||||
pub _2025: _2015Pattern,
|
||||
pub _2026: _2015Pattern,
|
||||
}
|
||||
|
||||
impl MetricsTree_Market_Dca_ClassStack {
|
||||
@@ -4287,6 +4292,7 @@ impl MetricsTree_Market_Dca_ClassStack {
|
||||
_2023: _2015Pattern::new(client.clone(), "dca_class_2023_stack".to_string()),
|
||||
_2024: _2015Pattern::new(client.clone(), "dca_class_2024_stack".to_string()),
|
||||
_2025: _2015Pattern::new(client.clone(), "dca_class_2025_stack".to_string()),
|
||||
_2026: _2015Pattern::new(client.clone(), "dca_class_2026_stack".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5014,7 +5020,11 @@ impl MetricsTree_Price_Cents_Split {
|
||||
|
||||
/// Metrics tree node.
|
||||
pub struct MetricsTree_Price_Oracle {
|
||||
pub close_ohlc_cents: MetricPattern6<OHLCCents>,
|
||||
pub close_ohlc_dollars: MetricPattern6<OHLCDollars>,
|
||||
pub height_to_first_pairoutputindex: MetricPattern11<PairOutputIndex>,
|
||||
pub mid_ohlc_cents: MetricPattern6<OHLCCents>,
|
||||
pub mid_ohlc_dollars: MetricPattern6<OHLCDollars>,
|
||||
pub ohlc_cents: MetricPattern6<OHLCCents>,
|
||||
pub ohlc_dollars: MetricPattern6<OHLCDollars>,
|
||||
pub output0_value: MetricPattern33<Sats>,
|
||||
@@ -5045,7 +5055,11 @@ pub struct MetricsTree_Price_Oracle {
|
||||
impl MetricsTree_Price_Oracle {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
close_ohlc_cents: MetricPattern6::new(client.clone(), "close_ohlc_cents".to_string()),
|
||||
close_ohlc_dollars: MetricPattern6::new(client.clone(), "close_ohlc_dollars".to_string()),
|
||||
height_to_first_pairoutputindex: MetricPattern11::new(client.clone(), "height_to_first_pairoutputindex".to_string()),
|
||||
mid_ohlc_cents: MetricPattern6::new(client.clone(), "mid_ohlc_cents".to_string()),
|
||||
mid_ohlc_dollars: MetricPattern6::new(client.clone(), "mid_ohlc_dollars".to_string()),
|
||||
ohlc_cents: MetricPattern6::new(client.clone(), "oracle_ohlc_cents".to_string()),
|
||||
ohlc_dollars: MetricPattern6::new(client.clone(), "oracle_ohlc".to_string()),
|
||||
output0_value: MetricPattern33::new(client.clone(), "pair_output0_value".to_string()),
|
||||
@@ -5407,6 +5421,7 @@ pub struct MetricsTree_Transactions_Volume {
|
||||
pub annualized_volume: _2015Pattern,
|
||||
pub inputs_per_sec: MetricPattern4<StoredF32>,
|
||||
pub outputs_per_sec: MetricPattern4<StoredF32>,
|
||||
pub received_sum: ActiveSupplyPattern,
|
||||
pub sent_sum: ActiveSupplyPattern,
|
||||
pub tx_per_sec: MetricPattern4<StoredF32>,
|
||||
}
|
||||
@@ -5417,6 +5432,7 @@ impl MetricsTree_Transactions_Volume {
|
||||
annualized_volume: _2015Pattern::new(client.clone(), "annualized_volume".to_string()),
|
||||
inputs_per_sec: MetricPattern4::new(client.clone(), "inputs_per_sec".to_string()),
|
||||
outputs_per_sec: MetricPattern4::new(client.clone(), "outputs_per_sec".to_string()),
|
||||
received_sum: ActiveSupplyPattern::new(client.clone(), "received_sum".to_string()),
|
||||
sent_sum: ActiveSupplyPattern::new(client.clone(), "sent_sum".to_string()),
|
||||
tx_per_sec: MetricPattern4::new(client.clone(), "tx_per_sec".to_string()),
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ where
|
||||
pub dates: LazyDateDerivedFull<T>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
const VERSION: Version = Version::ONE;
|
||||
|
||||
impl<T> TxDerivedFull<T>
|
||||
where
|
||||
@@ -111,7 +111,7 @@ where
|
||||
|
||||
self.dateindex.compute(
|
||||
starting_indexes.dateindex,
|
||||
&self.height.average().0,
|
||||
&self.height.sum().0,
|
||||
&indexes.dateindex.first_height,
|
||||
&indexes.dateindex.height_count,
|
||||
exit,
|
||||
|
||||
@@ -14,6 +14,7 @@ pub const DCA_CLASS_YEARS: ByDcaClass<u16> = ByDcaClass {
|
||||
_2023: 2023,
|
||||
_2024: 2024,
|
||||
_2025: 2025,
|
||||
_2026: 2026,
|
||||
};
|
||||
|
||||
/// DCA class names
|
||||
@@ -29,6 +30,7 @@ pub const DCA_CLASS_NAMES: ByDcaClass<&'static str> = ByDcaClass {
|
||||
_2023: "dca_class_2023",
|
||||
_2024: "dca_class_2024",
|
||||
_2025: "dca_class_2025",
|
||||
_2026: "dca_class_2026",
|
||||
};
|
||||
|
||||
/// Generic wrapper for DCA year class data
|
||||
@@ -45,6 +47,7 @@ pub struct ByDcaClass<T> {
|
||||
pub _2023: T,
|
||||
pub _2024: T,
|
||||
pub _2025: T,
|
||||
pub _2026: T,
|
||||
}
|
||||
|
||||
impl<T> ByDcaClass<T> {
|
||||
@@ -66,6 +69,7 @@ impl<T> ByDcaClass<T> {
|
||||
_2023: create(n._2023, y._2023, Self::dateindex(y._2023)),
|
||||
_2024: create(n._2024, y._2024, Self::dateindex(y._2024)),
|
||||
_2025: create(n._2025, y._2025, Self::dateindex(y._2025)),
|
||||
_2026: create(n._2026, y._2026, Self::dateindex(y._2026)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +91,7 @@ impl<T> ByDcaClass<T> {
|
||||
_2023: create(n._2023, y._2023, Self::dateindex(y._2023))?,
|
||||
_2024: create(n._2024, y._2024, Self::dateindex(y._2024))?,
|
||||
_2025: create(n._2025, y._2025, Self::dateindex(y._2025))?,
|
||||
_2026: create(n._2026, y._2026, Self::dateindex(y._2026))?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -107,6 +112,7 @@ impl<T> ByDcaClass<T> {
|
||||
&self._2023,
|
||||
&self._2024,
|
||||
&self._2025,
|
||||
&self._2026,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
@@ -124,6 +130,7 @@ impl<T> ByDcaClass<T> {
|
||||
&mut self._2023,
|
||||
&mut self._2024,
|
||||
&mut self._2025,
|
||||
&mut self._2026,
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
@@ -142,11 +149,12 @@ impl<T> ByDcaClass<T> {
|
||||
(&mut self._2023, Self::dateindex(y._2023)),
|
||||
(&mut self._2024, Self::dateindex(y._2024)),
|
||||
(&mut self._2025, Self::dateindex(y._2025)),
|
||||
(&mut self._2026, Self::dateindex(y._2026)),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
pub fn dateindexes() -> [DateIndex; 11] {
|
||||
pub fn dateindexes() -> [DateIndex; 12] {
|
||||
let y = DCA_CLASS_YEARS;
|
||||
[
|
||||
Self::dateindex(y._2015),
|
||||
@@ -160,6 +168,7 @@ impl<T> ByDcaClass<T> {
|
||||
Self::dateindex(y._2023),
|
||||
Self::dateindex(y._2024),
|
||||
Self::dateindex(y._2025),
|
||||
Self::dateindex(y._2026),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -176,6 +185,7 @@ impl<T> ByDcaClass<T> {
|
||||
_2023: (self._2023, other._2023),
|
||||
_2024: (self._2024, other._2024),
|
||||
_2025: (self._2025, other._2025),
|
||||
_2026: (self._2026, other._2026),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +202,7 @@ impl<T> ByDcaClass<T> {
|
||||
_2023: (&self._2023, &other._2023),
|
||||
_2024: (&self._2024, &other._2024),
|
||||
_2025: (&self._2025, &other._2025),
|
||||
_2026: (&self._2026, &other._2026),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +219,7 @@ impl<T> ByDcaClass<T> {
|
||||
_2023: f(self._2023),
|
||||
_2024: f(self._2024),
|
||||
_2025: f(self._2025),
|
||||
_2026: f(self._2026),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,9 @@ impl Vecs {
|
||||
// Step 7: Aggregate to daily OHLC
|
||||
self.compute_daily_ohlc(indexes, starting_indexes, exit)?;
|
||||
|
||||
// Step 7b: Compute close-only and mid-price daily OHLC
|
||||
self.compute_close_and_mid_ohlc(indexes, price_cents, starting_indexes, exit)?;
|
||||
|
||||
// Step 8: Compute Phase Oracle V2 (round USD template matching)
|
||||
// 8a: Per-block 200-bin histograms (uses ALL outputs, not pair-filtered)
|
||||
self.compute_phase_v2_histograms(indexer, indexes, starting_indexes, exit)?;
|
||||
@@ -1120,6 +1123,143 @@ impl Vecs {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compute daily OHLC from height close only and mid price ((open+close)/2)
|
||||
fn compute_close_and_mid_ohlc(
|
||||
&mut self,
|
||||
indexes: &indexes::Vecs,
|
||||
price_cents: ¢s::Vecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let last_dateindex = DateIndex::from(indexes.dateindex.date.len());
|
||||
let start_dateindex = starting_indexes
|
||||
.dateindex
|
||||
.min(DateIndex::from(self.close_ohlc_cents.len()))
|
||||
.min(DateIndex::from(self.mid_ohlc_cents.len()));
|
||||
|
||||
if start_dateindex >= last_dateindex {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let last_height = Height::from(price_cents.ohlc.height.len());
|
||||
let mut close_iter = price_cents.split.height.close.iter();
|
||||
let mut open_iter = price_cents.split.height.open.iter();
|
||||
let mut dateindex_to_first_height_iter = indexes.dateindex.first_height.iter();
|
||||
let mut height_count_iter = indexes.dateindex.height_count.iter();
|
||||
|
||||
for dateindex in start_dateindex.to_usize()..last_dateindex.to_usize() {
|
||||
let dateindex = DateIndex::from(dateindex);
|
||||
let first_height = dateindex_to_first_height_iter.get_unwrap(dateindex);
|
||||
let count = height_count_iter.get_unwrap(dateindex);
|
||||
|
||||
if *count == 0 || first_height >= last_height {
|
||||
continue;
|
||||
}
|
||||
|
||||
let count = *count as usize;
|
||||
|
||||
// Close-only OHLC
|
||||
let mut close_open = None;
|
||||
let mut close_high = Cents::from(0i64);
|
||||
let mut close_low = Cents::from(i64::MAX);
|
||||
let mut close_close = Cents::from(0i64);
|
||||
|
||||
// Mid-price OHLC
|
||||
let mut mid_open = None;
|
||||
let mut mid_high = Cents::from(0i64);
|
||||
let mut mid_low = Cents::from(i64::MAX);
|
||||
let mut mid_close = Cents::from(0i64);
|
||||
|
||||
for i in 0..count {
|
||||
let height = first_height + Height::from(i);
|
||||
if height >= last_height {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get close price for this height
|
||||
if let Some(close_price) = close_iter.get(height) {
|
||||
let close_cents = Cents::from(*close_price);
|
||||
|
||||
// Close-only OHLC
|
||||
if close_open.is_none() {
|
||||
close_open = Some(close_cents);
|
||||
}
|
||||
if close_cents > close_high {
|
||||
close_high = close_cents;
|
||||
}
|
||||
if close_cents < close_low {
|
||||
close_low = close_cents;
|
||||
}
|
||||
close_close = close_cents;
|
||||
|
||||
// Mid-price OHLC
|
||||
if let Some(open_price) = open_iter.get(height) {
|
||||
let open_cents = Cents::from(*open_price);
|
||||
let mid_cents =
|
||||
Cents::from((i64::from(open_cents) + i64::from(close_cents)) / 2);
|
||||
|
||||
if mid_open.is_none() {
|
||||
mid_open = Some(mid_cents);
|
||||
}
|
||||
if mid_cents > mid_high {
|
||||
mid_high = mid_cents;
|
||||
}
|
||||
if mid_cents < mid_low {
|
||||
mid_low = mid_cents;
|
||||
}
|
||||
mid_close = mid_cents;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build close-only OHLC
|
||||
let close_ohlc = if let Some(open_price) = close_open {
|
||||
OHLCCents {
|
||||
open: Open::new(open_price),
|
||||
high: High::new(close_high),
|
||||
low: Low::new(close_low),
|
||||
close: Close::new(close_close),
|
||||
}
|
||||
} else if dateindex > DateIndex::from(0usize) {
|
||||
self.close_ohlc_cents
|
||||
.iter()?
|
||||
.get(dateindex.decremented().unwrap())
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
OHLCCents::default()
|
||||
};
|
||||
|
||||
// Build mid-price OHLC
|
||||
let mid_ohlc = if let Some(open_price) = mid_open {
|
||||
OHLCCents {
|
||||
open: Open::new(open_price),
|
||||
high: High::new(mid_high),
|
||||
low: Low::new(mid_low),
|
||||
close: Close::new(mid_close),
|
||||
}
|
||||
} else if dateindex > DateIndex::from(0usize) {
|
||||
self.mid_ohlc_cents
|
||||
.iter()?
|
||||
.get(dateindex.decremented().unwrap())
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
OHLCCents::default()
|
||||
};
|
||||
|
||||
self.close_ohlc_cents.truncate_push(dateindex, close_ohlc)?;
|
||||
self.mid_ohlc_cents.truncate_push(dateindex, mid_ohlc)?;
|
||||
}
|
||||
|
||||
// Write daily data
|
||||
{
|
||||
let _lock = exit.lock();
|
||||
self.close_ohlc_cents.write()?;
|
||||
self.mid_ohlc_cents.write()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compute Phase Oracle V2 - Step 1: Per-block 200-bin phase histograms
|
||||
///
|
||||
/// Uses ALL outputs (like Python test), filtered only by sats range (1k-100k BTC).
|
||||
|
||||
@@ -46,6 +46,24 @@ impl Vecs {
|
||||
|di: DateIndex, iter| iter.get(di).map(|o: OHLCCents| OHLCDollars::from(o)),
|
||||
);
|
||||
|
||||
// Daily OHLC from height close only
|
||||
let close_ohlc_cents = BytesVec::forced_import(db, "close_ohlc_cents", version)?;
|
||||
let close_ohlc_dollars = LazyVecFrom1::init(
|
||||
"close_ohlc_dollars",
|
||||
version,
|
||||
close_ohlc_cents.boxed_clone(),
|
||||
|di: DateIndex, iter| iter.get(di).map(|o: OHLCCents| OHLCDollars::from(o)),
|
||||
);
|
||||
|
||||
// Daily OHLC from height mid price ((open+close)/2)
|
||||
let mid_ohlc_cents = BytesVec::forced_import(db, "mid_ohlc_cents", version)?;
|
||||
let mid_ohlc_dollars = LazyVecFrom1::init(
|
||||
"mid_ohlc_dollars",
|
||||
version,
|
||||
mid_ohlc_cents.boxed_clone(),
|
||||
|di: DateIndex, iter| iter.get(di).map(|o: OHLCCents| OHLCDollars::from(o)),
|
||||
);
|
||||
|
||||
// Phase Oracle V2 (round USD template matching)
|
||||
// v3: Peak prices use 100 bins (downsampled from 200)
|
||||
let phase_v2_version = version + Version::new(3);
|
||||
@@ -111,6 +129,10 @@ impl Vecs {
|
||||
ohlc_cents,
|
||||
ohlc_dollars,
|
||||
tx_count,
|
||||
close_ohlc_cents,
|
||||
close_ohlc_dollars,
|
||||
mid_ohlc_cents,
|
||||
mid_ohlc_dollars,
|
||||
phase_v2_histogram,
|
||||
phase_v2_price_cents,
|
||||
phase_v2_peak_price_cents,
|
||||
|
||||
@@ -56,6 +56,20 @@ pub struct Vecs {
|
||||
/// Number of qualifying transactions per day (for confidence)
|
||||
pub tx_count: PcoVec<DateIndex, StoredU32>,
|
||||
|
||||
// ========== Daily OHLC from height close only ==========
|
||||
/// Daily OHLC computed from height close prices only
|
||||
pub close_ohlc_cents: BytesVec<DateIndex, OHLCCents>,
|
||||
|
||||
/// Daily OHLC from close in dollars (lazy conversion)
|
||||
pub close_ohlc_dollars: LazyVecFrom1<DateIndex, OHLCDollars, DateIndex, OHLCCents>,
|
||||
|
||||
// ========== Daily OHLC from height mid price (open+close)/2 ==========
|
||||
/// Daily OHLC computed from height mid prices ((open+close)/2)
|
||||
pub mid_ohlc_cents: BytesVec<DateIndex, OHLCCents>,
|
||||
|
||||
/// Daily OHLC from mid in dollars (lazy conversion)
|
||||
pub mid_ohlc_dollars: LazyVecFrom1<DateIndex, OHLCDollars, DateIndex, OHLCCents>,
|
||||
|
||||
// ========== Phase Oracle V2 (round USD template matching) ==========
|
||||
/// Per-block 200-bin phase histogram
|
||||
pub phase_v2_histogram: BytesVec<Height, OracleBinsV2>,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,18 @@ impl Vecs {
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.received_sum
|
||||
.compute_all(indexes, starting_indexes, exit, |v| {
|
||||
v.compute_sum_from_indexes(
|
||||
starting_indexes.height,
|
||||
&indexer.vecs.transactions.first_txindex,
|
||||
&indexes.height.txindex_count,
|
||||
&fees_vecs.output_value,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
self.annualized_volume.compute_sats(|v| {
|
||||
v.compute_sum(
|
||||
starting_indexes.dateindex,
|
||||
|
||||
@@ -23,6 +23,13 @@ impl Vecs {
|
||||
indexes,
|
||||
price,
|
||||
)?,
|
||||
received_sum: ValueFromHeightSum::forced_import(
|
||||
db,
|
||||
"received_sum",
|
||||
version,
|
||||
indexes,
|
||||
price,
|
||||
)?,
|
||||
annualized_volume: ValueFromDateLast::forced_import(
|
||||
db,
|
||||
"annualized_volume",
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::internal::{ComputedFromDateLast, ValueFromHeightSum, ValueFromDateLas
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Vecs {
|
||||
pub sent_sum: ValueFromHeightSum,
|
||||
pub received_sum: ValueFromHeightSum,
|
||||
pub annualized_volume: ValueFromDateLast,
|
||||
pub tx_per_sec: ComputedFromDateLast<StoredF32>,
|
||||
pub outputs_per_sec: ComputedFromDateLast<StoredF32>,
|
||||
|
||||
@@ -9,7 +9,7 @@ repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jiff = { workspace = true }
|
||||
owo-colors = "4.2.3"
|
||||
owo-colors = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tracing-log = "0.2"
|
||||
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "env-filter", "std"] }
|
||||
|
||||
@@ -15,6 +15,7 @@ brk_fetcher = { workspace = true }
|
||||
brk_indexer = { workspace = true }
|
||||
brk_logger = { workspace = true }
|
||||
brk_types = { workspace = true }
|
||||
jiff = { workspace = true }
|
||||
memmap2 = "0.9"
|
||||
plotters = "0.3"
|
||||
tracing = { workspace = true }
|
||||
@@ -27,3 +28,15 @@ path = "examples/heatmap.rs"
|
||||
[[example]]
|
||||
name = "oracle"
|
||||
path = "examples/oracle.rs"
|
||||
|
||||
[[example]]
|
||||
name = "plot_oracle"
|
||||
path = "examples/plot_oracle.rs"
|
||||
|
||||
[[example]]
|
||||
name = "tune_smooth"
|
||||
path = "examples/tune_smooth.rs"
|
||||
|
||||
[[example]]
|
||||
name = "debug_oracle"
|
||||
path = "examples/debug_oracle.rs"
|
||||
|
||||
@@ -16,7 +16,7 @@ pub mod signal;
|
||||
|
||||
pub use anchors::{Ohlc, get_anchor_ohlc, get_anchor_range};
|
||||
pub use conditions::{MappedOutputConditions, out_bits, tx_bits};
|
||||
pub use constants::{NUM_BINS, OutputFilter, ROUND_USD_AMOUNTS};
|
||||
pub use constants::{NUM_BINS, OutputFilter, ROUND_USD_AMOUNTS, START_HEIGHT};
|
||||
pub use filters::FILTERS;
|
||||
pub use histogram::load_or_compute_output_conditions;
|
||||
pub use oracle::{
|
||||
|
||||
@@ -13,6 +13,7 @@ axum = { workspace = true }
|
||||
include_dir = "0.7"
|
||||
# importmap = { path = "../../../importmap", features = ["embedded"] }
|
||||
importmap = { version = "0.4.0", features = ["embedded"] }
|
||||
serde = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
sync::OnceLock,
|
||||
};
|
||||
|
||||
use importmap::ImportMap;
|
||||
use include_dir::{Dir, include_dir};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::{Error, Result};
|
||||
@@ -16,8 +18,11 @@ pub static EMBEDDED_WEBSITE: Dir = include_dir!("$CARGO_MANIFEST_DIR/website");
|
||||
/// Cached index.html with importmap injected
|
||||
static INDEX_HTML: OnceLock<String> = OnceLock::new();
|
||||
|
||||
/// Source for serving the website
|
||||
#[derive(Debug, Clone, Default)]
|
||||
/// Website configuration:
|
||||
/// - `true` or omitted: serve embedded website
|
||||
/// - `false`: disable website serving
|
||||
/// - `"/path/to/website"`: serve custom website from path
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Website {
|
||||
Disabled,
|
||||
#[default]
|
||||
@@ -181,3 +186,59 @@ impl Website {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Website {
|
||||
type Err = std::convert::Infallible;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
Ok(match s.to_lowercase().as_str() {
|
||||
"true" | "1" | "yes" | "on" => Self::Default,
|
||||
"false" | "0" | "no" | "off" => Self::Disabled,
|
||||
_ => Self::Filesystem(PathBuf::from(s)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Website {
|
||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
|
||||
match self {
|
||||
Self::Disabled => serializer.serialize_bool(false),
|
||||
Self::Default => serializer.serialize_bool(true),
|
||||
Self::Filesystem(p) => p.serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Website {
|
||||
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
|
||||
use serde::de::{self, Visitor};
|
||||
|
||||
struct WebsiteVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for WebsiteVisitor {
|
||||
type Value = Website;
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
f.write_str("a boolean or a path string")
|
||||
}
|
||||
|
||||
fn visit_bool<E: de::Error>(self, v: bool) -> std::result::Result<Self::Value, E> {
|
||||
Ok(if v {
|
||||
Website::Default
|
||||
} else {
|
||||
Website::Disabled
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, v: &str) -> std::result::Result<Self::Value, E> {
|
||||
Ok(Website::Filesystem(PathBuf::from(v)))
|
||||
}
|
||||
|
||||
fn visit_string<E: de::Error>(self, v: String) -> std::result::Result<Self::Value, E> {
|
||||
Ok(Website::Filesystem(PathBuf::from(v)))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(WebsiteVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
+281
-265
@@ -1647,59 +1647,6 @@ function createPrice111dSmaPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} PercentilesPattern
|
||||
* @property {MetricPattern4<Dollars>} pct05
|
||||
* @property {MetricPattern4<Dollars>} pct10
|
||||
* @property {MetricPattern4<Dollars>} pct15
|
||||
* @property {MetricPattern4<Dollars>} pct20
|
||||
* @property {MetricPattern4<Dollars>} pct25
|
||||
* @property {MetricPattern4<Dollars>} pct30
|
||||
* @property {MetricPattern4<Dollars>} pct35
|
||||
* @property {MetricPattern4<Dollars>} pct40
|
||||
* @property {MetricPattern4<Dollars>} pct45
|
||||
* @property {MetricPattern4<Dollars>} pct50
|
||||
* @property {MetricPattern4<Dollars>} pct55
|
||||
* @property {MetricPattern4<Dollars>} pct60
|
||||
* @property {MetricPattern4<Dollars>} pct65
|
||||
* @property {MetricPattern4<Dollars>} pct70
|
||||
* @property {MetricPattern4<Dollars>} pct75
|
||||
* @property {MetricPattern4<Dollars>} pct80
|
||||
* @property {MetricPattern4<Dollars>} pct85
|
||||
* @property {MetricPattern4<Dollars>} pct90
|
||||
* @property {MetricPattern4<Dollars>} pct95
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a PercentilesPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {PercentilesPattern}
|
||||
*/
|
||||
function createPercentilesPattern(client, acc) {
|
||||
return {
|
||||
pct05: createMetricPattern4(client, _m(acc, 'pct05')),
|
||||
pct10: createMetricPattern4(client, _m(acc, 'pct10')),
|
||||
pct15: createMetricPattern4(client, _m(acc, 'pct15')),
|
||||
pct20: createMetricPattern4(client, _m(acc, 'pct20')),
|
||||
pct25: createMetricPattern4(client, _m(acc, 'pct25')),
|
||||
pct30: createMetricPattern4(client, _m(acc, 'pct30')),
|
||||
pct35: createMetricPattern4(client, _m(acc, 'pct35')),
|
||||
pct40: createMetricPattern4(client, _m(acc, 'pct40')),
|
||||
pct45: createMetricPattern4(client, _m(acc, 'pct45')),
|
||||
pct50: createMetricPattern4(client, _m(acc, 'pct50')),
|
||||
pct55: createMetricPattern4(client, _m(acc, 'pct55')),
|
||||
pct60: createMetricPattern4(client, _m(acc, 'pct60')),
|
||||
pct65: createMetricPattern4(client, _m(acc, 'pct65')),
|
||||
pct70: createMetricPattern4(client, _m(acc, 'pct70')),
|
||||
pct75: createMetricPattern4(client, _m(acc, 'pct75')),
|
||||
pct80: createMetricPattern4(client, _m(acc, 'pct80')),
|
||||
pct85: createMetricPattern4(client, _m(acc, 'pct85')),
|
||||
pct90: createMetricPattern4(client, _m(acc, 'pct90')),
|
||||
pct95: createMetricPattern4(client, _m(acc, 'pct95')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ActivePriceRatioPattern
|
||||
* @property {MetricPattern4<StoredF32>} ratio
|
||||
@@ -1753,6 +1700,59 @@ function createActivePriceRatioPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} PercentilesPattern
|
||||
* @property {MetricPattern4<Dollars>} pct05
|
||||
* @property {MetricPattern4<Dollars>} pct10
|
||||
* @property {MetricPattern4<Dollars>} pct15
|
||||
* @property {MetricPattern4<Dollars>} pct20
|
||||
* @property {MetricPattern4<Dollars>} pct25
|
||||
* @property {MetricPattern4<Dollars>} pct30
|
||||
* @property {MetricPattern4<Dollars>} pct35
|
||||
* @property {MetricPattern4<Dollars>} pct40
|
||||
* @property {MetricPattern4<Dollars>} pct45
|
||||
* @property {MetricPattern4<Dollars>} pct50
|
||||
* @property {MetricPattern4<Dollars>} pct55
|
||||
* @property {MetricPattern4<Dollars>} pct60
|
||||
* @property {MetricPattern4<Dollars>} pct65
|
||||
* @property {MetricPattern4<Dollars>} pct70
|
||||
* @property {MetricPattern4<Dollars>} pct75
|
||||
* @property {MetricPattern4<Dollars>} pct80
|
||||
* @property {MetricPattern4<Dollars>} pct85
|
||||
* @property {MetricPattern4<Dollars>} pct90
|
||||
* @property {MetricPattern4<Dollars>} pct95
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a PercentilesPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {PercentilesPattern}
|
||||
*/
|
||||
function createPercentilesPattern(client, acc) {
|
||||
return {
|
||||
pct05: createMetricPattern4(client, _m(acc, 'pct05')),
|
||||
pct10: createMetricPattern4(client, _m(acc, 'pct10')),
|
||||
pct15: createMetricPattern4(client, _m(acc, 'pct15')),
|
||||
pct20: createMetricPattern4(client, _m(acc, 'pct20')),
|
||||
pct25: createMetricPattern4(client, _m(acc, 'pct25')),
|
||||
pct30: createMetricPattern4(client, _m(acc, 'pct30')),
|
||||
pct35: createMetricPattern4(client, _m(acc, 'pct35')),
|
||||
pct40: createMetricPattern4(client, _m(acc, 'pct40')),
|
||||
pct45: createMetricPattern4(client, _m(acc, 'pct45')),
|
||||
pct50: createMetricPattern4(client, _m(acc, 'pct50')),
|
||||
pct55: createMetricPattern4(client, _m(acc, 'pct55')),
|
||||
pct60: createMetricPattern4(client, _m(acc, 'pct60')),
|
||||
pct65: createMetricPattern4(client, _m(acc, 'pct65')),
|
||||
pct70: createMetricPattern4(client, _m(acc, 'pct70')),
|
||||
pct75: createMetricPattern4(client, _m(acc, 'pct75')),
|
||||
pct80: createMetricPattern4(client, _m(acc, 'pct80')),
|
||||
pct85: createMetricPattern4(client, _m(acc, 'pct85')),
|
||||
pct90: createMetricPattern4(client, _m(acc, 'pct90')),
|
||||
pct95: createMetricPattern4(client, _m(acc, 'pct95')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} RelativePattern5
|
||||
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToMarketCap
|
||||
@@ -1970,6 +1970,47 @@ function createPeriodAveragePricePattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} ClassAveragePricePattern
|
||||
* @property {MetricPattern4<T>} _2015
|
||||
* @property {MetricPattern4<T>} _2016
|
||||
* @property {MetricPattern4<T>} _2017
|
||||
* @property {MetricPattern4<T>} _2018
|
||||
* @property {MetricPattern4<T>} _2019
|
||||
* @property {MetricPattern4<T>} _2020
|
||||
* @property {MetricPattern4<T>} _2021
|
||||
* @property {MetricPattern4<T>} _2022
|
||||
* @property {MetricPattern4<T>} _2023
|
||||
* @property {MetricPattern4<T>} _2024
|
||||
* @property {MetricPattern4<T>} _2025
|
||||
* @property {MetricPattern4<T>} _2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a ClassAveragePricePattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {ClassAveragePricePattern<T>}
|
||||
*/
|
||||
function createClassAveragePricePattern(client, acc) {
|
||||
return {
|
||||
_2015: createMetricPattern4(client, _m(acc, '2015_returns')),
|
||||
_2016: createMetricPattern4(client, _m(acc, '2016_returns')),
|
||||
_2017: createMetricPattern4(client, _m(acc, '2017_returns')),
|
||||
_2018: createMetricPattern4(client, _m(acc, '2018_returns')),
|
||||
_2019: createMetricPattern4(client, _m(acc, '2019_returns')),
|
||||
_2020: createMetricPattern4(client, _m(acc, '2020_returns')),
|
||||
_2021: createMetricPattern4(client, _m(acc, '2021_returns')),
|
||||
_2022: createMetricPattern4(client, _m(acc, '2022_returns')),
|
||||
_2023: createMetricPattern4(client, _m(acc, '2023_returns')),
|
||||
_2024: createMetricPattern4(client, _m(acc, '2024_returns')),
|
||||
_2025: createMetricPattern4(client, _m(acc, '2025_returns')),
|
||||
_2026: createMetricPattern4(client, _m(acc, '2026_returns')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BitcoinPattern
|
||||
* @property {MetricPattern2<Bitcoin>} average
|
||||
@@ -2007,45 +2048,6 @@ function createBitcoinPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} ClassAveragePricePattern
|
||||
* @property {MetricPattern4<T>} _2015
|
||||
* @property {MetricPattern4<T>} _2016
|
||||
* @property {MetricPattern4<T>} _2017
|
||||
* @property {MetricPattern4<T>} _2018
|
||||
* @property {MetricPattern4<T>} _2019
|
||||
* @property {MetricPattern4<T>} _2020
|
||||
* @property {MetricPattern4<T>} _2021
|
||||
* @property {MetricPattern4<T>} _2022
|
||||
* @property {MetricPattern4<T>} _2023
|
||||
* @property {MetricPattern4<T>} _2024
|
||||
* @property {MetricPattern4<T>} _2025
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a ClassAveragePricePattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {ClassAveragePricePattern<T>}
|
||||
*/
|
||||
function createClassAveragePricePattern(client, acc) {
|
||||
return {
|
||||
_2015: createMetricPattern4(client, _m(acc, '2015_returns')),
|
||||
_2016: createMetricPattern4(client, _m(acc, '2016_returns')),
|
||||
_2017: createMetricPattern4(client, _m(acc, '2017_returns')),
|
||||
_2018: createMetricPattern4(client, _m(acc, '2018_returns')),
|
||||
_2019: createMetricPattern4(client, _m(acc, '2019_returns')),
|
||||
_2020: createMetricPattern4(client, _m(acc, '2020_returns')),
|
||||
_2021: createMetricPattern4(client, _m(acc, '2021_returns')),
|
||||
_2022: createMetricPattern4(client, _m(acc, '2022_returns')),
|
||||
_2023: createMetricPattern4(client, _m(acc, '2023_returns')),
|
||||
_2024: createMetricPattern4(client, _m(acc, '2024_returns')),
|
||||
_2025: createMetricPattern4(client, _m(acc, '2025_returns')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} DollarsPattern
|
||||
@@ -2389,28 +2391,86 @@ function create_10yTo12yPattern(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _10yPattern
|
||||
* @typedef {Object} UnrealizedPattern
|
||||
* @property {MetricPattern1<Dollars>} negUnrealizedLoss
|
||||
* @property {MetricPattern1<Dollars>} netUnrealizedPnl
|
||||
* @property {ActiveSupplyPattern} supplyInLoss
|
||||
* @property {ActiveSupplyPattern} supplyInProfit
|
||||
* @property {MetricPattern1<Dollars>} totalUnrealizedPnl
|
||||
* @property {MetricPattern1<Dollars>} unrealizedLoss
|
||||
* @property {MetricPattern1<Dollars>} unrealizedProfit
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a UnrealizedPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {UnrealizedPattern}
|
||||
*/
|
||||
function createUnrealizedPattern(client, acc) {
|
||||
return {
|
||||
negUnrealizedLoss: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss')),
|
||||
netUnrealizedPnl: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl')),
|
||||
supplyInLoss: createActiveSupplyPattern(client, _m(acc, 'supply_in_loss')),
|
||||
supplyInProfit: createActiveSupplyPattern(client, _m(acc, 'supply_in_profit')),
|
||||
totalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'total_unrealized_pnl')),
|
||||
unrealizedLoss: createMetricPattern1(client, _m(acc, 'unrealized_loss')),
|
||||
unrealizedProfit: createMetricPattern1(client, _m(acc, 'unrealized_profit')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _0satsPattern2
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern4} realized
|
||||
* @property {RealizedPattern} realized
|
||||
* @property {RelativePattern4} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _0satsPattern2 pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_0satsPattern2}
|
||||
*/
|
||||
function create_0satsPattern2(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, 'utxo_count')),
|
||||
realized: createRealizedPattern(client, acc),
|
||||
relative: createRelativePattern4(client, _m(acc, 'supply_in')),
|
||||
supply: createSupplyPattern2(client, _m(acc, 'supply')),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _100btcPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern} realized
|
||||
* @property {RelativePattern} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _10yPattern pattern node
|
||||
* Create a _100btcPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_10yPattern}
|
||||
* @returns {_100btcPattern}
|
||||
*/
|
||||
function create_10yPattern(client, acc) {
|
||||
function create_100btcPattern(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, 'utxo_count')),
|
||||
realized: createRealizedPattern4(client, acc),
|
||||
realized: createRealizedPattern(client, acc),
|
||||
relative: createRelativePattern(client, acc),
|
||||
supply: createSupplyPattern2(client, _m(acc, 'supply')),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
@@ -2447,86 +2507,28 @@ function createPeriodCagrPattern(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _0satsPattern2
|
||||
* @typedef {Object} _10yPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern} realized
|
||||
* @property {RelativePattern4} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _0satsPattern2 pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_0satsPattern2}
|
||||
*/
|
||||
function create_0satsPattern2(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, 'utxo_count')),
|
||||
realized: createRealizedPattern(client, acc),
|
||||
relative: createRelativePattern4(client, _m(acc, 'supply_in')),
|
||||
supply: createSupplyPattern2(client, _m(acc, 'supply')),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} UnrealizedPattern
|
||||
* @property {MetricPattern1<Dollars>} negUnrealizedLoss
|
||||
* @property {MetricPattern1<Dollars>} netUnrealizedPnl
|
||||
* @property {ActiveSupplyPattern} supplyInLoss
|
||||
* @property {ActiveSupplyPattern} supplyInProfit
|
||||
* @property {MetricPattern1<Dollars>} totalUnrealizedPnl
|
||||
* @property {MetricPattern1<Dollars>} unrealizedLoss
|
||||
* @property {MetricPattern1<Dollars>} unrealizedProfit
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a UnrealizedPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {UnrealizedPattern}
|
||||
*/
|
||||
function createUnrealizedPattern(client, acc) {
|
||||
return {
|
||||
negUnrealizedLoss: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss')),
|
||||
netUnrealizedPnl: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl')),
|
||||
supplyInLoss: createActiveSupplyPattern(client, _m(acc, 'supply_in_loss')),
|
||||
supplyInProfit: createActiveSupplyPattern(client, _m(acc, 'supply_in_profit')),
|
||||
totalUnrealizedPnl: createMetricPattern1(client, _m(acc, 'total_unrealized_pnl')),
|
||||
unrealizedLoss: createMetricPattern1(client, _m(acc, 'unrealized_loss')),
|
||||
unrealizedProfit: createMetricPattern1(client, _m(acc, 'unrealized_profit')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _100btcPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern} realized
|
||||
* @property {RealizedPattern4} realized
|
||||
* @property {RelativePattern} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _100btcPattern pattern node
|
||||
* Create a _10yPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_100btcPattern}
|
||||
* @returns {_10yPattern}
|
||||
*/
|
||||
function create_100btcPattern(client, acc) {
|
||||
function create_10yPattern(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, 'utxo_count')),
|
||||
realized: createRealizedPattern(client, acc),
|
||||
realized: createRealizedPattern4(client, acc),
|
||||
relative: createRelativePattern(client, acc),
|
||||
supply: createSupplyPattern2(client, _m(acc, 'supply')),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
@@ -2583,6 +2585,27 @@ function createSplitPattern2(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SegwitAdoptionPattern
|
||||
* @property {MetricPattern11<StoredF32>} base
|
||||
* @property {MetricPattern2<StoredF32>} cumulative
|
||||
* @property {MetricPattern2<StoredF32>} sum
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a SegwitAdoptionPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {SegwitAdoptionPattern}
|
||||
*/
|
||||
function createSegwitAdoptionPattern(client, acc) {
|
||||
return {
|
||||
base: createMetricPattern11(client, acc),
|
||||
cumulative: createMetricPattern2(client, _m(acc, 'cumulative')),
|
||||
sum: createMetricPattern2(client, _m(acc, 'sum')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} UnclaimedRewardsPattern
|
||||
* @property {BitcoinPattern2<Bitcoin>} bitcoin
|
||||
@@ -2625,27 +2648,6 @@ function createActiveSupplyPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _2015Pattern
|
||||
* @property {MetricPattern4<Bitcoin>} bitcoin
|
||||
* @property {MetricPattern4<Dollars>} dollars
|
||||
* @property {MetricPattern4<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _2015Pattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_2015Pattern}
|
||||
*/
|
||||
function create_2015Pattern(client, acc) {
|
||||
return {
|
||||
bitcoin: createMetricPattern4(client, _m(acc, 'btc')),
|
||||
dollars: createMetricPattern4(client, _m(acc, 'usd')),
|
||||
sats: createMetricPattern4(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CoinbasePattern2
|
||||
* @property {BlockCountPattern<Bitcoin>} bitcoin
|
||||
@@ -2667,48 +2669,6 @@ function createCoinbasePattern2(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SegwitAdoptionPattern
|
||||
* @property {MetricPattern11<StoredF32>} base
|
||||
* @property {MetricPattern2<StoredF32>} cumulative
|
||||
* @property {MetricPattern2<StoredF32>} sum
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a SegwitAdoptionPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {SegwitAdoptionPattern}
|
||||
*/
|
||||
function createSegwitAdoptionPattern(client, acc) {
|
||||
return {
|
||||
base: createMetricPattern11(client, acc),
|
||||
cumulative: createMetricPattern2(client, _m(acc, 'cumulative')),
|
||||
sum: createMetricPattern2(client, _m(acc, 'sum')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CoinbasePattern
|
||||
* @property {BitcoinPattern} bitcoin
|
||||
* @property {DollarsPattern<Dollars>} dollars
|
||||
* @property {DollarsPattern<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CoinbasePattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CoinbasePattern}
|
||||
*/
|
||||
function createCoinbasePattern(client, acc) {
|
||||
return {
|
||||
bitcoin: createBitcoinPattern(client, _m(acc, 'btc')),
|
||||
dollars: createDollarsPattern(client, _m(acc, 'usd')),
|
||||
sats: createDollarsPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CostBasisPattern2
|
||||
* @property {MetricPattern1<Dollars>} max
|
||||
@@ -2730,6 +2690,48 @@ function createCostBasisPattern2(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _2015Pattern
|
||||
* @property {MetricPattern4<Bitcoin>} bitcoin
|
||||
* @property {MetricPattern4<Dollars>} dollars
|
||||
* @property {MetricPattern4<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _2015Pattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_2015Pattern}
|
||||
*/
|
||||
function create_2015Pattern(client, acc) {
|
||||
return {
|
||||
bitcoin: createMetricPattern4(client, _m(acc, 'btc')),
|
||||
dollars: createMetricPattern4(client, _m(acc, 'usd')),
|
||||
sats: createMetricPattern4(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CoinbasePattern
|
||||
* @property {BitcoinPattern} bitcoin
|
||||
* @property {DollarsPattern<Dollars>} dollars
|
||||
* @property {DollarsPattern<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CoinbasePattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CoinbasePattern}
|
||||
*/
|
||||
function createCoinbasePattern(client, acc) {
|
||||
return {
|
||||
bitcoin: createBitcoinPattern(client, _m(acc, 'btc')),
|
||||
dollars: createDollarsPattern(client, _m(acc, 'usd')),
|
||||
sats: createDollarsPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} RelativePattern4
|
||||
* @property {MetricPattern1<StoredF64>} supplyInLossRelToOwnSupply
|
||||
@@ -2749,25 +2751,6 @@ function createRelativePattern4(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CostBasisPattern
|
||||
* @property {MetricPattern1<Dollars>} max
|
||||
* @property {MetricPattern1<Dollars>} min
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CostBasisPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CostBasisPattern}
|
||||
*/
|
||||
function createCostBasisPattern(client, acc) {
|
||||
return {
|
||||
max: createMetricPattern1(client, _m(acc, 'max_cost_basis')),
|
||||
min: createMetricPattern1(client, _m(acc, 'min_cost_basis')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _1dReturns1mSdPattern
|
||||
* @property {MetricPattern4<StoredF32>} sd
|
||||
@@ -2787,6 +2770,25 @@ function create_1dReturns1mSdPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CostBasisPattern
|
||||
* @property {MetricPattern1<Dollars>} max
|
||||
* @property {MetricPattern1<Dollars>} min
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CostBasisPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CostBasisPattern}
|
||||
*/
|
||||
function createCostBasisPattern(client, acc) {
|
||||
return {
|
||||
max: createMetricPattern1(client, _m(acc, 'max_cost_basis')),
|
||||
min: createMetricPattern1(client, _m(acc, 'min_cost_basis')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SupplyPattern2
|
||||
* @property {ActiveSupplyPattern} halved
|
||||
@@ -2806,27 +2808,6 @@ function createSupplyPattern2(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} BitcoinPattern2
|
||||
* @property {MetricPattern2<T>} cumulative
|
||||
* @property {MetricPattern1<T>} sum
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a BitcoinPattern2 pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {BitcoinPattern2<T>}
|
||||
*/
|
||||
function createBitcoinPattern2(client, acc) {
|
||||
return {
|
||||
cumulative: createMetricPattern2(client, _m(acc, 'cumulative')),
|
||||
sum: createMetricPattern1(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} SatsPattern
|
||||
@@ -2848,6 +2829,27 @@ function createSatsPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} BitcoinPattern2
|
||||
* @property {MetricPattern2<T>} cumulative
|
||||
* @property {MetricPattern1<T>} sum
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a BitcoinPattern2 pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {BitcoinPattern2<T>}
|
||||
*/
|
||||
function createBitcoinPattern2(client, acc) {
|
||||
return {
|
||||
cumulative: createMetricPattern2(client, _m(acc, 'cumulative')),
|
||||
sum: createMetricPattern1(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} BlockCountPattern
|
||||
@@ -3730,6 +3732,7 @@ function createRealizedPriceExtraPattern(client, acc) {
|
||||
* @property {MetricPattern4<Dollars>} _2023
|
||||
* @property {MetricPattern4<Dollars>} _2024
|
||||
* @property {MetricPattern4<Dollars>} _2025
|
||||
* @property {MetricPattern4<Dollars>} _2026
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -3745,6 +3748,7 @@ function createRealizedPriceExtraPattern(client, acc) {
|
||||
* @property {_2015Pattern} _2023
|
||||
* @property {_2015Pattern} _2024
|
||||
* @property {_2015Pattern} _2025
|
||||
* @property {_2015Pattern} _2026
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -4087,7 +4091,11 @@ function createRealizedPriceExtraPattern(client, acc) {
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Price_Oracle
|
||||
* @property {MetricPattern6<OHLCCents>} closeOhlcCents
|
||||
* @property {MetricPattern6<OHLCDollars>} closeOhlcDollars
|
||||
* @property {MetricPattern11<PairOutputIndex>} heightToFirstPairoutputindex
|
||||
* @property {MetricPattern6<OHLCCents>} midOhlcCents
|
||||
* @property {MetricPattern6<OHLCDollars>} midOhlcDollars
|
||||
* @property {MetricPattern6<OHLCCents>} ohlcCents
|
||||
* @property {MetricPattern6<OHLCDollars>} ohlcDollars
|
||||
* @property {MetricPattern33<Sats>} output0Value
|
||||
@@ -4261,6 +4269,7 @@ function createRealizedPriceExtraPattern(client, acc) {
|
||||
* @property {_2015Pattern} annualizedVolume
|
||||
* @property {MetricPattern4<StoredF32>} inputsPerSec
|
||||
* @property {MetricPattern4<StoredF32>} outputsPerSec
|
||||
* @property {ActiveSupplyPattern} receivedSum
|
||||
* @property {ActiveSupplyPattern} sentSum
|
||||
* @property {MetricPattern4<StoredF32>} txPerSec
|
||||
*/
|
||||
@@ -5755,6 +5764,7 @@ class BrkClient extends BrkClientBase {
|
||||
_2023: createMetricPattern4(this, 'dca_class_2023_average_price'),
|
||||
_2024: createMetricPattern4(this, 'dca_class_2024_average_price'),
|
||||
_2025: createMetricPattern4(this, 'dca_class_2025_average_price'),
|
||||
_2026: createMetricPattern4(this, 'dca_class_2026_average_price'),
|
||||
},
|
||||
classReturns: createClassAveragePricePattern(this, 'dca_class'),
|
||||
classStack: {
|
||||
@@ -5769,6 +5779,7 @@ class BrkClient extends BrkClientBase {
|
||||
_2023: create_2015Pattern(this, 'dca_class_2023_stack'),
|
||||
_2024: create_2015Pattern(this, 'dca_class_2024_stack'),
|
||||
_2025: create_2015Pattern(this, 'dca_class_2025_stack'),
|
||||
_2026: create_2015Pattern(this, 'dca_class_2026_stack'),
|
||||
},
|
||||
periodAveragePrice: createPeriodAveragePricePattern(this, 'dca_average_price'),
|
||||
periodCagr: createPeriodCagrPattern(this, 'dca_cagr'),
|
||||
@@ -6077,7 +6088,11 @@ class BrkClient extends BrkClientBase {
|
||||
},
|
||||
},
|
||||
oracle: {
|
||||
closeOhlcCents: createMetricPattern6(this, 'close_ohlc_cents'),
|
||||
closeOhlcDollars: createMetricPattern6(this, 'close_ohlc_dollars'),
|
||||
heightToFirstPairoutputindex: createMetricPattern11(this, 'height_to_first_pairoutputindex'),
|
||||
midOhlcCents: createMetricPattern6(this, 'mid_ohlc_cents'),
|
||||
midOhlcDollars: createMetricPattern6(this, 'mid_ohlc_dollars'),
|
||||
ohlcCents: createMetricPattern6(this, 'oracle_ohlc_cents'),
|
||||
ohlcDollars: createMetricPattern6(this, 'oracle_ohlc'),
|
||||
output0Value: createMetricPattern33(this, 'pair_output0_value'),
|
||||
@@ -6208,6 +6223,7 @@ class BrkClient extends BrkClientBase {
|
||||
annualizedVolume: create_2015Pattern(this, 'annualized_volume'),
|
||||
inputsPerSec: createMetricPattern4(this, 'inputs_per_sec'),
|
||||
outputsPerSec: createMetricPattern4(this, 'outputs_per_sec'),
|
||||
receivedSum: createActiveSupplyPattern(this, 'received_sum'),
|
||||
sentSum: createActiveSupplyPattern(this, 'sent_sum'),
|
||||
txPerSec: createMetricPattern4(this, 'tx_per_sec'),
|
||||
},
|
||||
|
||||
@@ -1885,31 +1885,6 @@ class Price111dSmaPattern:
|
||||
self.ratio_pct99_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'ratio_pct99_usd'))
|
||||
self.ratio_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, 'ratio'))
|
||||
|
||||
class PercentilesPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.pct05: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct05'))
|
||||
self.pct10: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct10'))
|
||||
self.pct15: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct15'))
|
||||
self.pct20: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct20'))
|
||||
self.pct25: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct25'))
|
||||
self.pct30: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct30'))
|
||||
self.pct35: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct35'))
|
||||
self.pct40: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct40'))
|
||||
self.pct45: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct45'))
|
||||
self.pct50: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct50'))
|
||||
self.pct55: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct55'))
|
||||
self.pct60: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct60'))
|
||||
self.pct65: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct65'))
|
||||
self.pct70: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct70'))
|
||||
self.pct75: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct75'))
|
||||
self.pct80: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct80'))
|
||||
self.pct85: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct85'))
|
||||
self.pct90: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct90'))
|
||||
self.pct95: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct95'))
|
||||
|
||||
class ActivePriceRatioPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -1935,6 +1910,31 @@ class ActivePriceRatioPattern:
|
||||
self.ratio_pct99_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct99_usd'))
|
||||
self.ratio_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, acc)
|
||||
|
||||
class PercentilesPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.pct05: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct05'))
|
||||
self.pct10: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct10'))
|
||||
self.pct15: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct15'))
|
||||
self.pct20: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct20'))
|
||||
self.pct25: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct25'))
|
||||
self.pct30: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct30'))
|
||||
self.pct35: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct35'))
|
||||
self.pct40: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct40'))
|
||||
self.pct45: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct45'))
|
||||
self.pct50: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct50'))
|
||||
self.pct55: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct55'))
|
||||
self.pct60: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct60'))
|
||||
self.pct65: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct65'))
|
||||
self.pct70: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct70'))
|
||||
self.pct75: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct75'))
|
||||
self.pct80: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct80'))
|
||||
self.pct85: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct85'))
|
||||
self.pct90: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct90'))
|
||||
self.pct95: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct95'))
|
||||
|
||||
class RelativePattern5:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2034,23 +2034,6 @@ class PeriodAveragePricePattern(Generic[T]):
|
||||
self._6y: MetricPattern4[T] = MetricPattern4(client, _p('6y', acc))
|
||||
self._8y: MetricPattern4[T] = MetricPattern4(client, _p('8y', acc))
|
||||
|
||||
class BitcoinPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.average: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'average'))
|
||||
self.base: MetricPattern11[Bitcoin] = MetricPattern11(client, acc)
|
||||
self.cumulative: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'cumulative'))
|
||||
self.max: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'max'))
|
||||
self.median: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'median'))
|
||||
self.min: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'min'))
|
||||
self.pct10: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'pct10'))
|
||||
self.pct25: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'pct25'))
|
||||
self.pct75: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'pct75'))
|
||||
self.pct90: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'pct90'))
|
||||
self.sum: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'sum'))
|
||||
|
||||
class ClassAveragePricePattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2067,6 +2050,24 @@ class ClassAveragePricePattern(Generic[T]):
|
||||
self._2023: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2023_returns'))
|
||||
self._2024: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2024_returns'))
|
||||
self._2025: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2025_returns'))
|
||||
self._2026: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2026_returns'))
|
||||
|
||||
class BitcoinPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.average: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'average'))
|
||||
self.base: MetricPattern11[Bitcoin] = MetricPattern11(client, acc)
|
||||
self.cumulative: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'cumulative'))
|
||||
self.max: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'max'))
|
||||
self.median: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'median'))
|
||||
self.min: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'min'))
|
||||
self.pct10: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'pct10'))
|
||||
self.pct25: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'pct25'))
|
||||
self.pct75: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'pct75'))
|
||||
self.pct90: MetricPattern6[Bitcoin] = MetricPattern6(client, _m(acc, 'pct90'))
|
||||
self.sum: MetricPattern2[Bitcoin] = MetricPattern2(client, _m(acc, 'sum'))
|
||||
|
||||
class DollarsPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -2219,7 +2220,20 @@ class _10yTo12yPattern:
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
|
||||
class _10yPattern:
|
||||
class UnrealizedPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.neg_unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss'))
|
||||
self.net_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl'))
|
||||
self.supply_in_loss: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'supply_in_loss'))
|
||||
self.supply_in_profit: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'supply_in_profit'))
|
||||
self.total_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_unrealized_pnl'))
|
||||
self.unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_loss'))
|
||||
self.unrealized_profit: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_profit'))
|
||||
|
||||
class _0satsPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
@@ -2227,7 +2241,20 @@ class _10yPattern:
|
||||
self.activity: ActivityPattern2 = ActivityPattern2(client, acc)
|
||||
self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc)
|
||||
self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count'))
|
||||
self.realized: RealizedPattern4 = RealizedPattern4(client, acc)
|
||||
self.realized: RealizedPattern = RealizedPattern(client, acc)
|
||||
self.relative: RelativePattern4 = RelativePattern4(client, _m(acc, 'supply_in'))
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
|
||||
class _100btcPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.activity: ActivityPattern2 = ActivityPattern2(client, acc)
|
||||
self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc)
|
||||
self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count'))
|
||||
self.realized: RealizedPattern = RealizedPattern(client, acc)
|
||||
self.relative: RelativePattern = RelativePattern(client, acc)
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
@@ -2245,7 +2272,7 @@ class PeriodCagrPattern:
|
||||
self._6y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('6y', acc))
|
||||
self._8y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('8y', acc))
|
||||
|
||||
class _0satsPattern2:
|
||||
class _10yPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
@@ -2253,33 +2280,7 @@ class _0satsPattern2:
|
||||
self.activity: ActivityPattern2 = ActivityPattern2(client, acc)
|
||||
self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc)
|
||||
self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count'))
|
||||
self.realized: RealizedPattern = RealizedPattern(client, acc)
|
||||
self.relative: RelativePattern4 = RelativePattern4(client, _m(acc, 'supply_in'))
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
|
||||
class UnrealizedPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.neg_unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss'))
|
||||
self.net_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl'))
|
||||
self.supply_in_loss: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'supply_in_loss'))
|
||||
self.supply_in_profit: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'supply_in_profit'))
|
||||
self.total_unrealized_pnl: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'total_unrealized_pnl'))
|
||||
self.unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_loss'))
|
||||
self.unrealized_profit: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_profit'))
|
||||
|
||||
class _100btcPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.activity: ActivityPattern2 = ActivityPattern2(client, acc)
|
||||
self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc)
|
||||
self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count'))
|
||||
self.realized: RealizedPattern = RealizedPattern(client, acc)
|
||||
self.realized: RealizedPattern4 = RealizedPattern4(client, acc)
|
||||
self.relative: RelativePattern = RelativePattern(client, acc)
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
@@ -2305,6 +2306,15 @@ class SplitPattern2(Generic[T]):
|
||||
self.low: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'low'))
|
||||
self.open: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'open'))
|
||||
|
||||
class SegwitAdoptionPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.base: MetricPattern11[StoredF32] = MetricPattern11(client, acc)
|
||||
self.cumulative: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'cumulative'))
|
||||
self.sum: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'sum'))
|
||||
|
||||
class UnclaimedRewardsPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2323,15 +2333,6 @@ class ActiveSupplyPattern:
|
||||
self.dollars: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'usd'))
|
||||
self.sats: MetricPattern1[Sats] = MetricPattern1(client, acc)
|
||||
|
||||
class _2015Pattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.bitcoin: MetricPattern4[Bitcoin] = MetricPattern4(client, _m(acc, 'btc'))
|
||||
self.dollars: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'usd'))
|
||||
self.sats: MetricPattern4[Sats] = MetricPattern4(client, acc)
|
||||
|
||||
class CoinbasePattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2341,24 +2342,6 @@ class CoinbasePattern2:
|
||||
self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd'))
|
||||
self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc)
|
||||
|
||||
class SegwitAdoptionPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.base: MetricPattern11[StoredF32] = MetricPattern11(client, acc)
|
||||
self.cumulative: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'cumulative'))
|
||||
self.sum: MetricPattern2[StoredF32] = MetricPattern2(client, _m(acc, 'sum'))
|
||||
|
||||
class CoinbasePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.bitcoin: BitcoinPattern = BitcoinPattern(client, _m(acc, 'btc'))
|
||||
self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd'))
|
||||
self.sats: DollarsPattern[Sats] = DollarsPattern(client, acc)
|
||||
|
||||
class CostBasisPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2368,6 +2351,24 @@ class CostBasisPattern2:
|
||||
self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis'))
|
||||
self.percentiles: PercentilesPattern = PercentilesPattern(client, _m(acc, 'cost_basis'))
|
||||
|
||||
class _2015Pattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.bitcoin: MetricPattern4[Bitcoin] = MetricPattern4(client, _m(acc, 'btc'))
|
||||
self.dollars: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'usd'))
|
||||
self.sats: MetricPattern4[Sats] = MetricPattern4(client, acc)
|
||||
|
||||
class CoinbasePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.bitcoin: BitcoinPattern = BitcoinPattern(client, _m(acc, 'btc'))
|
||||
self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd'))
|
||||
self.sats: DollarsPattern[Sats] = DollarsPattern(client, acc)
|
||||
|
||||
class RelativePattern4:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2376,14 +2377,6 @@ class RelativePattern4:
|
||||
self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'loss_rel_to_own_supply'))
|
||||
self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'profit_rel_to_own_supply'))
|
||||
|
||||
class CostBasisPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis'))
|
||||
self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis'))
|
||||
|
||||
class _1dReturns1mSdPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2392,6 +2385,14 @@ class _1dReturns1mSdPattern:
|
||||
self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd'))
|
||||
self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma'))
|
||||
|
||||
class CostBasisPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.max: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'max_cost_basis'))
|
||||
self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis'))
|
||||
|
||||
class SupplyPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2400,14 +2401,6 @@ class SupplyPattern2:
|
||||
self.halved: ActiveSupplyPattern = ActiveSupplyPattern(client, _m(acc, 'halved'))
|
||||
self.total: ActiveSupplyPattern = ActiveSupplyPattern(client, acc)
|
||||
|
||||
class BitcoinPattern2(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.cumulative: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'cumulative'))
|
||||
self.sum: MetricPattern1[T] = MetricPattern1(client, acc)
|
||||
|
||||
class SatsPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2416,6 +2409,14 @@ class SatsPattern(Generic[T]):
|
||||
self.ohlc: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'ohlc_sats'))
|
||||
self.split: SplitPattern2[T] = SplitPattern2(client, _m(acc, 'sats'))
|
||||
|
||||
class BitcoinPattern2(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.cumulative: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'cumulative'))
|
||||
self.sum: MetricPattern1[T] = MetricPattern1(client, acc)
|
||||
|
||||
class BlockCountPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -3296,6 +3297,7 @@ class MetricsTree_Market_Dca_ClassAveragePrice:
|
||||
self._2023: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2023_average_price')
|
||||
self._2024: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2024_average_price')
|
||||
self._2025: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2025_average_price')
|
||||
self._2026: MetricPattern4[Dollars] = MetricPattern4(client, 'dca_class_2026_average_price')
|
||||
|
||||
class MetricsTree_Market_Dca_ClassStack:
|
||||
"""Metrics tree node."""
|
||||
@@ -3312,6 +3314,7 @@ class MetricsTree_Market_Dca_ClassStack:
|
||||
self._2023: _2015Pattern = _2015Pattern(client, 'dca_class_2023_stack')
|
||||
self._2024: _2015Pattern = _2015Pattern(client, 'dca_class_2024_stack')
|
||||
self._2025: _2015Pattern = _2015Pattern(client, 'dca_class_2025_stack')
|
||||
self._2026: _2015Pattern = _2015Pattern(client, 'dca_class_2026_stack')
|
||||
|
||||
class MetricsTree_Market_Dca:
|
||||
"""Metrics tree node."""
|
||||
@@ -3687,7 +3690,11 @@ class MetricsTree_Price_Oracle:
|
||||
"""Metrics tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.close_ohlc_cents: MetricPattern6[OHLCCents] = MetricPattern6(client, 'close_ohlc_cents')
|
||||
self.close_ohlc_dollars: MetricPattern6[OHLCDollars] = MetricPattern6(client, 'close_ohlc_dollars')
|
||||
self.height_to_first_pairoutputindex: MetricPattern11[PairOutputIndex] = MetricPattern11(client, 'height_to_first_pairoutputindex')
|
||||
self.mid_ohlc_cents: MetricPattern6[OHLCCents] = MetricPattern6(client, 'mid_ohlc_cents')
|
||||
self.mid_ohlc_dollars: MetricPattern6[OHLCDollars] = MetricPattern6(client, 'mid_ohlc_dollars')
|
||||
self.ohlc_cents: MetricPattern6[OHLCCents] = MetricPattern6(client, 'oracle_ohlc_cents')
|
||||
self.ohlc_dollars: MetricPattern6[OHLCDollars] = MetricPattern6(client, 'oracle_ohlc')
|
||||
self.output0_value: MetricPattern33[Sats] = MetricPattern33(client, 'pair_output0_value')
|
||||
@@ -3866,6 +3873,7 @@ class MetricsTree_Transactions_Volume:
|
||||
self.annualized_volume: _2015Pattern = _2015Pattern(client, 'annualized_volume')
|
||||
self.inputs_per_sec: MetricPattern4[StoredF32] = MetricPattern4(client, 'inputs_per_sec')
|
||||
self.outputs_per_sec: MetricPattern4[StoredF32] = MetricPattern4(client, 'outputs_per_sec')
|
||||
self.received_sum: ActiveSupplyPattern = ActiveSupplyPattern(client, 'received_sum')
|
||||
self.sent_sum: ActiveSupplyPattern = ActiveSupplyPattern(client, 'sent_sum')
|
||||
self.tx_per_sec: MetricPattern4[StoredF32] = MetricPattern4(client, 'tx_per_sec')
|
||||
|
||||
|
||||
@@ -77,12 +77,7 @@ const lineWidth = /** @type {any} */ (1.5);
|
||||
* @param {BrkClient} args.brk
|
||||
* @param {true} [args.fitContent]
|
||||
*/
|
||||
export function createChart({
|
||||
parent,
|
||||
id: chartId,
|
||||
brk,
|
||||
fitContent,
|
||||
}) {
|
||||
export function createChart({ parent, id: chartId, brk, fitContent }) {
|
||||
const baseUrl = brk.baseUrl.replace(/\/$/, "");
|
||||
|
||||
/** @param {ChartableIndex} idx */
|
||||
@@ -468,6 +463,8 @@ export function createChart({
|
||||
* @param {Color[]} args.colors
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {number} args.paneIndex
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {(order: number) => void} args.setOrder
|
||||
* @param {() => void} args.show
|
||||
@@ -484,6 +481,8 @@ export function createChart({
|
||||
name,
|
||||
order,
|
||||
paneIndex,
|
||||
unit,
|
||||
key: customKey,
|
||||
defaultActive,
|
||||
colors,
|
||||
setOrder,
|
||||
@@ -496,16 +495,16 @@ export function createChart({
|
||||
update,
|
||||
onRemove,
|
||||
}) {
|
||||
const key = stringToId(name);
|
||||
const id = `${key}-${paneIndex}`;
|
||||
const key = customKey ?? stringToId(name);
|
||||
const id = `${unit.id}-${key}`;
|
||||
|
||||
// Reuse existing state if same name (links legends across panes)
|
||||
// Reuse existing state if same name (links legends across panes, regardless of unit)
|
||||
const existingActive = serieses.activeStates.get(key);
|
||||
const active =
|
||||
existingActive ??
|
||||
createPersistedValue({
|
||||
defaultValue: defaultActive ?? true,
|
||||
storageKey: id,
|
||||
storageKey: key,
|
||||
urlKey: key,
|
||||
...serdeBool,
|
||||
});
|
||||
@@ -517,6 +516,8 @@ export function createChart({
|
||||
|
||||
let hasData = false;
|
||||
let lastTime = -Infinity;
|
||||
/** @type {string | null} */
|
||||
let lastStamp = null;
|
||||
|
||||
/** @type {VoidFunction | null} */
|
||||
let _fetch = null;
|
||||
@@ -527,7 +528,8 @@ export function createChart({
|
||||
setActive(value) {
|
||||
const wasActive = active.value;
|
||||
active.set(value);
|
||||
serieses.byKey.get(key)?.forEach((s) => {
|
||||
const linkedSeries = serieses.byKey.get(key);
|
||||
linkedSeries?.forEach((s) => {
|
||||
value ? s.show() : s.hide();
|
||||
});
|
||||
document.querySelectorAll(`[data-series="${key}"]`).forEach((el) => {
|
||||
@@ -535,7 +537,10 @@ export function createChart({
|
||||
el.checked = value;
|
||||
}
|
||||
});
|
||||
if (value && !wasActive) _fetch?.();
|
||||
// Fetch data for ALL linked series, not just this one
|
||||
if (value && !wasActive) {
|
||||
linkedSeries?.forEach((s) => s.fetch?.());
|
||||
}
|
||||
panes.updateVisibility();
|
||||
},
|
||||
setOrder,
|
||||
@@ -558,7 +563,7 @@ export function createChart({
|
||||
},
|
||||
};
|
||||
|
||||
// Register series for cross-pane linking
|
||||
// Register series for cross-pane linking (by name only)
|
||||
let keySet = serieses.byKey.get(key);
|
||||
if (!keySet) {
|
||||
keySet = new Set();
|
||||
@@ -698,7 +703,11 @@ export function createChart({
|
||||
getTimeEndpoint(idx).slice(-10000).fetch(),
|
||||
valuesEndpoint.slice(-10000).fetch(),
|
||||
]);
|
||||
if (timeResult?.data?.length && valuesResult?.data?.length) {
|
||||
if (valuesResult.stamp === lastStamp) {
|
||||
return;
|
||||
}
|
||||
lastStamp = valuesResult.stamp;
|
||||
if (timeResult.data.length && valuesResult.data.length) {
|
||||
processData(timeResult.data, valuesResult.data);
|
||||
}
|
||||
}
|
||||
@@ -724,6 +733,8 @@ export function createChart({
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {number} [args.paneIndex]
|
||||
* @param {[Color, Color]} [args.colors] - [upColor, downColor] for legend
|
||||
* @param {boolean} [args.defaultActive]
|
||||
@@ -732,7 +743,9 @@ export function createChart({
|
||||
addCandlestick({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
unit,
|
||||
paneIndex = 0,
|
||||
colors: customColors,
|
||||
defaultActive,
|
||||
@@ -804,8 +817,10 @@ export function createChart({
|
||||
const series = serieses.create({
|
||||
colors: [upColor, downColor],
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
setOrder(order) {
|
||||
@@ -866,6 +881,8 @@ export function createChart({
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @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 {number} [args.paneIndex]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
@@ -874,8 +891,10 @@ export function createChart({
|
||||
addHistogram({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
color = [colors.green, colors.red],
|
||||
order,
|
||||
unit,
|
||||
paneIndex = 0,
|
||||
defaultActive,
|
||||
options,
|
||||
@@ -912,8 +931,10 @@ export function createChart({
|
||||
const series = serieses.create({
|
||||
colors: isDualColor ? [positiveColor, negativeColor] : [positiveColor],
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
@@ -969,6 +990,8 @@ export function createChart({
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color} args.color
|
||||
* @param {number} [args.paneIndex]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
@@ -977,8 +1000,10 @@ export function createChart({
|
||||
addLine({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
color,
|
||||
unit,
|
||||
paneIndex = 0,
|
||||
defaultActive,
|
||||
options,
|
||||
@@ -1012,8 +1037,10 @@ export function createChart({
|
||||
const series = serieses.create({
|
||||
colors: [color],
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
@@ -1055,6 +1082,8 @@ export function createChart({
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color} args.color
|
||||
* @param {number} [args.paneIndex]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
@@ -1063,8 +1092,10 @@ export function createChart({
|
||||
addDots({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
color,
|
||||
unit,
|
||||
paneIndex = 0,
|
||||
defaultActive,
|
||||
options,
|
||||
@@ -1111,8 +1142,10 @@ export function createChart({
|
||||
const series = serieses.create({
|
||||
colors: [color],
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
@@ -1155,6 +1188,8 @@ export function createChart({
|
||||
* @param {string} args.name
|
||||
* @param {number} args.order
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {number} [args.paneIndex]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {Color} [args.topColor]
|
||||
@@ -1164,7 +1199,9 @@ export function createChart({
|
||||
addBaseline({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
unit,
|
||||
paneIndex: _paneIndex,
|
||||
defaultActive,
|
||||
topColor = colors.green,
|
||||
@@ -1211,8 +1248,10 @@ export function createChart({
|
||||
const series = serieses.create({
|
||||
colors: [topColor, bottomColor],
|
||||
name,
|
||||
key,
|
||||
order,
|
||||
paneIndex,
|
||||
unit,
|
||||
defaultActive,
|
||||
metric,
|
||||
setOrder: (order) => iseries.setSeriesOrder(order),
|
||||
@@ -1345,15 +1384,13 @@ export function createChart({
|
||||
serieses.addBaseline({
|
||||
metric: blueprint.metric,
|
||||
name: blueprint.title,
|
||||
key: blueprint.key,
|
||||
defaultActive: blueprint.defaultActive,
|
||||
paneIndex,
|
||||
options: {
|
||||
...options,
|
||||
topLineColor:
|
||||
blueprint.color?.() ?? blueprint.colors?.[0](),
|
||||
bottomLineColor:
|
||||
blueprint.color?.() ?? blueprint.colors?.[1](),
|
||||
},
|
||||
unit,
|
||||
topColor: blueprint.colors?.[0] ?? blueprint.color,
|
||||
bottomColor: blueprint.colors?.[1] ?? blueprint.color,
|
||||
options,
|
||||
order,
|
||||
}),
|
||||
);
|
||||
@@ -1364,9 +1401,11 @@ export function createChart({
|
||||
serieses.addHistogram({
|
||||
metric: blueprint.metric,
|
||||
name: blueprint.title,
|
||||
key: blueprint.key,
|
||||
color: blueprint.color,
|
||||
defaultActive: blueprint.defaultActive,
|
||||
paneIndex,
|
||||
unit,
|
||||
options,
|
||||
order,
|
||||
}),
|
||||
@@ -1378,9 +1417,11 @@ export function createChart({
|
||||
serieses.addCandlestick({
|
||||
metric: blueprint.metric,
|
||||
name: blueprint.title,
|
||||
key: blueprint.key,
|
||||
colors: blueprint.colors,
|
||||
defaultActive: blueprint.defaultActive,
|
||||
paneIndex,
|
||||
unit,
|
||||
options,
|
||||
order,
|
||||
}),
|
||||
@@ -1393,8 +1434,10 @@ export function createChart({
|
||||
metric: blueprint.metric,
|
||||
color: blueprint.color ?? defaultColor,
|
||||
name: blueprint.title,
|
||||
key: blueprint.key,
|
||||
defaultActive: blueprint.defaultActive,
|
||||
paneIndex,
|
||||
unit,
|
||||
options,
|
||||
order,
|
||||
}),
|
||||
@@ -1408,8 +1451,10 @@ export function createChart({
|
||||
metric: blueprint.metric,
|
||||
color: blueprint.color ?? defaultColor,
|
||||
name: blueprint.title,
|
||||
key: blueprint.key,
|
||||
defaultActive: blueprint.defaultActive,
|
||||
paneIndex,
|
||||
unit,
|
||||
options,
|
||||
order,
|
||||
}),
|
||||
|
||||
@@ -56,8 +56,9 @@ export function createLegend() {
|
||||
inputValue: "value",
|
||||
title: "Click to toggle",
|
||||
inputChecked: series.active.value,
|
||||
onClick: () => {
|
||||
series.setActive(input.checked);
|
||||
onClick: (event) => {
|
||||
event.preventDefault();
|
||||
series.setActive(!series.active.value);
|
||||
},
|
||||
type: "checkbox",
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Chain section builder - typed tree-based patterns */
|
||||
|
||||
import { Unit } from "../utils/units.js";
|
||||
import { priceLine } from "./constants.js";
|
||||
import { line, baseline, dots } from "./series.js";
|
||||
import { satsBtcUsd } from "./shared.js";
|
||||
|
||||
@@ -13,9 +14,9 @@ export function createChainSection(ctx) {
|
||||
const {
|
||||
colors,
|
||||
brk,
|
||||
createPriceLine,
|
||||
fromSizePattern,
|
||||
fromFullnessPattern,
|
||||
fromDollarsPattern,
|
||||
fromFeeRatePattern,
|
||||
fromCoinbasePattern,
|
||||
fromValuePattern,
|
||||
@@ -46,7 +47,7 @@ export function createChainSection(ctx) {
|
||||
tree: [
|
||||
{
|
||||
name: "Dominance",
|
||||
title: `Mining Dominance of ${poolName}`,
|
||||
title: `${poolName} Dominance`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pool._24hDominance,
|
||||
@@ -85,7 +86,7 @@ export function createChainSection(ctx) {
|
||||
},
|
||||
{
|
||||
name: "Blocks mined",
|
||||
title: `Blocks mined by ${poolName}`,
|
||||
title: `${poolName} Blocks`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pool.blocksMined.sum,
|
||||
@@ -123,7 +124,7 @@ export function createChainSection(ctx) {
|
||||
},
|
||||
{
|
||||
name: "Rewards",
|
||||
title: `Rewards collected by ${poolName}`,
|
||||
title: `${poolName} Rewards`,
|
||||
bottom: [
|
||||
...fromValuePattern(
|
||||
pool.coinbase,
|
||||
@@ -142,7 +143,7 @@ export function createChainSection(ctx) {
|
||||
},
|
||||
{
|
||||
name: "Days since block",
|
||||
title: `Days since ${poolName} mined a block`,
|
||||
title: `${poolName} Last Block`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: pool.daysSinceBlock,
|
||||
@@ -166,11 +167,7 @@ export function createChainSection(ctx) {
|
||||
name: "Count",
|
||||
title: "Block Count",
|
||||
bottom: [
|
||||
...fromBlockCountWithUnit(
|
||||
blocks.count.blockCount,
|
||||
"Block",
|
||||
Unit.count,
|
||||
),
|
||||
...fromBlockCountWithUnit(blocks.count.blockCount, Unit.count),
|
||||
line({
|
||||
metric: blocks.count.blockCountTarget,
|
||||
name: "Target",
|
||||
@@ -205,17 +202,17 @@ export function createChainSection(ctx) {
|
||||
name: "Interval",
|
||||
title: "Block Interval",
|
||||
bottom: [
|
||||
...fromIntervalPattern(blocks.interval, "Interval", Unit.secs),
|
||||
createPriceLine({ unit: Unit.secs, name: "Target", number: 600 }),
|
||||
...fromIntervalPattern(blocks.interval, Unit.secs),
|
||||
priceLine({ ctx, unit: Unit.secs, name: "Target", number: 600 }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Size",
|
||||
title: "Block Size",
|
||||
bottom: [
|
||||
...fromSizePattern(blocks.size, "Size", Unit.bytes),
|
||||
...fromFullnessPattern(blocks.vbytes, "Vbytes", Unit.vb),
|
||||
...fromFullnessPattern(blocks.weight, "Weight", Unit.wu),
|
||||
...fromSizePattern(blocks.size, Unit.bytes),
|
||||
...fromFullnessPattern(blocks.vbytes, Unit.vb),
|
||||
...fromFullnessPattern(blocks.weight, Unit.wu),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -228,17 +225,16 @@ export function createChainSection(ctx) {
|
||||
{
|
||||
name: "Count",
|
||||
title: "Transaction Count",
|
||||
bottom: fromFullnessPattern(
|
||||
transactions.count.txCount,
|
||||
"Count",
|
||||
Unit.count,
|
||||
),
|
||||
bottom: fromDollarsPattern(transactions.count.txCount, Unit.count),
|
||||
},
|
||||
{
|
||||
name: "Volume",
|
||||
title: "Transaction Volume",
|
||||
bottom: [
|
||||
...satsBtcUsd( transactions.volume.sentSum, "Sent"),
|
||||
...satsBtcUsd(transactions.volume.sentSum, "Sent"),
|
||||
...satsBtcUsd(transactions.volume.receivedSum, "Received", colors.cyan, {
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: transactions.volume.annualizedVolume.sats,
|
||||
name: "annualized",
|
||||
@@ -266,12 +262,8 @@ export function createChainSection(ctx) {
|
||||
name: "Size",
|
||||
title: "Transaction Size",
|
||||
bottom: [
|
||||
...fromFeeRatePattern(
|
||||
transactions.size.weight,
|
||||
"weight",
|
||||
Unit.wu,
|
||||
),
|
||||
...fromFeeRatePattern(transactions.size.vsize, "vsize", Unit.vb),
|
||||
...fromFeeRatePattern(transactions.size.weight, Unit.wu),
|
||||
...fromFeeRatePattern(transactions.size.vsize, Unit.vb),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -280,22 +272,22 @@ export function createChainSection(ctx) {
|
||||
bottom: [
|
||||
...fromBlockCountWithUnit(
|
||||
transactions.versions.v1,
|
||||
"v1",
|
||||
Unit.count,
|
||||
"v1",
|
||||
colors.orange,
|
||||
colors.red,
|
||||
),
|
||||
...fromBlockCountWithUnit(
|
||||
transactions.versions.v2,
|
||||
"v2",
|
||||
Unit.count,
|
||||
"v2",
|
||||
colors.cyan,
|
||||
colors.blue,
|
||||
),
|
||||
...fromBlockCountWithUnit(
|
||||
transactions.versions.v3,
|
||||
"v3",
|
||||
Unit.count,
|
||||
"v3",
|
||||
colors.lime,
|
||||
colors.green,
|
||||
),
|
||||
@@ -322,7 +314,7 @@ export function createChainSection(ctx) {
|
||||
name: "Speed",
|
||||
title: "Transactions Per Second",
|
||||
bottom: [
|
||||
line({
|
||||
dots({
|
||||
metric: transactions.volume.txPerSec,
|
||||
name: "Transactions",
|
||||
unit: Unit.perSec,
|
||||
@@ -338,14 +330,14 @@ export function createChainSection(ctx) {
|
||||
tree: [
|
||||
{
|
||||
name: "Count",
|
||||
title: "Transaction Input Count",
|
||||
bottom: [...fromSizePattern(inputs.count, "Input", Unit.count)],
|
||||
title: "Input Count",
|
||||
bottom: [...fromSizePattern(inputs.count, Unit.count)],
|
||||
},
|
||||
{
|
||||
name: "Speed",
|
||||
title: "Inputs Per Second",
|
||||
bottom: [
|
||||
line({
|
||||
dots({
|
||||
metric: transactions.volume.inputsPerSec,
|
||||
name: "Inputs",
|
||||
unit: Unit.perSec,
|
||||
@@ -361,20 +353,14 @@ export function createChainSection(ctx) {
|
||||
tree: [
|
||||
{
|
||||
name: "Count",
|
||||
title: "Transaction Output Count",
|
||||
bottom: [
|
||||
...fromSizePattern(
|
||||
outputs.count.totalCount,
|
||||
"Output",
|
||||
Unit.count,
|
||||
),
|
||||
],
|
||||
title: "Output Count",
|
||||
bottom: [...fromSizePattern(outputs.count.totalCount, Unit.count)],
|
||||
},
|
||||
{
|
||||
name: "Speed",
|
||||
title: "Outputs Per Second",
|
||||
bottom: [
|
||||
line({
|
||||
dots({
|
||||
metric: transactions.volume.outputsPerSec,
|
||||
name: "Outputs",
|
||||
unit: Unit.perSec,
|
||||
@@ -713,22 +699,22 @@ export function createChainSection(ctx) {
|
||||
},
|
||||
{
|
||||
name: "Halving",
|
||||
title: "Halving Info",
|
||||
title: "Halving",
|
||||
bottom: [
|
||||
line({
|
||||
metric: blocks.halving.blocksBeforeNextHalving,
|
||||
name: "Blocks until halving",
|
||||
name: "Blocks before next",
|
||||
unit: Unit.blocks,
|
||||
}),
|
||||
line({
|
||||
metric: blocks.halving.daysBeforeNextHalving,
|
||||
name: "Days until halving",
|
||||
name: "Days before next",
|
||||
color: colors.orange,
|
||||
unit: Unit.days,
|
||||
}),
|
||||
line({
|
||||
metric: blocks.halving.epoch,
|
||||
name: "Halving epoch",
|
||||
name: "Epoch",
|
||||
color: colors.purple,
|
||||
unit: Unit.epoch,
|
||||
defaultActive: false,
|
||||
@@ -744,7 +730,7 @@ export function createChainSection(ctx) {
|
||||
name: "Puell Multiple",
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.ratio, number: 1 }),
|
||||
priceLine({ ctx, unit: Unit.ratio, number: 1 }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -771,11 +757,7 @@ export function createChainSection(ctx) {
|
||||
{
|
||||
name: "Outputs",
|
||||
title: "OP_RETURN Outputs",
|
||||
bottom: fromFullnessPattern(
|
||||
scripts.count.opreturn,
|
||||
"Count",
|
||||
Unit.count,
|
||||
),
|
||||
bottom: fromFullnessPattern(scripts.count.opreturn, Unit.count),
|
||||
},
|
||||
{
|
||||
name: "Supply",
|
||||
@@ -810,7 +792,7 @@ export function createChainSection(ctx) {
|
||||
// Unclaimed Rewards
|
||||
{
|
||||
name: "Unclaimed Rewards",
|
||||
title: "Unclaimed Block Rewards",
|
||||
title: "Unclaimed Rewards",
|
||||
bottom: fromValuePattern(blocks.rewards.unclaimedRewards, "Unclaimed"),
|
||||
},
|
||||
],
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { priceLine } from "../constants.js";
|
||||
import { line, baseline } from "../series.js";
|
||||
import {
|
||||
createSingleSupplySeries,
|
||||
@@ -102,7 +103,7 @@ export function createAddressCohortFolder(ctx, args) {
|
||||
)),
|
||||
{
|
||||
name: "capitalization",
|
||||
title: `Realized Capitalization ${title}`,
|
||||
title: `Realized Cap ${title}`,
|
||||
bottom: createRealizedCapWithExtras(ctx, list, args, useGroupName),
|
||||
},
|
||||
...(!useGroupName
|
||||
@@ -134,7 +135,7 @@ export function createAddressCohortFolder(ctx, args) {
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function createRealizedPriceOptions(args, title) {
|
||||
const { tree, color } = args;
|
||||
const { tree, color } = args;
|
||||
|
||||
return [
|
||||
{
|
||||
@@ -161,7 +162,6 @@ function createRealizedPriceOptions(args, title) {
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function createRealizedCapWithExtras(ctx, list, args, useGroupName) {
|
||||
const { createPriceLine } = ctx;
|
||||
const isSingle = !("list" in args);
|
||||
|
||||
return list.flatMap(({ color, name, tree }) => [
|
||||
@@ -179,7 +179,7 @@ function createRealizedCapWithExtras(ctx, list, args, useGroupName) {
|
||||
unit: Unit.usd,
|
||||
defaultActive: false,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.usd, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.usd, defaultActive: false }),
|
||||
]
|
||||
: []),
|
||||
// RealizedPattern (address cohorts) doesn't have realizedCapRelToOwnMarketCap
|
||||
@@ -200,7 +200,7 @@ function createRealizedPnlSection(ctx, args, title) {
|
||||
return [
|
||||
{
|
||||
name: "pnl",
|
||||
title: `Realized Profit And Loss ${title}`,
|
||||
title: `Realized P&L ${title}`,
|
||||
bottom: [
|
||||
line({
|
||||
metric: realized.realizedProfit.sum,
|
||||
@@ -257,7 +257,7 @@ function createUnrealizedSection(ctx, list, useGroupName, title) {
|
||||
tree: [
|
||||
{
|
||||
name: "nupl",
|
||||
title: `Net Unrealized Profit/Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
metric: tree.unrealized.netUnrealizedPnl,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Shared cohort chart section builders */
|
||||
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { priceLine } from "../constants.js";
|
||||
import { line } from "../series.js";
|
||||
import { satsBtcUsd } from "../shared.js";
|
||||
|
||||
@@ -11,11 +12,11 @@ import { satsBtcUsd } from "../shared.js";
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function createSingleSupplySeries(ctx, cohort) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
const { tree } = cohort;
|
||||
|
||||
return [
|
||||
...satsBtcUsd( tree.supply.total, "Supply", colors.default),
|
||||
...satsBtcUsd(tree.supply.total, "Supply", colors.default),
|
||||
...("supplyRelToCirculatingSupply" in tree.relative
|
||||
? [
|
||||
line({
|
||||
@@ -26,9 +27,9 @@ export function createSingleSupplySeries(ctx, cohort) {
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
...satsBtcUsd( tree.unrealized.supplyInProfit, "In Profit", colors.green),
|
||||
...satsBtcUsd( tree.unrealized.supplyInLoss, "In Loss", colors.red),
|
||||
...satsBtcUsd( tree.supply.halved, "half", colors.gray).map((s) => ({
|
||||
...satsBtcUsd(tree.unrealized.supplyInProfit, "In Profit", colors.green),
|
||||
...satsBtcUsd(tree.unrealized.supplyInLoss, "In Loss", colors.red),
|
||||
...satsBtcUsd(tree.supply.halved, "half", colors.gray).map((s) => ({
|
||||
...s,
|
||||
options: { lineStyle: 4 },
|
||||
})),
|
||||
@@ -60,13 +61,14 @@ export function createSingleSupplySeries(ctx, cohort) {
|
||||
color: colors.red,
|
||||
unit: Unit.pctOwn,
|
||||
}),
|
||||
createPriceLine({
|
||||
priceLine({
|
||||
ctx,
|
||||
unit: Unit.pctOwn,
|
||||
number: 100,
|
||||
lineStyle: 0,
|
||||
style: 0,
|
||||
color: colors.default,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.pctOwn, number: 50 }),
|
||||
priceLine({ ctx, unit: Unit.pctOwn, number: 50 }),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -81,7 +83,7 @@ export function createGroupedSupplyTotalSeries(ctx, list) {
|
||||
const constant100 = brk.metrics.constants.constant100;
|
||||
|
||||
return list.flatMap(({ color, name, tree }) => [
|
||||
...satsBtcUsd( tree.supply.total, name, color),
|
||||
...satsBtcUsd(tree.supply.total, name, color),
|
||||
line({
|
||||
metric:
|
||||
"supplyRelToCirculatingSupply" in tree.relative
|
||||
@@ -100,9 +102,8 @@ export function createGroupedSupplyTotalSeries(ctx, list) {
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function createGroupedSupplyInProfitSeries(list) {
|
||||
|
||||
return list.flatMap(({ color, name, tree }) => [
|
||||
...satsBtcUsd( tree.unrealized.supplyInProfit, name, color),
|
||||
...satsBtcUsd(tree.unrealized.supplyInProfit, name, color),
|
||||
...("supplyInProfitRelToCirculatingSupply" in tree.relative
|
||||
? [
|
||||
line({
|
||||
@@ -122,9 +123,8 @@ export function createGroupedSupplyInProfitSeries(list) {
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function createGroupedSupplyInLossSeries(list) {
|
||||
|
||||
return list.flatMap(({ color, name, tree }) => [
|
||||
...satsBtcUsd( tree.unrealized.supplyInLoss, name, color),
|
||||
...satsBtcUsd(tree.unrealized.supplyInLoss, name, color),
|
||||
...("supplyInLossRelToCirculatingSupply" in tree.relative
|
||||
? [
|
||||
line({
|
||||
@@ -193,8 +193,6 @@ export function createRealizedPriceSeries(list) {
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function createRealizedPriceRatioSeries(ctx, list) {
|
||||
const { createPriceLine } = ctx;
|
||||
|
||||
return [
|
||||
...list.map(({ color, name, tree }) =>
|
||||
line({
|
||||
@@ -204,7 +202,7 @@ export function createRealizedPriceRatioSeries(ctx, list) {
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
),
|
||||
createPriceLine({ unit: Unit.ratio, number: 1 }),
|
||||
priceLine({ ctx, unit: Unit.ratio, number: 1 }),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
} from "./shared.js";
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { line, baseline } from "../series.js";
|
||||
import { priceLine } from "../constants.js";
|
||||
|
||||
// ============================================================================
|
||||
// Folder Builders (4 variants based on pattern capabilities)
|
||||
@@ -260,7 +261,7 @@ function createSingleUtxoCountChart(cohort, title) {
|
||||
return {
|
||||
name: "utxo count",
|
||||
title: `UTXO Count ${title}`,
|
||||
bottom: createUtxoCountSeries( [cohort], false),
|
||||
bottom: createUtxoCountSeries([cohort], false),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -274,7 +275,7 @@ function createGroupedUtxoCountChart(list, title) {
|
||||
return {
|
||||
name: "utxo count",
|
||||
title: `UTXO Count ${title}`,
|
||||
bottom: createUtxoCountSeries( list, true),
|
||||
bottom: createUtxoCountSeries(list, true),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -292,7 +293,7 @@ function createSingleRealizedSectionWithAdjusted(ctx, cohort, title) {
|
||||
createSingleRealizedPriceChart(cohort, title),
|
||||
{
|
||||
name: "capitalization",
|
||||
title: `Realized Capitalization ${title}`,
|
||||
title: `Realized Cap ${title}`,
|
||||
bottom: createSingleRealizedCapSeries(ctx, cohort),
|
||||
},
|
||||
...createSingleRealizedPnlSection(ctx, cohort, title),
|
||||
@@ -324,7 +325,7 @@ function createGroupedRealizedSectionWithAdjusted(ctx, list, title) {
|
||||
},
|
||||
{
|
||||
name: "capitalization",
|
||||
title: `Realized Capitalization ${title}`,
|
||||
title: `Realized Cap ${title}`,
|
||||
bottom: createGroupedRealizedCapSeries(list),
|
||||
},
|
||||
...createGroupedRealizedPnlSections(ctx, list, title),
|
||||
@@ -347,7 +348,7 @@ function createSingleRealizedSectionBasic(ctx, cohort, title) {
|
||||
createSingleRealizedPriceChart(cohort, title),
|
||||
{
|
||||
name: "capitalization",
|
||||
title: `Realized Capitalization ${title}`,
|
||||
title: `Realized Cap ${title}`,
|
||||
bottom: createSingleRealizedCapSeries(ctx, cohort),
|
||||
},
|
||||
...createSingleRealizedPnlSection(ctx, cohort, title),
|
||||
@@ -379,7 +380,7 @@ function createGroupedRealizedSectionBasic(ctx, list, title) {
|
||||
},
|
||||
{
|
||||
name: "capitalization",
|
||||
title: `Realized Capitalization ${title}`,
|
||||
title: `Realized Cap ${title}`,
|
||||
bottom: createGroupedRealizedCapSeries(list),
|
||||
},
|
||||
...createGroupedRealizedPnlSections(ctx, list, title),
|
||||
@@ -395,7 +396,7 @@ function createGroupedRealizedSectionBasic(ctx, list, title) {
|
||||
* @returns {PartialChartOption}
|
||||
*/
|
||||
function createSingleRealizedPriceChart(cohort, title) {
|
||||
const { tree, color } = cohort;
|
||||
const { tree, color } = cohort;
|
||||
|
||||
return {
|
||||
name: "price",
|
||||
@@ -418,7 +419,7 @@ function createSingleRealizedPriceChart(cohort, title) {
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
function createSingleRealizedCapSeries(ctx, cohort) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
const { color, tree } = cohort;
|
||||
|
||||
return [
|
||||
@@ -434,7 +435,7 @@ function createSingleRealizedCapSeries(ctx, cohort) {
|
||||
unit: Unit.usd,
|
||||
defaultActive: false,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.usd, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.usd, defaultActive: false }),
|
||||
...("realizedCapRelToOwnMarketCap" in tree.realized
|
||||
? [
|
||||
baseline({
|
||||
@@ -444,7 +445,8 @@ function createSingleRealizedCapSeries(ctx, cohort) {
|
||||
options: { baseValue: { price: 100 } },
|
||||
color: [colors.red, colors.green],
|
||||
}),
|
||||
createPriceLine({
|
||||
priceLine({
|
||||
ctx,
|
||||
unit: Unit.pctOwnMcap,
|
||||
defaultActive: true,
|
||||
number: 100,
|
||||
@@ -478,29 +480,24 @@ function createGroupedRealizedCapSeries(list) {
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function createSingleRealizedPnlSection(ctx, cohort, title) {
|
||||
const {
|
||||
colors,
|
||||
createPriceLine,
|
||||
fromBlockCountWithUnit,
|
||||
fromBitcoinPatternWithUnit,
|
||||
} = ctx;
|
||||
const { colors, fromBlockCountWithUnit, fromBitcoinPatternWithUnit } = ctx;
|
||||
const { tree } = cohort;
|
||||
|
||||
return [
|
||||
{
|
||||
name: "pnl",
|
||||
title: `Realized Profit And Loss ${title}`,
|
||||
title: `Realized P&L ${title}`,
|
||||
bottom: [
|
||||
...fromBlockCountWithUnit(
|
||||
tree.realized.realizedProfit,
|
||||
"Profit",
|
||||
Unit.usd,
|
||||
"Profit",
|
||||
colors.green,
|
||||
),
|
||||
...fromBlockCountWithUnit(
|
||||
tree.realized.realizedLoss,
|
||||
"Loss",
|
||||
Unit.usd,
|
||||
"Loss",
|
||||
colors.red,
|
||||
),
|
||||
...fromBitcoinPatternWithUnit(
|
||||
@@ -538,18 +535,18 @@ function createSingleRealizedPnlSection(ctx, cohort, title) {
|
||||
color: colors.red,
|
||||
unit: Unit.pctRcap,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.pctRcap }),
|
||||
createPriceLine({ unit: Unit.usd, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.pctRcap }),
|
||||
priceLine({ ctx, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Realized Profit And Loss ${title}`,
|
||||
title: `Net Realized P&L ${title}`,
|
||||
bottom: [
|
||||
...fromBlockCountWithUnit(
|
||||
tree.realized.netRealizedPnl,
|
||||
"Net",
|
||||
Unit.usd,
|
||||
"Net",
|
||||
),
|
||||
baseline({
|
||||
metric: tree.realized.netRealizedPnlCumulative30dDelta,
|
||||
@@ -574,9 +571,9 @@ function createSingleRealizedPnlSection(ctx, cohort, title) {
|
||||
name: "Cumulative 30d change",
|
||||
unit: Unit.pctMcap,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.pctMcap }),
|
||||
createPriceLine({ unit: Unit.pctRcap }),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.pctMcap }),
|
||||
priceLine({ ctx, unit: Unit.pctRcap }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -590,8 +587,6 @@ function createSingleRealizedPnlSection(ctx, cohort, title) {
|
||||
* @returns {PartialOptionsTree}
|
||||
*/
|
||||
function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
|
||||
return [
|
||||
{
|
||||
name: "profit",
|
||||
@@ -611,7 +606,7 @@ function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
unit: Unit.pctRcap,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -632,12 +627,12 @@ function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
unit: Unit.pctRcap,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Total pnl",
|
||||
title: `Total Realized Profit And Loss ${title}`,
|
||||
title: `Total Realized P&L ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
line({
|
||||
@@ -661,7 +656,7 @@ function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Realized Profit And Loss ${title}`,
|
||||
title: `Net Realized P&L ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -677,8 +672,8 @@ function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
unit: Unit.pctRcap,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
createPriceLine({ unit: Unit.pctRcap }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.pctRcap }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -710,7 +705,7 @@ function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Cumulative Net Realized Profit And Loss ${title}`,
|
||||
title: `Cumulative Net Realized P&L ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -721,12 +716,12 @@ function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
defaultActive: false,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Net pnl 30d change",
|
||||
title: `Cumulative Net Realized Profit And Loss 30 Day Change ${title}`,
|
||||
title: `Net Realized P&L 30d Change ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -751,9 +746,9 @@ function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
unit: Unit.pctMcap,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
createPriceLine({ unit: Unit.pctMcap }),
|
||||
createPriceLine({ unit: Unit.pctRcap }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.pctMcap }),
|
||||
priceLine({ ctx, unit: Unit.pctRcap }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -787,12 +782,12 @@ function createGroupedRealizedPnlSections(ctx, list, title) {
|
||||
* @returns {PartialChartOption}
|
||||
*/
|
||||
function createSingleBaseSoprChart(ctx, cohort, title) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
const { tree } = cohort;
|
||||
|
||||
return {
|
||||
name: "Normal",
|
||||
title: `Spent Output Profit Ratio ${title}`,
|
||||
title: `SOPR ${title}`,
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: tree.realized.sopr,
|
||||
@@ -816,7 +811,7 @@ function createSingleBaseSoprChart(ctx, cohort, title) {
|
||||
defaultActive: false,
|
||||
options: { baseValue: { price: 1 } },
|
||||
}),
|
||||
createPriceLine({ number: 1, unit: Unit.ratio }),
|
||||
priceLine({ ctx, number: 1, unit: Unit.ratio }),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -829,12 +824,12 @@ function createSingleBaseSoprChart(ctx, cohort, title) {
|
||||
* @returns {PartialChartOption}
|
||||
*/
|
||||
function createSingleAdjustedSoprChart(ctx, cohort, title) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
const { tree } = cohort;
|
||||
|
||||
return {
|
||||
name: "Adjusted",
|
||||
title: `Adjusted Spent Output Profit Ratio ${title}`,
|
||||
title: `aSOPR ${title}`,
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: tree.realized.adjustedSopr,
|
||||
@@ -859,7 +854,7 @@ function createSingleAdjustedSoprChart(ctx, cohort, title) {
|
||||
defaultActive: false,
|
||||
options: { baseValue: { price: 1 } },
|
||||
}),
|
||||
createPriceLine({ number: 1, unit: Unit.ratio }),
|
||||
priceLine({ ctx, number: 1, unit: Unit.ratio }),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -872,11 +867,9 @@ function createSingleAdjustedSoprChart(ctx, cohort, title) {
|
||||
* @returns {PartialChartOption}
|
||||
*/
|
||||
function createGroupedBaseSoprChart(ctx, list, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
|
||||
return {
|
||||
name: "Normal",
|
||||
title: `Spent Output Profit Ratio ${title}`,
|
||||
title: `SOPR ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -903,7 +896,7 @@ function createGroupedBaseSoprChart(ctx, list, title) {
|
||||
options: { baseValue: { price: 1 } },
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ number: 1, unit: Unit.ratio }),
|
||||
priceLine({ ctx, number: 1, unit: Unit.ratio }),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -916,11 +909,9 @@ function createGroupedBaseSoprChart(ctx, list, title) {
|
||||
* @returns {PartialChartOption}
|
||||
*/
|
||||
function createGroupedAdjustedSoprChart(ctx, list, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
|
||||
return {
|
||||
name: "Adjusted",
|
||||
title: `Adjusted Spent Output Profit Ratio ${title}`,
|
||||
title: `aSOPR ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -947,7 +938,7 @@ function createGroupedAdjustedSoprChart(ctx, list, title) {
|
||||
options: { baseValue: { price: 1 } },
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ number: 1, unit: Unit.ratio }),
|
||||
priceLine({ ctx, number: 1, unit: Unit.ratio }),
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -1056,7 +1047,7 @@ function createUnrealizedPnlRelToMarketCapMetrics(ctx, rel) {
|
||||
* @param {RelativeWithOwnMarketCap} rel
|
||||
*/
|
||||
function createUnrealizedPnlRelToOwnMarketCapMetrics(ctx, rel) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
return [
|
||||
line({
|
||||
metric: rel.unrealizedProfitRelToOwnMarketCap,
|
||||
@@ -1077,8 +1068,8 @@ function createUnrealizedPnlRelToOwnMarketCapMetrics(ctx, rel) {
|
||||
color: colors.red,
|
||||
unit: Unit.pctOwnMcap,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.pctOwnMcap, number: 100 }),
|
||||
createPriceLine({ unit: Unit.pctOwnMcap }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnMcap, number: 100 }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnMcap }),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1087,7 +1078,7 @@ function createUnrealizedPnlRelToOwnMarketCapMetrics(ctx, rel) {
|
||||
* @param {RelativeWithOwnPnl} rel
|
||||
*/
|
||||
function createUnrealizedPnlRelToOwnPnlMetrics(ctx, rel) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
return [
|
||||
line({
|
||||
metric: rel.unrealizedProfitRelToOwnTotalUnrealizedPnl,
|
||||
@@ -1108,8 +1099,8 @@ function createUnrealizedPnlRelToOwnPnlMetrics(ctx, rel) {
|
||||
color: colors.red,
|
||||
unit: Unit.pctOwnPnl,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.pctOwnPnl, number: 100 }),
|
||||
createPriceLine({ unit: Unit.pctOwnPnl }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnPnl, number: 100 }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnPnl }),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1117,7 +1108,7 @@ function createUnrealizedPnlRelToOwnPnlMetrics(ctx, rel) {
|
||||
* @param {RelativeWithMarketCap} rel
|
||||
*/
|
||||
function createNetUnrealizedPnlRelToMarketCapMetrics(rel) {
|
||||
return [
|
||||
return [
|
||||
baseline({
|
||||
metric: rel.netUnrealizedPnlRelToMarketCap,
|
||||
name: "Net",
|
||||
@@ -1131,14 +1122,13 @@ function createNetUnrealizedPnlRelToMarketCapMetrics(rel) {
|
||||
* @param {RelativeWithOwnMarketCap} rel
|
||||
*/
|
||||
function createNetUnrealizedPnlRelToOwnMarketCapMetrics(ctx, rel) {
|
||||
const { createPriceLine } = ctx;
|
||||
return [
|
||||
baseline({
|
||||
metric: rel.netUnrealizedPnlRelToOwnMarketCap,
|
||||
name: "Net",
|
||||
unit: Unit.pctOwnMcap,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.pctOwnMcap }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnMcap }),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1147,14 +1137,13 @@ function createNetUnrealizedPnlRelToOwnMarketCapMetrics(ctx, rel) {
|
||||
* @param {RelativeWithOwnPnl} rel
|
||||
*/
|
||||
function createNetUnrealizedPnlRelToOwnPnlMetrics(ctx, rel) {
|
||||
const { createPriceLine } = ctx;
|
||||
return [
|
||||
baseline({
|
||||
metric: rel.netUnrealizedPnlRelToOwnTotalUnrealizedPnl,
|
||||
name: "Net",
|
||||
unit: Unit.pctOwnPnl,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.pctOwnPnl }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnPnl }),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1199,7 +1188,7 @@ function createUnrealizedPnlBaseMetrics(ctx, tree) {
|
||||
* @param {{ unrealized: { netUnrealizedPnl: AnyMetricPattern } }} tree
|
||||
*/
|
||||
function createNetUnrealizedPnlBaseMetric(tree) {
|
||||
return baseline({
|
||||
return baseline({
|
||||
metric: tree.unrealized.netUnrealizedPnl,
|
||||
name: "Net",
|
||||
unit: Unit.ratio,
|
||||
@@ -1219,27 +1208,26 @@ function createNetUnrealizedPnlBaseMetric(tree) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createSingleUnrealizedSectionAll(ctx, cohort, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
const { tree } = cohort;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
{
|
||||
name: "pnl",
|
||||
title: `Unrealized Profit And Loss ${title}`,
|
||||
title: `Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...createUnrealizedPnlBaseMetrics(ctx, tree),
|
||||
...createUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative),
|
||||
createPriceLine({ unit: Unit.usd, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
createNetUnrealizedPnlBaseMetric(tree),
|
||||
...createNetUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1254,33 +1242,32 @@ function createSingleUnrealizedSectionAll(ctx, cohort, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createSingleUnrealizedSectionFull(ctx, cohort, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
const { tree } = cohort;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
{
|
||||
name: "pnl",
|
||||
title: `Unrealized Profit And Loss ${title}`,
|
||||
title: `Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...createUnrealizedPnlBaseMetrics(ctx, tree),
|
||||
...createUnrealizedPnlRelToMarketCapMetrics(ctx, tree.relative),
|
||||
...createUnrealizedPnlRelToOwnMarketCapMetrics(ctx, tree.relative),
|
||||
...createUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative),
|
||||
createPriceLine({ unit: Unit.usd, defaultActive: false }),
|
||||
createPriceLine({ unit: Unit.pctMcap, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.usd, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.pctMcap, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
createNetUnrealizedPnlBaseMetric(tree),
|
||||
...createNetUnrealizedPnlRelToMarketCapMetrics(tree.relative),
|
||||
...createNetUnrealizedPnlRelToOwnMarketCapMetrics(ctx, tree.relative),
|
||||
...createNetUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
createPriceLine({ unit: Unit.pctMcap }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.pctMcap }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1295,29 +1282,28 @@ function createSingleUnrealizedSectionFull(ctx, cohort, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createSingleUnrealizedSectionWithMarketCap(ctx, cohort, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
const { tree } = cohort;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
{
|
||||
name: "pnl",
|
||||
title: `Unrealized Profit And Loss ${title}`,
|
||||
title: `Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...createUnrealizedPnlBaseMetrics(ctx, tree),
|
||||
...createUnrealizedPnlRelToMarketCapMetrics(ctx, tree.relative),
|
||||
createPriceLine({ unit: Unit.usd, defaultActive: false }),
|
||||
createPriceLine({ unit: Unit.pctMcap, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.usd, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.pctMcap, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
createNetUnrealizedPnlBaseMetric(tree),
|
||||
...createNetUnrealizedPnlRelToMarketCapMetrics(tree.relative),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
createPriceLine({ unit: Unit.pctMcap }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.pctMcap }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1333,29 +1319,28 @@ function createSingleUnrealizedSectionWithMarketCap(ctx, cohort, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createSingleUnrealizedSectionWithOwnCaps(ctx, cohort, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
const { tree } = cohort;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
{
|
||||
name: "pnl",
|
||||
title: `Unrealized Profit And Loss ${title}`,
|
||||
title: `Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...createUnrealizedPnlBaseMetrics(ctx, tree),
|
||||
...createUnrealizedPnlRelToOwnMarketCapMetrics(ctx, tree.relative),
|
||||
...createUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative),
|
||||
createPriceLine({ unit: Unit.usd, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
createNetUnrealizedPnlBaseMetric(tree),
|
||||
...createNetUnrealizedPnlRelToOwnMarketCapMetrics(ctx, tree.relative),
|
||||
...createNetUnrealizedPnlRelToOwnPnlMetrics(ctx, tree.relative),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1371,25 +1356,24 @@ function createSingleUnrealizedSectionWithOwnCaps(ctx, cohort, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createSingleUnrealizedSectionBase(ctx, cohort, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
const { tree } = cohort;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
{
|
||||
name: "pnl",
|
||||
title: `Unrealized Profit And Loss ${title}`,
|
||||
title: `Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...createUnrealizedPnlBaseMetrics(ctx, tree),
|
||||
createPriceLine({ unit: Unit.usd, defaultActive: false }),
|
||||
priceLine({ ctx, unit: Unit.usd, defaultActive: false }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
createNetUnrealizedPnlBaseMetric(tree),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1402,7 +1386,7 @@ function createSingleUnrealizedSectionBase(ctx, cohort, title) {
|
||||
* @param {string} title
|
||||
*/
|
||||
function createGroupedUnrealizedBaseCharts(list, title) {
|
||||
return [
|
||||
return [
|
||||
{
|
||||
name: "profit",
|
||||
title: `Unrealized Profit ${title}`,
|
||||
@@ -1429,7 +1413,7 @@ function createGroupedUnrealizedBaseCharts(list, title) {
|
||||
},
|
||||
{
|
||||
name: "total pnl",
|
||||
title: `Unrealized Total Profit And Loss ${title}`,
|
||||
title: `Unrealized Total P&L ${title}`,
|
||||
bottom: list.flatMap(({ color, name, tree }) => [
|
||||
line({
|
||||
metric: tree.unrealized.totalUnrealizedPnl,
|
||||
@@ -1450,14 +1434,13 @@ function createGroupedUnrealizedBaseCharts(list, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createGroupedUnrealizedSectionFull(ctx, list, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
...createGroupedUnrealizedBaseCharts(list, title),
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -1485,10 +1468,10 @@ function createGroupedUnrealizedSectionFull(ctx, list, title) {
|
||||
unit: Unit.pctOwnPnl,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
createPriceLine({ unit: Unit.pctMcap }),
|
||||
createPriceLine({ unit: Unit.pctOwnMcap }),
|
||||
createPriceLine({ unit: Unit.pctOwnPnl }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.pctMcap }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnMcap }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnPnl }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1503,14 +1486,13 @@ function createGroupedUnrealizedSectionFull(ctx, list, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createGroupedUnrealizedSectionWithMarketCap(ctx, list, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
...createGroupedUnrealizedBaseCharts(list, title),
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -1526,8 +1508,8 @@ function createGroupedUnrealizedSectionWithMarketCap(ctx, list, title) {
|
||||
unit: Unit.pctMcap,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
createPriceLine({ unit: Unit.pctMcap }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.pctMcap }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1542,14 +1524,13 @@ function createGroupedUnrealizedSectionWithMarketCap(ctx, list, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createGroupedUnrealizedSectionWithOwnCaps(ctx, list, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
...createGroupedUnrealizedBaseCharts(list, title),
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -1571,9 +1552,9 @@ function createGroupedUnrealizedSectionWithOwnCaps(ctx, list, title) {
|
||||
unit: Unit.pctOwnPnl,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
createPriceLine({ unit: Unit.pctOwnMcap }),
|
||||
createPriceLine({ unit: Unit.pctOwnPnl }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnMcap }),
|
||||
priceLine({ ctx, unit: Unit.pctOwnPnl }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1588,14 +1569,13 @@ function createGroupedUnrealizedSectionWithOwnCaps(ctx, list, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createGroupedUnrealizedSectionBase(ctx, list, title) {
|
||||
const { createPriceLine } = ctx;
|
||||
return {
|
||||
name: "Unrealized",
|
||||
tree: [
|
||||
...createGroupedUnrealizedBaseCharts(list, title),
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Net Unrealized Profit And Loss ${title}`,
|
||||
title: `Net Unrealized P&L ${title}`,
|
||||
bottom: [
|
||||
...list.flatMap(({ color, name, tree }) => [
|
||||
baseline({
|
||||
@@ -1605,7 +1585,7 @@ function createGroupedUnrealizedSectionBase(ctx, list, title) {
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
]),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -1619,7 +1599,7 @@ function createGroupedUnrealizedSectionBase(ctx, list, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createSingleCostBasisSectionWithPercentiles(cohort, title) {
|
||||
const { color, tree } = cohort;
|
||||
const { color, tree } = cohort;
|
||||
|
||||
return {
|
||||
name: "Cost Basis",
|
||||
@@ -1652,7 +1632,7 @@ function createSingleCostBasisSectionWithPercentiles(cohort, title) {
|
||||
{
|
||||
name: "percentiles",
|
||||
title: `Cost Basis Percentiles ${title}`,
|
||||
top: createCostBasisPercentilesSeries( [cohort], false),
|
||||
top: createCostBasisPercentilesSeries([cohort], false),
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1705,7 +1685,7 @@ function createGroupedCostBasisSectionWithPercentiles(list, title) {
|
||||
* @returns {PartialOptionsGroup}
|
||||
*/
|
||||
function createSingleCostBasisSection(cohort, title) {
|
||||
const { color, tree } = cohort;
|
||||
const { color, tree } = cohort;
|
||||
|
||||
return {
|
||||
name: "Cost Basis",
|
||||
@@ -2083,7 +2063,7 @@ function createGroupedActivitySectionWithAdjusted(list, title) {
|
||||
tree: [
|
||||
{
|
||||
name: "Sum",
|
||||
title: `Sum of Coins Destroyed ${title}`,
|
||||
title: `Coins Destroyed ${title}`,
|
||||
bottom: list.flatMap(({ color, name, tree }) => [
|
||||
line({
|
||||
metric: tree.activity.coinblocksDestroyed.sum,
|
||||
@@ -2176,7 +2156,7 @@ function createGroupedActivitySectionBasic(list, title) {
|
||||
tree: [
|
||||
{
|
||||
name: "Sum",
|
||||
title: `Sum of Coins Destroyed ${title}`,
|
||||
title: `Coins Destroyed ${title}`,
|
||||
bottom: list.flatMap(({ color, name, tree }) => [
|
||||
line({
|
||||
metric: tree.activity.coinblocksDestroyed.sum,
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/** Cointime section builder - typed tree-based patterns */
|
||||
|
||||
import { Unit } from "../utils/units.js";
|
||||
import { priceLine, priceLines } from "./constants.js";
|
||||
import { line, baseline } from "./series.js";
|
||||
import {
|
||||
satsBtcUsd,
|
||||
priceLines,
|
||||
percentileUsdMap,
|
||||
percentileMap,
|
||||
sdPatterns,
|
||||
@@ -26,7 +24,7 @@ function createCointimePriceWithRatioOptions(
|
||||
ctx,
|
||||
{ title, legend, price, ratio, color },
|
||||
) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
|
||||
const pctUsdMap = percentileUsdMap(colors, ratio);
|
||||
const pctMap = percentileMap(colors, ratio);
|
||||
@@ -113,7 +111,7 @@ function createCointimePriceWithRatioOptions(
|
||||
options: { lineStyle: 1 },
|
||||
}),
|
||||
),
|
||||
createPriceLine({ unit: Unit.ratio, number: 1 }),
|
||||
priceLine({ ctx, unit: Unit.ratio, number: 1 }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -122,34 +120,34 @@ function createCointimePriceWithRatioOptions(
|
||||
// Compare all Z-Scores
|
||||
{
|
||||
name: "Compare",
|
||||
title: `Compare ${title} Z-Scores`,
|
||||
title: `${title} Z-Scores`,
|
||||
top: [
|
||||
line({ metric: price, name: legend, color, unit: Unit.usd }),
|
||||
line({
|
||||
metric: ratio.ratio1ySd._0sdUsd,
|
||||
name: "1y 0sd",
|
||||
color: colors.fuchsia,
|
||||
name: "1y 0σ",
|
||||
color: colors.orange,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio2ySd._0sdUsd,
|
||||
name: "2y 0sd",
|
||||
color: colors.purple,
|
||||
name: "2y 0σ",
|
||||
color: colors.yellow,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio4ySd._0sdUsd,
|
||||
name: "4y 0sd",
|
||||
color: colors.violet,
|
||||
name: "4y 0σ",
|
||||
color: colors.lime,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratioSd._0sdUsd,
|
||||
name: "0sd",
|
||||
color: colors.indigo,
|
||||
name: "all 0σ",
|
||||
color: colors.blue,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
@@ -157,8 +155,8 @@ function createCointimePriceWithRatioOptions(
|
||||
bottom: [
|
||||
line({
|
||||
metric: ratio.ratioSd.zscore,
|
||||
name: "All",
|
||||
color: colors.default,
|
||||
name: "all",
|
||||
color: colors.blue,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
line({
|
||||
@@ -170,34 +168,48 @@ function createCointimePriceWithRatioOptions(
|
||||
line({
|
||||
metric: ratio.ratio2ySd.zscore,
|
||||
name: "2y",
|
||||
color: colors.avocado,
|
||||
color: colors.yellow,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio1ySd.zscore,
|
||||
name: "1y",
|
||||
color: colors.yellow,
|
||||
color: colors.orange,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
...priceLines(ctx, Unit.sd, [0, 1, -1, 2, -2, 3, -3, 4, -4]),
|
||||
...priceLines({
|
||||
ctx,
|
||||
unit: Unit.sd,
|
||||
numbers: [0, 1, -1, 2, -2, 3, -3, 4, -4],
|
||||
defaultActive: false,
|
||||
}),
|
||||
],
|
||||
},
|
||||
// Individual Z-Score charts
|
||||
...sdPats.map(({ nameAddon, titleAddon, sd }) => ({
|
||||
name: nameAddon,
|
||||
title: `${title} ${titleAddon} Z-Score`,
|
||||
top: sdBands(colors, sd).map(
|
||||
({ name: bandName, prop, color: bandColor }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
name: bandName,
|
||||
color: bandColor,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
),
|
||||
top: [
|
||||
line({ metric: price, name: legend, color, unit: Unit.usd }),
|
||||
...sdBands(colors, sd).map(
|
||||
({ name: bandName, prop, color: bandColor }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
name: bandName,
|
||||
color: bandColor,
|
||||
unit: Unit.usd,
|
||||
defaultActive: false,
|
||||
}),
|
||||
),
|
||||
],
|
||||
bottom: [
|
||||
line({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }),
|
||||
...priceLines(ctx, Unit.sd, [0, 1, -1, 2, -2, 3, -3]),
|
||||
...priceLines({
|
||||
ctx,
|
||||
unit: Unit.sd,
|
||||
numbers: [0, 1, -1, 2, -2, 3, -3],
|
||||
defaultActive: false,
|
||||
}),
|
||||
],
|
||||
})),
|
||||
],
|
||||
@@ -222,28 +234,28 @@ export function createCointimeSection(ctx) {
|
||||
price: pricing.trueMarketMean,
|
||||
ratio: pricing.trueMarketMeanRatio,
|
||||
name: "True market mean",
|
||||
title: "true market mean",
|
||||
title: "True Market Mean",
|
||||
color: colors.blue,
|
||||
},
|
||||
{
|
||||
price: pricing.vaultedPrice,
|
||||
ratio: pricing.vaultedPriceRatio,
|
||||
name: "Vaulted",
|
||||
title: "vaulted price",
|
||||
title: "Vaulted Price",
|
||||
color: colors.lime,
|
||||
},
|
||||
{
|
||||
price: pricing.activePrice,
|
||||
ratio: pricing.activePriceRatio,
|
||||
name: "Active",
|
||||
title: "active price",
|
||||
title: "Active Price",
|
||||
color: colors.rose,
|
||||
},
|
||||
{
|
||||
price: pricing.cointimePrice,
|
||||
ratio: pricing.cointimePriceRatio,
|
||||
name: "cointime",
|
||||
title: "cointime price",
|
||||
title: "Cointime Price",
|
||||
color: colors.yellow,
|
||||
},
|
||||
];
|
||||
@@ -253,31 +265,31 @@ export function createCointimeSection(ctx) {
|
||||
{
|
||||
metric: cap.vaultedCap,
|
||||
name: "vaulted",
|
||||
title: "vaulted Capitalization",
|
||||
title: "Vaulted Cap",
|
||||
color: colors.lime,
|
||||
},
|
||||
{
|
||||
metric: cap.activeCap,
|
||||
name: "active",
|
||||
title: "active Capitalization",
|
||||
title: "Active Cap",
|
||||
color: colors.rose,
|
||||
},
|
||||
{
|
||||
metric: cap.cointimeCap,
|
||||
name: "cointime",
|
||||
title: "cointime Capitalization",
|
||||
title: "Cointime Cap",
|
||||
color: colors.yellow,
|
||||
},
|
||||
{
|
||||
metric: cap.investorCap,
|
||||
name: "investor",
|
||||
title: "investor Capitalization",
|
||||
title: "Investor Cap",
|
||||
color: colors.fuchsia,
|
||||
},
|
||||
{
|
||||
metric: cap.thermoCap,
|
||||
name: "thermo",
|
||||
title: "thermo Capitalization",
|
||||
title: "Thermo Cap",
|
||||
color: colors.emerald,
|
||||
},
|
||||
];
|
||||
@@ -291,7 +303,7 @@ export function createCointimeSection(ctx) {
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: "Compare Cointime Prices",
|
||||
title: "Cointime Prices",
|
||||
top: cointimePrices.map(({ price, name, color }) =>
|
||||
line({ metric: price, name, color, unit: Unit.usd }),
|
||||
),
|
||||
@@ -315,7 +327,7 @@ export function createCointimeSection(ctx) {
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: "Compare Cointime Capitalizations",
|
||||
title: "Cointime Caps",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.marketCap,
|
||||
@@ -361,17 +373,9 @@ export function createCointimeSection(ctx) {
|
||||
name: "Supply",
|
||||
title: "Cointime Supply",
|
||||
bottom: [
|
||||
...satsBtcUsd( all.supply.total, "All", colors.orange),
|
||||
...satsBtcUsd(
|
||||
cointimeSupply.vaultedSupply,
|
||||
"Vaulted",
|
||||
colors.lime,
|
||||
),
|
||||
...satsBtcUsd(
|
||||
cointimeSupply.activeSupply,
|
||||
"Active",
|
||||
colors.rose,
|
||||
),
|
||||
...satsBtcUsd(all.supply.total, "All", colors.orange),
|
||||
...satsBtcUsd(cointimeSupply.vaultedSupply, "Vaulted", colors.lime),
|
||||
...satsBtcUsd(cointimeSupply.activeSupply, "Active", colors.rose),
|
||||
],
|
||||
},
|
||||
|
||||
@@ -457,7 +461,7 @@ export function createCointimeSection(ctx) {
|
||||
// Inflation
|
||||
{
|
||||
name: "Inflation",
|
||||
title: "Cointime-Adjusted Inflation Rate",
|
||||
title: "Adjusted Inflation",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.inflation,
|
||||
@@ -476,7 +480,7 @@ export function createCointimeSection(ctx) {
|
||||
// Velocity
|
||||
{
|
||||
name: "Velocity",
|
||||
title: "Cointime-Adjusted Transactions Velocity",
|
||||
title: "Adjusted Velocity",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.velocity.btc,
|
||||
|
||||
@@ -9,7 +9,7 @@ import { line } from "./series.js";
|
||||
* @param {number} num
|
||||
* @returns {AnyMetricPattern}
|
||||
*/
|
||||
export function getConstant(constants, num) {
|
||||
function getConstant(constants, num) {
|
||||
const key =
|
||||
num >= 0
|
||||
? `constant${String(num).replace(".", "")}`
|
||||
@@ -23,96 +23,31 @@ export function getConstant(constants, num) {
|
||||
|
||||
/**
|
||||
* Create a price line series (horizontal reference line)
|
||||
* @param {Object} args
|
||||
* @param {BrkClient["metrics"]["constants"]} args.constants
|
||||
* @param {Colors} args.colors
|
||||
* @param {number} [args.number]
|
||||
* @param {string} [args.name]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {number} [args.lineStyle]
|
||||
* @param {Color} [args.color]
|
||||
* @param {Unit} args.unit
|
||||
* @returns {FetchedLineSeriesBlueprint}
|
||||
* @param {{ ctx: PartialContext, number?: number, name?: string } & Omit<(Parameters<typeof line>)[0], 'name' | 'metric'>} args
|
||||
*/
|
||||
export function createPriceLine({
|
||||
constants,
|
||||
colors,
|
||||
number = 0,
|
||||
unit,
|
||||
defaultActive,
|
||||
color,
|
||||
name,
|
||||
lineStyle,
|
||||
}) {
|
||||
return {
|
||||
metric: getConstant(constants, number),
|
||||
title: name ?? `${number}`,
|
||||
unit,
|
||||
defaultActive,
|
||||
color: color ?? colors.gray,
|
||||
options: {
|
||||
lineStyle: lineStyle ?? 4,
|
||||
lastValueVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create multiple price lines from an array of numbers
|
||||
* @param {Object} args
|
||||
* @param {BrkClient["metrics"]["constants"]} args.constants
|
||||
* @param {Colors} args.colors
|
||||
* @param {number[]} args.numbers
|
||||
* @param {Unit} args.unit
|
||||
* @returns {FetchedLineSeriesBlueprint[]}
|
||||
*/
|
||||
export function createPriceLines({ constants, colors, numbers, unit }) {
|
||||
return numbers.map((number) => ({
|
||||
metric: getConstant(constants, number),
|
||||
title: `${number}`,
|
||||
unit,
|
||||
defaultActive: !number,
|
||||
color: colors.gray,
|
||||
options: {
|
||||
lineStyle: 4,
|
||||
lastValueVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a constant line series
|
||||
* @param {Object} args
|
||||
* @param {Colors} args.colors
|
||||
* @param {AnyMetricPattern} args.constant
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {Color} [args.color]
|
||||
* @param {number} [args.lineStyle]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @returns {FetchedLineSeriesBlueprint}
|
||||
*/
|
||||
export function constantLine({
|
||||
colors,
|
||||
constant,
|
||||
name,
|
||||
unit,
|
||||
color,
|
||||
lineStyle,
|
||||
defaultActive,
|
||||
}) {
|
||||
export function priceLine(args) {
|
||||
return line({
|
||||
metric: constant,
|
||||
name,
|
||||
unit,
|
||||
defaultActive,
|
||||
color: color ?? colors.gray,
|
||||
...args,
|
||||
metric: getConstant(args.ctx.brk.metrics.constants, args.number || 0),
|
||||
name: args.name || `${args.number ?? 0}`,
|
||||
color: args.color ?? args.ctx.colors.gray,
|
||||
options: {
|
||||
lineStyle: lineStyle ?? 4,
|
||||
lineStyle: args.style ?? 4,
|
||||
lastValueVisible: false,
|
||||
crosshairMarkerVisible: false,
|
||||
...args.options,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ numbers: number[] } & Omit<(Parameters<typeof priceLine>)[0], 'number'>} args
|
||||
*/
|
||||
export function priceLines(args) {
|
||||
return args.numbers.map((number) =>
|
||||
priceLine({
|
||||
...args,
|
||||
number,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
fromBlockSize,
|
||||
fromSizePattern,
|
||||
fromFullnessPattern,
|
||||
fromDollarsPattern,
|
||||
fromFeeRatePattern,
|
||||
fromCoinbasePattern,
|
||||
fromValuePattern,
|
||||
@@ -12,11 +13,6 @@ import {
|
||||
fromIntervalPattern,
|
||||
fromSupplyPattern,
|
||||
} from "./series.js";
|
||||
import {
|
||||
createPriceLine,
|
||||
createPriceLines,
|
||||
constantLine,
|
||||
} from "./constants.js";
|
||||
import { colors } from "../chart/colors.js";
|
||||
|
||||
/**
|
||||
@@ -26,8 +22,6 @@ import { colors } from "../chart/colors.js";
|
||||
* @returns {PartialContext}
|
||||
*/
|
||||
export function createContext({ brk }) {
|
||||
const constants = brk.metrics.constants;
|
||||
|
||||
return {
|
||||
colors,
|
||||
brk,
|
||||
@@ -38,12 +32,14 @@ export function createContext({ brk }) {
|
||||
fromBitcoin(colors, pattern, title, color),
|
||||
fromBlockSize: (pattern, title, color) =>
|
||||
fromBlockSize(colors, pattern, title, color),
|
||||
fromSizePattern: (pattern, title, unit) =>
|
||||
fromSizePattern(colors, pattern, title, unit),
|
||||
fromFullnessPattern: (pattern, title, unit) =>
|
||||
fromFullnessPattern(colors, pattern, title, unit),
|
||||
fromFeeRatePattern: (pattern, title, unit) =>
|
||||
fromFeeRatePattern(colors, pattern, title, unit),
|
||||
fromSizePattern: (pattern, unit, title) =>
|
||||
fromSizePattern(colors, pattern, unit, title),
|
||||
fromFullnessPattern: (pattern, unit, title) =>
|
||||
fromFullnessPattern(colors, pattern, unit, title),
|
||||
fromDollarsPattern: (pattern, unit, title) =>
|
||||
fromDollarsPattern(colors, pattern, unit, title),
|
||||
fromFeeRatePattern: (pattern, unit, title) =>
|
||||
fromFeeRatePattern(colors, pattern, unit, title),
|
||||
fromCoinbasePattern: (pattern, title) =>
|
||||
fromCoinbasePattern(colors, pattern, title),
|
||||
fromValuePattern: (pattern, title, sumColor, cumulativeColor) =>
|
||||
@@ -63,23 +59,18 @@ export function createContext({ brk }) {
|
||||
sumColor,
|
||||
cumulativeColor,
|
||||
),
|
||||
fromBlockCountWithUnit: (pattern, title, unit, sumColor, cumulativeColor) =>
|
||||
fromBlockCountWithUnit: (pattern, unit, title, sumColor, cumulativeColor) =>
|
||||
fromBlockCountWithUnit(
|
||||
colors,
|
||||
pattern,
|
||||
title,
|
||||
unit,
|
||||
title,
|
||||
sumColor,
|
||||
cumulativeColor,
|
||||
),
|
||||
fromIntervalPattern: (pattern, title, unit, color) =>
|
||||
fromIntervalPattern(colors, pattern, title, unit, color),
|
||||
fromIntervalPattern: (pattern, unit, title, color) =>
|
||||
fromIntervalPattern(colors, pattern, unit, title, color),
|
||||
fromSupplyPattern: (pattern, title, color) =>
|
||||
fromSupplyPattern(colors, pattern, title, color),
|
||||
|
||||
createPriceLine: (args) => createPriceLine({ constants, colors, ...args }),
|
||||
createPriceLines: (args) =>
|
||||
createPriceLines({ constants, colors, ...args }),
|
||||
constantLine: (args) => constantLine({ colors, ...args }),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/** Moving averages section */
|
||||
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { priceLine, priceLines } from "../constants.js";
|
||||
import { line, baseline } from "../series.js";
|
||||
import {
|
||||
priceLines,
|
||||
percentileUsdMap,
|
||||
percentileMap,
|
||||
sdPatterns,
|
||||
@@ -56,7 +56,7 @@ export function createPriceWithRatioOptions(
|
||||
ctx,
|
||||
{ title, legend, ratio, color },
|
||||
) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
const priceMetric = ratio.price;
|
||||
|
||||
const pctUsdMap = percentileUsdMap(colors, ratio);
|
||||
@@ -93,48 +93,47 @@ export function createPriceWithRatioOptions(
|
||||
color,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio1wSma,
|
||||
name: "1w SMA",
|
||||
color: colors.lime,
|
||||
unit: Unit.ratio,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio1mSma,
|
||||
name: "1m SMA",
|
||||
color: colors.teal,
|
||||
unit: Unit.ratio,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio1ySd.sma,
|
||||
name: "1y SMA",
|
||||
color: colors.sky,
|
||||
unit: Unit.ratio,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio2ySd.sma,
|
||||
name: "2y SMA",
|
||||
color: colors.indigo,
|
||||
unit: Unit.ratio,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio4ySd.sma,
|
||||
name: "4y SMA",
|
||||
color: colors.purple,
|
||||
unit: Unit.ratio,
|
||||
defaultActive: false,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratioSd.sma,
|
||||
name: "All SMA",
|
||||
color: colors.rose,
|
||||
unit: Unit.ratio,
|
||||
defaultActive: false,
|
||||
}),
|
||||
.../** @type {const} */ ([
|
||||
{
|
||||
metric: ratio.ratio1wSma,
|
||||
name: "1w SMA",
|
||||
color: colors.lime,
|
||||
},
|
||||
{
|
||||
metric: ratio.ratio1mSma,
|
||||
name: "1m SMA",
|
||||
color: colors.teal,
|
||||
},
|
||||
{
|
||||
metric: ratio.ratio1ySd.sma,
|
||||
name: "1y SMA",
|
||||
color: colors.sky,
|
||||
},
|
||||
{
|
||||
metric: ratio.ratio2ySd.sma,
|
||||
name: "2y SMA",
|
||||
color: colors.indigo,
|
||||
},
|
||||
{
|
||||
metric: ratio.ratio4ySd.sma,
|
||||
name: "4y SMA",
|
||||
color: colors.purple,
|
||||
},
|
||||
{
|
||||
metric: ratio.ratioSd.sma,
|
||||
name: "All SMA",
|
||||
color: colors.rose,
|
||||
},
|
||||
]).map(({ metric, name, color }) =>
|
||||
line({
|
||||
metric,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.ratio,
|
||||
defaultActive: false,
|
||||
style: 1,
|
||||
}),
|
||||
),
|
||||
...pctMap.map(({ name: pctName, prop, color: pctColor }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
@@ -142,31 +141,118 @@ export function createPriceWithRatioOptions(
|
||||
color: pctColor,
|
||||
defaultActive: false,
|
||||
unit: Unit.ratio,
|
||||
options: { lineStyle: 1 },
|
||||
style: 1,
|
||||
}),
|
||||
),
|
||||
createPriceLine({ unit: Unit.ratio, number: 1 }),
|
||||
priceLine({ ctx, unit: Unit.ratio, number: 1 }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ZScores",
|
||||
tree: sdPats.map(({ nameAddon, titleAddon, sd }) => ({
|
||||
name: nameAddon,
|
||||
title: `${title} ${titleAddon} Z-Score`,
|
||||
top: sdBands(colors, sd).map(
|
||||
({ name: bandName, prop, color: bandColor }) =>
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: `${title} Z-Scores`,
|
||||
top: [
|
||||
line({ metric: priceMetric, name: legend, color, unit: Unit.usd }),
|
||||
line({
|
||||
metric: prop,
|
||||
name: bandName,
|
||||
color: bandColor,
|
||||
metric: ratio.ratio1ySd._0sdUsd,
|
||||
name: "1y 0σ",
|
||||
color: colors.orange,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
),
|
||||
bottom: [
|
||||
line({ metric: sd.zscore, name: "Z-Score", color, unit: Unit.sd }),
|
||||
...priceLines(ctx, Unit.sd, [0, 1, -1, 2, -2, 3, -3]),
|
||||
],
|
||||
})),
|
||||
line({
|
||||
metric: ratio.ratio2ySd._0sdUsd,
|
||||
name: "2y 0σ",
|
||||
color: colors.yellow,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio4ySd._0sdUsd,
|
||||
name: "4y 0σ",
|
||||
color: colors.lime,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratioSd._0sdUsd,
|
||||
name: "all 0σ",
|
||||
color: colors.blue,
|
||||
defaultActive: false,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
],
|
||||
bottom: [
|
||||
line({
|
||||
metric: ratio.ratioSd.zscore,
|
||||
name: "all",
|
||||
color: colors.blue,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio4ySd.zscore,
|
||||
name: "4y",
|
||||
color: colors.lime,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio2ySd.zscore,
|
||||
name: "2y",
|
||||
color: colors.yellow,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
line({
|
||||
metric: ratio.ratio1ySd.zscore,
|
||||
name: "1y",
|
||||
color: colors.orange,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
...priceLines({
|
||||
ctx,
|
||||
unit: Unit.sd,
|
||||
numbers: [0, 1, -1, 2, -2, 3, -3],
|
||||
defaultActive: false,
|
||||
}),
|
||||
],
|
||||
},
|
||||
...sdPats.map(({ nameAddon, titleAddon, sd }) => ({
|
||||
name: nameAddon,
|
||||
title: `${title} ${titleAddon} Z-Score`,
|
||||
top: [
|
||||
line({ metric: priceMetric, name: legend, color, unit: Unit.usd }),
|
||||
...sdBands(colors, sd).map(
|
||||
({ name: bandName, prop, color: bandColor }) =>
|
||||
line({
|
||||
metric: prop,
|
||||
name: bandName,
|
||||
color: bandColor,
|
||||
unit: Unit.usd,
|
||||
defaultActive: false,
|
||||
}),
|
||||
),
|
||||
],
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: sd.zscore,
|
||||
name: "Z-Score",
|
||||
color,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
priceLine({
|
||||
ctx,
|
||||
unit: Unit.sd,
|
||||
}),
|
||||
...priceLines({
|
||||
ctx,
|
||||
unit: Unit.sd,
|
||||
numbers: [1, -1, 2, -2, 3, -3],
|
||||
defaultActive: false,
|
||||
}),
|
||||
],
|
||||
})),
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -177,7 +263,6 @@ export function createPriceWithRatioOptions(
|
||||
* @param {ReturnType<typeof buildAverages>} averages
|
||||
*/
|
||||
export function createAveragesSection(ctx, averages) {
|
||||
|
||||
return {
|
||||
name: "Averages",
|
||||
tree: [
|
||||
@@ -188,7 +273,7 @@ export function createAveragesSection(ctx, averages) {
|
||||
tree: [
|
||||
{
|
||||
name: "Compare",
|
||||
title: `Market Price ${nameAddon} Moving Averages`,
|
||||
title: `Price ${metricAddon.toUpperCase()}s`,
|
||||
top: averages.map(({ id, color, sma, ema }) =>
|
||||
line({
|
||||
metric: (metricAddon === "sma" ? sma : ema).price,
|
||||
@@ -202,7 +287,7 @@ export function createAveragesSection(ctx, averages) {
|
||||
name,
|
||||
tree: createPriceWithRatioOptions(ctx, {
|
||||
ratio: metricAddon === "sma" ? sma : ema,
|
||||
title: `${name} Market Price ${nameAddon} Moving Average`,
|
||||
title: `${name} ${metricAddon.toUpperCase()}`,
|
||||
legend: "average",
|
||||
color,
|
||||
}),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { localhost } from "../../utils/env.js";
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { line } from "../series.js";
|
||||
import { candlestick, line } from "../series.js";
|
||||
import { buildAverages, createAveragesSection } from "./averages.js";
|
||||
import { createPerformanceSection } from "./performance.js";
|
||||
import { createIndicatorsSection } from "./indicators/index.js";
|
||||
@@ -43,6 +43,16 @@ export function createMarketSection(ctx) {
|
||||
name: "Oracle",
|
||||
title: "Oracle Price",
|
||||
top: [
|
||||
candlestick({
|
||||
metric: price.oracle.closeOhlcDollars,
|
||||
name: "close",
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
candlestick({
|
||||
metric: price.oracle.midOhlcDollars,
|
||||
name: "mid",
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: price.oracle.phaseDailyDollars.median,
|
||||
name: "o. p50",
|
||||
@@ -105,7 +115,7 @@ export function createMarketSection(ctx) {
|
||||
// Capitalization
|
||||
{
|
||||
name: "Capitalization",
|
||||
title: "Market Capitalization",
|
||||
title: "Market Cap",
|
||||
bottom: [
|
||||
line({
|
||||
metric: supply.marketCap,
|
||||
|
||||
@@ -45,17 +45,19 @@ export function createBandsSection(ctx, { range, movingAverage }) {
|
||||
},
|
||||
].map(({ id, title, min, max }) => ({
|
||||
name: id,
|
||||
title: `Bitcoin Price ${title} MinMax Bands`,
|
||||
title: `${title} MinMax`,
|
||||
top: [
|
||||
line({
|
||||
metric: min,
|
||||
name: "Min",
|
||||
key: `price-min`,
|
||||
color: colors.red,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
line({
|
||||
metric: max,
|
||||
name: "Max",
|
||||
key: `price-max`,
|
||||
color: colors.green,
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Momentum indicators (RSI, StochRSI, Stochastic, MACD) */
|
||||
|
||||
import { Unit } from "../../../utils/units.js";
|
||||
import { priceLine, priceLines } from "../../constants.js";
|
||||
import { line, histogram } from "../../series.js";
|
||||
|
||||
/**
|
||||
@@ -9,14 +10,14 @@ import { line, histogram } from "../../series.js";
|
||||
* @param {Market["indicators"]} indicators
|
||||
*/
|
||||
export function createMomentumSection(ctx, indicators) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
|
||||
return {
|
||||
name: "Momentum",
|
||||
tree: [
|
||||
{
|
||||
name: "RSI",
|
||||
title: "Relative Strength Index (14d)",
|
||||
title: "RSI (14d)",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.rsi14d,
|
||||
@@ -38,13 +39,14 @@ export function createMomentumSection(ctx, indicators) {
|
||||
defaultActive: false,
|
||||
unit: Unit.index,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.index, number: 70 }),
|
||||
createPriceLine({
|
||||
priceLine({ ctx, unit: Unit.index, number: 70 }),
|
||||
priceLine({
|
||||
ctx,
|
||||
unit: Unit.index,
|
||||
number: 50,
|
||||
defaultActive: false,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.index, number: 30 }),
|
||||
priceLine({ ctx, unit: Unit.index, number: 30 }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -69,8 +71,7 @@ export function createMomentumSection(ctx, indicators) {
|
||||
color: colors.orange,
|
||||
unit: Unit.index,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.index, number: 80 }),
|
||||
createPriceLine({ unit: Unit.index, number: 20 }),
|
||||
...priceLines({ ctx, unit: Unit.index, numbers: [80, 20] }),
|
||||
],
|
||||
},
|
||||
// {
|
||||
@@ -79,13 +80,12 @@ export function createMomentumSection(ctx, indicators) {
|
||||
// bottom: [
|
||||
// line({ metric: indicators.stochK, name: "K", color: colors.blue, unit: Unit.index }),
|
||||
// line({ metric: indicators.stochD, name: "D", color: colors.orange, unit: Unit.index }),
|
||||
// createPriceLine({ unit: Unit.index, number: 80 }),
|
||||
// createPriceLine({ unit: Unit.index, number: 20 }),
|
||||
// priceLines({ ctx, unit: Unit.index, numbers: [80, 20] }),
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
name: "MACD",
|
||||
title: "Moving Average Convergence Divergence",
|
||||
title: "MACD",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.macdLine,
|
||||
@@ -104,7 +104,7 @@ export function createMomentumSection(ctx, indicators) {
|
||||
name: "Histogram",
|
||||
unit: Unit.usd,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.usd }),
|
||||
priceLine({ ctx, unit: Unit.usd }),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/** On-chain indicators (Pi Cycle, Puell, NVT, Gini) */
|
||||
|
||||
import { Unit } from "../../../utils/units.js";
|
||||
import { line } from "../../series.js";
|
||||
import { priceLine } from "../../constants.js";
|
||||
import { baseline, line } from "../../series.js";
|
||||
|
||||
/**
|
||||
* Create On-chain section
|
||||
@@ -11,14 +12,14 @@ import { line } from "../../series.js";
|
||||
* @param {Market["movingAverage"]} args.movingAverage
|
||||
*/
|
||||
export function createOnchainSection(ctx, { indicators, movingAverage }) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
|
||||
return {
|
||||
name: "On-chain",
|
||||
tree: [
|
||||
{
|
||||
name: "Pi Cycle",
|
||||
title: "Pi Cycle Top Indicator",
|
||||
title: "Pi Cycle",
|
||||
top: [
|
||||
line({
|
||||
metric: movingAverage.price111dSma.price,
|
||||
@@ -34,13 +35,13 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) {
|
||||
}),
|
||||
],
|
||||
bottom: [
|
||||
line({
|
||||
baseline({
|
||||
metric: indicators.piCycle,
|
||||
name: "Pi Cycle",
|
||||
color: colors.purple,
|
||||
unit: Unit.ratio,
|
||||
base: 1,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.ratio, number: 1 }),
|
||||
priceLine({ ctx, unit: Unit.ratio, number: 1 }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -57,7 +58,7 @@ export function createOnchainSection(ctx, { indicators, movingAverage }) {
|
||||
},
|
||||
{
|
||||
name: "NVT",
|
||||
title: "Network Value to Transactions Ratio",
|
||||
title: "NVT Ratio",
|
||||
bottom: [
|
||||
line({
|
||||
metric: indicators.nvt,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Volatility indicators (Index, True Range, Choppiness, Sharpe, Sortino) */
|
||||
|
||||
import { Unit } from "../../../utils/units.js";
|
||||
import { priceLine, priceLines } from "../../constants.js";
|
||||
import { line } from "../../series.js";
|
||||
|
||||
/**
|
||||
@@ -11,14 +12,14 @@ import { line } from "../../series.js";
|
||||
* @param {Market["range"]} args.range
|
||||
*/
|
||||
export function createVolatilitySection(ctx, { volatility, range }) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
|
||||
return {
|
||||
name: "Volatility",
|
||||
tree: [
|
||||
{
|
||||
name: "Index",
|
||||
title: "Bitcoin Price Volatility Index",
|
||||
title: "Volatility Index",
|
||||
bottom: [
|
||||
line({
|
||||
metric: volatility.price1wVolatility,
|
||||
@@ -42,7 +43,7 @@ export function createVolatilitySection(ctx, { volatility, range }) {
|
||||
},
|
||||
{
|
||||
name: "True Range",
|
||||
title: "Bitcoin Price True Range",
|
||||
title: "True Range",
|
||||
bottom: [
|
||||
line({
|
||||
metric: range.priceTrueRange,
|
||||
@@ -54,7 +55,7 @@ export function createVolatilitySection(ctx, { volatility, range }) {
|
||||
},
|
||||
{
|
||||
name: "Choppiness",
|
||||
title: "Bitcoin Price Choppiness Index",
|
||||
title: "Choppiness Index",
|
||||
bottom: [
|
||||
line({
|
||||
metric: range.price2wChoppinessIndex,
|
||||
@@ -62,8 +63,7 @@ export function createVolatilitySection(ctx, { volatility, range }) {
|
||||
color: colors.red,
|
||||
unit: Unit.index,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.index, number: 61.8 }),
|
||||
createPriceLine({ unit: Unit.index, number: 38.2 }),
|
||||
...priceLines({ ctx, unit: Unit.index, numbers: [61.8, 38.2] }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -88,7 +88,7 @@ export function createVolatilitySection(ctx, { volatility, range }) {
|
||||
color: colors.lime,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.ratio }),
|
||||
priceLine({ ctx, unit: Unit.ratio }),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -113,7 +113,7 @@ export function createVolatilitySection(ctx, { volatility, range }) {
|
||||
color: colors.lime,
|
||||
unit: Unit.ratio,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.ratio }),
|
||||
priceLine({ ctx, unit: Unit.ratio }),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Investing section (DCA) */
|
||||
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { priceLine } from "../constants.js";
|
||||
import { line, baseline } from "../series.js";
|
||||
import { satsBtcUsd } from "../shared.js";
|
||||
import { periodIdToName } from "./utils.js";
|
||||
@@ -12,6 +13,7 @@ import { periodIdToName } from "./utils.js";
|
||||
*/
|
||||
export function buildDcaClasses(colors, dca) {
|
||||
return /** @type {const} */ ([
|
||||
[2026, "rose", true],
|
||||
[2025, "pink", true],
|
||||
[2024, "fuchsia", true],
|
||||
[2023, "purple", true],
|
||||
@@ -42,7 +44,7 @@ export function buildDcaClasses(colors, dca) {
|
||||
* @param {Market["returns"]} args.returns
|
||||
*/
|
||||
export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
const dcaClasses = buildDcaClasses(colors, dca);
|
||||
|
||||
return {
|
||||
@@ -77,7 +79,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
tree: [
|
||||
{
|
||||
name: "Cost basis",
|
||||
title: `${name} DCA vs Lump Sum (Cost Basis)`,
|
||||
title: `${name} Cost Basis`,
|
||||
top: [
|
||||
line({
|
||||
metric: dcaCostBasis,
|
||||
@@ -95,7 +97,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
},
|
||||
{
|
||||
name: "Returns",
|
||||
title: `${name} DCA vs Lump Sum (Returns)`,
|
||||
title: `${name} Returns`,
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: dcaReturns,
|
||||
@@ -105,18 +107,18 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
baseline({
|
||||
metric: priceReturns,
|
||||
name: "Lump sum",
|
||||
color: [colors.lime, colors.red],
|
||||
color: [colors.cyan, colors.orange],
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
createPriceLine({ unit: Unit.percentage }),
|
||||
priceLine({ ctx, unit: Unit.percentage }),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Stack",
|
||||
title: `${name} DCA vs Lump Sum Stack ($100/day)`,
|
||||
title: `${name} Stack`,
|
||||
bottom: [
|
||||
...satsBtcUsd( dcaStack, "DCA", colors.green),
|
||||
...satsBtcUsd( lumpSumStack, "Lump sum", colors.orange),
|
||||
...satsBtcUsd(dcaStack, "DCA", colors.green),
|
||||
...satsBtcUsd(lumpSumStack, "Lump sum", colors.orange),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -134,7 +136,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
tree: [
|
||||
{
|
||||
name: "Cost basis",
|
||||
title: "DCA Cost Basis by Year",
|
||||
title: "DCA Cost Basis",
|
||||
top: dcaClasses.map(
|
||||
({ year, color, defaultActive, costBasis }) =>
|
||||
line({
|
||||
@@ -148,7 +150,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
},
|
||||
{
|
||||
name: "Returns",
|
||||
title: "DCA Returns by Year",
|
||||
title: "DCA Returns",
|
||||
bottom: dcaClasses.map(
|
||||
({ year, color, defaultActive, returns }) =>
|
||||
baseline({
|
||||
@@ -162,10 +164,10 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
},
|
||||
{
|
||||
name: "Stack",
|
||||
title: "DCA Stack by Year ($100/day)",
|
||||
title: "DCA Stack",
|
||||
bottom: dcaClasses.flatMap(
|
||||
({ year, color, defaultActive, stack }) =>
|
||||
satsBtcUsd( stack, `${year}`, color, { defaultActive }),
|
||||
satsBtcUsd(stack, `${year}`, color, { defaultActive }),
|
||||
),
|
||||
},
|
||||
],
|
||||
@@ -176,7 +178,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
tree: [
|
||||
{
|
||||
name: "Cost basis",
|
||||
title: `DCA Class ${year} Cost Basis`,
|
||||
title: `${year} Cost Basis`,
|
||||
top: [
|
||||
line({
|
||||
metric: costBasis,
|
||||
@@ -188,7 +190,7 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
},
|
||||
{
|
||||
name: "Returns",
|
||||
title: `DCA Class ${year} Returns`,
|
||||
title: `${year} Returns`,
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: returns,
|
||||
@@ -200,8 +202,8 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
|
||||
},
|
||||
{
|
||||
name: "Stack",
|
||||
title: `DCA Class ${year} Stack ($100/day)`,
|
||||
bottom: satsBtcUsd( stack, "Stack", color),
|
||||
title: `${year} Stack`,
|
||||
bottom: satsBtcUsd(stack, "Stack", color),
|
||||
},
|
||||
],
|
||||
})),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Performance section */
|
||||
|
||||
import { Unit } from "../../utils/units.js";
|
||||
import { priceLine } from "../constants.js";
|
||||
import { baseline } from "../series.js";
|
||||
import { periodIdToName } from "./utils.js";
|
||||
|
||||
@@ -10,7 +11,7 @@ import { periodIdToName } from "./utils.js";
|
||||
* @param {Market["returns"]} returns
|
||||
*/
|
||||
export function createPerformanceSection(ctx, returns) {
|
||||
const { colors, createPriceLine } = ctx;
|
||||
const { colors } = ctx;
|
||||
|
||||
return {
|
||||
name: "Performance",
|
||||
@@ -34,7 +35,7 @@ export function createPerformanceSection(ctx, returns) {
|
||||
const name = periodIdToName(id, true);
|
||||
return {
|
||||
name,
|
||||
title: `${name} Performance`,
|
||||
title: `${name} Returns`,
|
||||
bottom: [
|
||||
baseline({
|
||||
metric: priceReturns,
|
||||
@@ -46,12 +47,12 @@ export function createPerformanceSection(ctx, returns) {
|
||||
baseline({
|
||||
metric: cagr,
|
||||
name: "CAGR",
|
||||
color: [colors.lime, colors.pink],
|
||||
color: [colors.cyan, colors.orange],
|
||||
unit: Unit.percentage,
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
createPriceLine({ unit: Unit.percentage }),
|
||||
priceLine({ ctx, unit: Unit.percentage }),
|
||||
],
|
||||
};
|
||||
}),
|
||||
|
||||
@@ -8,19 +8,34 @@ import { Unit } from "../utils/units.js";
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {LineStyle} [args.style]
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {LineSeriesPartialOptions} [args.options]
|
||||
* @returns {FetchedLineSeriesBlueprint}
|
||||
*/
|
||||
export function line({ metric, name, color, defaultActive, unit, options }) {
|
||||
export function line({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
style,
|
||||
color,
|
||||
defaultActive,
|
||||
unit,
|
||||
options,
|
||||
}) {
|
||||
return {
|
||||
metric,
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
unit,
|
||||
defaultActive,
|
||||
options,
|
||||
options: {
|
||||
lineStyle: style,
|
||||
...options,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,16 +45,26 @@ export function line({ metric, name, color, defaultActive, unit, options }) {
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {Color} [args.color]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {LineSeriesPartialOptions} [args.options]
|
||||
* @returns {FetchedDotsSeriesBlueprint}
|
||||
*/
|
||||
export function dots({ metric, name, color, defaultActive, unit, options }) {
|
||||
export function dots({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
color,
|
||||
defaultActive,
|
||||
unit,
|
||||
options,
|
||||
}) {
|
||||
return {
|
||||
type: /** @type {const} */ ("Dots"),
|
||||
metric,
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
unit,
|
||||
defaultActive,
|
||||
@@ -53,6 +78,7 @@ export function dots({ metric, name, color, defaultActive, unit, options }) {
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {string} args.name
|
||||
* @param {Unit} args.unit
|
||||
* @param {string} [args.key] - Optional key for persistence (derived from name if not provided)
|
||||
* @param {[Color, Color]} [args.colors] - [upColor, downColor] for legend
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {CandlestickSeriesPartialOptions} [args.options]
|
||||
@@ -61,6 +87,7 @@ export function dots({ metric, name, color, defaultActive, unit, options }) {
|
||||
export function candlestick({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
colors,
|
||||
defaultActive,
|
||||
unit,
|
||||
@@ -70,6 +97,7 @@ export function candlestick({
|
||||
type: /** @type {const} */ ("Candlestick"),
|
||||
metric,
|
||||
title: name,
|
||||
key,
|
||||
colors,
|
||||
unit,
|
||||
defaultActive,
|
||||
@@ -83,9 +111,9 @@ export function candlestick({
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {string} args.name
|
||||
* @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 {boolean} [args.defaultActive]
|
||||
* @param {boolean} [args.defaultActive]
|
||||
* @param {number | undefined} [args.base]
|
||||
* @param {BaselineSeriesPartialOptions} [args.options]
|
||||
* @returns {FetchedBaselineSeriesBlueprint}
|
||||
@@ -93,6 +121,7 @@ export function candlestick({
|
||||
export function baseline({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
color,
|
||||
defaultActive,
|
||||
unit,
|
||||
@@ -104,6 +133,7 @@ export function baseline({
|
||||
type: /** @type {const} */ ("Baseline"),
|
||||
metric,
|
||||
title: name,
|
||||
key,
|
||||
color: isTuple ? undefined : color,
|
||||
colors: isTuple ? color : undefined,
|
||||
unit,
|
||||
@@ -123,6 +153,7 @@ export function baseline({
|
||||
* @param {AnyMetricPattern} args.metric
|
||||
* @param {string} args.name
|
||||
* @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 {boolean} [args.defaultActive]
|
||||
* @param {HistogramSeriesPartialOptions} [args.options]
|
||||
@@ -131,6 +162,7 @@ export function baseline({
|
||||
export function histogram({
|
||||
metric,
|
||||
name,
|
||||
key,
|
||||
color,
|
||||
defaultActive,
|
||||
unit,
|
||||
@@ -140,6 +172,7 @@ export function histogram({
|
||||
type: /** @type {const} */ ("Histogram"),
|
||||
metric,
|
||||
title: name,
|
||||
key,
|
||||
color,
|
||||
unit,
|
||||
defaultActive,
|
||||
@@ -238,7 +271,7 @@ export function fromBlockSize(colors, pattern, title, color) {
|
||||
{ metric: pattern.average, title: "Average", defaultActive: false },
|
||||
{
|
||||
metric: pattern.cumulative,
|
||||
title: `${title} (cum.)`,
|
||||
title: `Cumulative`,
|
||||
color: colors.cyan,
|
||||
defaultActive: false,
|
||||
},
|
||||
@@ -291,72 +324,72 @@ export function fromBlockSize(colors, pattern, title, color) {
|
||||
* Create series from a SizePattern ({ average, sum, cumulative, min, max, percentiles })
|
||||
* @param {Colors} colors
|
||||
* @param {AnyStatsPattern} pattern
|
||||
* @param {string} title
|
||||
* @param {Unit} unit
|
||||
* @param {string} [title]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function fromSizePattern(colors, pattern, title, unit) {
|
||||
export function fromSizePattern(colors, pattern, unit, title = "") {
|
||||
return [
|
||||
{ metric: pattern.average, title: `${title} avg`, unit },
|
||||
{ metric: pattern.average, title: `${title} avg`.trim(), unit },
|
||||
{
|
||||
metric: pattern.sum,
|
||||
title: `${title} sum`,
|
||||
title: `${title} sum`.trim(),
|
||||
color: colors.blue,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.cumulative,
|
||||
title: `${title} cumulative`,
|
||||
title: `${title} cumulative`.trim(),
|
||||
color: colors.indigo,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.min,
|
||||
title: `${title} min`,
|
||||
title: `${title} min`.trim(),
|
||||
color: colors.red,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.max,
|
||||
title: `${title} max`,
|
||||
title: `${title} max`.trim(),
|
||||
color: colors.green,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct10,
|
||||
title: `${title} pct10`,
|
||||
title: `${title} pct10`.trim(),
|
||||
color: colors.rose,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct25,
|
||||
title: `${title} pct25`,
|
||||
title: `${title} pct25`.trim(),
|
||||
color: colors.pink,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.median,
|
||||
title: `${title} median`,
|
||||
title: `${title} median`.trim(),
|
||||
color: colors.purple,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct75,
|
||||
title: `${title} pct75`,
|
||||
title: `${title} pct75`.trim(),
|
||||
color: colors.violet,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct90,
|
||||
title: `${title} pct90`,
|
||||
title: `${title} pct90`.trim(),
|
||||
color: colors.fuchsia,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
@@ -368,65 +401,148 @@ export function fromSizePattern(colors, pattern, title, unit) {
|
||||
* Create series from a FullnessPattern ({ base, average, sum, cumulative, min, max, percentiles })
|
||||
* @param {Colors} colors
|
||||
* @param {FullnessPattern<any>} pattern
|
||||
* @param {string} title
|
||||
* @param {Unit} unit
|
||||
* @param {string} [title]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function fromFullnessPattern(colors, pattern, title, unit) {
|
||||
export function fromFullnessPattern(colors, pattern, unit, title = "") {
|
||||
return [
|
||||
{ metric: pattern.base, title, unit },
|
||||
{ metric: pattern.base, title: title || "base", unit },
|
||||
{
|
||||
metric: pattern.average,
|
||||
title: `${title} avg`,
|
||||
title: `${title} avg`.trim(),
|
||||
color: colors.purple,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.min,
|
||||
title: `${title} min`,
|
||||
title: `${title} min`.trim(),
|
||||
color: colors.red,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.max,
|
||||
title: `${title} max`,
|
||||
title: `${title} max`.trim(),
|
||||
color: colors.green,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct10,
|
||||
title: `${title} pct10`,
|
||||
title: `${title} pct10`.trim(),
|
||||
color: colors.rose,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct25,
|
||||
title: `${title} pct25`,
|
||||
title: `${title} pct25`.trim(),
|
||||
color: colors.pink,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.median,
|
||||
title: `${title} median`,
|
||||
title: `${title} median`.trim(),
|
||||
color: colors.violet,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct75,
|
||||
title: `${title} pct75`,
|
||||
title: `${title} pct75`.trim(),
|
||||
color: colors.fuchsia,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct90,
|
||||
title: `${title} pct90`,
|
||||
title: `${title} pct90`.trim(),
|
||||
color: colors.amber,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create series from a DollarsPattern ({ base, sum, cumulative, average, min, max, percentiles })
|
||||
* @param {Colors} colors
|
||||
* @param {DollarsPattern<any>} pattern
|
||||
* @param {Unit} unit
|
||||
* @param {string} [title]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function fromDollarsPattern(colors, pattern, unit, title = "") {
|
||||
return [
|
||||
{ metric: pattern.base, title: title || "base", unit },
|
||||
{
|
||||
metric: pattern.sum,
|
||||
title: `${title} sum`.trim(),
|
||||
color: colors.blue,
|
||||
unit,
|
||||
},
|
||||
{
|
||||
metric: pattern.cumulative,
|
||||
title: `${title} cumulative`.trim(),
|
||||
color: colors.cyan,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.average,
|
||||
title: `${title} avg`.trim(),
|
||||
color: colors.purple,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.min,
|
||||
title: `${title} min`.trim(),
|
||||
color: colors.red,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.max,
|
||||
title: `${title} max`.trim(),
|
||||
color: colors.green,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct10,
|
||||
title: `${title} pct10`.trim(),
|
||||
color: colors.rose,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct25,
|
||||
title: `${title} pct25`.trim(),
|
||||
color: colors.pink,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.median,
|
||||
title: `${title} median`.trim(),
|
||||
color: colors.violet,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct75,
|
||||
title: `${title} pct75`.trim(),
|
||||
color: colors.fuchsia,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct90,
|
||||
title: `${title} pct90`.trim(),
|
||||
color: colors.amber,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
@@ -438,58 +554,58 @@ export function fromFullnessPattern(colors, pattern, title, unit) {
|
||||
* Create series from a FeeRatePattern ({ average, min, max, percentiles })
|
||||
* @param {Colors} colors
|
||||
* @param {FeeRatePattern<any>} pattern
|
||||
* @param {string} title
|
||||
* @param {Unit} unit
|
||||
* @param {string} [title]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function fromFeeRatePattern(colors, pattern, title, unit) {
|
||||
export function fromFeeRatePattern(colors, pattern, unit, title = "") {
|
||||
return [
|
||||
{ metric: pattern.average, title: `${title} avg`, unit },
|
||||
{ metric: pattern.average, title: `${title} avg`.trim(), unit },
|
||||
{
|
||||
metric: pattern.min,
|
||||
title: `${title} min`,
|
||||
title: `${title} min`.trim(),
|
||||
color: colors.red,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.max,
|
||||
title: `${title} max`,
|
||||
title: `${title} max`.trim(),
|
||||
color: colors.green,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct10,
|
||||
title: `${title} pct10`,
|
||||
title: `${title} pct10`.trim(),
|
||||
color: colors.rose,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct25,
|
||||
title: `${title} pct25`,
|
||||
title: `${title} pct25`.trim(),
|
||||
color: colors.pink,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.median,
|
||||
title: `${title} median`,
|
||||
title: `${title} median`.trim(),
|
||||
color: colors.purple,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct75,
|
||||
title: `${title} pct75`,
|
||||
title: `${title} pct75`.trim(),
|
||||
color: colors.violet,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct90,
|
||||
title: `${title} pct90`,
|
||||
title: `${title} pct90`.trim(),
|
||||
color: colors.fuchsia,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
@@ -506,9 +622,9 @@ export function fromFeeRatePattern(colors, pattern, title, unit) {
|
||||
*/
|
||||
export function fromCoinbasePattern(colors, pattern, title) {
|
||||
return [
|
||||
...fromFullnessPattern(colors, pattern.sats, title, Unit.sats),
|
||||
...fromFullnessPattern(colors, pattern.bitcoin, title, Unit.btc),
|
||||
...fromFullnessPattern(colors, pattern.dollars, title, Unit.usd),
|
||||
...fromFullnessPattern(colors, pattern.sats, Unit.sats, title),
|
||||
...fromFullnessPattern(colors, pattern.bitcoin, Unit.btc, title),
|
||||
...fromFullnessPattern(colors, pattern.dollars, Unit.usd, title),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -610,8 +726,8 @@ export function fromBitcoinPatternWithUnit(
|
||||
* Create sum/cumulative series from a BlockCountPattern with explicit unit and colors
|
||||
* @param {Colors} colors
|
||||
* @param {BlockCountPattern<any>} pattern
|
||||
* @param {string} title
|
||||
* @param {Unit} unit
|
||||
* @param {string} [title]
|
||||
* @param {Color} [sumColor]
|
||||
* @param {Color} [cumulativeColor]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
@@ -619,21 +735,21 @@ export function fromBitcoinPatternWithUnit(
|
||||
export function fromBlockCountWithUnit(
|
||||
colors,
|
||||
pattern,
|
||||
title,
|
||||
unit,
|
||||
title,
|
||||
sumColor,
|
||||
cumulativeColor,
|
||||
) {
|
||||
return [
|
||||
{
|
||||
metric: pattern.sum,
|
||||
title: `${title} sum`,
|
||||
title: `${title} sum`.trim(),
|
||||
color: sumColor,
|
||||
unit,
|
||||
},
|
||||
{
|
||||
metric: pattern.cumulative,
|
||||
title: `${title} cumulative`,
|
||||
title: `${title} cumulative`.trim(),
|
||||
color: cumulativeColor ?? colors.blue,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
@@ -645,66 +761,66 @@ export function fromBlockCountWithUnit(
|
||||
* Create series from an IntervalPattern (base + average/min/max/median/percentiles, no sum/cumulative)
|
||||
* @param {Colors} colors
|
||||
* @param {IntervalPattern} pattern
|
||||
* @param {string} title
|
||||
* @param {Unit} unit
|
||||
* @param {string} [title]
|
||||
* @param {Color} [color]
|
||||
* @returns {AnyFetchedSeriesBlueprint[]}
|
||||
*/
|
||||
export function fromIntervalPattern(colors, pattern, title, unit, color) {
|
||||
export function fromIntervalPattern(colors, pattern, unit, title = "", color) {
|
||||
return [
|
||||
{ metric: pattern.base, title, color, unit },
|
||||
{ metric: pattern.base, title: title ?? "base", color, unit },
|
||||
{
|
||||
metric: pattern.average,
|
||||
title: `${title} avg`,
|
||||
color: colors.purple,
|
||||
title: `${title} avg`.trim(),
|
||||
color: colors.cyan,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.min,
|
||||
title: `${title} min`,
|
||||
title: `${title} min`.trim(),
|
||||
color: colors.red,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.max,
|
||||
title: `${title} max`,
|
||||
title: `${title} max`.trim(),
|
||||
color: colors.green,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.median,
|
||||
title: `${title} median`,
|
||||
title: `${title} median`.trim(),
|
||||
color: colors.violet,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct10,
|
||||
title: `${title} pct10`,
|
||||
title: `${title} pct10`.trim(),
|
||||
color: colors.rose,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct25,
|
||||
title: `${title} pct25`,
|
||||
title: `${title} pct25`.trim(),
|
||||
color: colors.pink,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct75,
|
||||
title: `${title} pct75`,
|
||||
title: `${title} pct75`.trim(),
|
||||
color: colors.fuchsia,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
},
|
||||
{
|
||||
metric: pattern.pct90,
|
||||
title: `${title} pct90`,
|
||||
title: `${title} pct90`.trim(),
|
||||
color: colors.amber,
|
||||
unit,
|
||||
defaultActive: false,
|
||||
|
||||
@@ -15,21 +15,23 @@ export function satsBtcUsd(pattern, name, color, options) {
|
||||
const { defaultActive } = options || {};
|
||||
return [
|
||||
line({ metric: pattern.sats, name, color, unit: Unit.sats, defaultActive }),
|
||||
line({ metric: pattern.bitcoin, name, color, unit: Unit.btc, defaultActive }),
|
||||
line({ metric: pattern.dollars, name, color, unit: Unit.usd, defaultActive }),
|
||||
line({
|
||||
metric: pattern.bitcoin,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.btc,
|
||||
defaultActive,
|
||||
}),
|
||||
line({
|
||||
metric: pattern.dollars,
|
||||
name,
|
||||
color,
|
||||
unit: Unit.usd,
|
||||
defaultActive,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create multiple price lines with the same unit
|
||||
* @param {PartialContext} ctx
|
||||
* @param {Unit} unit
|
||||
* @param {number[]} numbers
|
||||
*/
|
||||
export function priceLines(ctx, unit, numbers) {
|
||||
return numbers.map((n) => ctx.createPriceLine({ unit, number: n }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build percentile USD mappings from a ratio pattern
|
||||
* @param {Colors} colors
|
||||
@@ -37,11 +39,11 @@ export function priceLines(ctx, unit, numbers) {
|
||||
*/
|
||||
export function percentileUsdMap(colors, ratio) {
|
||||
return /** @type {const} */ ([
|
||||
{ name: "pct99", prop: ratio.ratioPct99Usd, color: colors.rose },
|
||||
{ name: "pct98", prop: ratio.ratioPct98Usd, color: colors.pink },
|
||||
{ name: "pct95", prop: ratio.ratioPct95Usd, color: colors.fuchsia },
|
||||
{ name: "pct5", prop: ratio.ratioPct5Usd, color: colors.cyan },
|
||||
{ name: "pct98", prop: ratio.ratioPct98Usd, color: colors.pink },
|
||||
{ name: "pct2", prop: ratio.ratioPct2Usd, color: colors.sky },
|
||||
{ name: "pct99", prop: ratio.ratioPct99Usd, color: colors.rose },
|
||||
{ name: "pct1", prop: ratio.ratioPct1Usd, color: colors.blue },
|
||||
]);
|
||||
}
|
||||
@@ -53,11 +55,11 @@ export function percentileUsdMap(colors, ratio) {
|
||||
*/
|
||||
export function percentileMap(colors, ratio) {
|
||||
return /** @type {const} */ ([
|
||||
{ name: "pct99", prop: ratio.ratioPct99, color: colors.rose },
|
||||
{ name: "pct98", prop: ratio.ratioPct98, color: colors.pink },
|
||||
{ name: "pct95", prop: ratio.ratioPct95, color: colors.fuchsia },
|
||||
{ name: "pct5", prop: ratio.ratioPct5, color: colors.cyan },
|
||||
{ name: "pct98", prop: ratio.ratioPct98, color: colors.pink },
|
||||
{ name: "pct2", prop: ratio.ratioPct2, color: colors.sky },
|
||||
{ name: "pct99", prop: ratio.ratioPct99, color: colors.rose },
|
||||
{ name: "pct1", prop: ratio.ratioPct1, color: colors.blue },
|
||||
]);
|
||||
}
|
||||
@@ -84,16 +86,16 @@ export function sdBands(colors, sd) {
|
||||
return /** @type {const} */ ([
|
||||
{ name: "0σ", prop: sd._0sdUsd, color: colors.lime },
|
||||
{ name: "+0.5σ", prop: sd.p05sdUsd, color: colors.yellow },
|
||||
{ name: "+1σ", prop: sd.p1sdUsd, color: colors.amber },
|
||||
{ name: "+1.5σ", prop: sd.p15sdUsd, color: colors.orange },
|
||||
{ name: "+2σ", prop: sd.p2sdUsd, color: colors.red },
|
||||
{ name: "+2.5σ", prop: sd.p25sdUsd, color: colors.rose },
|
||||
{ name: "+3σ", prop: sd.p3sd, color: colors.pink },
|
||||
{ name: "−0.5σ", prop: sd.m05sdUsd, color: colors.teal },
|
||||
{ name: "+1σ", prop: sd.p1sdUsd, color: colors.amber },
|
||||
{ name: "−1σ", prop: sd.m1sdUsd, color: colors.cyan },
|
||||
{ name: "+1.5σ", prop: sd.p15sdUsd, color: colors.orange },
|
||||
{ name: "−1.5σ", prop: sd.m15sdUsd, color: colors.sky },
|
||||
{ name: "+2σ", prop: sd.p2sdUsd, color: colors.red },
|
||||
{ name: "−2σ", prop: sd.m2sdUsd, color: colors.blue },
|
||||
{ name: "+2.5σ", prop: sd.p25sdUsd, color: colors.rose },
|
||||
{ name: "−2.5σ", prop: sd.m25sdUsd, color: colors.indigo },
|
||||
{ name: "+3σ", prop: sd.p3sd, color: colors.pink },
|
||||
{ name: "−3σ", prop: sd.m3sd, color: colors.violet },
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* @typedef {Object} BaseSeriesBlueprint
|
||||
* @property {string} title
|
||||
* @property {string} [key] - Optional key for persistence (derived from title if not provided)
|
||||
* @property {boolean} [defaultActive]
|
||||
*
|
||||
* @typedef {Object} BaselineSeriesBlueprintSpecific
|
||||
@@ -239,18 +240,16 @@
|
||||
* @property {(pattern: BlockCountPattern<any>, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCount
|
||||
* @property {(pattern: FullnessPattern<any>, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBitcoin
|
||||
* @property {(pattern: AnyStatsPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockSize
|
||||
* @property {(pattern: AnyStatsPattern, title: string, unit: Unit) => AnyFetchedSeriesBlueprint[]} fromSizePattern
|
||||
* @property {(pattern: FullnessPattern<any>, title: string, unit: Unit) => AnyFetchedSeriesBlueprint[]} fromFullnessPattern
|
||||
* @property {(pattern: FeeRatePattern<any>, title: string, unit: Unit) => AnyFetchedSeriesBlueprint[]} fromFeeRatePattern
|
||||
* @property {(pattern: AnyStatsPattern, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromSizePattern
|
||||
* @property {(pattern: FullnessPattern<any>, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromFullnessPattern
|
||||
* @property {(pattern: DollarsPattern<any>, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromDollarsPattern
|
||||
* @property {(pattern: FeeRatePattern<any>, unit: Unit, title?: string) => AnyFetchedSeriesBlueprint[]} fromFeeRatePattern
|
||||
* @property {(pattern: CoinbasePattern, title: string) => AnyFetchedSeriesBlueprint[]} fromCoinbasePattern
|
||||
* @property {(pattern: ValuePattern, title: string, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromValuePattern
|
||||
* @property {(pattern: { sum: AnyMetricPattern, cumulative: AnyMetricPattern }, title: string, unit: Unit, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromBitcoinPatternWithUnit
|
||||
* @property {(pattern: BlockCountPattern<any>, title: string, unit: Unit, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCountWithUnit
|
||||
* @property {(pattern: IntervalPattern, title: string, unit: Unit, color?: Color) => AnyFetchedSeriesBlueprint[]} fromIntervalPattern
|
||||
* @property {(pattern: BlockCountPattern<any>, unit: Unit, title?: string, sumColor?: Color, cumulativeColor?: Color) => AnyFetchedSeriesBlueprint[]} fromBlockCountWithUnit
|
||||
* @property {(pattern: IntervalPattern, unit: Unit, title?: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromIntervalPattern
|
||||
* @property {(pattern: SupplyPattern, title: string, color?: Color) => AnyFetchedSeriesBlueprint[]} fromSupplyPattern
|
||||
* @property {(args: { number?: number, name?: string, defaultActive?: boolean, lineStyle?: LineStyle, color?: Color, unit: Unit }) => FetchedLineSeriesBlueprint} createPriceLine
|
||||
* @property {(args: { numbers: number[], unit: Unit }) => FetchedLineSeriesBlueprint[]} createPriceLines
|
||||
* @property {(args: { constant: AnyMetricPattern, name: string, unit: Unit, color?: Color, lineStyle?: number, defaultActive?: boolean }) => FetchedLineSeriesBlueprint} constantLine
|
||||
*/
|
||||
|
||||
// Re-export for type consumers
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
/** Track unused metrics (dev only) */
|
||||
|
||||
import { localhost } from "../utils/env.js";
|
||||
|
||||
/** @type {Set<AnyMetricPattern> | null} */
|
||||
export const unused = localhost ? new Set() : null;
|
||||
/** @type {Map<AnyMetricPattern, string[]> | null} */
|
||||
export const unused = localhost ? new Map() : null;
|
||||
|
||||
/**
|
||||
* Walk and collect AnyMetricPatterns
|
||||
* @param {TreeNode | null | undefined} node
|
||||
* @param {Set<AnyMetricPattern>} set
|
||||
* @param {Map<AnyMetricPattern, string[]>} map
|
||||
* @param {string[]} path
|
||||
*/
|
||||
function walk(node, set) {
|
||||
function walk(node, map, path) {
|
||||
if (node && "by" in node) {
|
||||
set.add(/** @type {AnyMetricPattern} */ (node));
|
||||
map.set(/** @type {AnyMetricPattern} */ (node), path);
|
||||
} else if (node && typeof node === "object") {
|
||||
for (const value of Object.values(node)) {
|
||||
walk(/** @type {TreeNode | null | undefined} */ (value), set);
|
||||
for (const [key, value] of Object.entries(node)) {
|
||||
walk(/** @type {TreeNode | null | undefined} */ (value), map, [
|
||||
...path,
|
||||
key,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +26,7 @@ function walk(node, set) {
|
||||
* @param {TreeNode} tree
|
||||
*/
|
||||
export function collect(tree) {
|
||||
if (unused) walk(tree, unused);
|
||||
if (unused) walk(tree, unused, []);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,6 +40,22 @@ export function markUsed(metric) {
|
||||
/** Log unused metrics to console */
|
||||
export function logUnused() {
|
||||
if (!unused?.size) return;
|
||||
const paths = [...unused].map((m) => Object.values(m.by)[0].path);
|
||||
console.warn("Unused metrics:", paths);
|
||||
|
||||
/** @type {Record<string, any>} */
|
||||
const tree = {};
|
||||
|
||||
for (const path of unused.values()) {
|
||||
let current = tree;
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
const part = path[i];
|
||||
if (i === path.length - 1) {
|
||||
current[part] = null;
|
||||
} else {
|
||||
current[part] = current[part] || {};
|
||||
current = current[part];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Unused metrics:", { count: unused.size, tree });
|
||||
}
|
||||
|
||||
@@ -81,6 +81,10 @@
|
||||
* @template T
|
||||
* @typedef {Brk.DollarsPattern<T>} SizePattern
|
||||
*/
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Brk.DollarsPattern<T>} DollarsPattern
|
||||
*/
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Brk.CountPattern2<T>} CountStatsPattern
|
||||
|
||||
@@ -41,7 +41,8 @@ a {
|
||||
color: var(--off-color);
|
||||
content: "↗";
|
||||
align-self: baseline;
|
||||
font-size: 75%;
|
||||
font-weight: 300;
|
||||
|
||||
margin-left: 0.25rem;
|
||||
line-height: 1;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
--light-gray: oklch(90% 0.01 44);
|
||||
--gray: oklch(60% 0.01 44);
|
||||
--dark-gray: oklch(30% 0.01 44);
|
||||
--black: oklch(15% 0.005 44);
|
||||
--black: oklch(16% 0.005 44);
|
||||
--red: oklch(0.607 0.241 26.328);
|
||||
--orange: oklch(67.64% 0.191 44.41);
|
||||
--amber: oklch(0.7175 0.1835 64.199);
|
||||
|
||||
Reference in New Issue
Block a user