mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-25 09:48:10 -07:00
website: snapshot
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user