Skip to content
This repository has been archived by the owner on May 30, 2023. It is now read-only.

add inverted_price to ema math and add fn inverted to Ratio #100

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
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
26 changes: 14 additions & 12 deletions src/ema/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,36 @@ pub type EmaLiquidity = (Balance, Balance);
/// Calculate the new oracle values by integrating `incoming` values with the `previous` oracle.
/// Uses a weighted average based on the `smoothing` factor.
pub fn calculate_new_by_integrating_incoming(
previous: (EmaPrice, EmaVolume, EmaLiquidity),
incoming: (EmaPrice, EmaVolume, EmaLiquidity),
previous: (EmaPrice, EmaVolume, EmaLiquidity, EmaPrice),
incoming: (EmaPrice, EmaVolume, EmaLiquidity, EmaPrice),
smoothing: Fraction,
) -> (EmaPrice, EmaVolume, EmaLiquidity) {
let (prev_price, prev_volume, prev_liquidity) = previous;
let (incoming_price, incoming_volume, incoming_liquidity) = incoming;
) -> (EmaPrice, EmaVolume, EmaLiquidity, EmaPrice) {
let (prev_price, prev_volume, prev_liquidity, prev_inverted_price) = previous;
let (incoming_price, incoming_volume, incoming_liquidity, incoming_inverted_price) = incoming;
let new_price = price_weighted_average(prev_price, incoming_price, smoothing);
let new_volume = volume_weighted_average(prev_volume, incoming_volume, smoothing);
let new_liquidity = liquidity_weighted_average(prev_liquidity, incoming_liquidity, smoothing);
(new_price, new_volume, new_liquidity)
let new_inverted_price = price_weighted_average(prev_inverted_price, incoming_inverted_price, smoothing);
(new_price, new_volume, new_liquidity, new_inverted_price)
}

/// Calculate the current oracle values from the `outdated` and `update_with` values using the `smoothing` factor with the old values being `iterations` out of date.
///
/// Note: The volume is always updated with zero values so it is not a parameter.
pub fn update_outdated_to_current(
iterations: u32,
outdated: (EmaPrice, EmaVolume, EmaLiquidity),
update_with: (EmaPrice, EmaLiquidity),
outdated: (EmaPrice, EmaVolume, EmaLiquidity, EmaPrice),
update_with: (EmaPrice, EmaLiquidity, EmaPrice),
smoothing: Fraction,
) -> (EmaPrice, EmaVolume, EmaLiquidity) {
let (prev_price, prev_volume, prev_liquidity) = outdated;
let (incoming_price, incoming_liquidity) = update_with;
) -> (EmaPrice, EmaVolume, EmaLiquidity, EmaPrice) {
let (prev_price, prev_volume, prev_liquidity, prev_inverted_price) = outdated;
let (incoming_price, incoming_liquidity, incoming_inverted_price) = update_with;
let smoothing = exp_smoothing(smoothing, iterations);
let new_price = price_weighted_average(prev_price, incoming_price, smoothing);
let new_volume = volume_weighted_average(prev_volume, (0, 0, 0, 0), smoothing);
let new_liquidity = liquidity_weighted_average(prev_liquidity, incoming_liquidity, smoothing);
(new_price, new_volume, new_liquidity)
let new_inverted_price = price_weighted_average(prev_inverted_price, incoming_inverted_price, smoothing);
(new_price, new_volume, new_liquidity, new_inverted_price)
}

/// Calculate the iterated exponential moving average for the given prices.
Expand Down
25 changes: 20 additions & 5 deletions src/ema/tests/invariants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,13 @@ proptest! {
let simple_price = price_weighted_average(prev_price, incoming_price, smoothing);
let simple_volume = volume_weighted_average(prev_volume, incoming_volume, smoothing);
let simple_liquidity = liquidity_weighted_average(prev_liquidity, incoming_liquidity, smoothing);
let new_oracle = calculate_new_by_integrating_incoming((prev_price, prev_volume, prev_liquidity), (incoming_price, incoming_volume, incoming_liquidity), smoothing);
prop_assert_eq!(new_oracle, (simple_price, simple_volume, simple_liquidity));
let simple_inverted_price = price_weighted_average(prev_price.inverted(), incoming_price.inverted(), smoothing);
let new_oracle = calculate_new_by_integrating_incoming(
(prev_price, prev_volume, prev_liquidity, prev_price.inverted()),
(incoming_price, incoming_volume, incoming_liquidity, incoming_price.inverted()),
smoothing
);
prop_assert_eq!(new_oracle, (simple_price, simple_volume, simple_liquidity, simple_inverted_price));
}
}

Expand All @@ -219,8 +224,14 @@ proptest! {
let iterated_price = iterated_price_ema(iterations, prev_price, incoming_price, smoothing);
let iterated_volume = iterated_volume_ema(iterations, prev_volume, smoothing);
let iterated_liquidity = iterated_liquidity_ema(iterations, prev_liquidity, incoming_liquidity, smoothing);
let current_oracle = update_outdated_to_current(iterations, (prev_price, prev_volume, prev_liquidity), (incoming_price, incoming_liquidity), smoothing);
prop_assert_eq!(current_oracle, (iterated_price, iterated_volume, iterated_liquidity));
let iterated_inverted_price = iterated_price_ema(iterations, prev_price.inverted(), incoming_price.inverted(), smoothing);
let current_oracle = update_outdated_to_current(
iterations,
(prev_price, prev_volume, prev_liquidity, prev_price.inverted()),
(incoming_price, incoming_liquidity, incoming_price.inverted()),
smoothing
);
prop_assert_eq!(current_oracle, (iterated_price, iterated_volume, iterated_liquidity, iterated_inverted_price));
}
}

Expand Down Expand Up @@ -417,7 +428,11 @@ proptest! {
) {
let smoothing = smoothing_from_period(period);

let expected = high_precision::precise_balance_weighted_average(start_balance, incoming_balance, high_precision::precise_exp_smoothing(fraction_to_high_precision(smoothing), iterations));
let expected = high_precision::precise_balance_weighted_average(
start_balance,
incoming_balance,
high_precision::precise_exp_smoothing(fraction_to_high_precision(smoothing), iterations)
);
let new_oracle = iterated_balance_ema(iterations, start_balance, incoming_balance, smoothing);

let tolerance = 1;
Expand Down
25 changes: 25 additions & 0 deletions src/ratio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,46 @@ impl Ratio {
Self { n, d }
}

/// Return a representation of one.
///
/// Note that more than one combination of `n` and `d` can be one.
pub const fn one() -> Self {
Self::new_unchecked(1, 1)
}

/// Return whether `self` is one.
///
/// Should a denominator of 0 happen, this function will return `false`.
///
/// Note that more than one combination of `n` and `d` can be one.
pub const fn is_one(&self) -> bool {
self.d > 0 && self.n == self.d
}

/// Return a representation of zero.
///
/// Note that any combination of `n == 0` and `d` represents zero.
pub const fn zero() -> Self {
Self::new_unchecked(0, 1)
}

/// Return whether `self` is zero.
///
/// Note that any combination of `n == 0` and `d` represents zero.
pub const fn is_zero(&self) -> bool {
self.n == 0
}

/// Invert `n/d` to `d/n`.
///
/// NOTE: Zero inverts to zero.
pub const fn inverted(self) -> Self {
if self.is_zero() {
self
} else {
Self { n: self.d, d: self.n }
}
}
}

impl From<Ratio> for (u128, u128) {
Expand Down