global: snapshot

This commit is contained in:
nym21
2026-03-01 12:46:07 +01:00
parent e10013fd2c
commit 7bf0220f25
35 changed files with 1450 additions and 2044 deletions
@@ -55,7 +55,7 @@ const _MS_PER_DAY = 86400000;
const _MS_PER_WEEK = 7 * _MS_PER_DAY; const _MS_PER_WEEK = 7 * _MS_PER_DAY;
const _EPOCH_MS = 1230768000000; const _EPOCH_MS = 1230768000000;
const _DATE_INDEXES = new Set([ const _DATE_INDEXES = new Set([
'minute1', 'minute5', 'minute10', 'minute30', 'minute10', 'minute30',
'hour1', 'hour4', 'hour12', 'hour1', 'hour4', 'hour12',
'day1', 'day3', 'week1', 'day1', 'day3', 'week1',
'month1', 'month3', 'month6', 'month1', 'month3', 'month6',
@@ -73,8 +73,6 @@ const _addMonths = (months) => new Date(2009, months, 1);
*/ */
function indexToDate(index, i) {{ function indexToDate(index, i) {{
switch (index) {{ switch (index) {{
case 'minute1': return new Date(_EPOCH_MS + i * 60000);
case 'minute5': return new Date(_EPOCH_MS + i * 300000);
case 'minute10': return new Date(_EPOCH_MS + i * 600000); case 'minute10': return new Date(_EPOCH_MS + i * 600000);
case 'minute30': return new Date(_EPOCH_MS + i * 1800000); case 'minute30': return new Date(_EPOCH_MS + i * 1800000);
case 'hour1': return new Date(_EPOCH_MS + i * 3600000); case 'hour1': return new Date(_EPOCH_MS + i * 3600000);
@@ -102,8 +100,6 @@ function indexToDate(index, i) {{
function dateToIndex(index, d) {{ function dateToIndex(index, d) {{
const ms = d.getTime(); const ms = d.getTime();
switch (index) {{ switch (index) {{
case 'minute1': return Math.floor((ms - _EPOCH_MS) / 60000);
case 'minute5': return Math.floor((ms - _EPOCH_MS) / 300000);
case 'minute10': return Math.floor((ms - _EPOCH_MS) / 600000); case 'minute10': return Math.floor((ms - _EPOCH_MS) / 600000);
case 'minute30': return Math.floor((ms - _EPOCH_MS) / 1800000); case 'minute30': return Math.floor((ms - _EPOCH_MS) / 1800000);
case 'hour1': return Math.floor((ms - _EPOCH_MS) / 3600000); case 'hour1': return Math.floor((ms - _EPOCH_MS) / 3600000);
@@ -136,7 +136,7 @@ _GENESIS = date(2009, 1, 3) # day1 0, week1 0
_DAY_ONE = date(2009, 1, 9) # day1 1 (6 day gap after genesis) _DAY_ONE = date(2009, 1, 9) # day1 1 (6 day gap after genesis)
_EPOCH = datetime(2009, 1, 1, tzinfo=timezone.utc) _EPOCH = datetime(2009, 1, 1, tzinfo=timezone.utc)
_DATE_INDEXES = frozenset([ _DATE_INDEXES = frozenset([
'minute1', 'minute5', 'minute10', 'minute30', 'minute10', 'minute30',
'hour1', 'hour4', 'hour12', 'hour1', 'hour4', 'hour12',
'day1', 'day3', 'week1', 'day1', 'day3', 'week1',
'month1', 'month3', 'month6', 'month1', 'month3', 'month6',
@@ -145,11 +145,7 @@ _DATE_INDEXES = frozenset([
def _index_to_date(index: str, i: int) -> Union[date, datetime]: def _index_to_date(index: str, i: int) -> Union[date, datetime]:
"""Convert an index value to a date/datetime for date-based indexes.""" """Convert an index value to a date/datetime for date-based indexes."""
if index == 'minute1': if index == 'minute10':
return _EPOCH + timedelta(minutes=i)
elif index == 'minute5':
return _EPOCH + timedelta(minutes=i * 5)
elif index == 'minute10':
return _EPOCH + timedelta(minutes=i * 10) return _EPOCH + timedelta(minutes=i * 10)
elif index == 'minute30': elif index == 'minute30':
return _EPOCH + timedelta(minutes=i * 30) return _EPOCH + timedelta(minutes=i * 30)
@@ -187,13 +183,13 @@ def _date_to_index(index: str, d: Union[date, datetime]) -> int:
Returns the floor index (latest index whose date is <= the given date). Returns the floor index (latest index whose date is <= the given date).
For sub-day indexes (minute*, hour*), a plain date is treated as midnight UTC. For sub-day indexes (minute*, hour*), a plain date is treated as midnight UTC.
""" """
if index in ('minute1', 'minute5', 'minute10', 'minute30', 'hour1', 'hour4', 'hour12'): if index in ('minute10', 'minute30', 'hour1', 'hour4', 'hour12'):
if isinstance(d, datetime): if isinstance(d, datetime):
dt = d if d.tzinfo else d.replace(tzinfo=timezone.utc) dt = d if d.tzinfo else d.replace(tzinfo=timezone.utc)
else: else:
dt = datetime(d.year, d.month, d.day, tzinfo=timezone.utc) dt = datetime(d.year, d.month, d.day, tzinfo=timezone.utc)
secs = int((dt - _EPOCH).total_seconds()) secs = int((dt - _EPOCH).total_seconds())
div = {{'minute1': 60, 'minute5': 300, 'minute10': 600, 'minute30': 1800, div = {{'minute10': 600, 'minute30': 1800,
'hour1': 3600, 'hour4': 14400, 'hour12': 43200}} 'hour1': 3600, 'hour4': 14400, 'hour12': 43200}}
return secs // div[index] return secs // div[index]
dd = d.date() if isinstance(d, datetime) else d dd = d.date() if isinstance(d, datetime) else d
File diff suppressed because it is too large Load Diff
-2
View File
@@ -24,8 +24,6 @@ pub const DB_NAME: &str = "blocks";
pub(crate) const TARGET_BLOCKS_PER_DAY_F64: f64 = 144.0; pub(crate) const TARGET_BLOCKS_PER_DAY_F64: f64 = 144.0;
pub(crate) const TARGET_BLOCKS_PER_DAY_F32: f32 = 144.0; pub(crate) const TARGET_BLOCKS_PER_DAY_F32: f32 = 144.0;
pub(crate) const TARGET_BLOCKS_PER_MINUTE1: u64 = 0;
pub(crate) const TARGET_BLOCKS_PER_MINUTE5: u64 = 0;
pub(crate) const TARGET_BLOCKS_PER_MINUTE10: u64 = 1; pub(crate) const TARGET_BLOCKS_PER_MINUTE10: u64 = 1;
pub(crate) const TARGET_BLOCKS_PER_MINUTE30: u64 = 3; pub(crate) const TARGET_BLOCKS_PER_MINUTE30: u64 = 3;
pub(crate) const TARGET_BLOCKS_PER_HOUR1: u64 = 6; pub(crate) const TARGET_BLOCKS_PER_HOUR1: u64 = 6;
+3 -5
View File
@@ -1,8 +1,8 @@
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Date, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Minute1, Date, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4,
Minute10, Minute30, Minute5, Month1, Month3, Month6, Timestamp, Week1, Year1, Year10, Minute10, Minute30, Month1, Month3, Month6, Timestamp, Week1, Year1, Year10,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use vecdb::{EagerVec, Exit, LazyVecFrom1, PcoVec, Rw, StorageMode}; use vecdb::{EagerVec, Exit, LazyVecFrom1, PcoVec, Rw, StorageMode};
@@ -19,7 +19,7 @@ pub struct Vecs<M: StorageMode = Rw> {
/// Per-period timestamp indexes. /// Per-period timestamp indexes.
/// ///
/// Time-based periods (minute1year10) are lazy: `idx.to_timestamp()` is a pure /// Time-based periods (minute10year10) are lazy: `idx.to_timestamp()` is a pure
/// function of the index, so no storage or decompression is needed. /// function of the index, so no storage or decompression is needed.
/// Epoch-based periods (halvingepoch, difficultyepoch) are eager: their timestamps /// Epoch-based periods (halvingepoch, difficultyepoch) are eager: their timestamps
/// come from block data via `compute_indirect`. /// come from block data via `compute_indirect`.
@@ -28,8 +28,6 @@ pub struct Vecs<M: StorageMode = Rw> {
pub struct TimestampIndexes<M: StorageMode = Rw>( pub struct TimestampIndexes<M: StorageMode = Rw>(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub Indexes< pub Indexes<
LazyVecFrom1<Minute1, Timestamp, Minute1, Height>,
LazyVecFrom1<Minute5, Timestamp, Minute5, Height>,
LazyVecFrom1<Minute10, Timestamp, Minute10, Height>, LazyVecFrom1<Minute10, Timestamp, Minute10, Height>,
LazyVecFrom1<Minute30, Timestamp, Minute30, Height>, LazyVecFrom1<Minute30, Timestamp, Minute30, Height>,
LazyVecFrom1<Hour1, Timestamp, Hour1, Height>, LazyVecFrom1<Hour1, Timestamp, Hour1, Height>,
@@ -867,6 +867,30 @@ impl RealizedBase {
exit, exit,
)?; )?;
self.lower_price_band.usd.height.compute_transform2(
starting_indexes.height,
&self.realized_price.usd.height,
&self.investor_price.usd.height,
|(i, rp, ip, ..)| {
let rp = f64::from(rp);
let ip = f64::from(ip);
(i, Dollars::from(rp * rp / ip))
},
exit,
)?;
self.upper_price_band.usd.height.compute_transform2(
starting_indexes.height,
&self.investor_price.usd.height,
&self.realized_price.usd.height,
|(i, ip, rp, ..)| {
let ip = f64::from(ip);
let rp = f64::from(rp);
(i, Dollars::from(ip * ip / rp))
},
exit,
)?;
self.realized_cap_30d_delta.height.compute_rolling_change( self.realized_cap_30d_delta.height.compute_rolling_change(
starting_indexes.height, starting_indexes.height,
&blocks.count.height_1m_ago, &blocks.count.height_1m_ago,
@@ -1,11 +1,12 @@
use brk_error::Result; use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Sats, StoredF32, StoredF64, Version}; use brk_types::{Dollars, Height, Sats, StoredF32, StoredF64, Version};
use vecdb::{Exit, ReadableVec, Rw, StorageMode}; use vecdb::{Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
use crate::internal::{ use crate::internal::{
ComputedFromHeightLast, ComputedFromHeightLast, LazyFromHeightLast,
NegPercentageDollarsF32, PercentageDollarsF32, PercentageSatsF64, NegPercentageDollarsF32, PercentageDollarsF32, PercentageSatsF64,
StoredF32Identity,
}; };
use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase}; use crate::distribution::metrics::{ImportConfig, RealizedBase, UnrealizedBase};
@@ -24,7 +25,7 @@ pub struct RelativeBase<M: StorageMode = Rw> {
pub unrealized_loss_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>, pub unrealized_loss_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>,
pub neg_unrealized_loss_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>, pub neg_unrealized_loss_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>,
pub net_unrealized_pnl_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>, pub net_unrealized_pnl_rel_to_market_cap: ComputedFromHeightLast<StoredF32, M>,
pub nupl: ComputedFromHeightLast<StoredF32, M>, pub nupl: LazyFromHeightLast<StoredF32, StoredF32>,
// === Invested Capital in Profit/Loss as % of Realized Cap === // === Invested Capital in Profit/Loss as % of Realized Cap ===
pub invested_capital_in_profit_pct: ComputedFromHeightLast<StoredF32, M>, pub invested_capital_in_profit_pct: ComputedFromHeightLast<StoredF32, M>,
@@ -36,6 +37,17 @@ impl RelativeBase {
let v1 = Version::ONE; let v1 = Version::ONE;
let v2 = Version::new(2); let v2 = Version::new(2);
let net_unrealized_pnl_rel_to_market_cap = ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("net_unrealized_pnl_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
)?;
let nupl = LazyFromHeightLast::from_computed::<StoredF32Identity>(
&cfg.name("nupl"),
cfg.version + v2,
net_unrealized_pnl_rel_to_market_cap.height.read_only_boxed_clone(),
&net_unrealized_pnl_rel_to_market_cap,
);
Ok(Self { Ok(Self {
supply_in_profit_rel_to_own_supply: ComputedFromHeightLast::forced_import( supply_in_profit_rel_to_own_supply: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("supply_in_profit_rel_to_own_supply"), cfg.version + v1, cfg.indexes, cfg.db, &cfg.name("supply_in_profit_rel_to_own_supply"), cfg.version + v1, cfg.indexes,
@@ -52,12 +64,8 @@ impl RelativeBase {
neg_unrealized_loss_rel_to_market_cap: ComputedFromHeightLast::forced_import( neg_unrealized_loss_rel_to_market_cap: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("neg_unrealized_loss_rel_to_market_cap"), cfg.version + v2, cfg.indexes, cfg.db, &cfg.name("neg_unrealized_loss_rel_to_market_cap"), cfg.version + v2, cfg.indexes,
)?, )?,
net_unrealized_pnl_rel_to_market_cap: ComputedFromHeightLast::forced_import( net_unrealized_pnl_rel_to_market_cap,
cfg.db, &cfg.name("net_unrealized_pnl_rel_to_market_cap"), cfg.version + v2, cfg.indexes, nupl,
)?,
nupl: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("nupl"), cfg.version + v2, cfg.indexes,
)?,
invested_capital_in_profit_pct: ComputedFromHeightLast::forced_import( invested_capital_in_profit_pct: ComputedFromHeightLast::forced_import(
cfg.db, &cfg.name("invested_capital_in_profit_pct"), cfg.version, cfg.indexes, cfg.db, &cfg.name("invested_capital_in_profit_pct"), cfg.version, cfg.indexes,
)?, )?,
@@ -100,10 +108,6 @@ impl RelativeBase {
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>( .compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.net_unrealized_pnl.height, market_cap, exit, max_from, &unrealized.net_unrealized_pnl.height, market_cap, exit,
)?; )?;
self.nupl
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.net_unrealized_pnl.height, market_cap, exit,
)?;
self.invested_capital_in_profit_pct self.invested_capital_in_profit_pct
.compute_binary::<Dollars, Dollars, PercentageDollarsF32>( .compute_binary::<Dollars, Dollars, PercentageDollarsF32>(
max_from, &unrealized.invested_capital_in_profit.height, &realized.realized_cap.height, exit, max_from, &unrealized.invested_capital_in_profit.height, &realized.realized_cap.height, exit,
+1 -5
View File
@@ -1,7 +1,7 @@
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Day1, Day3, Year10, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Day1, Day3, Year10, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4,
Minute1, Minute10, Minute30, Minute5, Month1, Month3, Month6, StoredU64, Version, Week1, Minute10, Minute30, Month1, Month3, Month6, StoredU64, Version, Week1,
Year1, Year1,
}; };
use vecdb::{Database, EagerVec, ImportableVec, PcoVec, Rw, StorageMode}; use vecdb::{Database, EagerVec, ImportableVec, PcoVec, Rw, StorageMode};
@@ -11,8 +11,6 @@ use brk_error::Result;
#[derive(Traversable)] #[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> { pub struct Vecs<M: StorageMode = Rw> {
pub identity: M::Stored<EagerVec<PcoVec<Height, Height>>>, pub identity: M::Stored<EagerVec<PcoVec<Height, Height>>>,
pub minute1: M::Stored<EagerVec<PcoVec<Height, Minute1>>>,
pub minute5: M::Stored<EagerVec<PcoVec<Height, Minute5>>>,
pub minute10: M::Stored<EagerVec<PcoVec<Height, Minute10>>>, pub minute10: M::Stored<EagerVec<PcoVec<Height, Minute10>>>,
pub minute30: M::Stored<EagerVec<PcoVec<Height, Minute30>>>, pub minute30: M::Stored<EagerVec<PcoVec<Height, Minute30>>>,
pub hour1: M::Stored<EagerVec<PcoVec<Height, Hour1>>>, pub hour1: M::Stored<EagerVec<PcoVec<Height, Hour1>>>,
@@ -35,8 +33,6 @@ impl Vecs {
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> { pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
Ok(Self { Ok(Self {
identity: EagerVec::forced_import(db, "height", version)?, identity: EagerVec::forced_import(db, "height", version)?,
minute1: EagerVec::forced_import(db, "minute1", version)?,
minute5: EagerVec::forced_import(db, "minute5", version)?,
minute10: EagerVec::forced_import(db, "minute10", version)?, minute10: EagerVec::forced_import(db, "minute10", version)?,
minute30: EagerVec::forced_import(db, "minute30", version)?, minute30: EagerVec::forced_import(db, "minute30", version)?,
hour1: EagerVec::forced_import(db, "hour1", version)?, hour1: EagerVec::forced_import(db, "hour1", version)?,
@@ -1,20 +0,0 @@
use brk_traversable::Traversable;
use brk_types::{Height, Minute1, Version};
use vecdb::{Database, EagerVec, ImportableVec, PcoVec, Rw, StorageMode};
use brk_error::Result;
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
pub identity: M::Stored<EagerVec<PcoVec<Minute1, Minute1>>>,
pub first_height: M::Stored<EagerVec<PcoVec<Minute1, Height>>>,
}
impl Vecs {
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
Ok(Self {
identity: EagerVec::forced_import(db, "minute1", version)?,
first_height: EagerVec::forced_import(db, "minute1_first_height", version)?,
})
}
}
@@ -1,20 +0,0 @@
use brk_traversable::Traversable;
use brk_types::{Height, Minute5, Version};
use vecdb::{Database, EagerVec, ImportableVec, PcoVec, Rw, StorageMode};
use brk_error::Result;
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
pub identity: M::Stored<EagerVec<PcoVec<Minute5, Minute5>>>,
pub first_height: M::Stored<EagerVec<PcoVec<Minute5, Height>>>,
}
impl Vecs {
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
Ok(Self {
identity: EagerVec::forced_import(db, "minute5", version)?,
first_height: EagerVec::forced_import(db, "minute5_first_height", version)?,
})
}
}
+1 -61
View File
@@ -7,10 +7,8 @@ mod height;
mod hour1; mod hour1;
mod hour12; mod hour12;
mod hour4; mod hour4;
mod minute1;
mod minute10; mod minute10;
mod minute30; mod minute30;
mod minute5;
mod month1; mod month1;
mod month3; mod month3;
mod month6; mod month6;
@@ -27,7 +25,7 @@ use brk_error::Result;
use brk_indexer::Indexer; use brk_indexer::Indexer;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Date, Day1, Day3, Hour1, Hour4, Hour12, Indexes, Minute1, Minute5, Minute10, Minute30, Month1, Date, Day1, Day3, Hour1, Hour4, Hour12, Indexes, Minute10, Minute30, Month1,
Month3, Month6, Version, Week1, Year1, Year10, Month3, Month6, Version, Week1, Year1, Year10,
}; };
use vecdb::{Database, Exit, PAGE_SIZE, ReadableVec, Rw, StorageMode}; use vecdb::{Database, Exit, PAGE_SIZE, ReadableVec, Rw, StorageMode};
@@ -44,8 +42,6 @@ pub use height::Vecs as HeightVecs;
pub use hour1::Vecs as Hour1Vecs; pub use hour1::Vecs as Hour1Vecs;
pub use hour4::Vecs as Hour4Vecs; pub use hour4::Vecs as Hour4Vecs;
pub use hour12::Vecs as Hour12Vecs; pub use hour12::Vecs as Hour12Vecs;
pub use minute1::Vecs as Minute1Vecs;
pub use minute5::Vecs as Minute5Vecs;
pub use minute10::Vecs as Minute10Vecs; pub use minute10::Vecs as Minute10Vecs;
pub use minute30::Vecs as Minute30Vecs; pub use minute30::Vecs as Minute30Vecs;
pub use month1::Vecs as Month1Vecs; pub use month1::Vecs as Month1Vecs;
@@ -68,8 +64,6 @@ pub struct Vecs<M: StorageMode = Rw> {
pub height: HeightVecs<M>, pub height: HeightVecs<M>,
pub difficultyepoch: DifficultyEpochVecs<M>, pub difficultyepoch: DifficultyEpochVecs<M>,
pub halvingepoch: HalvingEpochVecs<M>, pub halvingepoch: HalvingEpochVecs<M>,
pub minute1: Minute1Vecs<M>,
pub minute5: Minute5Vecs<M>,
pub minute10: Minute10Vecs<M>, pub minute10: Minute10Vecs<M>,
pub minute30: Minute30Vecs<M>, pub minute30: Minute30Vecs<M>,
pub hour1: Hour1Vecs<M>, pub hour1: Hour1Vecs<M>,
@@ -104,8 +98,6 @@ impl Vecs {
height: HeightVecs::forced_import(&db, version)?, height: HeightVecs::forced_import(&db, version)?,
difficultyepoch: DifficultyEpochVecs::forced_import(&db, version)?, difficultyepoch: DifficultyEpochVecs::forced_import(&db, version)?,
halvingepoch: HalvingEpochVecs::forced_import(&db, version)?, halvingepoch: HalvingEpochVecs::forced_import(&db, version)?,
minute1: Minute1Vecs::forced_import(&db, version)?,
minute5: Minute5Vecs::forced_import(&db, version)?,
minute10: Minute10Vecs::forced_import(&db, version)?, minute10: Minute10Vecs::forced_import(&db, version)?,
minute30: Minute30Vecs::forced_import(&db, version)?, minute30: Minute30Vecs::forced_import(&db, version)?,
hour1: Hour1Vecs::forced_import(&db, version)?, hour1: Hour1Vecs::forced_import(&db, version)?,
@@ -190,22 +182,6 @@ impl Vecs {
// --- Timestamp-based height → period mappings --- // --- Timestamp-based height → period mappings ---
// Minute1
self.height.minute1.compute_transform(
starting_indexes.height,
&blocks_time.timestamp_monotonic,
|(h, ts, _)| (h, Minute1::from_timestamp(ts)),
exit,
)?;
// Minute5
self.height.minute5.compute_transform(
starting_indexes.height,
&blocks_time.timestamp_monotonic,
|(h, ts, _)| (h, Minute5::from_timestamp(ts)),
exit,
)?;
// Minute10 // Minute10
self.height.minute10.compute_transform( self.height.minute10.compute_transform(
starting_indexes.height, starting_indexes.height,
@@ -376,16 +352,6 @@ impl Vecs {
// --- Starting values from height → period mappings --- // --- Starting values from height → period mappings ---
let starting_minute1 = self
.height
.minute1
.collect_one(decremented_starting_height)
.unwrap_or_default();
let starting_minute5 = self
.height
.minute5
.collect_one(decremented_starting_height)
.unwrap_or_default();
let starting_minute10 = self let starting_minute10 = self
.height .height
.minute10 .minute10
@@ -449,30 +415,6 @@ impl Vecs {
// --- Compute period-level vecs (first_height + identity) --- // --- Compute period-level vecs (first_height + identity) ---
// Minute1
self.minute1.first_height.compute_first_per_index(
starting_indexes.height,
&self.height.minute1,
exit,
)?;
self.minute1.identity.compute_from_index(
starting_minute1,
&self.minute1.first_height,
exit,
)?;
// Minute5
self.minute5.first_height.compute_first_per_index(
starting_indexes.height,
&self.height.minute5,
exit,
)?;
self.minute5.identity.compute_from_index(
starting_minute5,
&self.minute5.first_height,
exit,
)?;
// Minute10 // Minute10
self.minute10.first_height.compute_first_per_index( self.minute10.first_height.compute_first_per_index(
starting_indexes.height, starting_indexes.height,
@@ -669,8 +611,6 @@ impl Vecs {
Ok(ComputeIndexes::new( Ok(ComputeIndexes::new(
starting_indexes, starting_indexes,
starting_minute1,
starting_minute5,
starting_minute10, starting_minute10,
starting_minute30, starting_minute30,
starting_hour1, starting_hour1,
@@ -7,7 +7,7 @@ use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute1, Minute5, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12,
Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
@@ -18,7 +18,7 @@ use vecdb::{
}; };
use crate::{ use crate::{
ComputeIndexes, indexes, indexes_from, ComputeIndexes, indexes, indexes_apply, indexes_from,
internal::{ComputedVecValue, Indexes, NumericValue}, internal::{ComputedVecValue, Indexes, NumericValue},
}; };
@@ -27,8 +27,6 @@ use crate::{
pub struct EagerIndexes<T, M: StorageMode = Rw>( pub struct EagerIndexes<T, M: StorageMode = Rw>(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub Indexes< pub Indexes<
<M as StorageMode>::Stored<EagerVec<PcoVec<Minute1, T>>>,
<M as StorageMode>::Stored<EagerVec<PcoVec<Minute5, T>>>,
<M as StorageMode>::Stored<EagerVec<PcoVec<Minute10, T>>>, <M as StorageMode>::Stored<EagerVec<PcoVec<Minute10, T>>>,
<M as StorageMode>::Stored<EagerVec<PcoVec<Minute30, T>>>, <M as StorageMode>::Stored<EagerVec<PcoVec<Minute30, T>>>,
<M as StorageMode>::Stored<EagerVec<PcoVec<Hour1, T>>>, <M as StorageMode>::Stored<EagerVec<PcoVec<Hour1, T>>>,
@@ -86,23 +84,7 @@ where
}; };
} }
period!(minute1); indexes_apply!(period);
period!(minute5);
period!(minute10);
period!(minute30);
period!(hour1);
period!(hour4);
period!(hour12);
period!(day1);
period!(day3);
period!(week1);
period!(month1);
period!(month3);
period!(month6);
period!(year1);
period!(year10);
period!(halvingepoch);
period!(difficultyepoch);
Ok(()) Ok(())
} }
@@ -131,23 +113,7 @@ where
}; };
} }
period!(minute1); indexes_apply!(period);
period!(minute5);
period!(minute10);
period!(minute30);
period!(hour1);
period!(hour4);
period!(hour12);
period!(day1);
period!(day3);
period!(week1);
period!(month1);
period!(month3);
period!(month6);
period!(year1);
period!(year10);
period!(halvingepoch);
period!(difficultyepoch);
Ok(()) Ok(())
} }
@@ -176,23 +142,7 @@ where
}; };
} }
period!(minute1); indexes_apply!(period);
period!(minute5);
period!(minute10);
period!(minute30);
period!(hour1);
period!(hour4);
period!(hour12);
period!(day1);
period!(day3);
period!(week1);
period!(month1);
period!(month3);
period!(month6);
period!(year1);
period!(year10);
period!(halvingepoch);
period!(difficultyepoch);
Ok(()) Ok(())
} }
@@ -1,7 +1,7 @@
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Minute1, Minute10, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4,
Minute30, Minute5, Month1, Month3, Month6, Version, Week1, Year1, Year10, Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
}; };
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::Serialize; use serde::Serialize;
@@ -18,8 +18,6 @@ where
T: VecValue + Formattable + Serialize + JsonSchema, T: VecValue + Formattable + Serialize + JsonSchema,
{ {
pub height: LazyVecFrom1<Height, T, Height, Height>, pub height: LazyVecFrom1<Height, T, Height, Height>,
pub minute1: LazyVecFrom1<Minute1, T, Minute1, Minute1>,
pub minute5: LazyVecFrom1<Minute5, T, Minute5, Minute5>,
pub minute10: LazyVecFrom1<Minute10, T, Minute10, Minute10>, pub minute10: LazyVecFrom1<Minute10, T, Minute10, Minute10>,
pub minute30: LazyVecFrom1<Minute30, T, Minute30, Minute30>, pub minute30: LazyVecFrom1<Minute30, T, Minute30, Minute30>,
pub hour1: LazyVecFrom1<Hour1, T, Hour1, Hour1>, pub hour1: LazyVecFrom1<Hour1, T, Hour1, Hour1>,
@@ -42,8 +40,6 @@ impl<T: VecValue + Formattable + Serialize + JsonSchema> ConstantVecs<T> {
pub(crate) fn new<F>(name: &str, version: Version, indexes: &indexes::Vecs) -> Self pub(crate) fn new<F>(name: &str, version: Version, indexes: &indexes::Vecs) -> Self
where where
F: UnaryTransform<Height, T> F: UnaryTransform<Height, T>
+ UnaryTransform<Minute1, T>
+ UnaryTransform<Minute5, T>
+ UnaryTransform<Minute10, T> + UnaryTransform<Minute10, T>
+ UnaryTransform<Minute30, T> + UnaryTransform<Minute30, T>
+ UnaryTransform<Hour1, T> + UnaryTransform<Hour1, T>
@@ -76,8 +72,6 @@ impl<T: VecValue + Formattable + Serialize + JsonSchema> ConstantVecs<T> {
version, version,
indexes.height.identity.read_only_boxed_clone(), indexes.height.identity.read_only_boxed_clone(),
), ),
minute1: period!(minute1, Minute1),
minute5: period!(minute5, Minute5),
minute10: period!(minute10, Minute10), minute10: period!(minute10, Minute10),
minute30: period!(minute30, Minute30), minute30: period!(minute30, Minute30),
hour1: period!(hour1, Hour1), hour1: period!(hour1, Hour1),
@@ -3,7 +3,7 @@
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Day1, Day3, DifficultyEpoch, FromCoarserIndex, HalvingEpoch, Height, Hour1, Hour4, Hour12, Day1, Day3, DifficultyEpoch, FromCoarserIndex, HalvingEpoch, Height, Hour1, Hour4, Hour12,
Minute1, Minute5, Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use schemars::JsonSchema; use schemars::JsonSchema;
@@ -21,8 +21,6 @@ use crate::{
pub struct ComputedHeightDerivedLast<T>( pub struct ComputedHeightDerivedLast<T>(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub Indexes< pub Indexes<
LazyAggVec<Minute1, Option<T>, Height, Height, T>,
LazyAggVec<Minute5, Option<T>, Height, Height, T>,
LazyAggVec<Minute10, Option<T>, Height, Height, T>, LazyAggVec<Minute10, Option<T>, Height, Height, T>,
LazyAggVec<Minute30, Option<T>, Height, Height, T>, LazyAggVec<Minute30, Option<T>, Height, Height, T>,
LazyAggVec<Hour1, Option<T>, Height, Height, T>, LazyAggVec<Hour1, Option<T>, Height, Height, T>,
@@ -4,7 +4,7 @@ use std::marker::PhantomData;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute1, Minute5, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12,
Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
@@ -60,8 +60,6 @@ where
pub struct LazyHeightDerivedLast<T, S1T = T>( pub struct LazyHeightDerivedLast<T, S1T = T>(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub Indexes< pub Indexes<
LazyTransformLast<Minute1, Option<T>, Option<S1T>>,
LazyTransformLast<Minute5, Option<T>, Option<S1T>>,
LazyTransformLast<Minute10, Option<T>, Option<S1T>>, LazyTransformLast<Minute10, Option<T>, Option<S1T>>,
LazyTransformLast<Minute30, Option<T>, Option<S1T>>, LazyTransformLast<Minute30, Option<T>, Option<S1T>>,
LazyTransformLast<Hour1, Option<T>, Option<S1T>>, LazyTransformLast<Hour1, Option<T>, Option<S1T>>,
+26 -31
View File
@@ -1,15 +1,13 @@
//! Base generic struct with 17 type parameters — one per time period/epoch index. //! Base generic struct with 15 type parameters — one per time period/epoch index.
//! //!
//! Foundation for all per-index types. Replaces the repetitive 17-field pattern //! Foundation for all per-index types. Replaces the repetitive 15-field pattern
//! found throughout height_derived types. //! found throughout height_derived types.
use brk_traversable::Traversable; use brk_traversable::Traversable;
#[derive(Clone, Traversable)] #[derive(Clone, Traversable)]
#[traversable(merge)] #[traversable(merge)]
pub struct Indexes<M1, M5, M10, M30, H1, H4, H12, D1, D3, W1, Mo1, Mo3, Mo6, Y1, Y10, HE, DE> { pub struct Indexes<M10, M30, H1, H4, H12, D1, D3, W1, Mo1, Mo3, Mo6, Y1, Y10, HE, DE> {
pub minute1: M1,
pub minute5: M5,
pub minute10: M10, pub minute10: M10,
pub minute30: M30, pub minute30: M30,
pub hour1: H1, pub hour1: H1,
@@ -38,8 +36,6 @@ pub struct Indexes<M1, M5, M10, M30, H1, H4, H12, D1, D3, W1, Mo1, Mo3, Mo6, Y1,
macro_rules! indexes_from { macro_rules! indexes_from {
($period:ident, $epoch:ident) => { ($period:ident, $epoch:ident) => {
$crate::internal::Indexes { $crate::internal::Indexes {
minute1: $period!(minute1),
minute5: $period!(minute5),
minute10: $period!(minute10), minute10: $period!(minute10),
minute30: $period!(minute30), minute30: $period!(minute30),
hour1: $period!(hour1), hour1: $period!(hour1),
@@ -63,29 +59,28 @@ macro_rules! indexes_from {
}; };
} }
/// Helper macro to apply a function/macro to each field of an `Indexes` value. /// Imperative counterpart to `indexes_from!` — calls `$period!(field)` for each
/// period field and `$epoch!(field)` for each epoch field.
#[macro_export] #[macro_export]
macro_rules! indexes_map { macro_rules! indexes_apply {
($indexes:expr, |$field:ident| $body:expr) => {{ ($period:ident, $epoch:ident) => {
let src = $indexes; $period!(minute10);
$crate::internal::Indexes { $period!(minute30);
minute1: { let $field = src.minute1; $body }, $period!(hour1);
minute5: { let $field = src.minute5; $body }, $period!(hour4);
minute10: { let $field = src.minute10; $body }, $period!(hour12);
minute30: { let $field = src.minute30; $body }, $period!(day1);
hour1: { let $field = src.hour1; $body }, $period!(day3);
hour4: { let $field = src.hour4; $body }, $period!(week1);
hour12: { let $field = src.hour12; $body }, $period!(month1);
day1: { let $field = src.day1; $body }, $period!(month3);
day3: { let $field = src.day3; $body }, $period!(month6);
week1: { let $field = src.week1; $body }, $period!(year1);
month1: { let $field = src.month1; $body }, $period!(year10);
month3: { let $field = src.month3; $body }, $epoch!(halvingepoch);
month6: { let $field = src.month6; $body }, $epoch!(difficultyepoch);
year1: { let $field = src.year1; $body }, };
year10: { let $field = src.year10; $body }, ($m:ident) => {
halvingepoch: { let $field = src.halvingepoch; $body }, $crate::indexes_apply!($m, $m)
difficultyepoch: { let $field = src.difficultyepoch; $body }, };
}
}};
} }
@@ -5,8 +5,8 @@
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Hour1, Hour4, Hour12, Minute1, Minute5, Minute10, Day1, Day3, DifficultyEpoch, HalvingEpoch, Hour1, Hour4, Hour12,
Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10, Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use schemars::JsonSchema; use schemars::JsonSchema;
@@ -22,8 +22,6 @@ use crate::{
pub struct LazyEagerIndexes<T, S>( pub struct LazyEagerIndexes<T, S>(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub Indexes< pub Indexes<
LazyVecFrom1<Minute1, T, Minute1, S>,
LazyVecFrom1<Minute5, T, Minute5, S>,
LazyVecFrom1<Minute10, T, Minute10, S>, LazyVecFrom1<Minute10, T, Minute10, S>,
LazyVecFrom1<Minute30, T, Minute30, S>, LazyVecFrom1<Minute30, T, Minute30, S>,
LazyVecFrom1<Hour1, T, Hour1, S>, LazyVecFrom1<Hour1, T, Hour1, S>,
@@ -1,14 +1,14 @@
use brk_types::{ use brk_types::{
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4, Minute1, Minute10, Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour12, Hour4,
Minute30, Minute5, Month1, Month3, Month6, StoredU64, Week1, Year1, Year10, Minute10, Minute30, Month1, Month3, Month6, StoredU64, Week1, Year1, Year10,
}; };
use vecdb::UnaryTransform; use vecdb::UnaryTransform;
use crate::blocks::{ use crate::blocks::{
TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_DAY3, TARGET_BLOCKS_PER_DECADE, TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_DAY3, TARGET_BLOCKS_PER_DECADE,
TARGET_BLOCKS_PER_HALVING, TARGET_BLOCKS_PER_HOUR1, TARGET_BLOCKS_PER_HOUR12, TARGET_BLOCKS_PER_HALVING, TARGET_BLOCKS_PER_HOUR1, TARGET_BLOCKS_PER_HOUR12,
TARGET_BLOCKS_PER_HOUR4, TARGET_BLOCKS_PER_MINUTE1, TARGET_BLOCKS_PER_MINUTE10, TARGET_BLOCKS_PER_HOUR4, TARGET_BLOCKS_PER_MINUTE10,
TARGET_BLOCKS_PER_MINUTE30, TARGET_BLOCKS_PER_MINUTE5, TARGET_BLOCKS_PER_MONTH, TARGET_BLOCKS_PER_MINUTE30, TARGET_BLOCKS_PER_MONTH,
TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER, TARGET_BLOCKS_PER_WEEK, TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER, TARGET_BLOCKS_PER_WEEK,
TARGET_BLOCKS_PER_YEAR, TARGET_BLOCKS_PER_YEAR,
}; };
@@ -22,20 +22,6 @@ impl UnaryTransform<Height, StoredU64> for BlockCountTarget {
} }
} }
impl UnaryTransform<Minute1, StoredU64> for BlockCountTarget {
#[inline(always)]
fn apply(_: Minute1) -> StoredU64 {
StoredU64::from(TARGET_BLOCKS_PER_MINUTE1)
}
}
impl UnaryTransform<Minute5, StoredU64> for BlockCountTarget {
#[inline(always)]
fn apply(_: Minute5) -> StoredU64 {
StoredU64::from(TARGET_BLOCKS_PER_MINUTE5)
}
}
impl UnaryTransform<Minute10, StoredU64> for BlockCountTarget { impl UnaryTransform<Minute10, StoredU64> for BlockCountTarget {
#[inline(always)] #[inline(always)]
fn apply(_: Minute10) -> StoredU64 { fn apply(_: Minute10) -> StoredU64 {
@@ -3,7 +3,7 @@ use brk_types::StoredU16;
use vecdb::{Exit, ReadableVec, VecIndex}; use vecdb::{Exit, ReadableVec, VecIndex};
use super::Vecs; use super::Vecs;
use crate::{ComputeIndexes, prices}; use crate::{ComputeIndexes, prices, traits::ComputeDrawdown};
impl Vecs { impl Vecs {
pub(crate) fn compute( pub(crate) fn compute(
@@ -63,6 +63,13 @@ impl Vecs {
exit, exit,
)?; )?;
self.price_drawdown.height.compute_drawdown(
starting_indexes.height,
&prices.price.usd.height,
&self.price_ath.usd.height,
exit,
)?;
Ok(()) Ok(())
} }
} }
@@ -43,7 +43,7 @@ impl Vecs {
|(h, close, low, high, ..)| { |(h, close, low, high, ..)| {
let range = *high - *low; let range = *high - *low;
let stoch = if range == 0.0 { let stoch = if range == 0.0 {
StoredF32::from(50.0) StoredF32::NAN
} else { } else {
StoredF32::from(((*close - *low) / range * 100.0) as f32) StoredF32::from(((*close - *low) / range * 100.0) as f32)
}; };
@@ -72,7 +72,7 @@ pub(super) fn compute(
.map(|((r, mn), mx)| { .map(|((r, mn), mx)| {
let range = mx - mn; let range = mx - mn;
if range == 0.0 { if range == 0.0 {
50.0 f32::NAN
} else { } else {
(r - mn) / range * 100.0 (r - mn) / range * 100.0
} }
@@ -26,11 +26,7 @@ pub(super) fn compute_ema(source: &[f32], period: usize) -> Vec<f32> {
for (i, &val) in source.iter().enumerate() { for (i, &val) in source.iter().enumerate() {
if i < period { if i < period {
sum += val; sum += val;
if i == period - 1 { result.push(sum / (i + 1) as f32);
result.push(sum / period as f32);
} else {
result.push(val);
}
} else { } else {
let prev = result[i - 1]; let prev = result[i - 1];
result.push(val * k + prev * (1.0 - k)); result.push(val * k + prev * (1.0 - k));
@@ -102,18 +102,18 @@ impl Vecs {
exit, exit,
)?; )?;
// Choppiness index: 100 * log10(tr_2w_sum / (price_2w_max - price_2w_min)) / log10(14) self.price_2w_choppiness_index.height.compute_transform4(
let log10n = 14.0f32.log10();
self.price_2w_choppiness_index.height.compute_transform3(
starting_indexes.height, starting_indexes.height,
&self.price_true_range_2w_sum.height, &self.price_true_range_2w_sum.height,
&self.price_2w_max.usd.height, &self.price_2w_max.usd.height,
&self.price_2w_min.usd.height, &self.price_2w_min.usd.height,
|(h, tr_sum, max, min, ..)| { &blocks.count.height_2w_ago,
|(h, tr_sum, max, min, window_start, ..)| {
let range = *max - *min; let range = *max - *min;
let ci = if range > 0.0 { let n = (h.to_usize() - window_start.to_usize() + 1) as f32;
let ci = if range > 0.0 && n > 1.0 {
StoredF32::from( StoredF32::from(
100.0 * (*tr_sum / range as f32).log10() / log10n, 100.0 * (*tr_sum / range as f32).log10() / n.log10(),
) )
} else { } else {
StoredF32::NAN StoredF32::NAN
+3 -23
View File
@@ -2,7 +2,7 @@ use brk_error::Result;
use brk_traversable::Traversable; use brk_traversable::Traversable;
use brk_types::{ use brk_types::{
Cents, Close, Day1, Day3, DifficultyEpoch, HalvingEpoch, High, Hour1, Hour4, Hour12, Low, Cents, Close, Day1, Day3, DifficultyEpoch, HalvingEpoch, High, Hour1, Hour4, Hour12, Low,
Minute1, Minute5, Minute10, Minute30, Month1, Month3, Month6, OHLCCents, Open, Version, Week1, Minute10, Minute30, Month1, Month3, Month6, OHLCCents, Open, Version, Week1,
Year1, Year10, Year1, Year10,
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
@@ -14,7 +14,7 @@ use vecdb::{
}; };
use crate::{ use crate::{
ComputeIndexes, indexes_from, ComputeIndexes, indexes_apply, indexes_from,
internal::{ComputedHeightDerivedLast, EagerIndexes, Indexes}, internal::{ComputedHeightDerivedLast, EagerIndexes, Indexes},
}; };
@@ -25,8 +25,6 @@ use crate::{
pub struct OhlcVecs<T, M: StorageMode = Rw>( pub struct OhlcVecs<T, M: StorageMode = Rw>(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub Indexes< pub Indexes<
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute1, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute5, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute10, T>>>, <M as StorageMode>::Stored<EagerVec<BytesVec<Minute10, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Minute30, T>>>, <M as StorageMode>::Stored<EagerVec<BytesVec<Minute30, T>>>,
<M as StorageMode>::Stored<EagerVec<BytesVec<Hour1, T>>>, <M as StorageMode>::Stored<EagerVec<BytesVec<Hour1, T>>>,
@@ -132,23 +130,7 @@ impl OhlcVecs<OHLCCents> {
}; };
} }
period!(minute1); indexes_apply!(period, epoch);
period!(minute5);
period!(minute10);
period!(minute30);
period!(hour1);
period!(hour4);
period!(hour12);
period!(day1);
period!(day3);
period!(week1);
period!(month1);
period!(month3);
period!(month6);
period!(year1);
period!(year10);
epoch!(halvingepoch);
epoch!(difficultyepoch);
Ok(()) Ok(())
} }
@@ -161,8 +143,6 @@ impl OhlcVecs<OHLCCents> {
pub struct LazyOhlcVecs<T, S>( pub struct LazyOhlcVecs<T, S>(
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub Indexes< pub Indexes<
LazyVecFrom1<Minute1, T, Minute1, S>,
LazyVecFrom1<Minute5, T, Minute5, S>,
LazyVecFrom1<Minute10, T, Minute10, S>, LazyVecFrom1<Minute10, T, Minute10, S>,
LazyVecFrom1<Minute30, T, Minute30, S>, LazyVecFrom1<Minute30, T, Minute30, S>,
LazyVecFrom1<Hour1, T, Hour1, S>, LazyVecFrom1<Hour1, T, Hour1, S>,
+4 -18
View File
@@ -9,13 +9,13 @@ use crate::PairOutputIndex;
use super::{ use super::{
Date, Day1, Day3, Year10, DifficultyEpoch, EmptyAddressIndex, EmptyOutputIndex, HalvingEpoch, Date, Day1, Day3, Year10, DifficultyEpoch, EmptyAddressIndex, EmptyOutputIndex, HalvingEpoch,
Height, Hour1, Hour4, Hour12, FundedAddressIndex, Minute1, Minute5, Minute10, Minute30, Height, Hour1, Hour4, Hour12, FundedAddressIndex, Minute10, Minute30,
Month1, OpReturnIndex, P2AAddressIndex, P2MSOutputIndex, Month1, OpReturnIndex, P2AAddressIndex, P2MSOutputIndex,
P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex,
P2WPKHAddressIndex, P2WSHAddressIndex, Month3, Month6, Timestamp, TxInIndex, TxIndex, P2WPKHAddressIndex, P2WSHAddressIndex, Month3, Month6, Timestamp, TxInIndex, TxIndex,
TxOutIndex, UnknownOutputIndex, Week1, Year1, TxOutIndex, UnknownOutputIndex, Week1, Year1,
timestamp::INDEX_EPOCH, timestamp::INDEX_EPOCH,
minute1::MINUTE1_INTERVAL, minute5::MINUTE5_INTERVAL, minute10::MINUTE10_INTERVAL, minute10::MINUTE10_INTERVAL,
minute30::MINUTE30_INTERVAL, hour1::HOUR1_INTERVAL, hour4::HOUR4_INTERVAL, minute30::MINUTE30_INTERVAL, hour1::HOUR1_INTERVAL, hour4::HOUR4_INTERVAL,
hour12::HOUR12_INTERVAL, hour12::HOUR12_INTERVAL,
}; };
@@ -26,8 +26,6 @@ use super::{
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
#[schemars(example = Index::Day1)] #[schemars(example = Index::Day1)]
pub enum Index { pub enum Index {
Minute1,
Minute5,
Minute10, Minute10,
Minute30, Minute30,
Hour1, Hour1,
@@ -65,10 +63,8 @@ pub enum Index {
} }
impl Index { impl Index {
pub const fn all() -> [Self; 36] { pub const fn all() -> [Self; 34] {
[ [
Self::Minute1,
Self::Minute5,
Self::Minute10, Self::Minute10,
Self::Minute30, Self::Minute30,
Self::Hour1, Self::Hour1,
@@ -108,8 +104,6 @@ impl Index {
pub fn possible_values(&self) -> &'static [&'static str] { pub fn possible_values(&self) -> &'static [&'static str] {
match self { match self {
Self::Minute1 => Minute1::to_possible_strings(),
Self::Minute5 => Minute5::to_possible_strings(),
Self::Minute10 => Minute10::to_possible_strings(), Self::Minute10 => Minute10::to_possible_strings(),
Self::Minute30 => Minute30::to_possible_strings(), Self::Minute30 => Minute30::to_possible_strings(),
Self::Hour1 => Hour1::to_possible_strings(), Self::Hour1 => Hour1::to_possible_strings(),
@@ -157,8 +151,6 @@ impl Index {
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
match self { match self {
Self::Minute1 => <Minute1 as PrintableIndex>::to_string(),
Self::Minute5 => <Minute5 as PrintableIndex>::to_string(),
Self::Minute10 => <Minute10 as PrintableIndex>::to_string(), Self::Minute10 => <Minute10 as PrintableIndex>::to_string(),
Self::Minute30 => <Minute30 as PrintableIndex>::to_string(), Self::Minute30 => <Minute30 as PrintableIndex>::to_string(),
Self::Hour1 => <Hour1 as PrintableIndex>::to_string(), Self::Hour1 => <Hour1 as PrintableIndex>::to_string(),
@@ -209,9 +201,7 @@ impl Index {
pub const fn is_date_based(&self) -> bool { pub const fn is_date_based(&self) -> bool {
matches!( matches!(
self, self,
Self::Minute1 Self::Minute10
| Self::Minute5
| Self::Minute10
| Self::Minute30 | Self::Minute30
| Self::Hour1 | Self::Hour1
| Self::Hour4 | Self::Hour4
@@ -231,8 +221,6 @@ impl Index {
/// Returns None for non-time-based indexes. /// Returns None for non-time-based indexes.
pub fn index_to_timestamp(&self, i: usize) -> Option<Timestamp> { pub fn index_to_timestamp(&self, i: usize) -> Option<Timestamp> {
let interval = match self { let interval = match self {
Self::Minute1 => MINUTE1_INTERVAL,
Self::Minute5 => MINUTE5_INTERVAL,
Self::Minute10 => MINUTE10_INTERVAL, Self::Minute10 => MINUTE10_INTERVAL,
Self::Minute30 => MINUTE30_INTERVAL, Self::Minute30 => MINUTE30_INTERVAL,
Self::Hour1 => HOUR1_INTERVAL, Self::Hour1 => HOUR1_INTERVAL,
@@ -269,8 +257,6 @@ impl Index {
/// Returns None for non-date-based indexes. /// Returns None for non-date-based indexes.
pub fn timestamp_to_index(&self, ts: Timestamp) -> Option<usize> { pub fn timestamp_to_index(&self, ts: Timestamp) -> Option<usize> {
let interval = match self { let interval = match self {
Self::Minute1 => MINUTE1_INTERVAL,
Self::Minute5 => MINUTE5_INTERVAL,
Self::Minute10 => MINUTE10_INTERVAL, Self::Minute10 => MINUTE10_INTERVAL,
Self::Minute30 => MINUTE30_INTERVAL, Self::Minute30 => MINUTE30_INTERVAL,
Self::Hour1 => HOUR1_INTERVAL, Self::Hour1 => HOUR1_INTERVAL,
+1 -7
View File
@@ -2,7 +2,7 @@ use derive_more::{Deref, DerefMut};
use crate::{ use crate::{
Day1, Day3, Year10, DifficultyEpoch, EmptyOutputIndex, HalvingEpoch, Height, Day1, Day3, Year10, DifficultyEpoch, EmptyOutputIndex, HalvingEpoch, Height,
Hour1, Hour4, Hour12, Minute1, Minute5, Minute10, Minute30, Month1, Hour1, Hour4, Hour12, Minute10, Minute30, Month1,
OpReturnIndex, OutputType, P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex, OpReturnIndex, OutputType, P2AAddressIndex, P2MSOutputIndex, P2PK33AddressIndex,
P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex,
P2WSHAddressIndex, Month3, Month6, TxInIndex, TxIndex, TxOutIndex, TypeIndex, P2WSHAddressIndex, Month3, Month6, TxInIndex, TxIndex, TxOutIndex, TypeIndex,
@@ -74,8 +74,6 @@ pub struct ComputeIndexes {
#[deref] #[deref]
#[deref_mut] #[deref_mut]
indexes: Indexes, indexes: Indexes,
pub minute1: Minute1,
pub minute5: Minute5,
pub minute10: Minute10, pub minute10: Minute10,
pub minute30: Minute30, pub minute30: Minute30,
pub hour1: Hour1, pub hour1: Hour1,
@@ -97,8 +95,6 @@ impl ComputeIndexes {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
indexes: Indexes, indexes: Indexes,
minute1: Minute1,
minute5: Minute5,
minute10: Minute10, minute10: Minute10,
minute30: Minute30, minute30: Minute30,
hour1: Hour1, hour1: Hour1,
@@ -117,8 +113,6 @@ impl ComputeIndexes {
) -> Self { ) -> Self {
Self { Self {
indexes, indexes,
minute1,
minute5,
minute10, minute10,
minute30, minute30,
hour1, hour1,
-4
View File
@@ -96,8 +96,6 @@ mod day3;
mod hour1; mod hour1;
mod hour12; mod hour12;
mod hour4; mod hour4;
mod minute1;
mod minute5;
mod minute10; mod minute10;
mod minute30; mod minute30;
mod month1; mod month1;
@@ -285,8 +283,6 @@ pub use day3::*;
pub use hour1::*; pub use hour1::*;
pub use hour12::*; pub use hour12::*;
pub use hour4::*; pub use hour4::*;
pub use minute1::*;
pub use minute5::*;
pub use minute10::*; pub use minute10::*;
pub use minute30::*; pub use minute30::*;
pub use month1::*; pub use month1::*;
-7
View File
@@ -529,13 +529,6 @@ mod tests {
assert_eq!(Index::Hour1.timestamp_to_index(ts), Some(2)); assert_eq!(Index::Hour1.timestamp_to_index(ts), Some(2));
} }
#[test]
fn test_timestamp_to_index_minute5() {
// INDEX_EPOCH + 15 minutes (= 3 * 5min intervals)
let ts = Timestamp::new(1230768000 + 900);
assert_eq!(Index::Minute5.timestamp_to_index(ts), Some(3));
}
#[test] #[test]
fn test_timestamp_to_index_non_date_returns_none() { fn test_timestamp_to_index_non_date_returns_none() {
let ts = Timestamp::new(1230768000); let ts = Timestamp::new(1230768000);
-88
View File
@@ -1,88 +0,0 @@
use std::ops::Add;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex};
use super::{Timestamp, INDEX_EPOCH};
pub const MINUTE1_INTERVAL: u32 = 60;
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
Pco,
JsonSchema,
)]
pub struct Minute1(u32);
impl Minute1 {
pub fn from_timestamp(ts: Timestamp) -> Self {
Self((*ts - INDEX_EPOCH) / MINUTE1_INTERVAL)
}
pub fn to_timestamp(&self) -> Timestamp {
Timestamp::new(INDEX_EPOCH + self.0 * MINUTE1_INTERVAL)
}
}
impl From<Minute1> for usize {
#[inline]
fn from(value: Minute1) -> Self {
value.0 as usize
}
}
impl From<usize> for Minute1 {
#[inline]
fn from(value: usize) -> Self {
Self(value as u32)
}
}
impl Add<usize> for Minute1 {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs as u32)
}
}
impl CheckedSub for Minute1 {
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
}
impl PrintableIndex for Minute1 {
fn to_string() -> &'static str {
"minute1"
}
fn to_possible_strings() -> &'static [&'static str] {
&["1mn", "minute1"]
}
}
impl std::fmt::Display for Minute1 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut buf = itoa::Buffer::new();
let str = buf.format(self.0);
f.write_str(str)
}
}
impl Formattable for Minute1 {
#[inline(always)]
fn fmt_csv(&self, f: &mut String) -> std::fmt::Result {
use std::fmt::Write;
write!(f, "{}", self)
}
}
-88
View File
@@ -1,88 +0,0 @@
use std::ops::Add;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex};
use super::{Timestamp, INDEX_EPOCH};
pub const MINUTE5_INTERVAL: u32 = 300;
#[derive(
Debug,
Default,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
Pco,
JsonSchema,
)]
pub struct Minute5(u32);
impl Minute5 {
pub fn from_timestamp(ts: Timestamp) -> Self {
Self((*ts - INDEX_EPOCH) / MINUTE5_INTERVAL)
}
pub fn to_timestamp(&self) -> Timestamp {
Timestamp::new(INDEX_EPOCH + self.0 * MINUTE5_INTERVAL)
}
}
impl From<Minute5> for usize {
#[inline]
fn from(value: Minute5) -> Self {
value.0 as usize
}
}
impl From<usize> for Minute5 {
#[inline]
fn from(value: usize) -> Self {
Self(value as u32)
}
}
impl Add<usize> for Minute5 {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs as u32)
}
}
impl CheckedSub for Minute5 {
fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
}
impl PrintableIndex for Minute5 {
fn to_string() -> &'static str {
"minute5"
}
fn to_possible_strings() -> &'static [&'static str] {
&["5mn", "minute5"]
}
}
impl std::fmt::Display for Minute5 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut buf = itoa::Buffer::new();
let str = buf.format(self.0);
f.write_str(str)
}
}
impl Formattable for Minute5 {
#[inline(always)]
fn fmt_csv(&self, f: &mut String) -> std::fmt::Result {
use std::fmt::Write;
write!(f, "{}", self)
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -67,20 +67,6 @@ def hour1_metric():
) )
@pytest.fixture
def minute5_metric():
"""DateMetricData with minute5 (sub-daily)."""
return DateMetricData(
version=1,
index="minute5",
total=500000,
start=0,
end=3,
stamp="2024-01-01T00:00:00Z",
data=[1, 2, 3],
)
@pytest.fixture @pytest.fixture
def week1_metric(): def week1_metric():
"""DateMetricData with week1.""" """DateMetricData with week1."""
@@ -150,9 +136,6 @@ class TestIsDateBased:
def test_hour1(self, hour1_metric): def test_hour1(self, hour1_metric):
assert hour1_metric.is_date_based is True assert hour1_metric.is_date_based is True
def test_minute5(self, minute5_metric):
assert minute5_metric.is_date_based is True
def test_week1(self, week1_metric): def test_week1(self, week1_metric):
assert week1_metric.is_date_based is True assert week1_metric.is_date_based is True
@@ -304,13 +287,6 @@ class TestIndexToDate:
assert dates[1] == datetime(2009, 1, 1, 1, 0, 0, tzinfo=timezone.utc) assert dates[1] == datetime(2009, 1, 1, 1, 0, 0, tzinfo=timezone.utc)
assert dates[2] == datetime(2009, 1, 1, 2, 0, 0, tzinfo=timezone.utc) assert dates[2] == datetime(2009, 1, 1, 2, 0, 0, tzinfo=timezone.utc)
def test_minute5_returns_datetime(self, minute5_metric):
dates = minute5_metric.dates()
assert isinstance(dates[0], datetime)
assert dates[0] == datetime(2009, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
assert dates[1] == datetime(2009, 1, 1, 0, 5, 0, tzinfo=timezone.utc)
assert dates[2] == datetime(2009, 1, 1, 0, 10, 0, tzinfo=timezone.utc)
# ============ _date_to_index conversions ============ # ============ _date_to_index conversions ============
@@ -359,13 +335,6 @@ class TestDateToIndex:
assert _date_to_index("hour1", epoch + timedelta(hours=1)) == 1 assert _date_to_index("hour1", epoch + timedelta(hours=1)) == 1
assert _date_to_index("hour1", epoch + timedelta(hours=24)) == 24 assert _date_to_index("hour1", epoch + timedelta(hours=24)) == 24
def test_minute5_with_datetime(self):
from brk_client import _date_to_index
epoch = datetime(2009, 1, 1, tzinfo=timezone.utc)
assert _date_to_index("minute5", epoch) == 0
assert _date_to_index("minute5", epoch + timedelta(minutes=5)) == 1
assert _date_to_index("minute5", epoch + timedelta(minutes=12)) == 2 # floor
def test_hour1_with_plain_date(self): def test_hour1_with_plain_date(self):
"""Plain date is treated as midnight UTC for sub-daily.""" """Plain date is treated as midnight UTC for sub-daily."""
from brk_client import _date_to_index from brk_client import _date_to_index
+1 -1
View File
@@ -118,7 +118,7 @@ const ALL_GROUPS = [
{ {
label: "Time", label: "Time",
items: [ items: [
"1mn", "5mn", "10mn", "30mn", "10mn", "30mn",
"1h", "4h", "12h", "1h", "4h", "12h",
"1d", "3d", "1w", "1d", "3d", "1w",
"1m", "3m", "6m", "1m", "3m", "6m",
+1 -1
View File
@@ -21,7 +21,7 @@ export const serdeBool = {
export const INDEX_LABEL = /** @type {const} */ ({ export const INDEX_LABEL = /** @type {const} */ ({
height: "blk", height: "blk",
minute1: "1mn", minute5: "5mn", minute10: "10mn", minute30: "30mn", minute10: "10mn", minute30: "30mn",
hour1: "1h", hour4: "4h", hour12: "12h", hour1: "1h", hour4: "4h", hour12: "12h",
day1: "1d", day3: "3d", week1: "1w", day1: "1d", day3: "3d", week1: "1w",
month1: "1m", month3: "3m", month6: "6m", month1: "1m", month3: "3m", month6: "6m",