mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -3325,8 +3325,10 @@ dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
|
||||
@@ -1268,56 +1268,6 @@ impl Price111dSmaPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct ActivePriceRatioPattern {
|
||||
pub ratio: MetricPattern4<StoredF32>,
|
||||
pub ratio_1m_sma: MetricPattern4<StoredF32>,
|
||||
pub ratio_1w_sma: MetricPattern4<StoredF32>,
|
||||
pub ratio_1y_sd: Ratio1ySdPattern,
|
||||
pub ratio_2y_sd: Ratio1ySdPattern,
|
||||
pub ratio_4y_sd: Ratio1ySdPattern,
|
||||
pub ratio_pct1: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct1_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct2: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct2_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct5: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct5_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct95: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct95_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct98: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct98_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct99: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct99_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_sd: Ratio1ySdPattern,
|
||||
}
|
||||
|
||||
impl ActivePriceRatioPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
ratio: MetricPattern4::new(client.clone(), acc.clone()),
|
||||
ratio_1m_sma: MetricPattern4::new(client.clone(), _m(&acc, "1m_sma")),
|
||||
ratio_1w_sma: MetricPattern4::new(client.clone(), _m(&acc, "1w_sma")),
|
||||
ratio_1y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "1y")),
|
||||
ratio_2y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "2y")),
|
||||
ratio_4y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "4y")),
|
||||
ratio_pct1: MetricPattern4::new(client.clone(), _m(&acc, "pct1")),
|
||||
ratio_pct1_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct1_usd")),
|
||||
ratio_pct2: MetricPattern4::new(client.clone(), _m(&acc, "pct2")),
|
||||
ratio_pct2_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct2_usd")),
|
||||
ratio_pct5: MetricPattern4::new(client.clone(), _m(&acc, "pct5")),
|
||||
ratio_pct5_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct5_usd")),
|
||||
ratio_pct95: MetricPattern4::new(client.clone(), _m(&acc, "pct95")),
|
||||
ratio_pct95_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct95_usd")),
|
||||
ratio_pct98: MetricPattern4::new(client.clone(), _m(&acc, "pct98")),
|
||||
ratio_pct98_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct98_usd")),
|
||||
ratio_pct99: MetricPattern4::new(client.clone(), _m(&acc, "pct99")),
|
||||
ratio_pct99_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct99_usd")),
|
||||
ratio_sd: Ratio1ySdPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct PercentilesPattern {
|
||||
pub pct05: MetricPattern4<Dollars>,
|
||||
@@ -1368,6 +1318,56 @@ impl PercentilesPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct ActivePriceRatioPattern {
|
||||
pub ratio: MetricPattern4<StoredF32>,
|
||||
pub ratio_1m_sma: MetricPattern4<StoredF32>,
|
||||
pub ratio_1w_sma: MetricPattern4<StoredF32>,
|
||||
pub ratio_1y_sd: Ratio1ySdPattern,
|
||||
pub ratio_2y_sd: Ratio1ySdPattern,
|
||||
pub ratio_4y_sd: Ratio1ySdPattern,
|
||||
pub ratio_pct1: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct1_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct2: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct2_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct5: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct5_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct95: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct95_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct98: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct98_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_pct99: MetricPattern4<StoredF32>,
|
||||
pub ratio_pct99_usd: MetricPattern4<Dollars>,
|
||||
pub ratio_sd: Ratio1ySdPattern,
|
||||
}
|
||||
|
||||
impl ActivePriceRatioPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
ratio: MetricPattern4::new(client.clone(), acc.clone()),
|
||||
ratio_1m_sma: MetricPattern4::new(client.clone(), _m(&acc, "1m_sma")),
|
||||
ratio_1w_sma: MetricPattern4::new(client.clone(), _m(&acc, "1w_sma")),
|
||||
ratio_1y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "1y")),
|
||||
ratio_2y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "2y")),
|
||||
ratio_4y_sd: Ratio1ySdPattern::new(client.clone(), _m(&acc, "4y")),
|
||||
ratio_pct1: MetricPattern4::new(client.clone(), _m(&acc, "pct1")),
|
||||
ratio_pct1_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct1_usd")),
|
||||
ratio_pct2: MetricPattern4::new(client.clone(), _m(&acc, "pct2")),
|
||||
ratio_pct2_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct2_usd")),
|
||||
ratio_pct5: MetricPattern4::new(client.clone(), _m(&acc, "pct5")),
|
||||
ratio_pct5_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct5_usd")),
|
||||
ratio_pct95: MetricPattern4::new(client.clone(), _m(&acc, "pct95")),
|
||||
ratio_pct95_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct95_usd")),
|
||||
ratio_pct98: MetricPattern4::new(client.clone(), _m(&acc, "pct98")),
|
||||
ratio_pct98_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct98_usd")),
|
||||
ratio_pct99: MetricPattern4::new(client.clone(), _m(&acc, "pct99")),
|
||||
ratio_pct99_usd: MetricPattern4::new(client.clone(), _m(&acc, "pct99_usd")),
|
||||
ratio_sd: Ratio1ySdPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct RelativePattern5 {
|
||||
pub neg_unrealized_loss_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
@@ -1600,40 +1600,6 @@ impl BitcoinPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct DollarsPattern<T> {
|
||||
pub average: MetricPattern2<T>,
|
||||
pub base: MetricPattern11<T>,
|
||||
pub cumulative: MetricPattern1<T>,
|
||||
pub max: MetricPattern2<T>,
|
||||
pub median: MetricPattern6<T>,
|
||||
pub min: MetricPattern2<T>,
|
||||
pub pct10: MetricPattern6<T>,
|
||||
pub pct25: MetricPattern6<T>,
|
||||
pub pct75: MetricPattern6<T>,
|
||||
pub pct90: MetricPattern6<T>,
|
||||
pub sum: MetricPattern2<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> DollarsPattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
average: MetricPattern2::new(client.clone(), _m(&acc, "average")),
|
||||
base: MetricPattern11::new(client.clone(), acc.clone()),
|
||||
cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")),
|
||||
max: MetricPattern2::new(client.clone(), _m(&acc, "max")),
|
||||
median: MetricPattern6::new(client.clone(), _m(&acc, "median")),
|
||||
min: MetricPattern2::new(client.clone(), _m(&acc, "min")),
|
||||
pct10: MetricPattern6::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct25: MetricPattern6::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct75: MetricPattern6::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct90: MetricPattern6::new(client.clone(), _m(&acc, "pct90")),
|
||||
sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct ClassAveragePricePattern<T> {
|
||||
pub _2015: MetricPattern4<T>,
|
||||
@@ -1669,33 +1635,35 @@ impl<T: DeserializeOwned> ClassAveragePricePattern<T> {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct RelativePattern {
|
||||
pub neg_unrealized_loss_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
pub net_unrealized_pnl_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
pub nupl: MetricPattern1<StoredF32>,
|
||||
pub supply_in_loss_rel_to_circulating_supply: MetricPattern1<StoredF64>,
|
||||
pub supply_in_loss_rel_to_own_supply: MetricPattern1<StoredF64>,
|
||||
pub supply_in_profit_rel_to_circulating_supply: MetricPattern1<StoredF64>,
|
||||
pub supply_in_profit_rel_to_own_supply: MetricPattern1<StoredF64>,
|
||||
pub supply_rel_to_circulating_supply: MetricPattern4<StoredF64>,
|
||||
pub unrealized_loss_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
pub unrealized_profit_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
pub struct DollarsPattern<T> {
|
||||
pub average: MetricPattern2<T>,
|
||||
pub base: MetricPattern11<T>,
|
||||
pub cumulative: MetricPattern1<T>,
|
||||
pub max: MetricPattern2<T>,
|
||||
pub median: MetricPattern6<T>,
|
||||
pub min: MetricPattern2<T>,
|
||||
pub pct10: MetricPattern6<T>,
|
||||
pub pct25: MetricPattern6<T>,
|
||||
pub pct75: MetricPattern6<T>,
|
||||
pub pct90: MetricPattern6<T>,
|
||||
pub sum: MetricPattern2<T>,
|
||||
}
|
||||
|
||||
impl RelativePattern {
|
||||
impl<T: DeserializeOwned> DollarsPattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
neg_unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")),
|
||||
net_unrealized_pnl_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_market_cap")),
|
||||
nupl: MetricPattern1::new(client.clone(), _m(&acc, "nupl")),
|
||||
supply_in_loss_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")),
|
||||
supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")),
|
||||
supply_in_profit_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")),
|
||||
supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")),
|
||||
supply_rel_to_circulating_supply: MetricPattern4::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")),
|
||||
unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")),
|
||||
unrealized_profit_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")),
|
||||
average: MetricPattern2::new(client.clone(), _m(&acc, "average")),
|
||||
base: MetricPattern11::new(client.clone(), acc.clone()),
|
||||
cumulative: MetricPattern1::new(client.clone(), _m(&acc, "cumulative")),
|
||||
max: MetricPattern2::new(client.clone(), _m(&acc, "max")),
|
||||
median: MetricPattern6::new(client.clone(), _m(&acc, "median")),
|
||||
min: MetricPattern2::new(client.clone(), _m(&acc, "min")),
|
||||
pct10: MetricPattern6::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct25: MetricPattern6::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct75: MetricPattern6::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct90: MetricPattern6::new(client.clone(), _m(&acc, "pct90")),
|
||||
sum: MetricPattern2::new(client.clone(), _m(&acc, "sum")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1732,6 +1700,38 @@ impl RelativePattern2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct RelativePattern {
|
||||
pub neg_unrealized_loss_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
pub net_unrealized_pnl_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
pub nupl: MetricPattern1<StoredF32>,
|
||||
pub supply_in_loss_rel_to_circulating_supply: MetricPattern1<StoredF64>,
|
||||
pub supply_in_loss_rel_to_own_supply: MetricPattern1<StoredF64>,
|
||||
pub supply_in_profit_rel_to_circulating_supply: MetricPattern1<StoredF64>,
|
||||
pub supply_in_profit_rel_to_own_supply: MetricPattern1<StoredF64>,
|
||||
pub supply_rel_to_circulating_supply: MetricPattern4<StoredF64>,
|
||||
pub unrealized_loss_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
pub unrealized_profit_rel_to_market_cap: MetricPattern1<StoredF32>,
|
||||
}
|
||||
|
||||
impl RelativePattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
neg_unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "neg_unrealized_loss_rel_to_market_cap")),
|
||||
net_unrealized_pnl_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "net_unrealized_pnl_rel_to_market_cap")),
|
||||
nupl: MetricPattern1::new(client.clone(), _m(&acc, "nupl")),
|
||||
supply_in_loss_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_circulating_supply")),
|
||||
supply_in_loss_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_loss_rel_to_own_supply")),
|
||||
supply_in_profit_rel_to_circulating_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_circulating_supply")),
|
||||
supply_in_profit_rel_to_own_supply: MetricPattern1::new(client.clone(), _m(&acc, "supply_in_profit_rel_to_own_supply")),
|
||||
supply_rel_to_circulating_supply: MetricPattern4::new(client.clone(), _m(&acc, "supply_rel_to_circulating_supply")),
|
||||
unrealized_loss_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_loss_rel_to_market_cap")),
|
||||
unrealized_profit_rel_to_market_cap: MetricPattern1::new(client.clone(), _m(&acc, "unrealized_profit_rel_to_market_cap")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CountPattern2<T> {
|
||||
pub average: MetricPattern1<T>,
|
||||
@@ -1794,36 +1794,6 @@ impl AddrCountPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct FeeRatePattern<T> {
|
||||
pub average: MetricPattern1<T>,
|
||||
pub max: MetricPattern1<T>,
|
||||
pub median: MetricPattern11<T>,
|
||||
pub min: MetricPattern1<T>,
|
||||
pub pct10: MetricPattern11<T>,
|
||||
pub pct25: MetricPattern11<T>,
|
||||
pub pct75: MetricPattern11<T>,
|
||||
pub pct90: MetricPattern11<T>,
|
||||
pub txindex: MetricPattern27<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> FeeRatePattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
average: MetricPattern1::new(client.clone(), _m(&acc, "average")),
|
||||
max: MetricPattern1::new(client.clone(), _m(&acc, "max")),
|
||||
median: MetricPattern11::new(client.clone(), _m(&acc, "median")),
|
||||
min: MetricPattern1::new(client.clone(), _m(&acc, "min")),
|
||||
pct10: MetricPattern11::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct25: MetricPattern11::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct75: MetricPattern11::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct90: MetricPattern11::new(client.clone(), _m(&acc, "pct90")),
|
||||
txindex: MetricPattern27::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct FullnessPattern<T> {
|
||||
pub average: MetricPattern2<T>,
|
||||
@@ -1854,6 +1824,36 @@ impl<T: DeserializeOwned> FullnessPattern<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct FeeRatePattern<T> {
|
||||
pub average: MetricPattern1<T>,
|
||||
pub max: MetricPattern1<T>,
|
||||
pub median: MetricPattern11<T>,
|
||||
pub min: MetricPattern1<T>,
|
||||
pub pct10: MetricPattern11<T>,
|
||||
pub pct25: MetricPattern11<T>,
|
||||
pub pct75: MetricPattern11<T>,
|
||||
pub pct90: MetricPattern11<T>,
|
||||
pub txindex: MetricPattern27<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> FeeRatePattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
average: MetricPattern1::new(client.clone(), _m(&acc, "average")),
|
||||
max: MetricPattern1::new(client.clone(), _m(&acc, "max")),
|
||||
median: MetricPattern11::new(client.clone(), _m(&acc, "median")),
|
||||
min: MetricPattern1::new(client.clone(), _m(&acc, "min")),
|
||||
pct10: MetricPattern11::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct25: MetricPattern11::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct75: MetricPattern11::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct90: MetricPattern11::new(client.clone(), _m(&acc, "pct90")),
|
||||
txindex: MetricPattern27::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _0satsPattern {
|
||||
pub activity: ActivityPattern2,
|
||||
@@ -1910,32 +1910,6 @@ impl<T: DeserializeOwned> PhaseDailyCentsPattern<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _10yPattern {
|
||||
pub activity: ActivityPattern2,
|
||||
pub cost_basis: CostBasisPattern,
|
||||
pub outputs: OutputsPattern,
|
||||
pub realized: RealizedPattern4,
|
||||
pub relative: RelativePattern,
|
||||
pub supply: SupplyPattern2,
|
||||
pub unrealized: UnrealizedPattern,
|
||||
}
|
||||
|
||||
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: 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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct UnrealizedPattern {
|
||||
pub neg_unrealized_loss: MetricPattern1<Dollars>,
|
||||
@@ -1963,25 +1937,25 @@ impl UnrealizedPattern {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _0satsPattern2 {
|
||||
pub struct _10yTo12yPattern {
|
||||
pub activity: ActivityPattern2,
|
||||
pub cost_basis: CostBasisPattern,
|
||||
pub cost_basis: CostBasisPattern2,
|
||||
pub outputs: OutputsPattern,
|
||||
pub realized: RealizedPattern,
|
||||
pub relative: RelativePattern4,
|
||||
pub realized: RealizedPattern2,
|
||||
pub relative: RelativePattern2,
|
||||
pub supply: SupplyPattern2,
|
||||
pub unrealized: UnrealizedPattern,
|
||||
}
|
||||
|
||||
impl _0satsPattern2 {
|
||||
impl _10yTo12yPattern {
|
||||
/// 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()),
|
||||
cost_basis: CostBasisPattern2::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")),
|
||||
realized: RealizedPattern2::new(client.clone(), acc.clone()),
|
||||
relative: RelativePattern2::new(client.clone(), acc.clone()),
|
||||
supply: SupplyPattern2::new(client.clone(), _m(&acc, "supply")),
|
||||
unrealized: UnrealizedPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
@@ -2014,6 +1988,32 @@ impl PeriodCagrPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _10yPattern {
|
||||
pub activity: ActivityPattern2,
|
||||
pub cost_basis: CostBasisPattern,
|
||||
pub outputs: OutputsPattern,
|
||||
pub realized: RealizedPattern4,
|
||||
pub relative: RelativePattern,
|
||||
pub supply: SupplyPattern2,
|
||||
pub unrealized: UnrealizedPattern,
|
||||
}
|
||||
|
||||
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: 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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _100btcPattern {
|
||||
pub activity: ActivityPattern2,
|
||||
@@ -2041,25 +2041,25 @@ impl _100btcPattern {
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _10yTo12yPattern {
|
||||
pub struct _0satsPattern2 {
|
||||
pub activity: ActivityPattern2,
|
||||
pub cost_basis: CostBasisPattern2,
|
||||
pub cost_basis: CostBasisPattern,
|
||||
pub outputs: OutputsPattern,
|
||||
pub realized: RealizedPattern2,
|
||||
pub relative: RelativePattern2,
|
||||
pub realized: RealizedPattern,
|
||||
pub relative: RelativePattern4,
|
||||
pub supply: SupplyPattern2,
|
||||
pub unrealized: UnrealizedPattern,
|
||||
}
|
||||
|
||||
impl _10yTo12yPattern {
|
||||
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: CostBasisPattern2::new(client.clone(), acc.clone()),
|
||||
cost_basis: CostBasisPattern::new(client.clone(), acc.clone()),
|
||||
outputs: OutputsPattern::new(client.clone(), _m(&acc, "utxo_count")),
|
||||
realized: RealizedPattern2::new(client.clone(), acc.clone()),
|
||||
relative: RelativePattern2::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()),
|
||||
}
|
||||
@@ -2108,6 +2108,42 @@ impl<T: DeserializeOwned> SplitPattern2<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 ActiveSupplyPattern {
|
||||
pub bitcoin: MetricPattern1<Bitcoin>,
|
||||
pub dollars: MetricPattern1<Dollars>,
|
||||
pub sats: MetricPattern1<Sats>,
|
||||
}
|
||||
|
||||
impl ActiveSupplyPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
bitcoin: MetricPattern1::new(client.clone(), _m(&acc, "btc")),
|
||||
dollars: MetricPattern1::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: MetricPattern1::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CostBasisPattern2 {
|
||||
pub max: MetricPattern1<Dollars>,
|
||||
@@ -2126,6 +2162,24 @@ impl CostBasisPattern2 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct CoinbasePattern2 {
|
||||
pub bitcoin: BlockCountPattern<Bitcoin>,
|
||||
pub dollars: BlockCountPattern<Dollars>,
|
||||
pub sats: BlockCountPattern<Sats>,
|
||||
}
|
||||
|
||||
impl CoinbasePattern2 {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")),
|
||||
dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: BlockCountPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct SegwitAdoptionPattern {
|
||||
pub base: MetricPattern11<StoredF32>,
|
||||
@@ -2162,60 +2216,6 @@ impl CoinbasePattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
pub dollars: BlockCountPattern<Dollars>,
|
||||
pub sats: BlockCountPattern<Sats>,
|
||||
}
|
||||
|
||||
impl CoinbasePattern2 {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
bitcoin: BlockCountPattern::new(client.clone(), _m(&acc, "btc")),
|
||||
dollars: BlockCountPattern::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: BlockCountPattern::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct ActiveSupplyPattern {
|
||||
pub bitcoin: MetricPattern1<Bitcoin>,
|
||||
pub dollars: MetricPattern1<Dollars>,
|
||||
pub sats: MetricPattern1<Sats>,
|
||||
}
|
||||
|
||||
impl ActiveSupplyPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
bitcoin: MetricPattern1::new(client.clone(), _m(&acc, "btc")),
|
||||
dollars: MetricPattern1::new(client.clone(), _m(&acc, "usd")),
|
||||
sats: MetricPattern1::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct UnclaimedRewardsPattern {
|
||||
pub bitcoin: BitcoinPattern2<Bitcoin>,
|
||||
@@ -2234,22 +2234,6 @@ impl UnclaimedRewardsPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _1dReturns1mSdPattern {
|
||||
pub sd: MetricPattern4<StoredF32>,
|
||||
pub sma: MetricPattern4<StoredF32>,
|
||||
}
|
||||
|
||||
impl _1dReturns1mSdPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")),
|
||||
sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct SupplyPattern2 {
|
||||
pub halved: ActiveSupplyPattern,
|
||||
@@ -2298,6 +2282,22 @@ impl CostBasisPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct _1dReturns1mSdPattern {
|
||||
pub sd: MetricPattern4<StoredF32>,
|
||||
pub sma: MetricPattern4<StoredF32>,
|
||||
}
|
||||
|
||||
impl _1dReturns1mSdPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
sd: MetricPattern4::new(client.clone(), _m(&acc, "sd")),
|
||||
sma: MetricPattern4::new(client.clone(), _m(&acc, "sma")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BitcoinPattern2<T> {
|
||||
pub cumulative: MetricPattern2<T>,
|
||||
@@ -2340,22 +2340,8 @@ impl<T: DeserializeOwned> SatsPattern<T> {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
ohlc: MetricPattern1::new(client.clone(), _m(&acc, "ohlc_sats")),
|
||||
split: SplitPattern2::new(client.clone(), _m(&acc, "sats")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct OutputsPattern {
|
||||
pub utxo_count: MetricPattern1<StoredU64>,
|
||||
}
|
||||
|
||||
impl OutputsPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
utxo_count: MetricPattern1::new(client.clone(), acc.clone()),
|
||||
ohlc: MetricPattern1::new(client.clone(), _m(&acc, "ohlc")),
|
||||
split: SplitPattern2::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2374,6 +2360,20 @@ impl RealizedPriceExtraPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct OutputsPattern {
|
||||
pub utxo_count: MetricPattern1<StoredU64>,
|
||||
}
|
||||
|
||||
impl OutputsPattern {
|
||||
/// Create a new pattern node with accumulated metric name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
utxo_count: MetricPattern1::new(client.clone(), acc.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Metrics tree
|
||||
|
||||
/// Metrics tree node.
|
||||
@@ -3932,7 +3932,7 @@ pub struct MetricsTree_Indexes_Height {
|
||||
impl MetricsTree_Indexes_Height {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
dateindex: MetricPattern11::new(client.clone(), "height_dateindex".to_string()),
|
||||
dateindex: MetricPattern11::new(client.clone(), "dateindex".to_string()),
|
||||
difficultyepoch: MetricPattern11::new(client.clone(), "difficultyepoch".to_string()),
|
||||
halvingepoch: MetricPattern11::new(client.clone(), "halvingepoch".to_string()),
|
||||
identity: MetricPattern11::new(client.clone(), "height".to_string()),
|
||||
@@ -4942,8 +4942,8 @@ impl MetricsTree_Positions {
|
||||
pub struct MetricsTree_Price {
|
||||
pub cents: MetricsTree_Price_Cents,
|
||||
pub oracle: MetricsTree_Price_Oracle,
|
||||
pub sats: SatsPattern<OHLCSats>,
|
||||
pub usd: MetricsTree_Price_Usd,
|
||||
pub sats: MetricsTree_Price_Sats,
|
||||
pub usd: SatsPattern<OHLCDollars>,
|
||||
}
|
||||
|
||||
impl MetricsTree_Price {
|
||||
@@ -4951,8 +4951,8 @@ impl MetricsTree_Price {
|
||||
Self {
|
||||
cents: MetricsTree_Price_Cents::new(client.clone(), format!("{base_path}_cents")),
|
||||
oracle: MetricsTree_Price_Oracle::new(client.clone(), format!("{base_path}_oracle")),
|
||||
sats: SatsPattern::new(client.clone(), "price".to_string()),
|
||||
usd: MetricsTree_Price_Usd::new(client.clone(), format!("{base_path}_usd")),
|
||||
sats: MetricsTree_Price_Sats::new(client.clone(), format!("{base_path}_sats")),
|
||||
usd: SatsPattern::new(client.clone(), "price".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5027,16 +5027,16 @@ impl MetricsTree_Price_Oracle {
|
||||
}
|
||||
|
||||
/// Metrics tree node.
|
||||
pub struct MetricsTree_Price_Usd {
|
||||
pub ohlc: MetricPattern1<OHLCDollars>,
|
||||
pub split: SplitPattern2<Dollars>,
|
||||
pub struct MetricsTree_Price_Sats {
|
||||
pub ohlc: MetricPattern1<OHLCSats>,
|
||||
pub split: SplitPattern2<Sats>,
|
||||
}
|
||||
|
||||
impl MetricsTree_Price_Usd {
|
||||
impl MetricsTree_Price_Sats {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
ohlc: MetricPattern1::new(client.clone(), "price_ohlc".to_string()),
|
||||
split: SplitPattern2::new(client.clone(), "price".to_string()),
|
||||
ohlc: MetricPattern1::new(client.clone(), "price_ohlc_sats".to_string()),
|
||||
split: SplitPattern2::new(client.clone(), "price_sats".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ impl Vecs {
|
||||
pub fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
Ok(Self {
|
||||
identity: EagerVec::forced_import(db, "height", version)?,
|
||||
dateindex: EagerVec::forced_import(db, "height_dateindex", version)?,
|
||||
dateindex: EagerVec::forced_import(db, "dateindex", version)?,
|
||||
difficultyepoch: EagerVec::forced_import(db, "difficultyepoch", version)?,
|
||||
halvingepoch: EagerVec::forced_import(db, "halvingepoch", version)?,
|
||||
txindex_count: EagerVec::forced_import(db, "txindex_count", version)?,
|
||||
|
||||
@@ -24,8 +24,8 @@ impl Vecs {
|
||||
let phase_histogram = BytesVec::forced_import(db, "phase_histogram", version)?;
|
||||
|
||||
// Layer 5: Phase Oracle prices
|
||||
// v32: Revert to simple anchor-based decade selection (no prev_price tracking)
|
||||
let phase_version = version + Version::new(25);
|
||||
// v45: Back to decades (10x) + anchor only
|
||||
let phase_version = version + Version::new(38);
|
||||
let phase_price_cents = PcoVec::forced_import(db, "phase_price_cents", phase_version)?;
|
||||
let phase_daily_cents = Distribution::forced_import(db, "phase_daily", phase_version)?;
|
||||
let phase_daily_dollars = LazyTransformDistribution::from_distribution::<CentsToDollars>(
|
||||
|
||||
@@ -33,7 +33,7 @@ serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tower-http = { version = "0.6.8", features = ["compression-full", "trace"] }
|
||||
tower-http = { version = "0.6.8", features = ["catch-panic", "compression-full", "cors", "normalize-path", "timeout", "trace"] }
|
||||
|
||||
[build-dependencies]
|
||||
# importmap = { path = "../../../importmap" }
|
||||
|
||||
@@ -14,7 +14,8 @@ fn main() {
|
||||
let map = if is_dev {
|
||||
importmap::ImportMap::empty()
|
||||
} else {
|
||||
importmap::ImportMap::scan(&website_path, "").unwrap_or_else(|_| importmap::ImportMap::empty())
|
||||
importmap::ImportMap::scan(&website_path, "")
|
||||
.unwrap_or_else(|_| importmap::ImportMap::empty())
|
||||
};
|
||||
|
||||
let _ = map.update_html_file(&website_path.join("index.html"));
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
use aide::axum::{ApiRouter, routing::get_with};
|
||||
use axum::{
|
||||
extract::State,
|
||||
http::HeaderMap,
|
||||
response::Redirect,
|
||||
routing::get,
|
||||
};
|
||||
use axum::{extract::State, http::HeaderMap, response::Redirect, routing::get};
|
||||
use brk_types::{MempoolBlock, MempoolInfo, RecommendedFees, Txid};
|
||||
|
||||
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
||||
|
||||
@@ -6,6 +6,7 @@ use axum::{
|
||||
http::{HeaderMap, StatusCode, Uri},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use brk_error::Result;
|
||||
use brk_types::{Format, MetricSelection, Output};
|
||||
use quick_cache::sync::GuardResult;
|
||||
|
||||
@@ -24,12 +25,7 @@ pub async fn handler(
|
||||
) -> Response {
|
||||
match req_to_response_res(uri, headers, query, state).await {
|
||||
Ok(response) => response,
|
||||
Err(error) => {
|
||||
let mut response =
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
response
|
||||
}
|
||||
Err(error) => (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,19 +34,16 @@ async fn req_to_response_res(
|
||||
headers: HeaderMap,
|
||||
Query(params): Query<MetricSelection>,
|
||||
AppState { query, cache, .. }: AppState,
|
||||
) -> brk_error::Result<Response> {
|
||||
) -> Result<Response> {
|
||||
// Phase 1: Search and resolve metadata (cheap)
|
||||
let resolved = query
|
||||
.run(move |q| q.resolve(params, MAX_WEIGHT))
|
||||
.await?;
|
||||
let resolved = query.run(move |q| q.resolve(params, MAX_WEIGHT)).await?;
|
||||
|
||||
let format = resolved.format();
|
||||
let etag = resolved.etag();
|
||||
|
||||
// Check if client has fresh cache
|
||||
if headers.has_etag(etag.as_str()) {
|
||||
let mut response = (StatusCode::NOT_MODIFIED, "").into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
let response = (StatusCode::NOT_MODIFIED, "").into_response();
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
@@ -81,7 +74,6 @@ async fn req_to_response_res(
|
||||
};
|
||||
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_etag(etag.as_str());
|
||||
headers.insert_cache_control(CACHE_CONTROL);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use axum::{
|
||||
http::{HeaderMap, StatusCode, Uri},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use brk_error::Result;
|
||||
use brk_types::{Format, MetricSelection, Output};
|
||||
use quick_cache::sync::GuardResult;
|
||||
|
||||
@@ -24,12 +25,7 @@ pub async fn handler(
|
||||
) -> Response {
|
||||
match req_to_response_res(uri, headers, query, state).await {
|
||||
Ok(response) => response,
|
||||
Err(error) => {
|
||||
let mut response =
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
response
|
||||
}
|
||||
Err(error) => (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,19 +34,16 @@ async fn req_to_response_res(
|
||||
headers: HeaderMap,
|
||||
Query(params): Query<MetricSelection>,
|
||||
AppState { query, cache, .. }: AppState,
|
||||
) -> brk_error::Result<Response> {
|
||||
) -> Result<Response> {
|
||||
// Phase 1: Search and resolve metadata (cheap)
|
||||
let resolved = query
|
||||
.run(move |q| q.resolve(params, MAX_WEIGHT))
|
||||
.await?;
|
||||
let resolved = query.run(move |q| q.resolve(params, MAX_WEIGHT)).await?;
|
||||
|
||||
let format = resolved.format();
|
||||
let etag = resolved.etag();
|
||||
|
||||
// Check if client has fresh cache
|
||||
if headers.has_etag(etag.as_str()) {
|
||||
let mut response = (StatusCode::NOT_MODIFIED, "").into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
let response = (StatusCode::NOT_MODIFIED, "").into_response();
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
@@ -81,7 +74,6 @@ async fn req_to_response_res(
|
||||
};
|
||||
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_etag(etag.as_str());
|
||||
headers.insert_cache_control(CACHE_CONTROL);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use axum::{
|
||||
http::{HeaderMap, StatusCode, Uri},
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use brk_error::Result;
|
||||
use brk_types::{Format, MetricSelection, OutputLegacy};
|
||||
use quick_cache::sync::GuardResult;
|
||||
|
||||
@@ -24,12 +25,7 @@ pub async fn handler(
|
||||
) -> Response {
|
||||
match req_to_response_res(uri, headers, query, state).await {
|
||||
Ok(response) => response,
|
||||
Err(error) => {
|
||||
let mut response =
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
response
|
||||
}
|
||||
Err(error) => (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,19 +34,16 @@ async fn req_to_response_res(
|
||||
headers: HeaderMap,
|
||||
Query(params): Query<MetricSelection>,
|
||||
AppState { query, cache, .. }: AppState,
|
||||
) -> brk_error::Result<Response> {
|
||||
) -> Result<Response> {
|
||||
// Phase 1: Search and resolve metadata (cheap)
|
||||
let resolved = query
|
||||
.run(move |q| q.resolve(params, MAX_WEIGHT))
|
||||
.await?;
|
||||
let resolved = query.run(move |q| q.resolve(params, MAX_WEIGHT)).await?;
|
||||
|
||||
let format = resolved.format();
|
||||
let etag = resolved.etag();
|
||||
|
||||
// Check if client has fresh cache
|
||||
if headers.has_etag(etag.as_str()) {
|
||||
let mut response = (StatusCode::NOT_MODIFIED, "").into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
let response = (StatusCode::NOT_MODIFIED, "").into_response();
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
@@ -62,9 +55,7 @@ async fn req_to_response_res(
|
||||
Response::new(Body::from(v))
|
||||
} else {
|
||||
// Phase 2: Format (expensive, only on cache miss)
|
||||
let metric_output = query
|
||||
.run(move |q| q.format_legacy(resolved))
|
||||
.await?;
|
||||
let metric_output = query.run(move |q| q.format_legacy(resolved)).await?;
|
||||
|
||||
match metric_output.output {
|
||||
OutputLegacy::CSV(s) => {
|
||||
@@ -84,7 +75,6 @@ async fn req_to_response_res(
|
||||
};
|
||||
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_etag(etag.as_str());
|
||||
headers.insert_cache_control(CACHE_CONTROL);
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ use axum::{
|
||||
routing::get,
|
||||
};
|
||||
use brk_types::{
|
||||
BlockCountParam, BlockFeesEntry, BlockRewardsEntry, BlockSizesWeights,
|
||||
DifficultyAdjustment, DifficultyAdjustmentEntry, HashrateSummary, PoolDetail, PoolInfo,
|
||||
PoolSlugParam, PoolsSummary, RewardStats, TimePeriodParam,
|
||||
BlockCountParam, BlockFeesEntry, BlockRewardsEntry, BlockSizesWeights, DifficultyAdjustment,
|
||||
DifficultyAdjustmentEntry, HashrateSummary, PoolDetail, PoolInfo, PoolSlugParam, PoolsSummary,
|
||||
RewardStats, TimePeriodParam,
|
||||
};
|
||||
|
||||
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
||||
|
||||
@@ -377,7 +377,10 @@ mod tests {
|
||||
|
||||
let props = &parsed["components"]["schemas"]["AddressStats"]["properties"];
|
||||
assert_eq!(props["address"], "Address", "address should be simplified");
|
||||
assert_eq!(props["chain_stats"], "AddressChainStats", "chain_stats should be simplified");
|
||||
assert_eq!(
|
||||
props["chain_stats"], "AddressChainStats",
|
||||
"chain_stats should be simplified"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -19,8 +19,6 @@ pub enum ModifiedState {
|
||||
}
|
||||
|
||||
pub trait HeaderMapExtended {
|
||||
fn insert_cors(&mut self);
|
||||
|
||||
fn has_etag(&self, etag: &str) -> bool;
|
||||
|
||||
fn get_if_modified_since(&self) -> Option<DateTime>;
|
||||
@@ -52,11 +50,6 @@ pub trait HeaderMapExtended {
|
||||
}
|
||||
|
||||
impl HeaderMapExtended for HeaderMap {
|
||||
fn insert_cors(&mut self) {
|
||||
self.insert(header::ACCESS_CONTROL_ALLOW_ORIGIN, "*".parse().unwrap());
|
||||
self.insert(header::ACCESS_CONTROL_ALLOW_HEADERS, "*".parse().unwrap());
|
||||
}
|
||||
|
||||
fn insert_cache_control(&mut self, value: &str) {
|
||||
self.insert(header::CACHE_CONTROL, value.parse().unwrap());
|
||||
}
|
||||
|
||||
@@ -36,8 +36,7 @@ where
|
||||
impl ResponseExtended for Response<Body> {
|
||||
fn new_not_modified() -> Response<Body> {
|
||||
let mut response = (StatusCode::NOT_MODIFIED, "").into_response();
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
let _headers = response.headers_mut();
|
||||
response
|
||||
}
|
||||
|
||||
@@ -56,7 +55,6 @@ impl ResponseExtended for Response<Body> {
|
||||
let mut response = Response::builder().body(bytes.into()).unwrap();
|
||||
*response.status_mut() = status;
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_content_type_application_json();
|
||||
headers.insert_cache_control_must_revalidate();
|
||||
headers.insert_etag(etag);
|
||||
@@ -68,12 +66,9 @@ impl ResponseExtended for Response<Body> {
|
||||
}
|
||||
|
||||
fn new_text_with(status: StatusCode, value: &str, etag: &str) -> Self {
|
||||
let mut response = Response::builder()
|
||||
.body(value.to_string().into())
|
||||
.unwrap();
|
||||
let mut response = Response::builder().body(value.to_string().into()).unwrap();
|
||||
*response.status_mut() = status;
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_content_type_text_plain();
|
||||
headers.insert_cache_control_must_revalidate();
|
||||
headers.insert_etag(etag);
|
||||
@@ -88,7 +83,6 @@ impl ResponseExtended for Response<Body> {
|
||||
let mut response = Response::builder().body(value.into()).unwrap();
|
||||
*response.status_mut() = status;
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_content_type_octet_stream();
|
||||
headers.insert_cache_control_must_revalidate();
|
||||
headers.insert_etag(etag);
|
||||
@@ -102,7 +96,6 @@ impl ResponseExtended for Response<Body> {
|
||||
let bytes = serde_json::to_vec(&value).unwrap();
|
||||
let mut response = Response::builder().body(bytes.into()).unwrap();
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_content_type_application_json();
|
||||
headers.insert_cache_control(¶ms.cache_control);
|
||||
if let Some(etag) = ¶ms.etag {
|
||||
@@ -123,11 +116,8 @@ impl ResponseExtended for Response<Body> {
|
||||
}
|
||||
|
||||
fn new_text_cached(value: &str, params: &CacheParams) -> Self {
|
||||
let mut response = Response::builder()
|
||||
.body(value.to_string().into())
|
||||
.unwrap();
|
||||
let mut response = Response::builder().body(value.to_string().into()).unwrap();
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_content_type_text_plain();
|
||||
headers.insert_cache_control(¶ms.cache_control);
|
||||
if let Some(etag) = ¶ms.etag {
|
||||
@@ -139,7 +129,6 @@ impl ResponseExtended for Response<Body> {
|
||||
fn new_bytes_cached(value: Vec<u8>, params: &CacheParams) -> Self {
|
||||
let mut response = Response::builder().body(value.into()).unwrap();
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_content_type_octet_stream();
|
||||
headers.insert_cache_control(¶ms.cache_control);
|
||||
if let Some(etag) = ¶ms.etag {
|
||||
|
||||
@@ -81,7 +81,6 @@ fn build_response(state: &AppState, path: &Path, content: Vec<u8>, cache_key: &s
|
||||
};
|
||||
|
||||
let headers = response.headers_mut();
|
||||
headers.insert_cors();
|
||||
headers.insert_content_type(path);
|
||||
|
||||
if cfg!(debug_assertions) || must_revalidate {
|
||||
@@ -114,9 +113,8 @@ fn embedded_handler(state: &AppState, path: Option<String>) -> Response {
|
||||
});
|
||||
|
||||
let Some(file) = file else {
|
||||
let mut response: Response<Body> =
|
||||
let response: Response<Body> =
|
||||
(StatusCode::NOT_FOUND, "File not found".to_string()).into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
return response;
|
||||
};
|
||||
|
||||
@@ -147,9 +145,8 @@ fn filesystem_handler(
|
||||
let allowed = canonical.starts_with(&canonical_base)
|
||||
|| project_root.is_some_and(|root| canonical.starts_with(root));
|
||||
if !allowed {
|
||||
let mut response: Response<Body> =
|
||||
let response: Response<Body> =
|
||||
(StatusCode::FORBIDDEN, "Access denied".to_string()).into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -165,12 +162,11 @@ fn filesystem_handler(
|
||||
// SPA fallback
|
||||
if !path.exists() || path.is_dir() {
|
||||
if path.extension().is_some() {
|
||||
let mut response: Response<Body> = (
|
||||
let response: Response<Body> = (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"File doesn't exist".to_string(),
|
||||
)
|
||||
.into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
return response;
|
||||
} else {
|
||||
path = files_path.join("index.html");
|
||||
@@ -188,12 +184,7 @@ fn filesystem_handler(
|
||||
fn path_to_response(headers: &HeaderMap, state: &AppState, path: &Path) -> Response {
|
||||
match path_to_response_(headers, state, path) {
|
||||
Ok(response) => response,
|
||||
Err(error) => {
|
||||
let mut response =
|
||||
(StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response();
|
||||
response.headers_mut().insert_cors();
|
||||
response
|
||||
}
|
||||
Err(error) => (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
use std::{panic, path::PathBuf, sync::Arc, time::{Duration, Instant}};
|
||||
use std::{
|
||||
panic,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use aide::axum::ApiRouter;
|
||||
use axum::{
|
||||
@@ -14,10 +19,14 @@ use axum::{
|
||||
};
|
||||
use brk_error::Result;
|
||||
use brk_query::AsyncQuery;
|
||||
use include_dir::{include_dir, Dir};
|
||||
use include_dir::{Dir, include_dir};
|
||||
use quick_cache::sync::Cache;
|
||||
use tokio::net::TcpListener;
|
||||
use tower_http::{compression::CompressionLayer, trace::TraceLayer};
|
||||
use tower_http::{
|
||||
catch_panic::CatchPanicLayer, classify::ServerErrorsFailureClass,
|
||||
compression::CompressionLayer, cors::CorsLayer, normalize_path::NormalizePathLayer,
|
||||
timeout::TimeoutLayer, trace::TraceLayer,
|
||||
};
|
||||
use tracing::{error, info};
|
||||
|
||||
/// Embedded website assets
|
||||
@@ -86,19 +95,25 @@ impl Server {
|
||||
|
||||
let trace_layer = TraceLayer::new_for_http()
|
||||
.on_request(())
|
||||
.on_response(|response: &Response<Body>, latency: Duration, _: &tracing::Span| {
|
||||
let status = response.status().as_u16();
|
||||
let uri = response.extensions().get::<Uri>().unwrap();
|
||||
match response.status() {
|
||||
StatusCode::OK => info!(status, %uri, ?latency),
|
||||
StatusCode::NOT_MODIFIED
|
||||
| StatusCode::TEMPORARY_REDIRECT
|
||||
| StatusCode::PERMANENT_REDIRECT => info!(status, %uri, ?latency),
|
||||
_ => error!(status, %uri, ?latency),
|
||||
}
|
||||
})
|
||||
.on_response(
|
||||
|response: &Response<Body>, latency: Duration, _: &tracing::Span| {
|
||||
let status = response.status().as_u16();
|
||||
let uri = response.extensions().get::<Uri>().unwrap();
|
||||
match response.status() {
|
||||
StatusCode::OK => info!(status, %uri, ?latency),
|
||||
StatusCode::NOT_MODIFIED
|
||||
| StatusCode::TEMPORARY_REDIRECT
|
||||
| StatusCode::PERMANENT_REDIRECT => info!(status, %uri, ?latency),
|
||||
_ => error!(status, %uri, ?latency),
|
||||
}
|
||||
},
|
||||
)
|
||||
.on_body_chunk(())
|
||||
.on_failure(())
|
||||
.on_failure(
|
||||
|error: ServerErrorsFailureClass, latency: Duration, _: &tracing::Span| {
|
||||
error!(?error, ?latency, "request failed");
|
||||
},
|
||||
)
|
||||
.on_eos(());
|
||||
|
||||
let vecs = state.query.inner().vecs();
|
||||
@@ -126,9 +141,13 @@ impl Server {
|
||||
)
|
||||
.route("/nostr", get(Redirect::temporary("https://primal.net/p/npub1jagmm3x39lmwfnrtvxcs9ac7g300y3dusv9lgzhk2e4x5frpxlrqa73v44")))
|
||||
.with_state(state)
|
||||
.layer(CatchPanicLayer::new())
|
||||
.layer(compression_layer)
|
||||
.layer(response_uri_layer)
|
||||
.layer(trace_layer);
|
||||
.layer(trace_layer)
|
||||
.layer(TimeoutLayer::with_status_code(StatusCode::GATEWAY_TIMEOUT, Duration::from_secs(5)))
|
||||
.layer(CorsLayer::permissive())
|
||||
.layer(NormalizePathLayer::trim_trailing_slash());
|
||||
|
||||
const BASE_PORT: u16 = 3110;
|
||||
const MAX_PORT: u16 = BASE_PORT + 100;
|
||||
|
||||
@@ -1644,59 +1644,6 @@ function createPrice111dSmaPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ActivePriceRatioPattern
|
||||
* @property {MetricPattern4<StoredF32>} ratio
|
||||
* @property {MetricPattern4<StoredF32>} ratio1mSma
|
||||
* @property {MetricPattern4<StoredF32>} ratio1wSma
|
||||
* @property {Ratio1ySdPattern} ratio1ySd
|
||||
* @property {Ratio1ySdPattern} ratio2ySd
|
||||
* @property {Ratio1ySdPattern} ratio4ySd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct1
|
||||
* @property {MetricPattern4<Dollars>} ratioPct1Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct2
|
||||
* @property {MetricPattern4<Dollars>} ratioPct2Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct5
|
||||
* @property {MetricPattern4<Dollars>} ratioPct5Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct95
|
||||
* @property {MetricPattern4<Dollars>} ratioPct95Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct98
|
||||
* @property {MetricPattern4<Dollars>} ratioPct98Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct99
|
||||
* @property {MetricPattern4<Dollars>} ratioPct99Usd
|
||||
* @property {Ratio1ySdPattern} ratioSd
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a ActivePriceRatioPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {ActivePriceRatioPattern}
|
||||
*/
|
||||
function createActivePriceRatioPattern(client, acc) {
|
||||
return {
|
||||
ratio: createMetricPattern4(client, acc),
|
||||
ratio1mSma: createMetricPattern4(client, _m(acc, '1m_sma')),
|
||||
ratio1wSma: createMetricPattern4(client, _m(acc, '1w_sma')),
|
||||
ratio1ySd: createRatio1ySdPattern(client, _m(acc, '1y')),
|
||||
ratio2ySd: createRatio1ySdPattern(client, _m(acc, '2y')),
|
||||
ratio4ySd: createRatio1ySdPattern(client, _m(acc, '4y')),
|
||||
ratioPct1: createMetricPattern4(client, _m(acc, 'pct1')),
|
||||
ratioPct1Usd: createMetricPattern4(client, _m(acc, 'pct1_usd')),
|
||||
ratioPct2: createMetricPattern4(client, _m(acc, 'pct2')),
|
||||
ratioPct2Usd: createMetricPattern4(client, _m(acc, 'pct2_usd')),
|
||||
ratioPct5: createMetricPattern4(client, _m(acc, 'pct5')),
|
||||
ratioPct5Usd: createMetricPattern4(client, _m(acc, 'pct5_usd')),
|
||||
ratioPct95: createMetricPattern4(client, _m(acc, 'pct95')),
|
||||
ratioPct95Usd: createMetricPattern4(client, _m(acc, 'pct95_usd')),
|
||||
ratioPct98: createMetricPattern4(client, _m(acc, 'pct98')),
|
||||
ratioPct98Usd: createMetricPattern4(client, _m(acc, 'pct98_usd')),
|
||||
ratioPct99: createMetricPattern4(client, _m(acc, 'pct99')),
|
||||
ratioPct99Usd: createMetricPattern4(client, _m(acc, 'pct99_usd')),
|
||||
ratioSd: createRatio1ySdPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} PercentilesPattern
|
||||
* @property {MetricPattern4<Dollars>} pct05
|
||||
@@ -1750,6 +1697,59 @@ function createPercentilesPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ActivePriceRatioPattern
|
||||
* @property {MetricPattern4<StoredF32>} ratio
|
||||
* @property {MetricPattern4<StoredF32>} ratio1mSma
|
||||
* @property {MetricPattern4<StoredF32>} ratio1wSma
|
||||
* @property {Ratio1ySdPattern} ratio1ySd
|
||||
* @property {Ratio1ySdPattern} ratio2ySd
|
||||
* @property {Ratio1ySdPattern} ratio4ySd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct1
|
||||
* @property {MetricPattern4<Dollars>} ratioPct1Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct2
|
||||
* @property {MetricPattern4<Dollars>} ratioPct2Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct5
|
||||
* @property {MetricPattern4<Dollars>} ratioPct5Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct95
|
||||
* @property {MetricPattern4<Dollars>} ratioPct95Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct98
|
||||
* @property {MetricPattern4<Dollars>} ratioPct98Usd
|
||||
* @property {MetricPattern4<StoredF32>} ratioPct99
|
||||
* @property {MetricPattern4<Dollars>} ratioPct99Usd
|
||||
* @property {Ratio1ySdPattern} ratioSd
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a ActivePriceRatioPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {ActivePriceRatioPattern}
|
||||
*/
|
||||
function createActivePriceRatioPattern(client, acc) {
|
||||
return {
|
||||
ratio: createMetricPattern4(client, acc),
|
||||
ratio1mSma: createMetricPattern4(client, _m(acc, '1m_sma')),
|
||||
ratio1wSma: createMetricPattern4(client, _m(acc, '1w_sma')),
|
||||
ratio1ySd: createRatio1ySdPattern(client, _m(acc, '1y')),
|
||||
ratio2ySd: createRatio1ySdPattern(client, _m(acc, '2y')),
|
||||
ratio4ySd: createRatio1ySdPattern(client, _m(acc, '4y')),
|
||||
ratioPct1: createMetricPattern4(client, _m(acc, 'pct1')),
|
||||
ratioPct1Usd: createMetricPattern4(client, _m(acc, 'pct1_usd')),
|
||||
ratioPct2: createMetricPattern4(client, _m(acc, 'pct2')),
|
||||
ratioPct2Usd: createMetricPattern4(client, _m(acc, 'pct2_usd')),
|
||||
ratioPct5: createMetricPattern4(client, _m(acc, 'pct5')),
|
||||
ratioPct5Usd: createMetricPattern4(client, _m(acc, 'pct5_usd')),
|
||||
ratioPct95: createMetricPattern4(client, _m(acc, 'pct95')),
|
||||
ratioPct95Usd: createMetricPattern4(client, _m(acc, 'pct95_usd')),
|
||||
ratioPct98: createMetricPattern4(client, _m(acc, 'pct98')),
|
||||
ratioPct98Usd: createMetricPattern4(client, _m(acc, 'pct98_usd')),
|
||||
ratioPct99: createMetricPattern4(client, _m(acc, 'pct99')),
|
||||
ratioPct99Usd: createMetricPattern4(client, _m(acc, 'pct99_usd')),
|
||||
ratioSd: createRatio1ySdPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} RelativePattern5
|
||||
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToMarketCap
|
||||
@@ -2004,45 +2004,6 @@ function createBitcoinPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} DollarsPattern
|
||||
* @property {MetricPattern2<T>} average
|
||||
* @property {MetricPattern11<T>} base
|
||||
* @property {MetricPattern1<T>} cumulative
|
||||
* @property {MetricPattern2<T>} max
|
||||
* @property {MetricPattern6<T>} median
|
||||
* @property {MetricPattern2<T>} min
|
||||
* @property {MetricPattern6<T>} pct10
|
||||
* @property {MetricPattern6<T>} pct25
|
||||
* @property {MetricPattern6<T>} pct75
|
||||
* @property {MetricPattern6<T>} pct90
|
||||
* @property {MetricPattern2<T>} sum
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a DollarsPattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {DollarsPattern<T>}
|
||||
*/
|
||||
function createDollarsPattern(client, acc) {
|
||||
return {
|
||||
average: createMetricPattern2(client, _m(acc, 'average')),
|
||||
base: createMetricPattern11(client, acc),
|
||||
cumulative: createMetricPattern1(client, _m(acc, 'cumulative')),
|
||||
max: createMetricPattern2(client, _m(acc, 'max')),
|
||||
median: createMetricPattern6(client, _m(acc, 'median')),
|
||||
min: createMetricPattern2(client, _m(acc, 'min')),
|
||||
pct10: createMetricPattern6(client, _m(acc, 'pct10')),
|
||||
pct25: createMetricPattern6(client, _m(acc, 'pct25')),
|
||||
pct75: createMetricPattern6(client, _m(acc, 'pct75')),
|
||||
pct90: createMetricPattern6(client, _m(acc, 'pct90')),
|
||||
sum: createMetricPattern2(client, _m(acc, 'sum')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} ClassAveragePricePattern
|
||||
@@ -2083,37 +2044,41 @@ function createClassAveragePricePattern(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} RelativePattern
|
||||
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToMarketCap
|
||||
* @property {MetricPattern1<StoredF32>} netUnrealizedPnlRelToMarketCap
|
||||
* @property {MetricPattern1<StoredF32>} nupl
|
||||
* @property {MetricPattern1<StoredF64>} supplyInLossRelToCirculatingSupply
|
||||
* @property {MetricPattern1<StoredF64>} supplyInLossRelToOwnSupply
|
||||
* @property {MetricPattern1<StoredF64>} supplyInProfitRelToCirculatingSupply
|
||||
* @property {MetricPattern1<StoredF64>} supplyInProfitRelToOwnSupply
|
||||
* @property {MetricPattern4<StoredF64>} supplyRelToCirculatingSupply
|
||||
* @property {MetricPattern1<StoredF32>} unrealizedLossRelToMarketCap
|
||||
* @property {MetricPattern1<StoredF32>} unrealizedProfitRelToMarketCap
|
||||
* @template T
|
||||
* @typedef {Object} DollarsPattern
|
||||
* @property {MetricPattern2<T>} average
|
||||
* @property {MetricPattern11<T>} base
|
||||
* @property {MetricPattern1<T>} cumulative
|
||||
* @property {MetricPattern2<T>} max
|
||||
* @property {MetricPattern6<T>} median
|
||||
* @property {MetricPattern2<T>} min
|
||||
* @property {MetricPattern6<T>} pct10
|
||||
* @property {MetricPattern6<T>} pct25
|
||||
* @property {MetricPattern6<T>} pct75
|
||||
* @property {MetricPattern6<T>} pct90
|
||||
* @property {MetricPattern2<T>} sum
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a RelativePattern pattern node
|
||||
* Create a DollarsPattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {RelativePattern}
|
||||
* @returns {DollarsPattern<T>}
|
||||
*/
|
||||
function createRelativePattern(client, acc) {
|
||||
function createDollarsPattern(client, acc) {
|
||||
return {
|
||||
negUnrealizedLossRelToMarketCap: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')),
|
||||
netUnrealizedPnlRelToMarketCap: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap')),
|
||||
nupl: createMetricPattern1(client, _m(acc, 'nupl')),
|
||||
supplyInLossRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')),
|
||||
supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply')),
|
||||
supplyInProfitRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')),
|
||||
supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply')),
|
||||
supplyRelToCirculatingSupply: createMetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')),
|
||||
unrealizedLossRelToMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap')),
|
||||
unrealizedProfitRelToMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap')),
|
||||
average: createMetricPattern2(client, _m(acc, 'average')),
|
||||
base: createMetricPattern11(client, acc),
|
||||
cumulative: createMetricPattern1(client, _m(acc, 'cumulative')),
|
||||
max: createMetricPattern2(client, _m(acc, 'max')),
|
||||
median: createMetricPattern6(client, _m(acc, 'median')),
|
||||
min: createMetricPattern2(client, _m(acc, 'min')),
|
||||
pct10: createMetricPattern6(client, _m(acc, 'pct10')),
|
||||
pct25: createMetricPattern6(client, _m(acc, 'pct25')),
|
||||
pct75: createMetricPattern6(client, _m(acc, 'pct75')),
|
||||
pct90: createMetricPattern6(client, _m(acc, 'pct90')),
|
||||
sum: createMetricPattern2(client, _m(acc, 'sum')),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2152,6 +2117,41 @@ function createRelativePattern2(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} RelativePattern
|
||||
* @property {MetricPattern1<StoredF32>} negUnrealizedLossRelToMarketCap
|
||||
* @property {MetricPattern1<StoredF32>} netUnrealizedPnlRelToMarketCap
|
||||
* @property {MetricPattern1<StoredF32>} nupl
|
||||
* @property {MetricPattern1<StoredF64>} supplyInLossRelToCirculatingSupply
|
||||
* @property {MetricPattern1<StoredF64>} supplyInLossRelToOwnSupply
|
||||
* @property {MetricPattern1<StoredF64>} supplyInProfitRelToCirculatingSupply
|
||||
* @property {MetricPattern1<StoredF64>} supplyInProfitRelToOwnSupply
|
||||
* @property {MetricPattern4<StoredF64>} supplyRelToCirculatingSupply
|
||||
* @property {MetricPattern1<StoredF32>} unrealizedLossRelToMarketCap
|
||||
* @property {MetricPattern1<StoredF32>} unrealizedProfitRelToMarketCap
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a RelativePattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {RelativePattern}
|
||||
*/
|
||||
function createRelativePattern(client, acc) {
|
||||
return {
|
||||
negUnrealizedLossRelToMarketCap: createMetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap')),
|
||||
netUnrealizedPnlRelToMarketCap: createMetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap')),
|
||||
nupl: createMetricPattern1(client, _m(acc, 'nupl')),
|
||||
supplyInLossRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply')),
|
||||
supplyInLossRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply')),
|
||||
supplyInProfitRelToCirculatingSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply')),
|
||||
supplyInProfitRelToOwnSupply: createMetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply')),
|
||||
supplyRelToCirculatingSupply: createMetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply')),
|
||||
unrealizedLossRelToMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap')),
|
||||
unrealizedProfitRelToMarketCap: createMetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} CountPattern2
|
||||
@@ -2222,41 +2222,6 @@ function createAddrCountPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} FeeRatePattern
|
||||
* @property {MetricPattern1<T>} average
|
||||
* @property {MetricPattern1<T>} max
|
||||
* @property {MetricPattern11<T>} median
|
||||
* @property {MetricPattern1<T>} min
|
||||
* @property {MetricPattern11<T>} pct10
|
||||
* @property {MetricPattern11<T>} pct25
|
||||
* @property {MetricPattern11<T>} pct75
|
||||
* @property {MetricPattern11<T>} pct90
|
||||
* @property {MetricPattern27<T>} txindex
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a FeeRatePattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {FeeRatePattern<T>}
|
||||
*/
|
||||
function createFeeRatePattern(client, acc) {
|
||||
return {
|
||||
average: createMetricPattern1(client, _m(acc, 'average')),
|
||||
max: createMetricPattern1(client, _m(acc, 'max')),
|
||||
median: createMetricPattern11(client, _m(acc, 'median')),
|
||||
min: createMetricPattern1(client, _m(acc, 'min')),
|
||||
pct10: createMetricPattern11(client, _m(acc, 'pct10')),
|
||||
pct25: createMetricPattern11(client, _m(acc, 'pct25')),
|
||||
pct75: createMetricPattern11(client, _m(acc, 'pct75')),
|
||||
pct90: createMetricPattern11(client, _m(acc, 'pct90')),
|
||||
txindex: createMetricPattern27(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} FullnessPattern
|
||||
@@ -2292,6 +2257,41 @@ function createFullnessPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} FeeRatePattern
|
||||
* @property {MetricPattern1<T>} average
|
||||
* @property {MetricPattern1<T>} max
|
||||
* @property {MetricPattern11<T>} median
|
||||
* @property {MetricPattern1<T>} min
|
||||
* @property {MetricPattern11<T>} pct10
|
||||
* @property {MetricPattern11<T>} pct25
|
||||
* @property {MetricPattern11<T>} pct75
|
||||
* @property {MetricPattern11<T>} pct90
|
||||
* @property {MetricPattern27<T>} txindex
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a FeeRatePattern pattern node
|
||||
* @template T
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {FeeRatePattern<T>}
|
||||
*/
|
||||
function createFeeRatePattern(client, acc) {
|
||||
return {
|
||||
average: createMetricPattern1(client, _m(acc, 'average')),
|
||||
max: createMetricPattern1(client, _m(acc, 'max')),
|
||||
median: createMetricPattern11(client, _m(acc, 'median')),
|
||||
min: createMetricPattern1(client, _m(acc, 'min')),
|
||||
pct10: createMetricPattern11(client, _m(acc, 'pct10')),
|
||||
pct25: createMetricPattern11(client, _m(acc, 'pct25')),
|
||||
pct75: createMetricPattern11(client, _m(acc, 'pct75')),
|
||||
pct90: createMetricPattern11(client, _m(acc, 'pct90')),
|
||||
txindex: createMetricPattern27(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _0satsPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
@@ -2356,35 +2356,6 @@ function createPhaseDailyCentsPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _10yPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern4} realized
|
||||
* @property {RelativePattern} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _10yPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_10yPattern}
|
||||
*/
|
||||
function create_10yPattern(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, 'utxo_count')),
|
||||
realized: createRealizedPattern4(client, acc),
|
||||
relative: createRelativePattern(client, acc),
|
||||
supply: createSupplyPattern2(client, _m(acc, 'supply')),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} UnrealizedPattern
|
||||
* @property {MetricPattern1<Dollars>} negUnrealizedLoss
|
||||
@@ -2415,29 +2386,29 @@ function createUnrealizedPattern(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _0satsPattern2
|
||||
* @typedef {Object} _10yTo12yPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {CostBasisPattern2} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern} realized
|
||||
* @property {RelativePattern4} relative
|
||||
* @property {RealizedPattern2} realized
|
||||
* @property {RelativePattern2} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _0satsPattern2 pattern node
|
||||
* Create a _10yTo12yPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_0satsPattern2}
|
||||
* @returns {_10yTo12yPattern}
|
||||
*/
|
||||
function create_0satsPattern2(client, acc) {
|
||||
function create_10yTo12yPattern(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
costBasis: createCostBasisPattern2(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, 'utxo_count')),
|
||||
realized: createRealizedPattern(client, acc),
|
||||
relative: createRelativePattern4(client, _m(acc, 'supply_in')),
|
||||
realized: createRealizedPattern2(client, acc),
|
||||
relative: createRelativePattern2(client, acc),
|
||||
supply: createSupplyPattern2(client, _m(acc, 'supply')),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
};
|
||||
@@ -2472,6 +2443,35 @@ function createPeriodCagrPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _10yPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern4} realized
|
||||
* @property {RelativePattern} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _10yPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_10yPattern}
|
||||
*/
|
||||
function create_10yPattern(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, 'utxo_count')),
|
||||
realized: createRealizedPattern4(client, acc),
|
||||
relative: createRelativePattern(client, acc),
|
||||
supply: createSupplyPattern2(client, _m(acc, 'supply')),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _100btcPattern
|
||||
* @property {ActivityPattern2} activity
|
||||
@@ -2502,29 +2502,29 @@ function create_100btcPattern(client, acc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _10yTo12yPattern
|
||||
* @typedef {Object} _0satsPattern2
|
||||
* @property {ActivityPattern2} activity
|
||||
* @property {CostBasisPattern2} costBasis
|
||||
* @property {CostBasisPattern} costBasis
|
||||
* @property {OutputsPattern} outputs
|
||||
* @property {RealizedPattern2} realized
|
||||
* @property {RelativePattern2} relative
|
||||
* @property {RealizedPattern} realized
|
||||
* @property {RelativePattern4} relative
|
||||
* @property {SupplyPattern2} supply
|
||||
* @property {UnrealizedPattern} unrealized
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _10yTo12yPattern pattern node
|
||||
* Create a _0satsPattern2 pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_10yTo12yPattern}
|
||||
* @returns {_0satsPattern2}
|
||||
*/
|
||||
function create_10yTo12yPattern(client, acc) {
|
||||
function create_0satsPattern2(client, acc) {
|
||||
return {
|
||||
activity: createActivityPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern2(client, acc),
|
||||
costBasis: createCostBasisPattern(client, acc),
|
||||
outputs: createOutputsPattern(client, _m(acc, 'utxo_count')),
|
||||
realized: createRealizedPattern2(client, acc),
|
||||
relative: createRelativePattern2(client, acc),
|
||||
realized: createRealizedPattern(client, acc),
|
||||
relative: createRelativePattern4(client, _m(acc, 'supply_in')),
|
||||
supply: createSupplyPattern2(client, _m(acc, 'supply')),
|
||||
unrealized: createUnrealizedPattern(client, acc),
|
||||
};
|
||||
@@ -2580,6 +2580,48 @@ function createSplitPattern2(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} ActiveSupplyPattern
|
||||
* @property {MetricPattern1<Bitcoin>} bitcoin
|
||||
* @property {MetricPattern1<Dollars>} dollars
|
||||
* @property {MetricPattern1<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a ActiveSupplyPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {ActiveSupplyPattern}
|
||||
*/
|
||||
function createActiveSupplyPattern(client, acc) {
|
||||
return {
|
||||
bitcoin: createMetricPattern1(client, _m(acc, 'btc')),
|
||||
dollars: createMetricPattern1(client, _m(acc, 'usd')),
|
||||
sats: createMetricPattern1(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CostBasisPattern2
|
||||
* @property {MetricPattern1<Dollars>} max
|
||||
@@ -2601,6 +2643,27 @@ function createCostBasisPattern2(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} CoinbasePattern2
|
||||
* @property {BlockCountPattern<Bitcoin>} bitcoin
|
||||
* @property {BlockCountPattern<Dollars>} dollars
|
||||
* @property {BlockCountPattern<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CoinbasePattern2 pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CoinbasePattern2}
|
||||
*/
|
||||
function createCoinbasePattern2(client, acc) {
|
||||
return {
|
||||
bitcoin: createBlockCountPattern(client, _m(acc, 'btc')),
|
||||
dollars: createBlockCountPattern(client, _m(acc, 'usd')),
|
||||
sats: createBlockCountPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SegwitAdoptionPattern
|
||||
* @property {MetricPattern11<StoredF32>} base
|
||||
@@ -2643,69 +2706,6 @@ function createCoinbasePattern(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
|
||||
* @property {BlockCountPattern<Dollars>} dollars
|
||||
* @property {BlockCountPattern<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a CoinbasePattern2 pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {CoinbasePattern2}
|
||||
*/
|
||||
function createCoinbasePattern2(client, acc) {
|
||||
return {
|
||||
bitcoin: createBlockCountPattern(client, _m(acc, 'btc')),
|
||||
dollars: createBlockCountPattern(client, _m(acc, 'usd')),
|
||||
sats: createBlockCountPattern(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} ActiveSupplyPattern
|
||||
* @property {MetricPattern1<Bitcoin>} bitcoin
|
||||
* @property {MetricPattern1<Dollars>} dollars
|
||||
* @property {MetricPattern1<Sats>} sats
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a ActiveSupplyPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {ActiveSupplyPattern}
|
||||
*/
|
||||
function createActiveSupplyPattern(client, acc) {
|
||||
return {
|
||||
bitcoin: createMetricPattern1(client, _m(acc, 'btc')),
|
||||
dollars: createMetricPattern1(client, _m(acc, 'usd')),
|
||||
sats: createMetricPattern1(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} UnclaimedRewardsPattern
|
||||
* @property {BitcoinPattern2<Bitcoin>} bitcoin
|
||||
@@ -2727,25 +2727,6 @@ function createUnclaimedRewardsPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _1dReturns1mSdPattern
|
||||
* @property {MetricPattern4<StoredF32>} sd
|
||||
* @property {MetricPattern4<StoredF32>} sma
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _1dReturns1mSdPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_1dReturns1mSdPattern}
|
||||
*/
|
||||
function create_1dReturns1mSdPattern(client, acc) {
|
||||
return {
|
||||
sd: createMetricPattern4(client, _m(acc, 'sd')),
|
||||
sma: createMetricPattern4(client, _m(acc, 'sma')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SupplyPattern2
|
||||
* @property {ActiveSupplyPattern} halved
|
||||
@@ -2803,6 +2784,25 @@ function createCostBasisPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} _1dReturns1mSdPattern
|
||||
* @property {MetricPattern4<StoredF32>} sd
|
||||
* @property {MetricPattern4<StoredF32>} sma
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a _1dReturns1mSdPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {_1dReturns1mSdPattern}
|
||||
*/
|
||||
function create_1dReturns1mSdPattern(client, acc) {
|
||||
return {
|
||||
sd: createMetricPattern4(client, _m(acc, 'sd')),
|
||||
sma: createMetricPattern4(client, _m(acc, 'sma')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} BitcoinPattern2
|
||||
@@ -2861,25 +2861,8 @@ function createBlockCountPattern(client, acc) {
|
||||
*/
|
||||
function createSatsPattern(client, acc) {
|
||||
return {
|
||||
ohlc: createMetricPattern1(client, _m(acc, 'ohlc_sats')),
|
||||
split: createSplitPattern2(client, _m(acc, 'sats')),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} OutputsPattern
|
||||
* @property {MetricPattern1<StoredU64>} utxoCount
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a OutputsPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {OutputsPattern}
|
||||
*/
|
||||
function createOutputsPattern(client, acc) {
|
||||
return {
|
||||
utxoCount: createMetricPattern1(client, acc),
|
||||
ohlc: createMetricPattern1(client, _m(acc, 'ohlc')),
|
||||
split: createSplitPattern2(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2900,6 +2883,23 @@ function createRealizedPriceExtraPattern(client, acc) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} OutputsPattern
|
||||
* @property {MetricPattern1<StoredU64>} utxoCount
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a OutputsPattern pattern node
|
||||
* @param {BrkClientBase} client
|
||||
* @param {string} acc - Accumulated metric name
|
||||
* @returns {OutputsPattern}
|
||||
*/
|
||||
function createOutputsPattern(client, acc) {
|
||||
return {
|
||||
utxoCount: createMetricPattern1(client, acc),
|
||||
};
|
||||
}
|
||||
|
||||
// Catalog tree typedefs
|
||||
|
||||
/**
|
||||
@@ -4055,8 +4055,8 @@ function createRealizedPriceExtraPattern(client, acc) {
|
||||
* @typedef {Object} MetricsTree_Price
|
||||
* @property {MetricsTree_Price_Cents} cents
|
||||
* @property {MetricsTree_Price_Oracle} oracle
|
||||
* @property {SatsPattern<OHLCSats>} sats
|
||||
* @property {MetricsTree_Price_Usd} usd
|
||||
* @property {MetricsTree_Price_Sats} sats
|
||||
* @property {SatsPattern<OHLCDollars>} usd
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -4090,9 +4090,9 @@ function createRealizedPriceExtraPattern(client, acc) {
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} MetricsTree_Price_Usd
|
||||
* @property {MetricPattern1<OHLCDollars>} ohlc
|
||||
* @property {SplitPattern2<Dollars>} split
|
||||
* @typedef {Object} MetricsTree_Price_Sats
|
||||
* @property {MetricPattern1<OHLCSats>} ohlc
|
||||
* @property {SplitPattern2<Sats>} split
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -5637,7 +5637,7 @@ class BrkClient extends BrkClientBase {
|
||||
identity: createMetricPattern10(this, 'halvingepoch'),
|
||||
},
|
||||
height: {
|
||||
dateindex: createMetricPattern11(this, 'height_dateindex'),
|
||||
dateindex: createMetricPattern11(this, 'dateindex'),
|
||||
difficultyepoch: createMetricPattern11(this, 'difficultyepoch'),
|
||||
halvingepoch: createMetricPattern11(this, 'halvingepoch'),
|
||||
identity: createMetricPattern11(this, 'height'),
|
||||
@@ -6058,11 +6058,11 @@ class BrkClient extends BrkClientBase {
|
||||
priceCents: createMetricPattern11(this, 'oracle_price_cents'),
|
||||
txCount: createMetricPattern6(this, 'oracle_tx_count'),
|
||||
},
|
||||
sats: createSatsPattern(this, 'price'),
|
||||
usd: {
|
||||
ohlc: createMetricPattern1(this, 'price_ohlc'),
|
||||
split: createSplitPattern2(this, 'price'),
|
||||
sats: {
|
||||
ohlc: createMetricPattern1(this, 'price_ohlc_sats'),
|
||||
split: createSplitPattern2(this, 'price_sats'),
|
||||
},
|
||||
usd: createSatsPattern(this, 'price'),
|
||||
},
|
||||
scripts: {
|
||||
count: {
|
||||
|
||||
@@ -1882,31 +1882,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 ActivePriceRatioPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, acc)
|
||||
self.ratio_1m_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1m_sma'))
|
||||
self.ratio_1w_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1w_sma'))
|
||||
self.ratio_1y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '1y'))
|
||||
self.ratio_2y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '2y'))
|
||||
self.ratio_4y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '4y'))
|
||||
self.ratio_pct1: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct1'))
|
||||
self.ratio_pct1_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct1_usd'))
|
||||
self.ratio_pct2: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct2'))
|
||||
self.ratio_pct2_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct2_usd'))
|
||||
self.ratio_pct5: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct5'))
|
||||
self.ratio_pct5_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct5_usd'))
|
||||
self.ratio_pct95: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct95'))
|
||||
self.ratio_pct95_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct95_usd'))
|
||||
self.ratio_pct98: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct98'))
|
||||
self.ratio_pct98_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct98_usd'))
|
||||
self.ratio_pct99: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct99'))
|
||||
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."""
|
||||
|
||||
@@ -1932,6 +1907,31 @@ class PercentilesPattern:
|
||||
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."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, acc)
|
||||
self.ratio_1m_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1m_sma'))
|
||||
self.ratio_1w_sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, '1w_sma'))
|
||||
self.ratio_1y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '1y'))
|
||||
self.ratio_2y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '2y'))
|
||||
self.ratio_4y_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, _m(acc, '4y'))
|
||||
self.ratio_pct1: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct1'))
|
||||
self.ratio_pct1_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct1_usd'))
|
||||
self.ratio_pct2: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct2'))
|
||||
self.ratio_pct2_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct2_usd'))
|
||||
self.ratio_pct5: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct5'))
|
||||
self.ratio_pct5_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct5_usd'))
|
||||
self.ratio_pct95: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct95'))
|
||||
self.ratio_pct95_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct95_usd'))
|
||||
self.ratio_pct98: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct98'))
|
||||
self.ratio_pct98_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct98_usd'))
|
||||
self.ratio_pct99: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'pct99'))
|
||||
self.ratio_pct99_usd: MetricPattern4[Dollars] = MetricPattern4(client, _m(acc, 'pct99_usd'))
|
||||
self.ratio_sd: Ratio1ySdPattern = Ratio1ySdPattern(client, acc)
|
||||
|
||||
class RelativePattern5:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2048,23 +2048,6 @@ class BitcoinPattern:
|
||||
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."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.average: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'average'))
|
||||
self.base: MetricPattern11[T] = MetricPattern11(client, acc)
|
||||
self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative'))
|
||||
self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max'))
|
||||
self.median: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'median'))
|
||||
self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min'))
|
||||
self.pct10: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct10'))
|
||||
self.pct25: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct25'))
|
||||
self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75'))
|
||||
self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90'))
|
||||
self.sum: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum'))
|
||||
|
||||
class ClassAveragePricePattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2082,21 +2065,22 @@ class ClassAveragePricePattern(Generic[T]):
|
||||
self._2024: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2024_average_price'))
|
||||
self._2025: MetricPattern4[T] = MetricPattern4(client, _m(acc, '2025_average_price'))
|
||||
|
||||
class RelativePattern:
|
||||
class DollarsPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.neg_unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap'))
|
||||
self.net_unrealized_pnl_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap'))
|
||||
self.nupl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'nupl'))
|
||||
self.supply_in_loss_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply'))
|
||||
self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply'))
|
||||
self.supply_in_profit_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply'))
|
||||
self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply'))
|
||||
self.supply_rel_to_circulating_supply: MetricPattern4[StoredF64] = MetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply'))
|
||||
self.unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap'))
|
||||
self.unrealized_profit_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap'))
|
||||
self.average: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'average'))
|
||||
self.base: MetricPattern11[T] = MetricPattern11(client, acc)
|
||||
self.cumulative: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'cumulative'))
|
||||
self.max: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'max'))
|
||||
self.median: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'median'))
|
||||
self.min: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'min'))
|
||||
self.pct10: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct10'))
|
||||
self.pct25: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct25'))
|
||||
self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75'))
|
||||
self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90'))
|
||||
self.sum: MetricPattern2[T] = MetricPattern2(client, _m(acc, 'sum'))
|
||||
|
||||
class RelativePattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -2114,6 +2098,22 @@ class RelativePattern2:
|
||||
self.unrealized_profit_rel_to_own_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_market_cap'))
|
||||
self.unrealized_profit_rel_to_own_total_unrealized_pnl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_own_total_unrealized_pnl'))
|
||||
|
||||
class RelativePattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.neg_unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'neg_unrealized_loss_rel_to_market_cap'))
|
||||
self.net_unrealized_pnl_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'net_unrealized_pnl_rel_to_market_cap'))
|
||||
self.nupl: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'nupl'))
|
||||
self.supply_in_loss_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_circulating_supply'))
|
||||
self.supply_in_loss_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_loss_rel_to_own_supply'))
|
||||
self.supply_in_profit_rel_to_circulating_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_circulating_supply'))
|
||||
self.supply_in_profit_rel_to_own_supply: MetricPattern1[StoredF64] = MetricPattern1(client, _m(acc, 'supply_in_profit_rel_to_own_supply'))
|
||||
self.supply_rel_to_circulating_supply: MetricPattern4[StoredF64] = MetricPattern4(client, _m(acc, 'supply_rel_to_circulating_supply'))
|
||||
self.unrealized_loss_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_loss_rel_to_market_cap'))
|
||||
self.unrealized_profit_rel_to_market_cap: MetricPattern1[StoredF32] = MetricPattern1(client, _m(acc, 'unrealized_profit_rel_to_market_cap'))
|
||||
|
||||
class CountPattern2(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2145,21 +2145,6 @@ class AddrCountPattern:
|
||||
self.p2wpkh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wpkh', acc))
|
||||
self.p2wsh: MetricPattern1[StoredU64] = MetricPattern1(client, _p('p2wsh', acc))
|
||||
|
||||
class FeeRatePattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.average: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'average'))
|
||||
self.max: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'max'))
|
||||
self.median: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'median'))
|
||||
self.min: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'min'))
|
||||
self.pct10: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct10'))
|
||||
self.pct25: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct25'))
|
||||
self.pct75: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct75'))
|
||||
self.pct90: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct90'))
|
||||
self.txindex: MetricPattern27[T] = MetricPattern27(client, acc)
|
||||
|
||||
class FullnessPattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2175,6 +2160,21 @@ class FullnessPattern(Generic[T]):
|
||||
self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75'))
|
||||
self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90'))
|
||||
|
||||
class FeeRatePattern(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.average: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'average'))
|
||||
self.max: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'max'))
|
||||
self.median: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'median'))
|
||||
self.min: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'min'))
|
||||
self.pct10: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct10'))
|
||||
self.pct25: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct25'))
|
||||
self.pct75: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct75'))
|
||||
self.pct90: MetricPattern11[T] = MetricPattern11(client, _m(acc, 'pct90'))
|
||||
self.txindex: MetricPattern27[T] = MetricPattern27(client, acc)
|
||||
|
||||
class _0satsPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2203,19 +2203,6 @@ class PhaseDailyCentsPattern(Generic[T]):
|
||||
self.pct75: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct75'))
|
||||
self.pct90: MetricPattern6[T] = MetricPattern6(client, _m(acc, 'pct90'))
|
||||
|
||||
class _10yPattern:
|
||||
"""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: RealizedPattern4 = RealizedPattern4(client, acc)
|
||||
self.relative: RelativePattern = RelativePattern(client, acc)
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
|
||||
class UnrealizedPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2229,16 +2216,16 @@ class UnrealizedPattern:
|
||||
self.unrealized_loss: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_loss'))
|
||||
self.unrealized_profit: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'unrealized_profit'))
|
||||
|
||||
class _0satsPattern2:
|
||||
class _10yTo12yPattern:
|
||||
"""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.cost_basis: CostBasisPattern2 = CostBasisPattern2(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.realized: RealizedPattern2 = RealizedPattern2(client, acc)
|
||||
self.relative: RelativePattern2 = RelativePattern2(client, acc)
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
|
||||
@@ -2255,6 +2242,19 @@ class PeriodCagrPattern:
|
||||
self._6y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('6y', acc))
|
||||
self._8y: MetricPattern4[StoredF32] = MetricPattern4(client, _p('8y', acc))
|
||||
|
||||
class _10yPattern:
|
||||
"""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: RealizedPattern4 = RealizedPattern4(client, acc)
|
||||
self.relative: RelativePattern = RelativePattern(client, acc)
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
|
||||
class _100btcPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2268,16 +2268,16 @@ class _100btcPattern:
|
||||
self.supply: SupplyPattern2 = SupplyPattern2(client, _m(acc, 'supply'))
|
||||
self.unrealized: UnrealizedPattern = UnrealizedPattern(client, acc)
|
||||
|
||||
class _10yTo12yPattern:
|
||||
class _0satsPattern2:
|
||||
"""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: CostBasisPattern2 = CostBasisPattern2(client, acc)
|
||||
self.cost_basis: CostBasisPattern = CostBasisPattern(client, acc)
|
||||
self.outputs: OutputsPattern = OutputsPattern(client, _m(acc, 'utxo_count'))
|
||||
self.realized: RealizedPattern2 = RealizedPattern2(client, acc)
|
||||
self.relative: RelativePattern2 = RelativePattern2(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)
|
||||
|
||||
@@ -2302,6 +2302,24 @@ class SplitPattern2(Generic[T]):
|
||||
self.low: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'low'))
|
||||
self.open: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'open'))
|
||||
|
||||
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 ActiveSupplyPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.bitcoin: MetricPattern1[Bitcoin] = MetricPattern1(client, _m(acc, 'btc'))
|
||||
self.dollars: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'usd'))
|
||||
self.sats: MetricPattern1[Sats] = MetricPattern1(client, acc)
|
||||
|
||||
class CostBasisPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2311,6 +2329,15 @@ class CostBasisPattern2:
|
||||
self.min: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'min_cost_basis'))
|
||||
self.percentiles: PercentilesPattern = PercentilesPattern(client, _m(acc, 'cost_basis'))
|
||||
|
||||
class CoinbasePattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.bitcoin: BlockCountPattern[Bitcoin] = BlockCountPattern(client, _m(acc, 'btc'))
|
||||
self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd'))
|
||||
self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc)
|
||||
|
||||
class SegwitAdoptionPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2329,33 +2356,6 @@ class CoinbasePattern:
|
||||
self.dollars: DollarsPattern[Dollars] = DollarsPattern(client, _m(acc, 'usd'))
|
||||
self.sats: DollarsPattern[Sats] = DollarsPattern(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."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.bitcoin: BlockCountPattern[Bitcoin] = BlockCountPattern(client, _m(acc, 'btc'))
|
||||
self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd'))
|
||||
self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc)
|
||||
|
||||
class ActiveSupplyPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.bitcoin: MetricPattern1[Bitcoin] = MetricPattern1(client, _m(acc, 'btc'))
|
||||
self.dollars: MetricPattern1[Dollars] = MetricPattern1(client, _m(acc, 'usd'))
|
||||
self.sats: MetricPattern1[Sats] = MetricPattern1(client, acc)
|
||||
|
||||
class UnclaimedRewardsPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2365,14 +2365,6 @@ class UnclaimedRewardsPattern:
|
||||
self.dollars: BlockCountPattern[Dollars] = BlockCountPattern(client, _m(acc, 'usd'))
|
||||
self.sats: BlockCountPattern[Sats] = BlockCountPattern(client, acc)
|
||||
|
||||
class _1dReturns1mSdPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd'))
|
||||
self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma'))
|
||||
|
||||
class SupplyPattern2:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2397,6 +2389,14 @@ class CostBasisPattern:
|
||||
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."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.sd: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sd'))
|
||||
self.sma: MetricPattern4[StoredF32] = MetricPattern4(client, _m(acc, 'sma'))
|
||||
|
||||
class BitcoinPattern2(Generic[T]):
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
@@ -2418,15 +2418,8 @@ class SatsPattern(Generic[T]):
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.ohlc: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'ohlc_sats'))
|
||||
self.split: SplitPattern2[T] = SplitPattern2(client, _m(acc, 'sats'))
|
||||
|
||||
class OutputsPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.utxo_count: MetricPattern1[StoredU64] = MetricPattern1(client, acc)
|
||||
self.ohlc: MetricPattern1[T] = MetricPattern1(client, _m(acc, 'ohlc'))
|
||||
self.split: SplitPattern2[T] = SplitPattern2(client, acc)
|
||||
|
||||
class RealizedPriceExtraPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
@@ -2435,6 +2428,13 @@ class RealizedPriceExtraPattern:
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.ratio: MetricPattern4[StoredF32] = MetricPattern4(client, acc)
|
||||
|
||||
class OutputsPattern:
|
||||
"""Pattern struct for repeated tree structure."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, acc: str):
|
||||
"""Create pattern node with accumulated metric name."""
|
||||
self.utxo_count: MetricPattern1[StoredU64] = MetricPattern1(client, acc)
|
||||
|
||||
# Metrics tree classes
|
||||
|
||||
class MetricsTree_Addresses:
|
||||
@@ -3144,7 +3144,7 @@ class MetricsTree_Indexes_Height:
|
||||
"""Metrics tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.dateindex: MetricPattern11[DateIndex] = MetricPattern11(client, 'height_dateindex')
|
||||
self.dateindex: MetricPattern11[DateIndex] = MetricPattern11(client, 'dateindex')
|
||||
self.difficultyepoch: MetricPattern11[DifficultyEpoch] = MetricPattern11(client, 'difficultyepoch')
|
||||
self.halvingepoch: MetricPattern11[HalvingEpoch] = MetricPattern11(client, 'halvingepoch')
|
||||
self.identity: MetricPattern11[Height] = MetricPattern11(client, 'height')
|
||||
@@ -3687,12 +3687,12 @@ class MetricsTree_Price_Oracle:
|
||||
self.price_cents: MetricPattern11[Cents] = MetricPattern11(client, 'oracle_price_cents')
|
||||
self.tx_count: MetricPattern6[StoredU32] = MetricPattern6(client, 'oracle_tx_count')
|
||||
|
||||
class MetricsTree_Price_Usd:
|
||||
class MetricsTree_Price_Sats:
|
||||
"""Metrics tree node."""
|
||||
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.ohlc: MetricPattern1[OHLCDollars] = MetricPattern1(client, 'price_ohlc')
|
||||
self.split: SplitPattern2[Dollars] = SplitPattern2(client, 'price')
|
||||
self.ohlc: MetricPattern1[OHLCSats] = MetricPattern1(client, 'price_ohlc_sats')
|
||||
self.split: SplitPattern2[Sats] = SplitPattern2(client, 'price_sats')
|
||||
|
||||
class MetricsTree_Price:
|
||||
"""Metrics tree node."""
|
||||
@@ -3700,8 +3700,8 @@ class MetricsTree_Price:
|
||||
def __init__(self, client: BrkClientBase, base_path: str = ''):
|
||||
self.cents: MetricsTree_Price_Cents = MetricsTree_Price_Cents(client)
|
||||
self.oracle: MetricsTree_Price_Oracle = MetricsTree_Price_Oracle(client)
|
||||
self.sats: SatsPattern[OHLCSats] = SatsPattern(client, 'price')
|
||||
self.usd: MetricsTree_Price_Usd = MetricsTree_Price_Usd(client)
|
||||
self.sats: MetricsTree_Price_Sats = MetricsTree_Price_Sats(client)
|
||||
self.usd: SatsPattern[OHLCDollars] = SatsPattern(client, 'price')
|
||||
|
||||
class MetricsTree_Scripts_Count:
|
||||
"""Metrics tree node."""
|
||||
|
||||
1081
research/analyze_price_signals.py
Normal file
1081
research/analyze_price_signals.py
Normal file
File diff suppressed because it is too large
Load Diff
174
research/oracle_filter_analysis.md
Normal file
174
research/oracle_filter_analysis.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# Oracle Filter Analysis
|
||||
|
||||
## Summary
|
||||
|
||||
Analysis of ~20M outputs across 2017-2018 to find filters that distinguish accurate price signals from noise.
|
||||
|
||||
## Key Finding: Round USD is the Only Reliable Filter
|
||||
|
||||
| Filter | Accuracy Advantage | Consistency |
|
||||
|--------|-------------------|-------------|
|
||||
| **Round USD = True** | **+20% to +29%** | **12/12 months** |
|
||||
| Round BTC | +12% to -8% | Flips with price |
|
||||
| Value range/Decade | varies | Shifts with price |
|
||||
| Same-day spend | ~3% | Weak |
|
||||
| Micro-round sats | 0-5% | Inconsistent |
|
||||
| Tx pattern | <5% | Weak |
|
||||
| Is smaller output | ~3-4% | Weak |
|
||||
|
||||
## Why Other Filters Fail
|
||||
|
||||
### Round BTC (Unreliable)
|
||||
- Jan-Mar 2017 ($1k): Round BTC = True is GOOD (+10-12%)
|
||||
- Jun-Jul 2017 ($2.5k): Round BTC = True is BAD (-7%)
|
||||
- Reason: Round BTC only correlates with accuracy when it happens to align with round USD at current price
|
||||
|
||||
### Value Range / Decade (Price-Dependent)
|
||||
- At $1,000/BTC: Decade 5 (100k-1M sats) is good
|
||||
- At $10,000/BTC: Decade 6 (1M-10M sats) is good
|
||||
- At $100,000/BTC: Decade 7 (10M-100M sats) would be good
|
||||
- These shift with price, making them useless as static filters
|
||||
|
||||
## The Round USD Insight
|
||||
|
||||
Round USD amounts ($1, $5, $10, $20, $50, $100, etc.) always map to the **same phase bins** regardless of price level:
|
||||
|
||||
```
|
||||
$100 at $10,000/BTC = 1,000,000 sats → log10 = 6.0 → phase = 0.0 → bin 0
|
||||
$100 at $100,000/BTC = 100,000 sats → log10 = 5.0 → phase = 0.0 → bin 0
|
||||
$100 at $1,000/BTC = 10,000,000 sats → log10 = 7.0 → phase = 0.0 → bin 0
|
||||
```
|
||||
|
||||
The phase = `frac(log10(sats))` is **invariant** to price decade!
|
||||
|
||||
## Round USD Phase Bins
|
||||
|
||||
| USD Amount | log10(USD) | Phase = frac(log10) | Bin (×100) |
|
||||
|------------|------------|---------------------|------------|
|
||||
| $1, $10, $100, $1000 | 0, 1, 2, 3 | 0.00 | 0 |
|
||||
| $1.50, $15, $150 | 0.18, 1.18, 2.18 | 0.18 | 18 |
|
||||
| $2, $20, $200 | 0.30, 1.30, 2.30 | 0.30 | 30 |
|
||||
| $2.50, $25, $250 | 0.40, 1.40, 2.40 | 0.40 | 40 |
|
||||
| $3, $30, $300 | 0.48, 1.48, 2.48 | 0.48 | 48 |
|
||||
| $4, $40, $400 | 0.60, 1.60, 2.60 | 0.60 | 60 |
|
||||
| $5, $50, $500 | 0.70, 1.70, 2.70 | 0.70 | 70 |
|
||||
| $6, $60, $600 | 0.78, 1.78, 2.78 | 0.78 | 78 |
|
||||
| $7, $70, $700 | 0.85, 1.85, 2.85 | 0.85 | 85 |
|
||||
| $8, $80, $800 | 0.90, 1.90, 2.90 | 0.90 | 90 |
|
||||
| $9, $90, $900 | 0.95, 1.95, 2.95 | 0.95 | 95 |
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Approach: Phase-Based Round USD Filtering
|
||||
|
||||
Filter outputs to only those whose phase bin corresponds to a round USD amount. No price knowledge needed.
|
||||
|
||||
```rust
|
||||
/// Phase bins where round USD amounts cluster
|
||||
/// Computed as: bin = round(frac(log10(usd_cents)) * 100)
|
||||
const ROUND_USD_BINS: &[u8] = &[
|
||||
0, // $1, $10, $100, $1000 (and $0.10, $0.01)
|
||||
18, // $1.50, $15, $150
|
||||
30, // $2, $20, $200
|
||||
40, // $2.50, $25, $250
|
||||
48, // $3, $30, $300
|
||||
60, // $4, $40, $400
|
||||
70, // $5, $50, $500
|
||||
78, // $6, $60, $600
|
||||
85, // $7, $70, $700
|
||||
90, // $8, $80, $800
|
||||
95, // $9, $90, $900
|
||||
];
|
||||
|
||||
/// Check if a histogram bin corresponds to a round USD amount
|
||||
fn is_round_usd_bin(bin: usize, tolerance: u8) -> bool {
|
||||
let phase_bin = (bin % 100) as u8;
|
||||
ROUND_USD_BINS.iter().any(|&round_bin| {
|
||||
let diff = if phase_bin >= round_bin {
|
||||
phase_bin - round_bin
|
||||
} else {
|
||||
round_bin - phase_bin
|
||||
};
|
||||
// Handle wraparound (bin 99 is close to bin 0)
|
||||
diff <= tolerance || (100 - diff) <= tolerance
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Where to Apply Filter
|
||||
|
||||
In `compute.rs`, when adding outputs to histogram:
|
||||
|
||||
```rust
|
||||
for sats in values {
|
||||
if let Some(bin) = Histogram::sats_to_bin(sats) {
|
||||
// Only include outputs in round-USD phase bins
|
||||
if is_round_usd_bin(bin, 2) { // ±2 bin tolerance
|
||||
block_sparse.push((bin as u16, 1.0));
|
||||
// ... rest of processing
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Expected Impact
|
||||
|
||||
- Reduces histogram noise by ~60-70% (only ~35% of accurate outputs are round USD)
|
||||
- Remaining outputs are 2-3x more likely to be accurate signals
|
||||
- Stencil matching should be more reliable with cleaner signal
|
||||
- Decade selection via anchors remains unchanged
|
||||
|
||||
### Alternative: Weighted Approach
|
||||
|
||||
Instead of hard filtering, weight round-USD bins higher:
|
||||
|
||||
```rust
|
||||
let weight = if is_round_usd_bin(bin, 2) { 3.0 } else { 1.0 };
|
||||
block_sparse.push((bin as u16, weight));
|
||||
```
|
||||
|
||||
This preserves some signal from non-round outputs while emphasizing round USD.
|
||||
|
||||
## Bin Resolution: 100 vs 200
|
||||
|
||||
UTXOracle uses **200 bins per decade**. Current phase oracle uses 100.
|
||||
|
||||
| Resolution | Precision | Round USD cluster |
|
||||
|------------|-----------|-------------------|
|
||||
| 100 bins | 1% per bin | Wider, more overlap |
|
||||
| 200 bins | 0.5% per bin | Tighter, cleaner separation |
|
||||
|
||||
**Round USD bins at 200 resolution:**
|
||||
| USD Amount | Phase = frac(log10) | Bin (×200) |
|
||||
|------------|---------------------|------------|
|
||||
| $1, $10, $100 | 0.000 | 0 |
|
||||
| $1.50, $15, $150 | 0.176 | 35 |
|
||||
| $2, $20, $200 | 0.301 | 60 |
|
||||
| $2.50, $25, $250 | 0.398 | 80 |
|
||||
| $3, $30, $300 | 0.477 | 95 |
|
||||
| $4, $40, $400 | 0.602 | 120 |
|
||||
| $5, $50, $500 | 0.699 | 140 |
|
||||
| $6, $60, $600 | 0.778 | 156 |
|
||||
| $7, $70, $700 | 0.845 | 169 |
|
||||
| $8, $80, $800 | 0.903 | 181 |
|
||||
| $9, $90, $900 | 0.954 | 191 |
|
||||
|
||||
**Recommendation**: Use 200 bins for:
|
||||
1. Compatibility with UTXOracle stencil
|
||||
2. Tighter round-USD detection
|
||||
3. Better separation of signal from noise
|
||||
|
||||
## Questions to Resolve
|
||||
|
||||
1. **Tolerance**: ±2 bins (at 200) = ±1% vs ±4 bins = ±2%
|
||||
2. **Hard filter vs weight**: Filter completely or just weight higher?
|
||||
3. **Minimum count threshold**: What if too few outputs pass filter?
|
||||
4. **Interaction with existing smooth_round_btc()**: Still needed?
|
||||
5. **Migration**: Update PHASE_BINS constant from 100 to 200
|
||||
|
||||
## Validation Plan
|
||||
|
||||
1. Implement phase-based filtering
|
||||
2. Run on 2017-2018 data
|
||||
3. Compare accuracy vs current approach
|
||||
4. Tune tolerance parameter
|
||||
2549
research/price_signal_analysis_report.txt
Normal file
2549
research/price_signal_analysis_report.txt
Normal file
File diff suppressed because it is too large
Load Diff
282
research/test_phase_detection.py
Normal file
282
research/test_phase_detection.py
Normal file
@@ -0,0 +1,282 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test price phase detection from outputs alone.
|
||||
The idea: Round USD outputs create a fingerprint pattern that reveals the price phase.
|
||||
"""
|
||||
|
||||
import math
|
||||
import http.client
|
||||
import json
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
API_HOST = "localhost"
|
||||
API_PORT = 3110
|
||||
|
||||
# Round USD phases (fixed fingerprint)
|
||||
# These are frac(log10(usd_cents)) for round USD values
|
||||
ROUND_USD_PHASES = [
|
||||
0.00, # $1, $10, $100, $1000
|
||||
0.18, # $1.50, $15, $150
|
||||
0.30, # $2, $20, $200
|
||||
0.40, # $2.50, $25, $250
|
||||
0.48, # $3, $30, $300
|
||||
0.60, # $4, $40, $400
|
||||
0.70, # $5, $50, $500
|
||||
0.78, # $6, $60, $600
|
||||
0.85, # $7, $70, $700
|
||||
0.90, # $8, $80, $800
|
||||
0.95, # $9, $90, $900
|
||||
]
|
||||
|
||||
_conn = None
|
||||
|
||||
def get_conn():
|
||||
global _conn
|
||||
if _conn is None:
|
||||
_conn = http.client.HTTPConnection(API_HOST, API_PORT, timeout=300)
|
||||
return _conn
|
||||
|
||||
def reset_conn():
|
||||
global _conn
|
||||
if _conn:
|
||||
try:
|
||||
_conn.close()
|
||||
except:
|
||||
pass
|
||||
_conn = None
|
||||
|
||||
def fetch(path: str, retries: int = 3):
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
conn = get_conn()
|
||||
conn.request("GET", path)
|
||||
resp = conn.getresponse()
|
||||
data = resp.read().decode('utf-8')
|
||||
return json.loads(data)
|
||||
except Exception as e:
|
||||
reset_conn()
|
||||
if attempt < retries - 1:
|
||||
time.sleep(2)
|
||||
else:
|
||||
raise
|
||||
|
||||
def fetch_chunked(path_template: str, start: int, end: int, chunk_size: int = 25000) -> list:
|
||||
result = []
|
||||
for chunk_start in range(start, end, chunk_size):
|
||||
chunk_end = min(chunk_start + chunk_size, end)
|
||||
path = path_template.format(start=chunk_start, end=chunk_end)
|
||||
data = fetch(path)["data"]
|
||||
result.extend(data)
|
||||
return result
|
||||
|
||||
|
||||
def get_sats_phase(sats: int) -> float:
|
||||
"""Get the phase (fractional part of log10) for a sats value."""
|
||||
if sats <= 0:
|
||||
return 0.0
|
||||
return math.log10(sats) % 1.0
|
||||
|
||||
|
||||
def count_round_usd_matches(outputs: list, price_phase: float, tolerance: float = 0.02) -> int:
|
||||
"""
|
||||
Count how many outputs match round USD bins at the given price phase.
|
||||
|
||||
At price_phase P, round USD outputs should appear at sats_phase = (usd_phase - P) mod 1
|
||||
"""
|
||||
# Compute expected sats phases for round USD at this price phase
|
||||
expected_phases = [(usd_phase - price_phase) % 1.0 for usd_phase in ROUND_USD_PHASES]
|
||||
|
||||
count = 0
|
||||
for sats in outputs:
|
||||
if sats is None or sats < 1000:
|
||||
continue
|
||||
sats_phase = get_sats_phase(sats)
|
||||
|
||||
# Check if sats_phase matches any expected phase
|
||||
for exp_phase in expected_phases:
|
||||
diff = abs(sats_phase - exp_phase)
|
||||
# Handle wraparound (0.99 is close to 0.01)
|
||||
if diff < tolerance or diff > (1.0 - tolerance):
|
||||
count += 1
|
||||
break
|
||||
|
||||
return count
|
||||
|
||||
|
||||
def find_best_price_phase(outputs: list, tolerance: float = 0.02, resolution: int = 100) -> tuple:
|
||||
"""
|
||||
Find the price phase that maximizes round USD matches.
|
||||
Returns (best_phase, best_count, all_counts).
|
||||
"""
|
||||
counts = []
|
||||
best_phase = 0.0
|
||||
best_count = 0
|
||||
|
||||
for i in range(resolution):
|
||||
price_phase = i / resolution
|
||||
count = count_round_usd_matches(outputs, price_phase, tolerance)
|
||||
counts.append(count)
|
||||
|
||||
if count > best_count:
|
||||
best_count = count
|
||||
best_phase = price_phase
|
||||
|
||||
return best_phase, best_count, counts
|
||||
|
||||
|
||||
def actual_price_phase(price: float) -> float:
|
||||
"""Get the actual price phase from a price."""
|
||||
return math.log10(price) % 1.0
|
||||
|
||||
|
||||
def analyze_day(date_str: str, start_height: int, end_height: int, actual_price: float):
|
||||
"""Analyze a single day's outputs."""
|
||||
|
||||
# Get transaction range for these heights
|
||||
first_tx = fetch(f"/api/metric/first_txindex/height?start={start_height}&end={end_height}")
|
||||
first_txs = first_tx["data"]
|
||||
if not first_txs or len(first_txs) < 2:
|
||||
return None
|
||||
|
||||
tx_start = first_txs[0]
|
||||
tx_end = first_txs[-1]
|
||||
|
||||
# Get output range
|
||||
tx_first_out = fetch_chunked("/api/metric/first_txoutindex/txindex?start={start}&end={end}", tx_start, tx_end)
|
||||
if not tx_first_out:
|
||||
return None
|
||||
|
||||
out_start = tx_first_out[0]
|
||||
out_end = tx_first_out[-1] + 10 # estimate
|
||||
|
||||
# Fetch output values
|
||||
out_values = fetch_chunked("/api/metric/value/txoutindex?start={start}&end={end}", out_start, out_end)
|
||||
|
||||
# Filter to reasonable range (1000 sats to 100 BTC)
|
||||
outputs = [v for v in out_values if v and 1000 <= v <= 10_000_000_000]
|
||||
|
||||
if len(outputs) < 1000:
|
||||
return None
|
||||
|
||||
# Find best price phase
|
||||
detected_phase, match_count, _ = find_best_price_phase(outputs, tolerance=0.02)
|
||||
|
||||
# Compare with actual
|
||||
actual_phase = actual_price_phase(actual_price)
|
||||
|
||||
# Phase error (handle wraparound)
|
||||
phase_error = abs(detected_phase - actual_phase)
|
||||
if phase_error > 0.5:
|
||||
phase_error = 1.0 - phase_error
|
||||
|
||||
return {
|
||||
'date': date_str,
|
||||
'actual_price': actual_price,
|
||||
'actual_phase': actual_phase,
|
||||
'detected_phase': detected_phase,
|
||||
'phase_error': phase_error,
|
||||
'match_count': match_count,
|
||||
'total_outputs': len(outputs),
|
||||
'match_pct': 100 * match_count / len(outputs),
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("PRICE PHASE DETECTION TEST")
|
||||
print("=" * 60)
|
||||
print("\nIdea: Round USD outputs form a fingerprint pattern.")
|
||||
print("Sliding this pattern across the histogram reveals the price phase.\n")
|
||||
|
||||
# Fetch dates
|
||||
print("Fetching date index...")
|
||||
dates = fetch("/api/metric/date/dateindex?start=0&end=4000")["data"]
|
||||
|
||||
# Fetch daily OHLC
|
||||
print("Fetching daily prices...")
|
||||
ohlc_data = fetch("/api/metric/price_ohlc/dateindex?start=2800&end=3600")["data"]
|
||||
|
||||
# Fetch heights
|
||||
print("Fetching heights...")
|
||||
heights = fetch("/api/metric/first_height/dateindex?start=2800&end=3600")["data"]
|
||||
|
||||
results = []
|
||||
|
||||
# Test on 2017-2018 (roughly dateindex 2900-3600)
|
||||
# Sample every 7 days to speed up
|
||||
for di in range(2900, 3550, 7):
|
||||
if di - 2800 >= len(ohlc_data) or di - 2800 >= len(heights):
|
||||
continue
|
||||
|
||||
ohlc = ohlc_data[di - 2800]
|
||||
if not ohlc or len(ohlc) < 4:
|
||||
continue
|
||||
|
||||
# Use close price as "actual"
|
||||
actual_price = ohlc[3]
|
||||
if not actual_price or actual_price <= 0:
|
||||
continue
|
||||
|
||||
date_str = dates[di] if di < len(dates) else f"di={di}"
|
||||
|
||||
start_height = heights[di - 2800]
|
||||
end_height = heights[di - 2800 + 1] if di - 2800 + 1 < len(heights) else start_height + 144
|
||||
|
||||
if not start_height:
|
||||
continue
|
||||
|
||||
print(f"\nAnalyzing {date_str} (${actual_price:.0f})...")
|
||||
|
||||
try:
|
||||
result = analyze_day(date_str, start_height, end_height, actual_price)
|
||||
if result:
|
||||
results.append(result)
|
||||
print(f" Actual phase: {result['actual_phase']:.3f}")
|
||||
print(f" Detected phase: {result['detected_phase']:.3f}")
|
||||
print(f" Phase error: {result['phase_error']:.3f} ({result['phase_error']*100:.1f}%)")
|
||||
print(f" Matches: {result['match_count']:,} / {result['total_outputs']:,} ({result['match_pct']:.1f}%)")
|
||||
except Exception as e:
|
||||
print(f" Error: {e}")
|
||||
continue
|
||||
|
||||
# Summary
|
||||
if results:
|
||||
print("\n" + "=" * 60)
|
||||
print("SUMMARY")
|
||||
print("=" * 60)
|
||||
|
||||
errors = [r['phase_error'] for r in results]
|
||||
avg_error = sum(errors) / len(errors)
|
||||
|
||||
# Count how many are within various thresholds
|
||||
within_01 = sum(1 for e in errors if e <= 0.01)
|
||||
within_02 = sum(1 for e in errors if e <= 0.02)
|
||||
within_05 = sum(1 for e in errors if e <= 0.05)
|
||||
within_10 = sum(1 for e in errors if e <= 0.10)
|
||||
|
||||
print(f"\nTotal days analyzed: {len(results)}")
|
||||
print(f"Average phase error: {avg_error:.3f} ({avg_error*100:.1f}%)")
|
||||
print(f"\nPhase error distribution:")
|
||||
print(f" ≤1%: {within_01:3d} / {len(results)} ({100*within_01/len(results):.0f}%)")
|
||||
print(f" ≤2%: {within_02:3d} / {len(results)} ({100*within_02/len(results):.0f}%)")
|
||||
print(f" ≤5%: {within_05:3d} / {len(results)} ({100*within_05/len(results):.0f}%)")
|
||||
print(f" ≤10%: {within_10:3d} / {len(results)} ({100*within_10/len(results):.0f}%)")
|
||||
|
||||
# Show worst cases
|
||||
print(f"\nWorst cases:")
|
||||
worst = sorted(results, key=lambda r: -r['phase_error'])[:5]
|
||||
for r in worst:
|
||||
print(f" {r['date']}: detected {r['detected_phase']:.2f} vs actual {r['actual_phase']:.2f} "
|
||||
f"(error {r['phase_error']:.2f}, ${r['actual_price']:.0f})")
|
||||
|
||||
# Show best cases
|
||||
print(f"\nBest cases:")
|
||||
best = sorted(results, key=lambda r: r['phase_error'])[:5]
|
||||
for r in best:
|
||||
print(f" {r['date']}: detected {r['detected_phase']:.2f} vs actual {r['actual_phase']:.2f} "
|
||||
f"(error {r['phase_error']:.3f}, ${r['actual_price']:.0f})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -37,24 +37,30 @@ export function createMarketSection(ctx) {
|
||||
title: "Bitcoin Price",
|
||||
...(localhost && {
|
||||
top: [
|
||||
candlestick({
|
||||
metric: price.oracle.ohlcDollars,
|
||||
name: "Oracle",
|
||||
unit: Unit.usd,
|
||||
colors: [colors.cyan, colors.purple],
|
||||
}),
|
||||
// candlestick({
|
||||
// metric: price.oracle.ohlcDollars,
|
||||
// name: "Oracle base",
|
||||
// unit: Unit.usd,
|
||||
// colors: [colors.cyan, colors.purple],
|
||||
// }),
|
||||
line({
|
||||
metric: price.oracle.phaseDailyDollars.median,
|
||||
name: "Oracle2 median",
|
||||
unit: Unit.usd,
|
||||
color: colors.blue,
|
||||
}),
|
||||
line({
|
||||
metric: price.oracle.phaseDailyDollars.average,
|
||||
name: "Oracle2 average",
|
||||
name: "o. p50",
|
||||
unit: Unit.usd,
|
||||
color: colors.yellow,
|
||||
}),
|
||||
line({
|
||||
metric: price.oracle.phaseDailyDollars.max,
|
||||
name: "o. max",
|
||||
unit: Unit.usd,
|
||||
color: colors.lime,
|
||||
}),
|
||||
line({
|
||||
metric: price.oracle.phaseDailyDollars.min,
|
||||
name: "o. min",
|
||||
unit: Unit.usd,
|
||||
color: colors.rose,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user