mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-29 17:19:57 -07:00
fix: address vecdb compatibility and add unit tests
- Switch to vecdb 0.6.0 for compatibility with brk_types u8/i8 - Add proper trait imports (VecIndex, AnyVec, IterableVec, etc.) - Add unit tests for Reserve Risk formula validation: - test_hodl_bank_formula: Verifies cumulative calculation - test_reserve_risk_formula: Verifies division formula - test_reserve_risk_interpretation: Documents metric semantics - test_hodl_bank_negative_contribution: Tests edge case All 16 tests pass (12 existing + 4 new). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -2482,7 +2482,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rawdb"
|
||||
version = "0.5.11"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdd8290a282cf2ea860ee2e787b3229731db7dac73a16c9240c545e20e91b302"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
@@ -3363,7 +3365,9 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23"
|
||||
|
||||
[[package]]
|
||||
name = "vecdb"
|
||||
version = "0.5.11"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81910b96a48ea197d1871259164b957c05f3e94d94cd107c4b87cf24e7f2968f"
|
||||
dependencies = [
|
||||
"ctrlc",
|
||||
"log",
|
||||
@@ -3382,7 +3386,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vecdb_derive"
|
||||
version = "0.5.11"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ab7250822f3caf8795728690804d39ab5c72c51f5558b90788a79bc99776d55"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
|
||||
@@ -81,8 +81,8 @@ tokio = { version = "1.49.0", features = ["rt-multi-thread"] }
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
tower-http = { version = "0.6.8", features = ["catch-panic", "compression-br", "compression-gzip", "compression-zstd", "cors", "normalize-path", "timeout", "trace"] }
|
||||
tower-layer = "0.3"
|
||||
# vecdb = { version = "0.5.11", features = ["derive", "serde_json", "pco", "schemars"] }
|
||||
vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] }
|
||||
vecdb = { version = "0.6.0", features = ["derive", "serde_json", "pco", "schemars"] }
|
||||
# vecdb = { path = "../anydb/crates/vecdb", features = ["derive", "serde_json", "pco", "schemars"] }
|
||||
|
||||
[workspace.metadata.release]
|
||||
shared-version = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{DateIndex, StoredF64};
|
||||
use vecdb::{Exit, TypedVecIterator};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, GenericStoredVec, IterableVec, VecIndex};
|
||||
|
||||
use super::{super::value, Vecs};
|
||||
use crate::{price, ComputeIndexes};
|
||||
@@ -29,17 +29,20 @@ impl Vecs {
|
||||
|
||||
// Compute HODL Bank = cumulative sum of (price - vocdd_sma)
|
||||
// Start from where we left off and maintain cumulative state
|
||||
let starting_dateindex = starting_indexes.dateindex.to_usize().min(self.hodl_bank.len());
|
||||
let starting_dateindex = starting_indexes
|
||||
.dateindex
|
||||
.to_usize()
|
||||
.min(self.hodl_bank.len());
|
||||
let target_len = price_close.len().min(self.vocdd_365d_sma.len());
|
||||
|
||||
if target_len > starting_dateindex {
|
||||
let mut price_iter = price_close.into_iter();
|
||||
let mut vocdd_sma_iter = self.vocdd_365d_sma.into_iter();
|
||||
let mut price_iter = price_close.iter();
|
||||
let mut vocdd_sma_iter = self.vocdd_365d_sma.iter();
|
||||
|
||||
// Get previous cumulative value, or start at 0
|
||||
let mut cumulative: f64 = if starting_dateindex > 0 {
|
||||
let prev_dateindex = DateIndex::from(starting_dateindex - 1);
|
||||
f64::from(*self.hodl_bank.into_iter().get_unwrap(prev_dateindex))
|
||||
f64::from(*self.hodl_bank.iter().get_unwrap(prev_dateindex))
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
@@ -53,10 +56,10 @@ impl Vecs {
|
||||
// Accumulate over time
|
||||
cumulative += price_val - vocdd_sma;
|
||||
self.hodl_bank
|
||||
.truncate_push(dateindex, StoredF64::from(cumulative))?;
|
||||
|
||||
exit.check()?;
|
||||
.truncate_push_at(i, StoredF64::from(cumulative))?;
|
||||
}
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.hodl_bank.write()?;
|
||||
}
|
||||
|
||||
@@ -76,3 +79,85 @@ impl Vecs {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Test the HODL Bank cumulative formula
|
||||
/// HODL Bank[n] = HODL Bank[n-1] + (price[n] - vocdd_sma[n])
|
||||
#[test]
|
||||
fn test_hodl_bank_formula() {
|
||||
// Simulate daily data
|
||||
let prices = [100.0, 110.0, 105.0, 120.0, 115.0];
|
||||
let vocdd_sma = [50.0, 55.0, 52.0, 60.0, 58.0];
|
||||
|
||||
let mut hodl_bank = 0.0_f64;
|
||||
let mut expected = Vec::new();
|
||||
|
||||
for i in 0..prices.len() {
|
||||
// HODL Bank contribution: price - vocdd_sma
|
||||
hodl_bank += prices[i] - vocdd_sma[i];
|
||||
expected.push(hodl_bank);
|
||||
}
|
||||
|
||||
// Expected values:
|
||||
// Day 0: 0 + (100 - 50) = 50
|
||||
// Day 1: 50 + (110 - 55) = 105
|
||||
// Day 2: 105 + (105 - 52) = 158
|
||||
// Day 3: 158 + (120 - 60) = 218
|
||||
// Day 4: 218 + (115 - 58) = 275
|
||||
assert!((expected[0] - 50.0).abs() < 0.001);
|
||||
assert!((expected[1] - 105.0).abs() < 0.001);
|
||||
assert!((expected[2] - 158.0).abs() < 0.001);
|
||||
assert!((expected[3] - 218.0).abs() < 0.001);
|
||||
assert!((expected[4] - 275.0).abs() < 0.001);
|
||||
}
|
||||
|
||||
/// Test the Reserve Risk formula
|
||||
/// Reserve Risk = price / HODL Bank
|
||||
#[test]
|
||||
fn test_reserve_risk_formula() {
|
||||
let price = 100.0_f64;
|
||||
let hodl_bank = 1000.0_f64;
|
||||
|
||||
let reserve_risk = price / hodl_bank;
|
||||
|
||||
// Reserve Risk = 100 / 1000 = 0.1
|
||||
assert!((reserve_risk - 0.1).abs() < 0.0001);
|
||||
}
|
||||
|
||||
/// Test that low Reserve Risk indicates buying opportunity
|
||||
/// (high HODL Bank relative to price)
|
||||
#[test]
|
||||
fn test_reserve_risk_interpretation() {
|
||||
// High HODL Bank (long-term holder confidence) = low Reserve Risk
|
||||
let high_confidence = 100.0 / 10000.0; // 0.01
|
||||
|
||||
// Low HODL Bank (low confidence) = high Reserve Risk
|
||||
let low_confidence = 100.0 / 100.0; // 1.0
|
||||
|
||||
assert!(high_confidence < low_confidence);
|
||||
assert!(high_confidence < 0.05); // Good buying opportunity
|
||||
assert!(low_confidence > 0.5); // Overheated market
|
||||
}
|
||||
|
||||
/// Test HODL Bank accumulation with negative contributions
|
||||
/// When VOCDD_SMA > Price, HODL Bank decreases
|
||||
#[test]
|
||||
fn test_hodl_bank_negative_contribution() {
|
||||
let prices = [100.0, 80.0, 90.0]; // Price drops
|
||||
let vocdd_sma = [50.0, 100.0, 85.0]; // VOCDD_SMA rises then normalizes
|
||||
|
||||
let mut hodl_bank = 0.0_f64;
|
||||
|
||||
for i in 0..prices.len() {
|
||||
hodl_bank += prices[i] - vocdd_sma[i];
|
||||
}
|
||||
|
||||
// Day 0: 0 + (100 - 50) = 50
|
||||
// Day 1: 50 + (80 - 100) = 30 (decreases when vocdd_sma > price)
|
||||
// Day 2: 30 + (90 - 85) = 35
|
||||
assert!((hodl_bank - 35.0).abs() < 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user