mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-08 14:11:56 -07:00
global: add a bunch of realized datasets + charts
This commit is contained in:
@@ -52,7 +52,8 @@ pub async fn bundle(websites_path: &Path, source_folder: &str, watch: bool) -> i
|
||||
if let Some(start) = entry.find("main") {
|
||||
if let Some(end) = entry.find(".js") {
|
||||
let main_hashed = &entry[start..end];
|
||||
contents = contents.replace("/scripts/main.js", &format!("/scripts/{main_hashed}.js"));
|
||||
contents =
|
||||
contents.replace("/scripts/main.js", &format!("/scripts/{main_hashed}.js"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,11 @@ where
|
||||
Box::new(
|
||||
EagerVec::forced_import(
|
||||
path,
|
||||
&maybe_suffix("sum"),
|
||||
&(if !options.last {
|
||||
name.to_string()
|
||||
} else {
|
||||
maybe_suffix("sum")
|
||||
}),
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
)
|
||||
|
||||
@@ -57,7 +57,7 @@ pub struct Vecs {
|
||||
pub indexes_to_coinblocks_destroyed: ComputedVecsFromHeight<StoredF64>,
|
||||
pub indexes_to_coindays_destroyed: ComputedVecsFromHeight<StoredF64>,
|
||||
pub dateindex_to_adjusted_spent_output_profit_ratio: Option<EagerVec<DateIndex, StoredF32>>,
|
||||
pub dateindex_to_realized_cap_30d_change: Option<EagerVec<DateIndex, Dollars>>,
|
||||
pub indexes_to_realized_cap_30d_change: Option<ComputedVecsFromDateIndex<Dollars>>,
|
||||
pub dateindex_to_sell_side_risk_ratio: Option<EagerVec<DateIndex, StoredF32>>,
|
||||
pub dateindex_to_spent_output_profit_ratio: Option<EagerVec<DateIndex, StoredF32>>,
|
||||
pub indexes_to_adjusted_value_created: Option<ComputedVecsFromHeight<Dollars>>,
|
||||
@@ -89,6 +89,10 @@ pub struct Vecs {
|
||||
Option<EagerVec<Height, StoredF32>>,
|
||||
pub indexes_to_net_unrealized_profit_and_loss_relative_to_market_cap:
|
||||
Option<ComputedVecsFromDateIndex<StoredF32>>,
|
||||
pub indexes_to_realized_profit_relative_to_realized_cap:
|
||||
Option<ComputedVecsFromHeight<StoredF32>>,
|
||||
pub indexes_to_realized_loss_relative_to_realized_cap:
|
||||
Option<ComputedVecsFromHeight<StoredF32>>,
|
||||
pub indexes_to_net_realized_profit_and_loss_relative_to_realized_cap:
|
||||
Option<ComputedVecsFromHeight<StoredF32>>,
|
||||
pub height_to_supply_even_value: Option<ComputedHeightValueVecs>,
|
||||
@@ -117,6 +121,12 @@ pub struct Vecs {
|
||||
Option<ComputedVecsFromDateIndex<StoredF64>>,
|
||||
pub indexes_to_supply_in_profit_relative_to_circulating_supply:
|
||||
Option<ComputedVecsFromDateIndex<StoredF64>>,
|
||||
pub indexes_to_cumulative_net_realized_profit_and_loss_30d_change:
|
||||
Option<ComputedVecsFromDateIndex<Dollars>>,
|
||||
pub indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_realized_cap:
|
||||
Option<ComputedVecsFromDateIndex<StoredF32>>,
|
||||
pub indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_market_cap:
|
||||
Option<ComputedVecsFromDateIndex<StoredF32>>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
@@ -432,7 +442,9 @@ impl Vecs {
|
||||
false,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_sum(),
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
@@ -452,7 +464,9 @@ impl Vecs {
|
||||
false,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_sum(),
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
@@ -463,7 +477,7 @@ impl Vecs {
|
||||
true,
|
||||
version + VERSION + Version::ONE,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_sum(),
|
||||
StorableVecGeneatorOptions::default().add_sum().add_cumulative(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
@@ -558,12 +572,14 @@ impl Vecs {
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
dateindex_to_realized_cap_30d_change: compute_dollars.then(|| {
|
||||
EagerVec::forced_import(
|
||||
indexes_to_realized_cap_30d_change: compute_dollars.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&suffix("realized_cap_30d_change"),
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
@@ -574,7 +590,9 @@ impl Vecs {
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_sum(),
|
||||
StorableVecGeneatorOptions::default()
|
||||
.add_sum()
|
||||
.add_cumulative(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
@@ -686,15 +704,37 @@ impl Vecs {
|
||||
.unwrap()
|
||||
},
|
||||
),
|
||||
indexes_to_realized_profit_relative_to_realized_cap: compute_dollars.then(|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&suffix("realized_profit_relative_to_realized_cap"),
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_sum(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
indexes_to_realized_loss_relative_to_realized_cap: compute_dollars.then(|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&suffix("realized_loss_relative_to_realized_cap"),
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_sum(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
indexes_to_net_realized_profit_and_loss_relative_to_realized_cap: compute_dollars.then(
|
||||
|| {
|
||||
ComputedVecsFromHeight::forced_import(
|
||||
path,
|
||||
&suffix("net_realized_profit_and_loss_relative_to_realized_cap"),
|
||||
true,
|
||||
version + VERSION + Version::ZERO,
|
||||
version + VERSION + Version::ONE,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last(),
|
||||
StorableVecGeneatorOptions::default().add_sum(),
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
@@ -903,6 +943,39 @@ impl Vecs {
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_sum(),
|
||||
)?,
|
||||
indexes_to_cumulative_net_realized_profit_and_loss_30d_change: compute_dollars.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("cumulative_{}", suffix("net_realized_profit_and_loss_30d_change")),
|
||||
true,
|
||||
version + VERSION + Version::TWO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last()
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_realized_cap: compute_dollars.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("cumulative_{}", suffix("net_realized_profit_and_loss_30d_change_relative_to_realized_cap")),
|
||||
true,
|
||||
version + VERSION + Version::TWO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last()
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_market_cap: compute_dollars.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
path,
|
||||
&format!("cumulative_{}", suffix("net_realized_profit_and_loss_30d_change_relative_to_market_cap")),
|
||||
true,
|
||||
version + VERSION + Version::TWO,
|
||||
format,
|
||||
StorableVecGeneatorOptions::default().add_last()
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1877,6 +1950,7 @@ impl Vecs {
|
||||
height_to_supply: &impl AnyIterableVec<Height, Bitcoin>,
|
||||
dateindex_to_supply: &impl AnyIterableVec<DateIndex, Bitcoin>,
|
||||
height_to_realized_cap: Option<&impl AnyIterableVec<Height, Dollars>>,
|
||||
dateindex_to_realized_cap: Option<&impl AnyIterableVec<DateIndex, Dollars>>,
|
||||
exit: &Exit,
|
||||
) -> color_eyre::Result<()> {
|
||||
if let Some(v) = self
|
||||
@@ -2021,18 +2095,26 @@ impl Vecs {
|
||||
Some(self.height_to_adjusted_value_destroyed.as_ref().unwrap()),
|
||||
)?;
|
||||
|
||||
self.dateindex_to_realized_cap_30d_change
|
||||
self.indexes_to_realized_cap_30d_change
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.compute_change(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_realized_cap
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.dateindex
|
||||
.unwrap_last(),
|
||||
30,
|
||||
.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, _, starting_indexes, exit| {
|
||||
vec.compute_change(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_realized_cap
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.dateindex
|
||||
.unwrap_last(),
|
||||
30,
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_net_realized_profit_and_loss
|
||||
@@ -2280,6 +2362,42 @@ impl Vecs {
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_realized_profit_relative_to_realized_cap
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, _, starting_indexes, exit| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.height,
|
||||
self.height_to_realized_profit.as_ref().unwrap(),
|
||||
*height_to_realized_cap.as_ref().unwrap(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_realized_loss_relative_to_realized_cap
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|vec, _, _, starting_indexes, exit| {
|
||||
vec.compute_percentage(
|
||||
starting_indexes.height,
|
||||
self.height_to_realized_loss.as_ref().unwrap(),
|
||||
*height_to_realized_cap.as_ref().unwrap(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_net_realized_profit_and_loss_relative_to_realized_cap
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
@@ -2435,6 +2553,64 @@ impl Vecs {
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_change(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_net_realized_profit_and_loss
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.dateindex
|
||||
.unwrap_cumulative(),
|
||||
30,
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_realized_cap.
|
||||
as_mut()
|
||||
.unwrap()
|
||||
.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change.as_ref().unwrap().dateindex.as_ref().unwrap(),
|
||||
*dateindex_to_realized_cap.as_ref().unwrap(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_market_cap.
|
||||
as_mut()
|
||||
.unwrap()
|
||||
.compute_all(
|
||||
indexer,
|
||||
indexes,
|
||||
starting_indexes,
|
||||
exit,
|
||||
|v, _, _, starting_indexes, exit| {
|
||||
v.compute_percentage(
|
||||
starting_indexes.dateindex,
|
||||
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change.as_ref().unwrap().dateindex.as_ref().unwrap(),
|
||||
market.indexes_to_marketcap.dateindex.as_ref().unwrap(),
|
||||
exit,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
|
||||
if let Some(height_to_supply_even_relative_to_circulating_supply) = self
|
||||
.height_to_supply_even_relative_to_circulating_supply
|
||||
.as_mut()
|
||||
@@ -2618,9 +2794,9 @@ impl Vecs {
|
||||
self.indexes_to_adjusted_value_destroyed
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
self.dateindex_to_realized_cap_30d_change
|
||||
self.indexes_to_realized_cap_30d_change
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| vec![v]),
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
self.indexes_to_net_realized_profit_and_loss
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
@@ -2703,6 +2879,12 @@ impl Vecs {
|
||||
self.indexes_to_net_unrealized_profit_and_loss_relative_to_market_cap
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
self.indexes_to_realized_profit_relative_to_realized_cap
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
self.indexes_to_realized_loss_relative_to_realized_cap
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
self.indexes_to_net_realized_profit_and_loss_relative_to_realized_cap
|
||||
.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
@@ -2756,6 +2938,12 @@ impl Vecs {
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
self.indexes_to_coinblocks_destroyed.vecs(),
|
||||
self.indexes_to_coindays_destroyed.vecs(),
|
||||
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_realized_cap.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
self.indexes_to_cumulative_net_realized_profit_and_loss_30d_change_relative_to_market_cap.as_ref()
|
||||
.map_or(vec![], |v| v.vecs()),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
|
||||
@@ -4,8 +4,8 @@ use brk_core::{DateIndex, Height, InputIndex, OutputIndex, OutputType, Result, S
|
||||
use brk_exit::Exit;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_vec::{
|
||||
AnyCollectableVec, AnyVec, BaseVecIterator, CollectableVec, Computation, EagerVec, Format,
|
||||
GenericStoredVec, StoredIndex, StoredVec, UnsafeSlice, VecIterator,
|
||||
AnyCollectableVec, AnyVec, CollectableVec, Computation, EagerVec, Format, GenericStoredVec,
|
||||
StoredIndex, StoredVec, UnsafeSlice, VecIterator,
|
||||
};
|
||||
use log::info;
|
||||
use outputs::OutputCohorts;
|
||||
@@ -1343,268 +1343,265 @@ impl Vecs {
|
||||
.try_for_each(|(_, v)| v.state.price_to_amount.reset())?;
|
||||
}
|
||||
|
||||
if starting_height == Height::from(height_to_date_fixed.len()) {
|
||||
return Ok(());
|
||||
}
|
||||
if starting_height < Height::from(height_to_date_fixed.len()) {
|
||||
starting_indexes.update_from_height(starting_height, indexes);
|
||||
|
||||
// ---
|
||||
// INIT
|
||||
// ---
|
||||
separate_utxo_vecs
|
||||
.par_iter_mut()
|
||||
.for_each(|(_, v)| v.init(starting_height));
|
||||
|
||||
separate_utxo_vecs
|
||||
.par_iter_mut()
|
||||
.for_each(|(_, v)| v.init(starting_height));
|
||||
|
||||
let mut unspendable_supply = if let Some(prev_height) = starting_height.decremented() {
|
||||
self.height_to_unspendable_supply
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height)
|
||||
} else {
|
||||
Sats::ZERO
|
||||
};
|
||||
let mut opreturn_supply = if let Some(prev_height) = starting_height.decremented() {
|
||||
self.height_to_opreturn_supply
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height)
|
||||
} else {
|
||||
Sats::ZERO
|
||||
};
|
||||
|
||||
let mut height = starting_height;
|
||||
starting_indexes.update_from_height(height, indexes);
|
||||
|
||||
(height.unwrap_to_usize()..height_to_first_outputindex_iter.len())
|
||||
.map(Height::from)
|
||||
.try_for_each(|_height| -> color_eyre::Result<()> {
|
||||
height = _height;
|
||||
|
||||
self.utxos_vecs
|
||||
.as_mut_separate_vecs()
|
||||
.iter_mut()
|
||||
.for_each(|(_, v)| v.state.reset_single_iteration_values());
|
||||
|
||||
info!("Processing chain at {height}...");
|
||||
|
||||
let timestamp = height_to_timestamp_fixed_iter.unwrap_get_inner(height);
|
||||
let price = height_to_close_iter
|
||||
.as_mut()
|
||||
.map(|i| *i.unwrap_get_inner(height));
|
||||
let first_outputindex = height_to_first_outputindex_iter
|
||||
.unwrap_get_inner(height)
|
||||
.unwrap_to_usize();
|
||||
let first_inputindex = height_to_first_inputindex_iter
|
||||
.unwrap_get_inner(height)
|
||||
.unwrap_to_usize();
|
||||
let output_count = height_to_output_count_iter.unwrap_get_inner(height);
|
||||
let input_count = height_to_input_count_iter.unwrap_get_inner(height);
|
||||
|
||||
let (mut height_to_sent, mut received) = thread::scope(|s| {
|
||||
if chain_state_starting_height <= height {
|
||||
s.spawn(|| {
|
||||
self.utxos_vecs
|
||||
.tick_tock_next_block(&chain_state, timestamp);
|
||||
});
|
||||
}
|
||||
|
||||
let sent_handle = s.spawn(|| {
|
||||
// Skip coinbase
|
||||
(first_inputindex + 1..first_inputindex + *input_count)
|
||||
.into_par_iter()
|
||||
.map(InputIndex::from)
|
||||
.map(|inputindex| {
|
||||
let outputindex = inputindex_to_outputindex
|
||||
.get_or_read(inputindex, &inputindex_to_outputindex_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let value = outputindex_to_value
|
||||
.get_or_read(outputindex, &outputindex_to_value_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let input_type = outputindex_to_outputtype
|
||||
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
// dbg!(input_type);
|
||||
|
||||
if input_type.is_unspendable() {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
let input_txindex = outputindex_to_txindex
|
||||
.get_or_read(outputindex, &outputindex_to_txindex_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let height = txindex_to_height
|
||||
.get_or_read(input_txindex, &txindex_to_height_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
(height, value, input_type)
|
||||
})
|
||||
.fold(
|
||||
BTreeMap::<Height, Transacted>::default,
|
||||
|mut tree, (height, value, input_type)| {
|
||||
tree.entry(height).or_default().iterate(value, input_type);
|
||||
tree
|
||||
},
|
||||
)
|
||||
.reduce(BTreeMap::<Height, Transacted>::default, |first, second| {
|
||||
let (mut source, to_consume) = if first.len() > second.len() {
|
||||
(first, second)
|
||||
} else {
|
||||
(second, first)
|
||||
};
|
||||
to_consume.into_iter().for_each(|(k, v)| {
|
||||
*source.entry(k).or_default() += v;
|
||||
});
|
||||
source
|
||||
})
|
||||
});
|
||||
|
||||
let received_handle = s.spawn(|| {
|
||||
(first_outputindex..first_outputindex + *output_count)
|
||||
.into_par_iter()
|
||||
.map(OutputIndex::from)
|
||||
.map(|outputindex| {
|
||||
let value = outputindex_to_value
|
||||
.get_or_read(outputindex, &outputindex_to_value_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let output_type = outputindex_to_outputtype
|
||||
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
(value, output_type)
|
||||
})
|
||||
.fold(
|
||||
Transacted::default,
|
||||
|mut transacted, (value, output_type)| {
|
||||
transacted.iterate(value, output_type);
|
||||
transacted
|
||||
},
|
||||
)
|
||||
.reduce(Transacted::default, |acc, transacted| acc + transacted)
|
||||
});
|
||||
|
||||
(sent_handle.join().unwrap(), received_handle.join().unwrap())
|
||||
});
|
||||
|
||||
unspendable_supply += received
|
||||
.by_type
|
||||
.unspendable
|
||||
.as_vec()
|
||||
let mut unspendable_supply = if let Some(prev_height) = starting_height.decremented() {
|
||||
self.height_to_unspendable_supply
|
||||
.into_iter()
|
||||
.map(|state| state.value)
|
||||
.sum::<Sats>()
|
||||
+ height_to_unclaimed_rewards_iter.unwrap_get_inner(height);
|
||||
|
||||
opreturn_supply += received.by_type.unspendable.opreturn.value;
|
||||
|
||||
if height == Height::new(0) {
|
||||
received = Transacted::default();
|
||||
unspendable_supply += Sats::FIFTY_BTC;
|
||||
} else if height == Height::new(91_842) || height == Height::new(91_880) {
|
||||
// Need to destroy invalid coinbases due to duplicate txids
|
||||
if height == Height::new(91_842) {
|
||||
height_to_sent.entry(Height::new(91_812)).or_default()
|
||||
} else {
|
||||
height_to_sent.entry(Height::new(91_722)).or_default()
|
||||
}
|
||||
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
|
||||
};
|
||||
|
||||
if chain_state_starting_height <= height {
|
||||
// Push current block state before processing sends and receives
|
||||
chain_state.push(BlockState {
|
||||
supply: received.spendable_supply.clone(),
|
||||
price,
|
||||
timestamp,
|
||||
});
|
||||
|
||||
self.utxos_vecs.receive(received, height, price);
|
||||
|
||||
let unsafe_chain_state = UnsafeSlice::new(&mut chain_state);
|
||||
|
||||
height_to_sent.par_iter().for_each(|(height, sent)| unsafe {
|
||||
(*unsafe_chain_state.get(height.unwrap_to_usize())).supply -=
|
||||
&sent.spendable_supply;
|
||||
});
|
||||
|
||||
self.utxos_vecs.send(height_to_sent, chain_state.as_slice());
|
||||
} else {
|
||||
dbg!(chain_state_starting_height, height);
|
||||
panic!("temp, just making sure")
|
||||
}
|
||||
|
||||
let mut separate_utxo_vecs = self.utxos_vecs.as_mut_separate_vecs();
|
||||
|
||||
separate_utxo_vecs
|
||||
.iter_mut()
|
||||
.try_for_each(|(_, v)| v.forced_pushed_at(height, exit))?;
|
||||
|
||||
self.height_to_unspendable_supply.forced_push_at(
|
||||
height,
|
||||
unspendable_supply,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
.unwrap_get_inner(prev_height)
|
||||
} else {
|
||||
Sats::ZERO
|
||||
};
|
||||
let mut opreturn_supply = if let Some(prev_height) = starting_height.decremented() {
|
||||
self.height_to_opreturn_supply
|
||||
.forced_push_at(height, opreturn_supply, exit)?;
|
||||
.into_iter()
|
||||
.unwrap_get_inner(prev_height)
|
||||
} else {
|
||||
Sats::ZERO
|
||||
};
|
||||
|
||||
let date = height_to_date_fixed_iter.unwrap_get_inner(height);
|
||||
let dateindex = DateIndex::try_from(date).unwrap();
|
||||
let date_first_height = dateindex_to_first_height_iter.unwrap_get_inner(dateindex);
|
||||
let date_height_count = dateindex_to_height_count_iter.unwrap_get_inner(dateindex);
|
||||
let is_date_last_height = date_first_height
|
||||
+ Height::from(date_height_count).decremented().unwrap()
|
||||
== height;
|
||||
let date_price = dateindex_to_close_iter
|
||||
.as_mut()
|
||||
.map(|v| is_date_last_height.then(|| *v.unwrap_get_inner(dateindex)));
|
||||
let mut height = starting_height;
|
||||
|
||||
separate_utxo_vecs.par_iter_mut().try_for_each(|(_, v)| {
|
||||
v.compute_then_force_push_unrealized_states(
|
||||
(height.unwrap_to_usize()..height_to_date_fixed.len())
|
||||
.map(Height::from)
|
||||
.try_for_each(|_height| -> color_eyre::Result<()> {
|
||||
height = _height;
|
||||
|
||||
self.utxos_vecs
|
||||
.as_mut_separate_vecs()
|
||||
.iter_mut()
|
||||
.for_each(|(_, v)| v.state.reset_single_iteration_values());
|
||||
|
||||
info!("Processing chain at {height}...");
|
||||
|
||||
let timestamp = height_to_timestamp_fixed_iter.unwrap_get_inner(height);
|
||||
let price = height_to_close_iter
|
||||
.as_mut()
|
||||
.map(|i| *i.unwrap_get_inner(height));
|
||||
let first_outputindex = height_to_first_outputindex_iter
|
||||
.unwrap_get_inner(height)
|
||||
.unwrap_to_usize();
|
||||
let first_inputindex = height_to_first_inputindex_iter
|
||||
.unwrap_get_inner(height)
|
||||
.unwrap_to_usize();
|
||||
let output_count = height_to_output_count_iter.unwrap_get_inner(height);
|
||||
let input_count = height_to_input_count_iter.unwrap_get_inner(height);
|
||||
|
||||
let (mut height_to_sent, mut received) = thread::scope(|s| {
|
||||
if chain_state_starting_height <= height {
|
||||
s.spawn(|| {
|
||||
self.utxos_vecs
|
||||
.tick_tock_next_block(&chain_state, timestamp);
|
||||
});
|
||||
}
|
||||
|
||||
let sent_handle = s.spawn(|| {
|
||||
// Skip coinbase
|
||||
(first_inputindex + 1..first_inputindex + *input_count)
|
||||
.into_par_iter()
|
||||
.map(InputIndex::from)
|
||||
.map(|inputindex| {
|
||||
let outputindex = inputindex_to_outputindex
|
||||
.get_or_read(inputindex, &inputindex_to_outputindex_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let value = outputindex_to_value
|
||||
.get_or_read(outputindex, &outputindex_to_value_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let input_type = outputindex_to_outputtype
|
||||
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
// dbg!(input_type);
|
||||
|
||||
if input_type.is_unspendable() {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
let input_txindex = outputindex_to_txindex
|
||||
.get_or_read(outputindex, &outputindex_to_txindex_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let height = txindex_to_height
|
||||
.get_or_read(input_txindex, &txindex_to_height_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
(height, value, input_type)
|
||||
})
|
||||
.fold(
|
||||
BTreeMap::<Height, Transacted>::default,
|
||||
|mut tree, (height, value, input_type)| {
|
||||
tree.entry(height).or_default().iterate(value, input_type);
|
||||
tree
|
||||
},
|
||||
)
|
||||
.reduce(BTreeMap::<Height, Transacted>::default, |first, second| {
|
||||
let (mut source, to_consume) = if first.len() > second.len() {
|
||||
(first, second)
|
||||
} else {
|
||||
(second, first)
|
||||
};
|
||||
to_consume.into_iter().for_each(|(k, v)| {
|
||||
*source.entry(k).or_default() += v;
|
||||
});
|
||||
source
|
||||
})
|
||||
});
|
||||
|
||||
let received_handle = s.spawn(|| {
|
||||
(first_outputindex..first_outputindex + *output_count)
|
||||
.into_par_iter()
|
||||
.map(OutputIndex::from)
|
||||
.map(|outputindex| {
|
||||
let value = outputindex_to_value
|
||||
.get_or_read(outputindex, &outputindex_to_value_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
let output_type = outputindex_to_outputtype
|
||||
.get_or_read(outputindex, &outputindex_to_outputtype_mmap)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
|
||||
(value, output_type)
|
||||
})
|
||||
.fold(
|
||||
Transacted::default,
|
||||
|mut transacted, (value, output_type)| {
|
||||
transacted.iterate(value, output_type);
|
||||
transacted
|
||||
},
|
||||
)
|
||||
.reduce(Transacted::default, |acc, transacted| acc + transacted)
|
||||
});
|
||||
|
||||
(sent_handle.join().unwrap(), received_handle.join().unwrap())
|
||||
});
|
||||
|
||||
unspendable_supply += received
|
||||
.by_type
|
||||
.unspendable
|
||||
.as_vec()
|
||||
.into_iter()
|
||||
.map(|state| state.value)
|
||||
.sum::<Sats>()
|
||||
+ height_to_unclaimed_rewards_iter.unwrap_get_inner(height);
|
||||
|
||||
opreturn_supply += received.by_type.unspendable.opreturn.value;
|
||||
|
||||
if height == Height::new(0) {
|
||||
received = Transacted::default();
|
||||
unspendable_supply += Sats::FIFTY_BTC;
|
||||
} else if height == Height::new(91_842) || height == Height::new(91_880) {
|
||||
// Need to destroy invalid coinbases due to duplicate txids
|
||||
if height == Height::new(91_842) {
|
||||
height_to_sent.entry(Height::new(91_812)).or_default()
|
||||
} else {
|
||||
height_to_sent.entry(Height::new(91_722)).or_default()
|
||||
}
|
||||
.iterate(Sats::FIFTY_BTC, OutputType::P2PK65);
|
||||
};
|
||||
|
||||
if chain_state_starting_height <= height {
|
||||
// Push current block state before processing sends and receives
|
||||
chain_state.push(BlockState {
|
||||
supply: received.spendable_supply.clone(),
|
||||
price,
|
||||
timestamp,
|
||||
});
|
||||
|
||||
self.utxos_vecs.receive(received, height, price);
|
||||
|
||||
let unsafe_chain_state = UnsafeSlice::new(&mut chain_state);
|
||||
|
||||
height_to_sent.par_iter().for_each(|(height, sent)| unsafe {
|
||||
(*unsafe_chain_state.get(height.unwrap_to_usize())).supply -=
|
||||
&sent.spendable_supply;
|
||||
});
|
||||
|
||||
self.utxos_vecs.send(height_to_sent, chain_state.as_slice());
|
||||
} else {
|
||||
dbg!(chain_state_starting_height, height);
|
||||
panic!("temp, just making sure")
|
||||
}
|
||||
|
||||
let mut separate_utxo_vecs = self.utxos_vecs.as_mut_separate_vecs();
|
||||
|
||||
separate_utxo_vecs
|
||||
.iter_mut()
|
||||
.try_for_each(|(_, v)| v.forced_pushed_at(height, exit))?;
|
||||
|
||||
self.height_to_unspendable_supply.forced_push_at(
|
||||
height,
|
||||
price,
|
||||
is_date_last_height.then_some(dateindex),
|
||||
date_price,
|
||||
unspendable_supply,
|
||||
exit,
|
||||
)
|
||||
)?;
|
||||
|
||||
self.height_to_opreturn_supply
|
||||
.forced_push_at(height, opreturn_supply, exit)?;
|
||||
|
||||
let date = height_to_date_fixed_iter.unwrap_get_inner(height);
|
||||
let dateindex = DateIndex::try_from(date).unwrap();
|
||||
let date_first_height =
|
||||
dateindex_to_first_height_iter.unwrap_get_inner(dateindex);
|
||||
let date_height_count =
|
||||
dateindex_to_height_count_iter.unwrap_get_inner(dateindex);
|
||||
let is_date_last_height = date_first_height
|
||||
+ Height::from(date_height_count).decremented().unwrap()
|
||||
== height;
|
||||
let date_price = dateindex_to_close_iter
|
||||
.as_mut()
|
||||
.map(|v| is_date_last_height.then(|| *v.unwrap_get_inner(dateindex)));
|
||||
|
||||
separate_utxo_vecs.par_iter_mut().try_for_each(|(_, v)| {
|
||||
v.compute_then_force_push_unrealized_states(
|
||||
height,
|
||||
price,
|
||||
is_date_last_height.then_some(dateindex),
|
||||
date_price,
|
||||
exit,
|
||||
)
|
||||
})?;
|
||||
|
||||
if height != Height::ZERO && height.unwrap_to_usize() % 20_000 == 0 {
|
||||
info!("Flushing...");
|
||||
exit.block();
|
||||
self.flush_states(height, &chain_state, exit)?;
|
||||
exit.release();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if height != Height::ZERO && height.unwrap_to_usize() % 20_000 == 0 {
|
||||
info!("Flushing...");
|
||||
exit.block();
|
||||
self.flush_states(height, &chain_state, exit)?;
|
||||
exit.release();
|
||||
}
|
||||
exit.block();
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
info!("Flushing...");
|
||||
|
||||
exit.block();
|
||||
self.flush_states(height, &chain_state, exit)?;
|
||||
}
|
||||
|
||||
info!("Flushing...");
|
||||
|
||||
self.flush_states(height, &chain_state, exit)?;
|
||||
|
||||
info!("Computing overlaping...");
|
||||
info!("Computing overlapping...");
|
||||
|
||||
self.utxos_vecs
|
||||
.compute_overlaping_vecs(&starting_indexes, exit)?;
|
||||
.compute_overlapping_vecs(&starting_indexes, exit)?;
|
||||
|
||||
info!("Computing rest part 1...");
|
||||
|
||||
@@ -1627,6 +1624,13 @@ impl Vecs {
|
||||
.dateindex
|
||||
.clone();
|
||||
let height_to_realized_cap = self.utxos_vecs.all.1.height_to_realized_cap.clone();
|
||||
let dateindex_to_realized_cap = self
|
||||
.utxos_vecs
|
||||
.all
|
||||
.1
|
||||
.indexes_to_realized_cap
|
||||
.as_ref()
|
||||
.map(|v| v.dateindex.unwrap_last().clone());
|
||||
|
||||
self.utxos_vecs
|
||||
.as_mut_vecs()
|
||||
@@ -1641,6 +1645,7 @@ impl Vecs {
|
||||
&height_to_supply,
|
||||
dateindex_to_supply.as_ref().unwrap(),
|
||||
height_to_realized_cap.as_ref(),
|
||||
dateindex_to_realized_cap.as_ref(),
|
||||
exit,
|
||||
)
|
||||
})?;
|
||||
|
||||
@@ -14,7 +14,7 @@ pub trait OutputCohorts {
|
||||
fn tick_tock_next_block(&mut self, chain_state: &[BlockState], timestamp: Timestamp);
|
||||
fn send(&mut self, height_to_sent: BTreeMap<Height, Transacted>, chain_state: &[BlockState]);
|
||||
fn receive(&mut self, received: Transacted, height: Height, price: Option<Dollars>);
|
||||
fn compute_overlaping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
|
||||
fn compute_overlapping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()>;
|
||||
}
|
||||
|
||||
impl OutputCohorts for Outputs<(OutputFilter, cohort::Vecs)> {
|
||||
@@ -172,7 +172,7 @@ impl OutputCohorts for Outputs<(OutputFilter, cohort::Vecs)> {
|
||||
});
|
||||
}
|
||||
|
||||
fn compute_overlaping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
fn compute_overlapping_vecs(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
|
||||
let by_date_range = self.by_date_range.as_vec();
|
||||
let by_size_range = self.by_size_range.as_vec();
|
||||
|
||||
|
||||
@@ -3,5 +3,7 @@ use log::info;
|
||||
pub fn pause() {
|
||||
info!("Press enter to continue...");
|
||||
let mut buffer = String::new();
|
||||
std::io::stdin().read_line(&mut buffer).expect("Failed to read line");
|
||||
std::io::stdin()
|
||||
.read_line(&mut buffer)
|
||||
.expect("Failed to read line");
|
||||
}
|
||||
|
||||
@@ -28,9 +28,14 @@ impl<'a> VecTrees<'a> {
|
||||
|| s.starts_with("cumulative_from")
|
||||
}))
|
||||
&& !(split.len() == 4
|
||||
&& split
|
||||
.get(1)
|
||||
.is_some_and(|s| s == &"up" || s == &"start" || s.starts_with("from"))
|
||||
&& split.get(1).is_some_and(|s| {
|
||||
s == &"up"
|
||||
|| s == &"start"
|
||||
|| s.starts_with("from")
|
||||
|| s == &"cumulative_up"
|
||||
|| s == &"cumulative_start"
|
||||
|| s.starts_with("cumulative_from")
|
||||
})
|
||||
&& split.get(2).is_some_and(|s| s.ends_with("relative")))
|
||||
{
|
||||
dbg!(&name, &split);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ impl<T> Outputs<T> {
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn as_mut_overlaping_vecs(&mut self) -> Vec<&mut T> {
|
||||
pub fn as_mut_overlapping_vecs(&mut self) -> Vec<&mut T> {
|
||||
[&mut self.all]
|
||||
.into_iter()
|
||||
.chain(self.by_term.as_mut_vec())
|
||||
|
||||
@@ -141,7 +141,7 @@ function createChartElement({
|
||||
}
|
||||
: {}),
|
||||
// ..._options,
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
ichart.priceScale("right").applyOptions({
|
||||
@@ -173,7 +173,7 @@ function createChartElement({
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
signals.createEffect(index, (index) => {
|
||||
@@ -181,12 +181,12 @@ function createChartElement({
|
||||
index === /** @satisfies {MonthIndex} */ (7)
|
||||
? 1
|
||||
: index === /** @satisfies {QuarterIndex} */ (19)
|
||||
? 2
|
||||
: index === /** @satisfies {YearIndex} */ (23)
|
||||
? 6
|
||||
: index === /** @satisfies {DecadeIndex} */ (1)
|
||||
? 60
|
||||
: 0.5;
|
||||
? 2
|
||||
: index === /** @satisfies {YearIndex} */ (23)
|
||||
? 6
|
||||
: index === /** @satisfies {DecadeIndex} */ (1)
|
||||
? 60
|
||||
: 0.5;
|
||||
|
||||
ichart.applyOptions({
|
||||
timeScale: {
|
||||
@@ -209,7 +209,7 @@ function createChartElement({
|
||||
activeResources.forEach((v) => {
|
||||
v.fetch();
|
||||
});
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
if (fitContent) {
|
||||
@@ -240,8 +240,7 @@ function createChartElement({
|
||||
|
||||
const children = Array.from(parent.childNodes).filter(
|
||||
(element) =>
|
||||
/** @type {HTMLElement} */ (element).dataset.position ===
|
||||
position,
|
||||
/** @type {HTMLElement} */ (element).dataset.position === position
|
||||
);
|
||||
|
||||
if (children.length === 1) {
|
||||
@@ -263,7 +262,7 @@ function createChartElement({
|
||||
|
||||
fieldset.append(createChild(pane));
|
||||
}),
|
||||
paneIndex ? 50 : 0,
|
||||
paneIndex ? 50 : 0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -347,7 +346,7 @@ function createChartElement({
|
||||
// Or remove ?
|
||||
iseries.applyOptions({
|
||||
visible: active,
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
iseries.setSeriesOrder(order);
|
||||
@@ -378,7 +377,7 @@ function createChartElement({
|
||||
index,
|
||||
index === /** @satisfies {Height} */ (5)
|
||||
? "timestamp-fixed"
|
||||
: "timestamp",
|
||||
: "timestamp"
|
||||
);
|
||||
timeResource.fetch();
|
||||
|
||||
@@ -438,16 +437,18 @@ function createChartElement({
|
||||
if (sameTime) {
|
||||
console.log(data[offsetedI]);
|
||||
}
|
||||
const candles = /** @type {CandlestickData[]} */ (data);
|
||||
let [open, high, low, close] = v;
|
||||
candles[offsetedI] = {
|
||||
data[offsetedI] = {
|
||||
time,
|
||||
open: sameTime ? candles[offsetedI].open : open,
|
||||
// @ts-ignore
|
||||
open: sameTime ? data[offsetedI].open : open,
|
||||
high: sameTime
|
||||
? Math.max(candles[offsetedI].high, high)
|
||||
? // @ts-ignore
|
||||
Math.max(data[offsetedI].high, high)
|
||||
: high,
|
||||
low: sameTime
|
||||
? Math.min(candles[offsetedI].low, low)
|
||||
? // @ts-ignore
|
||||
Math.min(data[offsetedI].low, low)
|
||||
: low,
|
||||
close,
|
||||
};
|
||||
@@ -580,7 +581,7 @@ function createChartElement({
|
||||
});
|
||||
|
||||
console.timeEnd(consoleTimeLabel);
|
||||
},
|
||||
}
|
||||
);
|
||||
} else {
|
||||
activeResources.delete(valuesResource);
|
||||
@@ -673,7 +674,7 @@ function createChartElement({
|
||||
borderVisible: false,
|
||||
visible: defaultActive !== false,
|
||||
},
|
||||
paneIndex,
|
||||
paneIndex
|
||||
)
|
||||
);
|
||||
|
||||
@@ -729,7 +730,7 @@ function createChartElement({
|
||||
color: color(),
|
||||
...options,
|
||||
},
|
||||
paneIndex,
|
||||
paneIndex
|
||||
)
|
||||
);
|
||||
|
||||
@@ -797,7 +798,7 @@ function createChartElement({
|
||||
topFillColor2: "transparent",
|
||||
lineVisible: true,
|
||||
},
|
||||
paneIndex,
|
||||
paneIndex
|
||||
)
|
||||
);
|
||||
|
||||
@@ -960,7 +961,7 @@ function createLegend({ signals, utils }) {
|
||||
} else {
|
||||
spanColor.style.backgroundColor = tameColor(color);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1120,17 +1121,17 @@ function numberToShortUSFormat(value, digits) {
|
||||
if (modulused === 0) {
|
||||
return `${numberToUSFormat(
|
||||
value / (1_000_000 * 1_000 ** letterIndex),
|
||||
3,
|
||||
3
|
||||
)}${letter}`;
|
||||
} else if (modulused === 1) {
|
||||
return `${numberToUSFormat(
|
||||
value / (1_000_000 * 1_000 ** letterIndex),
|
||||
2,
|
||||
2
|
||||
)}${letter}`;
|
||||
} else {
|
||||
return `${numberToUSFormat(
|
||||
value / (1_000_000 * 1_000 ** letterIndex),
|
||||
1,
|
||||
1
|
||||
)}${letter}`;
|
||||
}
|
||||
}
|
||||
@@ -1180,7 +1181,7 @@ function createOklchToRGBA() {
|
||||
return rgb.map((c) =>
|
||||
Math.abs(c) > 0.0031308
|
||||
? (c < 0 ? -1 : 1) * (1.055 * Math.abs(c) ** (1 / 2.4) - 0.055)
|
||||
: 12.92 * c,
|
||||
: 12.92 * c
|
||||
);
|
||||
}
|
||||
/**
|
||||
@@ -1192,7 +1193,7 @@ function createOklchToRGBA() {
|
||||
1, 0.3963377773761749, 0.2158037573099136, 1, -0.1055613458156586,
|
||||
-0.0638541728258133, 1, -0.0894841775298119, -1.2914855480194092,
|
||||
]),
|
||||
lab,
|
||||
lab
|
||||
);
|
||||
const LMS = /** @type {[number, number, number]} */ (
|
||||
LMSg.map((val) => val ** 3)
|
||||
@@ -1203,7 +1204,7 @@ function createOklchToRGBA() {
|
||||
-0.0405757452148008, 1.112286803280317, -0.0717110580655164,
|
||||
-0.0763729366746601, -0.4214933324022432, 1.5869240198367816,
|
||||
]),
|
||||
LMS,
|
||||
LMS
|
||||
);
|
||||
}
|
||||
/**
|
||||
@@ -1216,7 +1217,7 @@ function createOklchToRGBA() {
|
||||
-0.9692436362808796, 1.8759675015077202, 0.04155505740717559,
|
||||
0.05563007969699366, -0.20397695888897652, 1.0569715142428786,
|
||||
],
|
||||
xyz,
|
||||
xyz
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1239,8 +1240,8 @@ function createOklchToRGBA() {
|
||||
});
|
||||
const rgb = srgbLinear2rgb(
|
||||
xyz2rgbLinear(
|
||||
oklab2xyz(oklch2oklab(/** @type {[number, number, number]} */ (lch))),
|
||||
),
|
||||
oklab2xyz(oklch2oklab(/** @type {[number, number, number]} */ (lch)))
|
||||
)
|
||||
).map((v) => {
|
||||
return Math.max(Math.min(Math.round(v * 255), 255), 0);
|
||||
});
|
||||
|
||||
@@ -396,6 +396,7 @@ export function init({
|
||||
blueprints[unit]?.forEach((blueprint, order) => {
|
||||
order += orderStart;
|
||||
|
||||
console.log(blueprint.key);
|
||||
const indexes = /** @type {readonly number[]} */ (
|
||||
vecIdToIndexes[blueprint.key]
|
||||
);
|
||||
|
||||
@@ -63,14 +63,14 @@ function initPackages() {
|
||||
const imports = {
|
||||
async signals() {
|
||||
return import("../packages/solid-signals/wrapper.js").then(
|
||||
(d) => d.default,
|
||||
(d) => d.default
|
||||
);
|
||||
},
|
||||
async lightweightCharts() {
|
||||
return window.document.fonts.ready.then(() =>
|
||||
import("../packages/lightweight-charts/wrapper.js").then(
|
||||
(d) => d.default,
|
||||
),
|
||||
(d) => d.default
|
||||
)
|
||||
);
|
||||
},
|
||||
async leanQr() {
|
||||
@@ -78,7 +78,7 @@ function initPackages() {
|
||||
},
|
||||
async ufuzzy() {
|
||||
return import("../packages/ufuzzy/v1.0.18/script.js").then(
|
||||
({ default: d }) => d,
|
||||
({ default: d }) => d
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -586,7 +586,7 @@ function createUtils() {
|
||||
window.history.pushState(
|
||||
null,
|
||||
"",
|
||||
`${pathname}?${urlParams.toString()}`,
|
||||
`${pathname}?${urlParams.toString()}`
|
||||
);
|
||||
} catch (_) {}
|
||||
},
|
||||
@@ -603,7 +603,7 @@ function createUtils() {
|
||||
window.history.replaceState(
|
||||
null,
|
||||
"",
|
||||
`${pathname}?${urlParams.toString()}`,
|
||||
`${pathname}?${urlParams.toString()}`
|
||||
);
|
||||
} catch (_) {}
|
||||
},
|
||||
@@ -839,7 +839,7 @@ function createUtils() {
|
||||
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
|
||||
unit = "Bytes";
|
||||
}
|
||||
if ((!unit || thoroughUnitCheck) && id.endsWith("standard-deviation")) {
|
||||
if ((!unit || thoroughUnitCheck) && id.endsWith("-sd")) {
|
||||
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
|
||||
unit = "sd";
|
||||
}
|
||||
@@ -1243,8 +1243,8 @@ function createUtils() {
|
||||
today.getUTCDate(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
),
|
||||
0
|
||||
)
|
||||
);
|
||||
},
|
||||
/**
|
||||
@@ -1265,12 +1265,6 @@ function createUtils() {
|
||||
return 0;
|
||||
return this.differenceBetween(date, new Date("2009-01-09"));
|
||||
},
|
||||
/**
|
||||
* @param {Date} start
|
||||
*/
|
||||
getRangeUpToToday(start) {
|
||||
return this.getRange(start, new Date());
|
||||
},
|
||||
/**
|
||||
* @param {Date} start
|
||||
* @param {Date} end
|
||||
@@ -1337,7 +1331,7 @@ function createUtils() {
|
||||
*/
|
||||
function getNumberOfDaysBetweenTwoDates(oldest, youngest) {
|
||||
return Math.round(
|
||||
Math.abs((youngest.getTime() - oldest.getTime()) / date.ONE_DAY_IN_MS),
|
||||
Math.abs((youngest.getTime() - oldest.getTime()) / date.ONE_DAY_IN_MS)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1555,7 +1549,7 @@ function createVecsResources(signals, utils) {
|
||||
const fetchedRecord = signals.createSignal(
|
||||
/** @type {Map<string, {loading: boolean, at: Date | null, vec: Signal<T[] | null>}>} */ (
|
||||
new Map()
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -1579,7 +1573,9 @@ function createVecsResources(signals, utils) {
|
||||
map.set(fetchedKey, {
|
||||
loading: false,
|
||||
at: null,
|
||||
vec: signals.createSignal(/** @type {T[] | null} */ (null)),
|
||||
vec: signals.createSignal(/** @type {T[] | null} */ (null), {
|
||||
equals: false,
|
||||
}),
|
||||
});
|
||||
return map;
|
||||
});
|
||||
@@ -1603,7 +1599,7 @@ function createVecsResources(signals, utils) {
|
||||
index,
|
||||
id,
|
||||
from,
|
||||
to,
|
||||
to
|
||||
)
|
||||
);
|
||||
fetched.at = new Date();
|
||||
@@ -1864,7 +1860,7 @@ function initWebSockets(signals, utils) {
|
||||
|
||||
window.document.addEventListener(
|
||||
"visibilitychange",
|
||||
reinitWebSocketIfDocumentNotHidden,
|
||||
reinitWebSocketIfDocumentNotHidden
|
||||
);
|
||||
|
||||
window.document.addEventListener("online", reinitWebSocket);
|
||||
@@ -1873,7 +1869,7 @@ function initWebSockets(signals, utils) {
|
||||
ws?.close();
|
||||
window.document.removeEventListener(
|
||||
"visibilitychange",
|
||||
reinitWebSocketIfDocumentNotHidden,
|
||||
reinitWebSocketIfDocumentNotHidden
|
||||
);
|
||||
window.document.removeEventListener("online", reinitWebSocket);
|
||||
live.set(false);
|
||||
@@ -1899,7 +1895,7 @@ function initWebSockets(signals, utils) {
|
||||
symbol: ["BTC/USD"],
|
||||
interval: 1440,
|
||||
},
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1928,7 +1924,7 @@ function initWebSockets(signals, utils) {
|
||||
|
||||
/** @type {ReturnType<typeof createWebsocket<CandlestickData>>} */
|
||||
const kraken1dCandle = createWebsocket((callback) =>
|
||||
krakenCandleWebSocketCreator(callback),
|
||||
krakenCandleWebSocketCreator(callback)
|
||||
);
|
||||
|
||||
kraken1dCandle.open();
|
||||
@@ -1987,7 +1983,7 @@ function main() {
|
||||
}
|
||||
|
||||
const frame = window.document.getElementById(
|
||||
/** @type {string} */ (input.value),
|
||||
/** @type {string} */ (input.value)
|
||||
);
|
||||
|
||||
if (!frame) {
|
||||
@@ -2085,23 +2081,23 @@ function main() {
|
||||
|
||||
function initDark() {
|
||||
const preferredColorSchemeMatchMedia = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
"(prefers-color-scheme: dark)"
|
||||
);
|
||||
const dark = signals.createSignal(
|
||||
preferredColorSchemeMatchMedia.matches,
|
||||
preferredColorSchemeMatchMedia.matches
|
||||
);
|
||||
preferredColorSchemeMatchMedia.addEventListener(
|
||||
"change",
|
||||
({ matches }) => {
|
||||
dark.set(matches);
|
||||
},
|
||||
}
|
||||
);
|
||||
return dark;
|
||||
}
|
||||
const dark = initDark();
|
||||
|
||||
const qrcode = signals.createSignal(
|
||||
/** @type {string | null} */ (null),
|
||||
/** @type {string | null} */ (null)
|
||||
);
|
||||
|
||||
function createLastHeightResource() {
|
||||
@@ -2112,7 +2108,7 @@ function main() {
|
||||
lastHeight.set(h);
|
||||
},
|
||||
/** @satisfies {Height} */ (5),
|
||||
"height",
|
||||
"height"
|
||||
);
|
||||
}
|
||||
fetchLastHeight();
|
||||
@@ -2156,10 +2152,10 @@ function main() {
|
||||
const owner = signals.getOwner();
|
||||
|
||||
const chartOption = signals.createSignal(
|
||||
/** @type {ChartOption | null} */ (null),
|
||||
/** @type {ChartOption | null} */ (null)
|
||||
);
|
||||
const simOption = signals.createSignal(
|
||||
/** @type {SimulationOption | null} */ (null),
|
||||
/** @type {SimulationOption | null} */ (null)
|
||||
);
|
||||
|
||||
let previousElement = /** @type {HTMLElement | undefined} */ (
|
||||
@@ -2205,9 +2201,9 @@ function main() {
|
||||
webSockets,
|
||||
vecsResources,
|
||||
vecIdToIndexes,
|
||||
}),
|
||||
),
|
||||
),
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
firstTimeLoadingChart = false;
|
||||
@@ -2228,8 +2224,8 @@ function main() {
|
||||
vecsResources,
|
||||
option,
|
||||
vecIdToIndexes,
|
||||
}),
|
||||
),
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
firstTimeLoadingTable = false;
|
||||
@@ -2253,9 +2249,9 @@ function main() {
|
||||
signals,
|
||||
utils,
|
||||
vecsResources,
|
||||
}),
|
||||
),
|
||||
),
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
firstTimeLoadingSimulation = false;
|
||||
@@ -2284,42 +2280,42 @@ function main() {
|
||||
createMobileSwitchEffect();
|
||||
|
||||
utils.dom.onFirstIntersection(elements.aside, () =>
|
||||
signals.runWithOwner(owner, initSelectedFrame),
|
||||
signals.runWithOwner(owner, initSelectedFrame)
|
||||
);
|
||||
}
|
||||
initSelected();
|
||||
|
||||
function initFolders() {
|
||||
// async function scrollToSelected() {
|
||||
// if (!options.selected()) throw "Selected should be set by now";
|
||||
// const selectedId = options.selected().id;
|
||||
async function scrollToSelected() {
|
||||
if (!options.selected()) throw "Selected should be set by now";
|
||||
const selectedId = options.selected().id;
|
||||
|
||||
// const path = options.selected().path;
|
||||
const path = options.selected().path;
|
||||
|
||||
// let i = 0;
|
||||
// while (i !== path.length) {
|
||||
// try {
|
||||
// const id = path[i];
|
||||
// const details = /** @type {HTMLDetailsElement} */ (
|
||||
// utils.dom.getElementById(id)
|
||||
// );
|
||||
// details.open = true;
|
||||
// i++;
|
||||
// } catch {
|
||||
// await utils.next();
|
||||
// }
|
||||
// }
|
||||
let i = 0;
|
||||
while (i !== path.length) {
|
||||
try {
|
||||
const id = path[i];
|
||||
const details = /** @type {HTMLDetailsElement} */ (
|
||||
utils.dom.getElementById(id)
|
||||
);
|
||||
details.open = true;
|
||||
i++;
|
||||
} catch {
|
||||
await utils.next();
|
||||
}
|
||||
}
|
||||
|
||||
// await utils.next();
|
||||
// await utils.next();
|
||||
await utils.next();
|
||||
await utils.next();
|
||||
|
||||
// utils.dom
|
||||
// .getElementById(`${selectedId}-nav-selector`)
|
||||
// .scrollIntoView({
|
||||
// behavior: "instant",
|
||||
// block: "center",
|
||||
// });
|
||||
// }
|
||||
utils.dom
|
||||
.getElementById(`${selectedId}-nav-selector`)
|
||||
.scrollIntoView({
|
||||
behavior: "instant",
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
|
||||
utils.dom.onFirstIntersection(elements.nav, () => {
|
||||
options.treeElement.set(() => {
|
||||
@@ -2329,7 +2325,9 @@ function main() {
|
||||
return treeElement;
|
||||
});
|
||||
|
||||
// setTimeout(scrollToSelected, 10);
|
||||
if (localhost) {
|
||||
setTimeout(scrollToSelected, 10);
|
||||
}
|
||||
});
|
||||
}
|
||||
initFolders();
|
||||
@@ -2362,7 +2360,7 @@ function main() {
|
||||
if (indexes?.length) {
|
||||
const maxIndex = Math.min(
|
||||
(order || indexes).length - 1,
|
||||
minIndex + RESULTS_PER_PAGE - 1,
|
||||
minIndex + RESULTS_PER_PAGE - 1
|
||||
);
|
||||
|
||||
list = Array(maxIndex - minIndex + 1);
|
||||
@@ -2438,7 +2436,7 @@ function main() {
|
||||
haystack,
|
||||
needle,
|
||||
undefined,
|
||||
infoThresh,
|
||||
infoThresh
|
||||
);
|
||||
|
||||
if (!result?.[0]?.length || !result?.[1]) {
|
||||
@@ -2446,7 +2444,7 @@ function main() {
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
infoThresh
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2455,7 +2453,7 @@ function main() {
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
infoThresh
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2464,7 +2462,7 @@ function main() {
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
infoThresh
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2473,7 +2471,7 @@ function main() {
|
||||
haystack,
|
||||
needle,
|
||||
undefined,
|
||||
infoThresh,
|
||||
infoThresh
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2482,7 +2480,7 @@ function main() {
|
||||
haystack,
|
||||
needle,
|
||||
outOfOrder,
|
||||
infoThresh,
|
||||
infoThresh
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2565,7 +2563,7 @@ function main() {
|
||||
|
||||
shareDiv.hidden = false;
|
||||
});
|
||||
}),
|
||||
})
|
||||
);
|
||||
}
|
||||
initShare();
|
||||
@@ -2589,7 +2587,7 @@ function main() {
|
||||
utils.storage.write(barWidthLocalStorageKey, String(width));
|
||||
} else {
|
||||
elements.main.style.width = elements.style.getPropertyValue(
|
||||
"--default-main-width",
|
||||
"--default-main-width"
|
||||
);
|
||||
utils.storage.remove(barWidthLocalStorageKey);
|
||||
}
|
||||
@@ -2626,9 +2624,9 @@ function main() {
|
||||
window.addEventListener("mouseleave", setResizeFalse);
|
||||
}
|
||||
initDesktopResizeBar();
|
||||
}),
|
||||
),
|
||||
),
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
main();
|
||||
|
||||
@@ -132,9 +132,6 @@ function createPartialOptions(colors) {
|
||||
* @typedef {"cumulative-"} CumulativePrefix
|
||||
* @typedef {StartsWith<CumulativePrefix>} CumulativeVecId
|
||||
* @typedef {WithoutPrefix<CumulativeVecId, CumulativePrefix>} CumulativeVecIdBase
|
||||
* @typedef {"-sum"} SumSuffix
|
||||
* @typedef {EndsWith<SumSuffix>} VecIdSum
|
||||
* @typedef {WithoutSuffix<VecIdSum, SumSuffix>} VecIdSumBase
|
||||
* @typedef {"-average"} AverageSuffix
|
||||
* @typedef {EndsWith<AverageSuffix>} VecIdAverage
|
||||
* @typedef {WithoutSuffix<VecIdAverage, AverageSuffix>} VecIdAverageBase
|
||||
@@ -832,13 +829,13 @@ function createPartialOptions(colors) {
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {VecIdSumBase & CumulativeVecIdBase} args.concat
|
||||
* @param {CumulativeVecIdBase} args.concat
|
||||
* @param {string} [args.name]
|
||||
*/
|
||||
function createSumCumulativeSeries({ concat, name }) {
|
||||
return /** @satisfies {AnyFetchedSeriesBlueprint[]} */ ([
|
||||
{
|
||||
key: `${concat}-sum`,
|
||||
key: concat,
|
||||
title: name ? `${name} Sum` : "Sum",
|
||||
color: colors.orange,
|
||||
},
|
||||
@@ -903,7 +900,7 @@ function createPartialOptions(colors) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VecIdAverageBase & VecIdSumBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key
|
||||
* @param {VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key
|
||||
*/
|
||||
function createAverageSumCumulativeMinMaxPercentilesSeries(key) {
|
||||
return [
|
||||
@@ -915,7 +912,7 @@ function createPartialOptions(colors) {
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {VecId & VecIdAverageBase & VecIdSumBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} args.key
|
||||
* @param {VecId & VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} args.key
|
||||
* @param {string} args.name
|
||||
*/
|
||||
function createBaseAverageSumCumulativeMinMaxPercentilesSeries({
|
||||
@@ -933,7 +930,7 @@ function createPartialOptions(colors) {
|
||||
|
||||
/**
|
||||
* @param {Object} args
|
||||
* @param {VecId & VecIdSumBase & CumulativeVecIdBase} args.key
|
||||
* @param {VecId & CumulativeVecIdBase} args.key
|
||||
* @param {string} args.name
|
||||
*/
|
||||
function createBaseSumCumulativeSeries({ key, name }) {
|
||||
@@ -1431,7 +1428,7 @@ function createPartialOptions(colors) {
|
||||
key: `${fixKey(key)}realized-price`,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
})
|
||||
),
|
||||
}
|
||||
: createPriceWithRatio({
|
||||
@@ -1452,19 +1449,170 @@ function createPartialOptions(colors) {
|
||||
name: "Profit",
|
||||
color: colors.green,
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `cumulative-${fixKey(args.key)}realized-profit`,
|
||||
name: "Cumulative Profit",
|
||||
color: colors.green,
|
||||
defaultActive: false,
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(args.key)}realized-loss`,
|
||||
name: "Loss",
|
||||
color: colors.red,
|
||||
defaultActive: false,
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `cumulative-${fixKey(args.key)}realized-loss`,
|
||||
name: "Cumulative Loss",
|
||||
color: colors.red,
|
||||
defaultActive: false,
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `${fixKey(args.key)}negative-realized-loss`,
|
||||
name: "Negative Loss",
|
||||
color: colors.red,
|
||||
}),
|
||||
createBaseSeries({
|
||||
key: `cumulative-${fixKey(
|
||||
args.key
|
||||
)}negative-realized-loss`,
|
||||
name: "Cumulative Negative Loss",
|
||||
color: colors.red,
|
||||
defaultActive: false,
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
)}realized-profit-relative-to-realized-cap`,
|
||||
title: "Profit",
|
||||
color: colors.green,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
args.key
|
||||
)}realized-loss-relative-to-realized-cap`,
|
||||
title: "Loss",
|
||||
color: colors.red,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `${args.title} Net Realized Profit And Loss`,
|
||||
bottom: list.flatMap(({ color, name, key }) => [
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(key)}net-realized-profit-and-loss`,
|
||||
title: "Net",
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `cumulative-${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss`,
|
||||
title: "Cumulative net",
|
||||
defaultActive: false,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `cumulative-${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss-30d-change`,
|
||||
title: "cum net 30d change",
|
||||
defaultActive: false,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss-relative-to-realized-cap`,
|
||||
title: "Net",
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `cumulative-${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss-30d-change-relative-to-realized-cap`,
|
||||
title: "cum net 30d change",
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `cumulative-${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss-30d-change-relative-to-market-cap`,
|
||||
title: "cum net 30d change",
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
},
|
||||
{
|
||||
name: "sopr",
|
||||
title: `${args.title} Spent Output Profit Ratio`,
|
||||
bottom: list.flatMap(({ color, name, key }) => [
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(key)}spent-output-profit-ratio`,
|
||||
title: "sopr",
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(key)}adjusted-spent-output-profit-ratio`,
|
||||
title: "asopr",
|
||||
colors: [colors.yellow, colors.pink],
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
@@ -1475,8 +1623,19 @@ function createPartialOptions(colors) {
|
||||
return /** @type {const} */ ([
|
||||
createBaseSeries({
|
||||
key: `${key}realized-profit`,
|
||||
name: useGroupName ? name : "Profit",
|
||||
color: useGroupName ? color : colors.green,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${key}realized-profit-relative-to-realized-cap`,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
}),
|
||||
@@ -1489,78 +1648,151 @@ function createPartialOptions(colors) {
|
||||
return /** @type {const} */ ([
|
||||
createBaseSeries({
|
||||
key: `${key}realized-loss`,
|
||||
name: useGroupName ? name : "Loss",
|
||||
color: useGroupName ? color : colors.red,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${key}realized-loss-relative-to-realized-cap`,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
}),
|
||||
},
|
||||
]),
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `${args.title} Net Realized Profit And Loss`,
|
||||
bottom: list.flatMap(({ color, name, key }) => [
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(key)}net-realized-profit-and-loss`,
|
||||
title: useGroupName ? name : "Net",
|
||||
color: useGroupName ? color : undefined,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key,
|
||||
)}net-realized-profit-and-loss-relative-to-realized-cap`,
|
||||
title: useGroupName ? name : "Net",
|
||||
color: useGroupName ? color : undefined,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
},
|
||||
...(!("list" in args)
|
||||
? [
|
||||
{
|
||||
name: "sopr",
|
||||
title: `${args.title} Spent Output Profit Ratio`,
|
||||
name: "Net pnl",
|
||||
title: `${args.title} Net Realized Profit And Loss`,
|
||||
bottom: list.flatMap(({ color, name, key }) => [
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(key)}spent-output-profit-ratio`,
|
||||
title: useGroupName ? name : "sopr",
|
||||
color: useGroupName ? color : undefined,
|
||||
key: `${fixKey(key)}net-realized-profit-and-loss`,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 1,
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(key)}adjusted-spent-output-profit-ratio`,
|
||||
title: useGroupName ? name : "asopr",
|
||||
color: useGroupName ? color : undefined,
|
||||
colors: useGroupName
|
||||
? undefined
|
||||
: [colors.yellow, colors.pink],
|
||||
key: `${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss-relative-to-realized-cap`,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 1,
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
name: "cumulative",
|
||||
tree: [
|
||||
{
|
||||
name: "profit",
|
||||
title: `Cumulative ${args.title} Realized Profit`,
|
||||
bottom: list.flatMap(({ color, name, key: _key }) => {
|
||||
const key = fixKey(_key);
|
||||
return /** @type {const} */ ([
|
||||
createBaseSeries({
|
||||
key: `cumulative-${key}realized-profit`,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
]);
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "loss",
|
||||
title: `Cumulative ${args.title} Realized Loss`,
|
||||
bottom: list.flatMap(({ color, name, key: _key }) => {
|
||||
const key = fixKey(_key);
|
||||
return /** @type {const} */ ([
|
||||
createBaseSeries({
|
||||
key: `cumulative-${key}realized-loss`,
|
||||
name,
|
||||
color,
|
||||
}),
|
||||
]);
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Net pnl",
|
||||
title: `Cumulative ${args.title} Net Realized Profit And Loss`,
|
||||
bottom: list.flatMap(({ color, name, key }) => [
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `cumulative-${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss`,
|
||||
title: name,
|
||||
color,
|
||||
defaultActive: false,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
},
|
||||
{
|
||||
name: "Net pnl 30d change",
|
||||
title: `Cumulative ${args.title} Net Realized Profit And Loss 30 Day Change`,
|
||||
bottom: list.flatMap(({ color, name, key }) => [
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `cumulative-${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss-30d-change`,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `cumulative-${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss-30d-change-relative-to-realized-cap`,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `cumulative-${fixKey(
|
||||
key
|
||||
)}net-realized-profit-and-loss-30d-change-relative-to-market-cap`,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "sopr",
|
||||
tree: [
|
||||
@@ -1571,8 +1803,8 @@ function createPartialOptions(colors) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(key)}spent-output-profit-ratio`,
|
||||
title: useGroupName ? name : "sopr",
|
||||
color: useGroupName ? color : undefined,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 1,
|
||||
@@ -1588,10 +1820,10 @@ function createPartialOptions(colors) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key,
|
||||
key
|
||||
)}adjusted-spent-output-profit-ratio`,
|
||||
title: useGroupName ? name : "asopr",
|
||||
color: useGroupName ? color : undefined,
|
||||
title: name,
|
||||
color,
|
||||
options: {
|
||||
createPriceLine: {
|
||||
value: 1,
|
||||
@@ -1611,7 +1843,7 @@ function createPartialOptions(colors) {
|
||||
key: `${fixKey(key)}sell-side-risk-ratio`,
|
||||
name: useGroupName ? name : "Risk",
|
||||
color: color,
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
],
|
||||
@@ -1700,7 +1932,7 @@ function createPartialOptions(colors) {
|
||||
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
|
||||
type: "Baseline",
|
||||
key: `${fixKey(
|
||||
key,
|
||||
key
|
||||
)}net-unrealized-profit-and-loss-relative-to-market-cap`,
|
||||
title: useGroupName ? name : "Net",
|
||||
color: useGroupName ? color : undefined,
|
||||
@@ -1878,7 +2110,7 @@ function createPartialOptions(colors) {
|
||||
key: `${key}-sma`,
|
||||
name: key,
|
||||
color,
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
...averages.map(({ key, name, color }) =>
|
||||
@@ -1888,7 +2120,7 @@ function createPartialOptions(colors) {
|
||||
title: `${name} Market Price Moving Average`,
|
||||
legend: "average",
|
||||
color,
|
||||
}),
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -1929,8 +2161,8 @@ function createPartialOptions(colors) {
|
||||
name: "Indicators",
|
||||
tree: [
|
||||
{
|
||||
name: "Mayer's multiple",
|
||||
title: "Mayer's multiple",
|
||||
name: "Mayer multiple",
|
||||
title: "Mayer multiple",
|
||||
top: [
|
||||
createBaseSeries({
|
||||
key: `200d-sma`,
|
||||
@@ -2005,7 +2237,7 @@ function createPartialOptions(colors) {
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
})
|
||||
),
|
||||
.../** @type {const} */ ([
|
||||
{ name: "2 Year", key: "2y" },
|
||||
@@ -2076,7 +2308,7 @@ function createPartialOptions(colors) {
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -2092,7 +2324,7 @@ function createPartialOptions(colors) {
|
||||
name: `${year}`,
|
||||
color,
|
||||
defaultActive,
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
...dcaClasses.map(
|
||||
@@ -2119,7 +2351,7 @@ function createPartialOptions(colors) {
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -2180,10 +2412,10 @@ function createPartialOptions(colors) {
|
||||
bottom: [
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries("fee"),
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
"fee-in-btc",
|
||||
"fee-in-btc"
|
||||
),
|
||||
...createAverageSumCumulativeMinMaxPercentilesSeries(
|
||||
"fee-in-usd",
|
||||
"fee-in-usd"
|
||||
),
|
||||
],
|
||||
},
|
||||
@@ -2779,7 +3011,7 @@ function createPartialOptions(colors) {
|
||||
bottom: [
|
||||
createBaseSeries({ key: "opreturn-count", name: "Count" }),
|
||||
createBaseSeries({
|
||||
key: "opreturn-count-sum",
|
||||
key: "opreturn-count",
|
||||
name: "sum",
|
||||
}),
|
||||
createBaseSeries({
|
||||
@@ -2939,7 +3171,7 @@ export function initOptions({ colors, signals, env, utils, qrcode }) {
|
||||
const detailsList = [];
|
||||
|
||||
const treeElement = signals.createSignal(
|
||||
/** @type {HTMLDivElement | null} */ (null),
|
||||
/** @type {HTMLDivElement | null} */ (null)
|
||||
);
|
||||
|
||||
/** @type {string[] | undefined} */
|
||||
@@ -3051,7 +3283,7 @@ export function initOptions({ colors, signals, env, utils, qrcode }) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
partialTree.forEach((anyPartial, partialIndex) => {
|
||||
@@ -3074,7 +3306,7 @@ export function initOptions({ colors, signals, env, utils, qrcode }) {
|
||||
|
||||
if ("tree" in anyPartial) {
|
||||
const folderId = utils.stringToId(
|
||||
`${(path || []).join(" ")} ${anyPartial.name} folder`,
|
||||
`${(path || []).join(" ")} ${anyPartial.name} folder`
|
||||
);
|
||||
|
||||
/** @type {Omit<OptionsGroup, keyof PartialOptionsGroup>} */
|
||||
@@ -3089,13 +3321,13 @@ export function initOptions({ colors, signals, env, utils, qrcode }) {
|
||||
const thisPath = groupAddons.id;
|
||||
|
||||
const passedDetails = signals.createSignal(
|
||||
/** @type {HTMLDivElement | HTMLDetailsElement | null} */ (null),
|
||||
/** @type {HTMLDivElement | HTMLDetailsElement | null} */ (null)
|
||||
);
|
||||
|
||||
const childOptionsCount = recursiveProcessPartialTree(
|
||||
anyPartial.tree,
|
||||
passedDetails,
|
||||
[...(path || []), thisPath],
|
||||
[...(path || []), thisPath]
|
||||
);
|
||||
|
||||
listForSum.push(childOptionsCount);
|
||||
@@ -3227,7 +3459,7 @@ export function initOptions({ colors, signals, env, utils, qrcode }) {
|
||||
});
|
||||
|
||||
return signals.createMemo(() =>
|
||||
listForSum.reduce((acc, s) => acc + s(), 0),
|
||||
listForSum.reduce((acc, s) => acc + s(), 0)
|
||||
);
|
||||
}
|
||||
recursiveProcessPartialTree(partialOptions, treeElement);
|
||||
@@ -3254,7 +3486,7 @@ export function initOptions({ colors, signals, env, utils, qrcode }) {
|
||||
console.log(
|
||||
[...m.entries()]
|
||||
.filter(([_, value]) => value > 1)
|
||||
.map(([key, _]) => key),
|
||||
.map(([key, _]) => key)
|
||||
);
|
||||
|
||||
throw Error("ID duplicate");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user