Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pindexer: implement symmetrization of charts #4941

Merged
merged 2 commits into from
Nov 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 42 additions & 7 deletions crates/bin/pindexer/src/dex_ex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ mod candle {
use penumbra_dex::CandlestickData;
use std::fmt::Display;

fn geo_mean(a: f64, b: f64) -> f64 {
(a * b).sqrt()
}

/// Candlestick data, unmoored from the prison of a particular block height.
///
/// In other words, this can represent candlesticks which span arbitrary windows,
Expand Down Expand Up @@ -57,6 +61,31 @@ mod candle {
self.direct_volume += that.direct_volume;
self.swap_volume += that.swap_volume;
}

/// Mix this candle with a candle going in the opposite direction of the pair.
pub fn mix(&mut self, op: &Self) {
// We use the geometric mean, resulting in all the prices in a.mix(b) being
// the inverse of the prices in b.mix(a), and the volumes being equal.
self.close /= geo_mean(self.close, op.close);
self.open /= geo_mean(self.open, op.open);
self.low = self.low.min(1.0 / op.low);
self.high = self.high.min(1.0 / op.high);
// Using the closing price to look backwards at volume.
self.direct_volume += op.direct_volume / self.close;
self.swap_volume += op.swap_volume / self.close;
}

/// Flip this candle to get the equivalent in the other direction.
pub fn flip(&self) -> Self {
Self {
open: 1.0 / self.open,
close: 1.0 / self.close,
low: 1.0 / self.low,
high: 1.0 / self.high,
direct_volume: self.direct_volume / self.close,
swap_volume: self.swap_volume / self.close,
}
}
}

impl From<CandlestickData> for Candle {
Expand Down Expand Up @@ -616,14 +645,20 @@ impl Events {
}

fn with_candle(&mut self, pair: DirectedTradingPair, candle: Candle) {
match self.candles.get_mut(&pair) {
None => {
self.candles.insert(pair, candle);
}
Some(current) => {
current.merge(&candle);
// Populate both this pair and the flipped pair, and if the flipped pair
// is already populated, we need to mix the two candles together.
let flip = pair.flip();
let new_candle = match self.candles.get(&flip).cloned() {
None => candle,
Some(flipped) => {
let mut out = candle;
out.mix(&flipped);
out
}
}
};

self.candles.insert(pair, new_candle);
self.candles.insert(flip, new_candle.flip());
}

fn metric(&mut self, pair: &DirectedTradingPair) -> &mut PairMetrics {
Expand Down
Loading