heatmaps: part 13

This commit is contained in:
nym21
2026-06-01 11:17:00 +02:00
parent e64ffac8d1
commit 102933b406
10 changed files with 162 additions and 142 deletions
+20 -20
View File
@@ -9865,40 +9865,40 @@ impl BrkClient {
self.base.get_json(&format!("/api/oracle/price"))
}
/// Live EMA histogram
/// Live payment output histogram
///
/// Smoothed round-dollar payment histogram at the live tip: the committed EMA with the forming mempool block blended in. A flat array of log-scale bins.
/// Live smoothed histogram of oracle-eligible payment outputs, binned by output value on the oracle log scale. It combines the committed oracle window with the forming mempool block. A flat array of log-scale bins.
///
/// Endpoint: `GET /api/oracle/histogram/ema/live`
pub fn get_oracle_histogram_ema_live(&self) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/ema/live"))
/// Endpoint: `GET /api/oracle/histogram/payments/live`
pub fn get_oracle_histogram_payments_live(&self) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/payments/live"))
}
/// EMA histogram at height or day
/// Payment output histogram at height or day
///
/// Smoothed round-dollar payment histogram for a confirmed point: a block height (`840000`) gives that block's EMA, a calendar date (`YYYY-MM-DD`) gives the average of that day's per-block EMAs. A flat array of log-scale bins.
/// Smoothed histogram of oracle-eligible payment outputs for a confirmed point. A block height (`840000`) gives that block's oracle payment histogram; a calendar date (`YYYY-MM-DD`) gives the average of that day's per-block payment histograms. A flat array of log-scale bins.
///
/// Endpoint: `GET /api/oracle/histogram/ema/{point}`
pub fn get_oracle_histogram_ema(&self, point: &str) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/ema/{point}"))
/// Endpoint: `GET /api/oracle/histogram/payments/{point}`
pub fn get_oracle_histogram_payments(&self, point: &str) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/payments/{point}"))
}
/// Live raw histogram
/// Live output value histogram
///
/// Unfiltered output histogram for the forming mempool block: every live output binned by value, with none of the round-dollar payment filters applied. A flat array of log-scale bins, all zero when no mempool is configured.
/// Live unfiltered output value histogram for the forming mempool block. Every live output is binned by value on the oracle log scale; no oracle payment filters are applied. A flat array of log-scale bins, all zero when no mempool is configured.
///
/// Endpoint: `GET /api/oracle/histogram/raw/live`
pub fn get_oracle_histogram_raw_live(&self) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/raw/live"))
/// Endpoint: `GET /api/oracle/histogram/outputs/live`
pub fn get_oracle_histogram_outputs_live(&self) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/outputs/live"))
}
/// Raw histogram at height or day
/// Output value histogram at height or day
///
/// Unfiltered output histogram for a confirmed point: a block height (`840000`) gives that block's outputs, coinbase included, binned by value with no payment filtering; a calendar date (`YYYY-MM-DD`) sums every block that day. A flat array of log-scale bins.
/// Unfiltered output value histogram for a confirmed point. A block height (`840000`) gives every output in that block, coinbase included, binned by value on the oracle log scale; a calendar date (`YYYY-MM-DD`) sums every block that day. A flat array of log-scale bins.
///
/// Endpoint: `GET /api/oracle/histogram/raw/{point}`
pub fn get_oracle_histogram_raw(&self, point: &str) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/raw/{point}"))
/// Endpoint: `GET /api/oracle/histogram/outputs/{point}`
pub fn get_oracle_histogram_outputs(&self, point: &str) -> Result<Vec<i64>> {
self.base.get_json(&format!("/api/oracle/histogram/outputs/{point}"))
}
/// Txid by index
+19 -10
View File
@@ -3,8 +3,8 @@ use std::ops::Range;
use brk_error::Result;
use brk_indexer::{Indexer, Lengths};
use brk_oracle::{
Config, HistogramRaw, Oracle, START_HEIGHT_FAST, START_HEIGHT_SLOW, bin_to_cents, cents_to_bin,
for_each_round_dollar_bin,
bin_to_cents, cents_to_bin, for_each_round_dollar_bin, Config, HistogramRaw, Oracle,
START_HEIGHT_FAST, START_HEIGHT_SLOW,
};
use brk_types::{Cents, OutputType, Sats, TxIndex, TxOutIndex};
use tracing::info;
@@ -115,13 +115,7 @@ impl Vecs {
let seed_bin = cents_to_bin(prev_cents.inner() as f64);
let warmup = config.window_size.min(committed - START_HEIGHT_SLOW);
let mut oracle = Oracle::from_checkpoint(seed_bin, config, |o| {
Self::feed_blocks_with(
o,
indexer,
(committed - warmup)..committed,
None,
|_, _, _| {},
);
Self::feed_blocks_for_warmup(o, indexer, (committed - warmup)..committed, None);
});
let num_new = total_heights - committed;
@@ -136,7 +130,12 @@ impl Vecs {
let mut ref_bins = Vec::with_capacity(num_new);
if committed < START_HEIGHT_FAST {
let slow_end = START_HEIGHT_FAST.min(total_heights);
ref_bins.extend(Self::feed_blocks(&mut oracle, indexer, committed..slow_end, None));
ref_bins.extend(Self::feed_blocks(
&mut oracle,
indexer,
committed..slow_end,
None,
));
if slow_end == START_HEIGHT_FAST {
oracle.reconfigure(Config::default());
}
@@ -197,6 +196,16 @@ impl Vecs {
ref_bins
}
/// Feed blocks into an Oracle when callers only need the warmed EMA/window state.
pub fn feed_blocks_for_warmup<IM: StorageMode>(
oracle: &mut Oracle,
indexer: &Indexer<IM>,
range: Range<usize>,
cap: Option<&Lengths>,
) {
Self::feed_blocks_with(oracle, indexer, range, cap, |_, _, _| {});
}
/// Feed a range of blocks into an Oracle and call `on_block` after each
/// processed block. This lets callers observe derived state such as EMA
/// without duplicating the histogram extraction path.
+1 -1
View File
@@ -66,7 +66,7 @@ impl Config {
/// Split a block range into sub-ranges with a single EMA configuration.
pub fn segments_for_range(range: Range<usize>) -> impl Iterator<Item = Range<usize>> {
let split = START_HEIGHT_FAST.clamp(range.start, range.end);
let split = START_HEIGHT_FAST.max(range.start).min(range.end);
[range.start..split, split..range.end]
.into_iter()
.filter(|range| !range.is_empty())
+26 -17
View File
@@ -18,30 +18,32 @@ impl Query {
Ok(self.live_oracle()?.price_dollars())
}
/// Smoothed EMA histogram at the live tip, quantized for the wire.
pub fn live_histogram_ema(&self) -> Result<HistogramEmaCompact> {
/// Smoothed payment output histogram at the live tip, quantized for the wire.
pub fn live_payment_histogram(&self) -> Result<HistogramEmaCompact> {
Ok(self.live_oracle()?.ema().to_compact())
}
/// Smoothed EMA histogram for a confirmed `height`, deterministically
/// Smoothed payment output histogram for a confirmed `height`, deterministically
/// reconstructed by replaying the window ending at `height`. EMA values are
/// seed-independent, so the result is exact.
pub fn confirmed_histogram_ema(&self, height: usize) -> Result<HistogramEmaCompact> {
pub fn confirmed_payment_histogram(&self, height: usize) -> Result<HistogramEmaCompact> {
let safe = self.check_histogram_height(height)?;
Ok(self.ema_oracle_at(height, &safe)?.ema().to_compact())
}
/// Smoothed EMA histogram for a calendar `day`: the bin-by-bin average of
/// Smoothed payment output histogram for a calendar `day`: the bin-by-bin average of
/// every confirmed block's per-block EMA. Each block's EMA is reconstructed
/// independently (seed-independent, so exact); averaging keeps the result an
/// intensive per-block rate rather than letting a busy day dominate.
pub fn confirmed_histogram_ema_day(&self, day: Day1) -> Result<HistogramEmaCompact> {
pub fn confirmed_payment_histogram_day(&self, day: Day1) -> Result<HistogramEmaCompact> {
let safe = self.safe_lengths();
let range = self.day_block_range(day, &safe)?;
Ok(self.average_histogram_ema_range(range, &safe)?.to_compact())
Ok(self
.average_payment_histogram_range(range, &safe)?
.to_compact())
}
fn average_histogram_ema_range(
fn average_payment_histogram_range(
&self,
range: Range<usize>,
safe: &Lengths,
@@ -72,7 +74,7 @@ impl Query {
/// Unfiltered per-bin output counts at the live tip: every forming-block
/// mempool output binned by value, with none of the round-dollar payment
/// filters applied. Zeros when no mempool is configured.
pub fn live_histogram_raw(&self) -> Result<HistogramRaw> {
pub fn live_output_histogram(&self) -> Result<HistogramRaw> {
Ok(match self.mempool() {
Some(mempool) => mempool.live_raw_histogram(),
None => HistogramRaw::zeros(),
@@ -81,18 +83,18 @@ impl Query {
/// Unfiltered per-bin output counts for a confirmed `height`: every output
/// in the block binned by value, with no payment filtering.
pub fn confirmed_histogram_raw(&self, height: usize) -> Result<HistogramRaw> {
pub fn confirmed_output_histogram(&self, height: usize) -> Result<HistogramRaw> {
let safe = self.check_histogram_height(height)?;
Ok(self.raw_histogram_for_blocks(height..height + 1, &safe))
Ok(self.output_histogram_for_blocks(height..height + 1, &safe))
}
/// Unfiltered per-bin output counts for a calendar `day`: every block's raw
/// Unfiltered per-bin output counts for a calendar `day`: every block's output
/// histogram summed bin-by-bin. Raw counts are additive, so the day total is
/// just the sum across its confirmed blocks.
pub fn confirmed_histogram_raw_day(&self, day: Day1) -> Result<HistogramRaw> {
pub fn confirmed_output_histogram_day(&self, day: Day1) -> Result<HistogramRaw> {
let safe = self.safe_lengths();
let range = self.day_block_range(day, &safe)?;
Ok(self.raw_histogram_for_blocks(range, &safe))
Ok(self.output_histogram_for_blocks(range, &safe))
}
/// The live tip oracle: the cached committed base, with the forming block's
@@ -124,7 +126,14 @@ impl Query {
return Ok(oracle);
}
let last = self.computer().prices.spot.cents.height.len().saturating_sub(1);
let last = self
.computer()
.prices
.spot
.cents
.height
.len()
.saturating_sub(1);
let seed_bin = self.seed_bin_at(last)?;
let oracle = Arc::new(self.warm_oracle(seed_bin, height.to_usize(), &safe));
@@ -150,7 +159,7 @@ impl Query {
let config = Config::for_height(end.saturating_sub(1));
let start = end.saturating_sub(config.window_size);
Oracle::from_checkpoint(seed_bin, config, |o| {
PricesVecs::feed_blocks_with(o, self.indexer(), start..end, Some(safe), |_, _, _| {});
PricesVecs::feed_blocks_for_warmup(o, self.indexer(), start..end, Some(safe));
})
}
@@ -222,7 +231,7 @@ impl Query {
/// coinbase included, binned by value via `sats_to_bin` with no payment
/// filtering. Raw counts are additive, so a day can be read as one output
/// range instead of one block at a time.
fn raw_histogram_for_blocks(&self, range: Range<usize>, safe: &Lengths) -> HistogramRaw {
fn output_histogram_for_blocks(&self, range: Range<usize>, safe: &Lengths) -> HistogramRaw {
let indexer = self.indexer();
let total_outputs = safe.txout_index.to_usize();
let collect_end = (range.end + 1).min(safe.height.to_usize());
+36 -33
View File
@@ -43,23 +43,24 @@ impl OracleRoutes for ApiRouter<AppState> {
),
)
.api_route(
"/api/oracle/histogram/ema/live",
"/api/oracle/histogram/payments/live",
get_with(
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
state
.respond_json(&headers, state.mempool_strategy(), &uri, |q| {
q.live_histogram_ema()
q.live_payment_histogram()
})
.await
},
|op| {
op.id("get_oracle_histogram_ema_live")
op.id("get_oracle_histogram_payments_live")
.oracle_tag()
.summary("Live EMA histogram")
.summary("Live payment output histogram")
.description(
"Smoothed round-dollar payment histogram at the live tip: the \
committed EMA with the forming mempool block blended in. \
A flat array of log-scale bins.",
"Live smoothed histogram of oracle-eligible payment outputs, binned \
by output value on the oracle log scale. It combines the committed \
oracle window with the forming mempool block. A flat array of \
log-scale bins.",
)
.json_response::<HistogramEmaCompact>()
.not_modified()
@@ -68,7 +69,7 @@ impl OracleRoutes for ApiRouter<AppState> {
),
)
.api_route(
"/api/oracle/histogram/ema/{point}",
"/api/oracle/histogram/payments/{point}",
get_with(
async |uri: Uri,
headers: HeaderMap,
@@ -81,7 +82,7 @@ impl OracleRoutes for ApiRouter<AppState> {
let strategy = state.date_strategy(version, date);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_histogram_ema_day(Day1::try_from(date)?)
q.confirmed_payment_histogram_day(Day1::try_from(date)?)
})
.await
}
@@ -89,7 +90,7 @@ impl OracleRoutes for ApiRouter<AppState> {
let strategy = state.height_strategy(version, height);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_histogram_ema(usize::from(height))
q.confirmed_payment_histogram(usize::from(height))
})
.await
}
@@ -97,14 +98,15 @@ impl OracleRoutes for ApiRouter<AppState> {
}
},
|op| {
op.id("get_oracle_histogram_ema")
op.id("get_oracle_histogram_payments")
.oracle_tag()
.summary("EMA histogram at height or day")
.summary("Payment output histogram at height or day")
.description(
"Smoothed round-dollar payment histogram for a confirmed point: a \
block height (`840000`) gives that block's EMA, a calendar date \
(`YYYY-MM-DD`) gives the average of that day's per-block EMAs. \
A flat array of log-scale bins.",
"Smoothed histogram of oracle-eligible payment outputs for a \
confirmed point. A block height (`840000`) gives that block's oracle \
payment histogram; a calendar date (`YYYY-MM-DD`) gives the average \
of that day's per-block payment histograms. A flat array of log-scale \
bins.",
)
.json_response::<HistogramEmaCompact>()
.not_modified()
@@ -115,24 +117,24 @@ impl OracleRoutes for ApiRouter<AppState> {
),
)
.api_route(
"/api/oracle/histogram/raw/live",
"/api/oracle/histogram/outputs/live",
get_with(
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
state
.respond_json(&headers, state.mempool_strategy(), &uri, |q| {
q.live_histogram_raw()
q.live_output_histogram()
})
.await
},
|op| {
op.id("get_oracle_histogram_raw_live")
op.id("get_oracle_histogram_outputs_live")
.oracle_tag()
.summary("Live raw histogram")
.summary("Live output value histogram")
.description(
"Unfiltered output histogram for the forming mempool block: every \
live output binned by value, with none of the round-dollar payment \
filters applied. A flat array of log-scale bins, all zero when no \
mempool is configured.",
"Live unfiltered output value histogram for the forming mempool \
block. Every live output is binned by value on the oracle log scale; \
no oracle payment filters are applied. A flat array of log-scale \
bins, all zero when no mempool is configured.",
)
.json_response::<HistogramRaw>()
.not_modified()
@@ -141,7 +143,7 @@ impl OracleRoutes for ApiRouter<AppState> {
),
)
.api_route(
"/api/oracle/histogram/raw/{point}",
"/api/oracle/histogram/outputs/{point}",
get_with(
async |uri: Uri,
headers: HeaderMap,
@@ -155,7 +157,7 @@ impl OracleRoutes for ApiRouter<AppState> {
let strategy = state.date_strategy(version, date);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_histogram_raw_day(Day1::try_from(date)?)
q.confirmed_output_histogram_day(Day1::try_from(date)?)
})
.await
}
@@ -163,7 +165,7 @@ impl OracleRoutes for ApiRouter<AppState> {
let strategy = state.height_strategy(version, height);
state
.respond_json(&headers, strategy, &uri, move |q| {
q.confirmed_histogram_raw(usize::from(height))
q.confirmed_output_histogram(usize::from(height))
})
.await
}
@@ -171,14 +173,15 @@ impl OracleRoutes for ApiRouter<AppState> {
}
},
|op| {
op.id("get_oracle_histogram_raw")
op.id("get_oracle_histogram_outputs")
.oracle_tag()
.summary("Raw histogram at height or day")
.summary("Output value histogram at height or day")
.description(
"Unfiltered output histogram for a confirmed point: a block height \
(`840000`) gives that block's outputs, coinbase included, binned by \
value with no payment filtering; a calendar date (`YYYY-MM-DD`) sums \
every block that day. A flat array of log-scale bins.",
"Unfiltered output value histogram for a confirmed point. A block \
height (`840000`) gives every output in that block, coinbase \
included, binned by value on the oracle log scale; a calendar date \
(`YYYY-MM-DD`) sums every block that day. A flat array of log-scale \
bins.",
)
.json_response::<HistogramRaw>()
.not_modified()
+20 -20
View File
@@ -11888,62 +11888,62 @@ class BrkClient extends BrkClientBase {
}
/**
* Live EMA histogram
* Live payment output histogram
*
* Smoothed round-dollar payment histogram at the live tip: the committed EMA with the forming mempool block blended in. A flat array of log-scale bins.
* Live smoothed histogram of oracle-eligible payment outputs, binned by output value on the oracle log scale. It combines the committed oracle window with the forming mempool block. A flat array of log-scale bins.
*
* Endpoint: `GET /api/oracle/histogram/ema/live`
* Endpoint: `GET /api/oracle/histogram/payments/live`
* @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options]
* @returns {Promise<number[]>}
*/
async getOracleHistogramEmaLive({ signal, onValue } = {}) {
const path = `/api/oracle/histogram/ema/live`;
async getOracleHistogramPaymentsLive({ signal, onValue } = {}) {
const path = `/api/oracle/histogram/payments/live`;
return this.getJson(path, { signal, onValue });
}
/**
* EMA histogram at height or day
* Payment output histogram at height or day
*
* Smoothed round-dollar payment histogram for a confirmed point: a block height (`840000`) gives that block's EMA, a calendar date (`YYYY-MM-DD`) gives the average of that day's per-block EMAs. A flat array of log-scale bins.
* Smoothed histogram of oracle-eligible payment outputs for a confirmed point. A block height (`840000`) gives that block's oracle payment histogram; a calendar date (`YYYY-MM-DD`) gives the average of that day's per-block payment histograms. A flat array of log-scale bins.
*
* Endpoint: `GET /api/oracle/histogram/ema/{point}`
* Endpoint: `GET /api/oracle/histogram/payments/{point}`
*
* @param {string} point
* @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options]
* @returns {Promise<number[]>}
*/
async getOracleHistogramEma(point, { signal, onValue } = {}) {
const path = `/api/oracle/histogram/ema/${point}`;
async getOracleHistogramPayments(point, { signal, onValue } = {}) {
const path = `/api/oracle/histogram/payments/${point}`;
return this.getJson(path, { signal, onValue });
}
/**
* Live raw histogram
* Live output value histogram
*
* Unfiltered output histogram for the forming mempool block: every live output binned by value, with none of the round-dollar payment filters applied. A flat array of log-scale bins, all zero when no mempool is configured.
* Live unfiltered output value histogram for the forming mempool block. Every live output is binned by value on the oracle log scale; no oracle payment filters are applied. A flat array of log-scale bins, all zero when no mempool is configured.
*
* Endpoint: `GET /api/oracle/histogram/raw/live`
* Endpoint: `GET /api/oracle/histogram/outputs/live`
* @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options]
* @returns {Promise<number[]>}
*/
async getOracleHistogramRawLive({ signal, onValue } = {}) {
const path = `/api/oracle/histogram/raw/live`;
async getOracleHistogramOutputsLive({ signal, onValue } = {}) {
const path = `/api/oracle/histogram/outputs/live`;
return this.getJson(path, { signal, onValue });
}
/**
* Raw histogram at height or day
* Output value histogram at height or day
*
* Unfiltered output histogram for a confirmed point: a block height (`840000`) gives that block's outputs, coinbase included, binned by value with no payment filtering; a calendar date (`YYYY-MM-DD`) sums every block that day. A flat array of log-scale bins.
* Unfiltered output value histogram for a confirmed point. A block height (`840000`) gives every output in that block, coinbase included, binned by value on the oracle log scale; a calendar date (`YYYY-MM-DD`) sums every block that day. A flat array of log-scale bins.
*
* Endpoint: `GET /api/oracle/histogram/raw/{point}`
* Endpoint: `GET /api/oracle/histogram/outputs/{point}`
*
* @param {string} point
* @param {{ signal?: AbortSignal, onValue?: (value: number[]) => void }} [options]
* @returns {Promise<number[]>}
*/
async getOracleHistogramRaw(point, { signal, onValue } = {}) {
const path = `/api/oracle/histogram/raw/${point}`;
async getOracleHistogramOutputs(point, { signal, onValue } = {}) {
const path = `/api/oracle/histogram/outputs/${point}`;
return this.getJson(path, { signal, onValue });
}
+20 -20
View File
@@ -8674,37 +8674,37 @@ class BrkClient(BrkClientBase):
Endpoint: `GET /api/oracle/price`"""
return self.get_json('/api/oracle/price')
def get_oracle_histogram_ema_live(self) -> List[int]:
"""Live EMA histogram.
def get_oracle_histogram_payments_live(self) -> List[int]:
"""Live payment output histogram.
Smoothed round-dollar payment histogram at the live tip: the committed EMA with the forming mempool block blended in. A flat array of log-scale bins.
Live smoothed histogram of oracle-eligible payment outputs, binned by output value on the oracle log scale. It combines the committed oracle window with the forming mempool block. A flat array of log-scale bins.
Endpoint: `GET /api/oracle/histogram/ema/live`"""
return self.get_json('/api/oracle/histogram/ema/live')
Endpoint: `GET /api/oracle/histogram/payments/live`"""
return self.get_json('/api/oracle/histogram/payments/live')
def get_oracle_histogram_ema(self, point: str) -> List[int]:
"""EMA histogram at height or day.
def get_oracle_histogram_payments(self, point: str) -> List[int]:
"""Payment output histogram at height or day.
Smoothed round-dollar payment histogram for a confirmed point: a block height (`840000`) gives that block's EMA, a calendar date (`YYYY-MM-DD`) gives the average of that day's per-block EMAs. A flat array of log-scale bins.
Smoothed histogram of oracle-eligible payment outputs for a confirmed point. A block height (`840000`) gives that block's oracle payment histogram; a calendar date (`YYYY-MM-DD`) gives the average of that day's per-block payment histograms. A flat array of log-scale bins.
Endpoint: `GET /api/oracle/histogram/ema/{point}`"""
return self.get_json(f'/api/oracle/histogram/ema/{point}')
Endpoint: `GET /api/oracle/histogram/payments/{point}`"""
return self.get_json(f'/api/oracle/histogram/payments/{point}')
def get_oracle_histogram_raw_live(self) -> List[int]:
"""Live raw histogram.
def get_oracle_histogram_outputs_live(self) -> List[int]:
"""Live output value histogram.
Unfiltered output histogram for the forming mempool block: every live output binned by value, with none of the round-dollar payment filters applied. A flat array of log-scale bins, all zero when no mempool is configured.
Live unfiltered output value histogram for the forming mempool block. Every live output is binned by value on the oracle log scale; no oracle payment filters are applied. A flat array of log-scale bins, all zero when no mempool is configured.
Endpoint: `GET /api/oracle/histogram/raw/live`"""
return self.get_json('/api/oracle/histogram/raw/live')
Endpoint: `GET /api/oracle/histogram/outputs/live`"""
return self.get_json('/api/oracle/histogram/outputs/live')
def get_oracle_histogram_raw(self, point: str) -> List[int]:
"""Raw histogram at height or day.
def get_oracle_histogram_outputs(self, point: str) -> List[int]:
"""Output value histogram at height or day.
Unfiltered output histogram for a confirmed point: a block height (`840000`) gives that block's outputs, coinbase included, binned by value with no payment filtering; a calendar date (`YYYY-MM-DD`) sums every block that day. A flat array of log-scale bins.
Unfiltered output value histogram for a confirmed point. A block height (`840000`) gives every output in that block, coinbase included, binned by value on the oracle log scale; a calendar date (`YYYY-MM-DD`) sums every block that day. A flat array of log-scale bins.
Endpoint: `GET /api/oracle/histogram/raw/{point}`"""
return self.get_json(f'/api/oracle/histogram/raw/{point}')
Endpoint: `GET /api/oracle/histogram/outputs/{point}`"""
return self.get_json(f'/api/oracle/histogram/outputs/{point}')
def get_tx_by_index(self, index: TxIndex) -> Txid:
"""Txid by index.
+4 -4
View File
@@ -27,8 +27,8 @@ import { createCointimeSection } from "./cointime.js";
import { createInvestingSection } from "./investing.js";
import { demoHeatmapOption } from "../../src/heatmap/demo.js";
import {
oracleEmaHeatmapOption,
oracleRawHeatmapOption,
oracleOutputsHeatmapOption,
oraclePaymentsHeatmapOption,
} from "../../src/heatmap/oracle.js";
// Re-export types for external consumers
@@ -306,8 +306,8 @@ export function createPartialOptions() {
tree: [
demoHeatmapOption,
{
name: "output values",
tree: [oracleRawHeatmapOption, oracleEmaHeatmapOption],
name: "oracle histograms",
tree: [oracleOutputsHeatmapOption, oraclePaymentsHeatmapOption],
},
],
},
+1 -1
View File
@@ -486,7 +486,7 @@ function updateYControls(option) {
const maxSelect = createSelect({
id: "heatmap-y-max",
label: "to",
choices,
choices: Array.from(choices).reverse(),
initialValue: maxChoice,
onChange(choice) {
maxChoice = choice;
+15 -16
View File
@@ -25,14 +25,17 @@ const AMOUNT_CHOICES = [
{ label: "10k BTC", value: 4 },
];
export const oracleRawHeatmapOption = createOracleHeatmapOption("raw", "raw");
export const oracleEmaHeatmapOption = createOracleHeatmapOption(
"ema",
"smoothed",
export const oracleOutputsHeatmapOption = createOracleHeatmapOption(
"outputs",
"outputs",
);
export const oraclePaymentsHeatmapOption = createOracleHeatmapOption(
"payments",
"payments",
);
/**
* @param {"raw" | "ema"} mode
* @param {"outputs" | "payments"} mode
* @param {string} name
* @returns {PartialHeatmapOption}
*/
@@ -40,7 +43,8 @@ function createOracleHeatmapOption(mode, name) {
return {
kind: "heatmap",
name,
title: `${capitalize(name)} Output Value Distribution`,
title:
mode === "outputs" ? "Output Value Histogram" : "Payment Output Histogram",
points: {
fetch: (date, signal, onPoints) =>
fetchOraclePoints(mode, date, signal, onPoints),
@@ -64,7 +68,7 @@ function createOracleHeatmapOption(mode, name) {
}
/**
* @param {"raw" | "ema"} mode
* @param {"outputs" | "payments"} mode
* @param {string} date
* @param {AbortSignal} signal
* @param {(points: HeatmapPoints) => void} [onPoints]
@@ -82,7 +86,7 @@ async function fetchOraclePoints(mode, date, signal, onPoints) {
}
/**
* @param {"raw" | "ema"} mode
* @param {"outputs" | "payments"} mode
* @param {string} date
* @param {AbortSignal} signal
* @param {(values: number[]) => void} [onValue]
@@ -90,9 +94,9 @@ async function fetchOraclePoints(mode, date, signal, onPoints) {
*/
function fetchOracleValues(mode, date, signal, onValue) {
return (
mode === "raw"
? brk.getOracleHistogramRaw(date, { signal, onValue })
: brk.getOracleHistogramEma(date, { signal, onValue })
mode === "outputs"
? brk.getOracleHistogramOutputs(date, { signal, onValue })
: brk.getOracleHistogramPayments(date, { signal, onValue })
);
}
@@ -138,8 +142,3 @@ function formatNumber(value) {
function trimNumber(value) {
return value.replace(/\.?0+$/, "");
}
/** @param {string} value */
function capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
}