Skip to content

Commit

Permalink
frank/oracle max conf multipliers (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
soundsonacid authored Mar 11, 2024
1 parent eba2d9a commit 2eeafa2
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.7.37
current_version = 0.7.38
commit = True
tag = True
tag_name = {new_version}
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,8 @@ Add support for prelisting oracles

## [0.7.37] - 2024-3-11

Fix bug where prelisting & switchboard oracles weren't properly decoded for cached drift client subscriptions
Fix bug where prelisting & switchboard oracles weren't properly decoded for cached drift client subscriptions

## [0.7.38] - 2024-3-11

Add max confidence interval multiplier to oracle validity calculations
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "driftpy"
version = "0.7.37"
version = "0.7.38"
description = "A Python client for the Drift DEX"
authors = ["x19 <https://twitter.com/[email protected]>", "bigz <https://twitter.com/bigz_pubkey>", "frank <https://twitter.com/soundsonacid>"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src/driftpy/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.7.37"
__version__ = "0.7.38"
34 changes: 31 additions & 3 deletions src/driftpy/math/oracles.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
from driftpy.constants.numeric_constants import BID_ASK_SPREAD_PRECISION, FIVE_MINUTE
from driftpy.types import AMM, HistoricalOracleData, OracleGuardRails, OraclePriceData
from driftpy.types import (
AMM,
ContractTier,
HistoricalOracleData,
OracleGuardRails,
OraclePriceData,
PerpMarketAccount,
)


def calculate_live_oracle_twap(
Expand Down Expand Up @@ -77,13 +84,15 @@ def get_new_oracle_conf_pct(


def is_oracle_valid(
amm: AMM,
market: PerpMarketAccount,
oracle_price_data: OraclePriceData,
oracle_guard_rails: OracleGuardRails,
slot: int,
) -> bool:
is_oracle_price_non_positive = oracle_price_data.price <= 0

amm = market.amm

lhs = (
oracle_price_data.price
// (max(1, amm.historical_oracle_data.last_oracle_price_twap))
Expand All @@ -95,10 +104,15 @@ def is_oracle_valid(

is_oracle_price_too_volatile = lhs or rhs

max_confidence_multiplier = get_max_confidence_interval_multiplier(market)

is_confidence_too_large = (
(max(1, oracle_price_data.confidence) * BID_ASK_SPREAD_PRECISION)
// oracle_price_data.price
) > oracle_guard_rails.validity.confidence_interval_max_size
) > (
oracle_guard_rails.validity.confidence_interval_max_size
* max_confidence_multiplier
)

is_oracle_stale = (
slot - oracle_price_data.slot
Expand All @@ -111,3 +125,17 @@ def is_oracle_valid(
or is_oracle_price_too_volatile
or is_confidence_too_large
)


def get_max_confidence_interval_multiplier(market: PerpMarketAccount) -> int:
match market.contract_tier:
case ContractTier.A():
return 1
case ContractTier.B():
return 1
case ContractTier.C():
return 2
case ContractTier.Speculative():
return 10
case ContractTier.Isolated():
return 50
18 changes: 10 additions & 8 deletions tests/math/spreads.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,35 +702,37 @@ async def test_live_update_functions():
)

# good oracle
assert is_oracle_valid(amm, oracle_price_data, oracle_guard_rails, slot + 5)
assert is_oracle_valid(perp_market, oracle_price_data, oracle_guard_rails, slot + 5)

# too confident
oracle_price_data.confidence = int(13.553 * PRICE_PRECISION * 0.021)
assert not is_oracle_valid(amm, oracle_price_data, oracle_guard_rails, slot)
assert not is_oracle_valid(perp_market, oracle_price_data, oracle_guard_rails, slot)

# not enough data points
oracle_price_data.confidence = 1
oracle_price_data.has_sufficient_number_of_data_points = False
assert not is_oracle_valid(amm, oracle_price_data, oracle_guard_rails, slot)
assert not is_oracle_valid(perp_market, oracle_price_data, oracle_guard_rails, slot)

# negative oracle price
oracle_price_data.has_sufficient_number_of_data_points = True
oracle_price_data.price = -1 * PRICE_PRECISION
assert not is_oracle_valid(amm, oracle_price_data, oracle_guard_rails, slot)
assert not is_oracle_valid(perp_market, oracle_price_data, oracle_guard_rails, slot)

# too delayed for amm
oracle_price_data.price = int(13.553 * PRICE_PRECISION)
assert not is_oracle_valid(amm, oracle_price_data, oracle_guard_rails, slot + 100)
assert not is_oracle_valid(
perp_market, oracle_price_data, oracle_guard_rails, slot + 100
)

# oracle slot is stale (should be valid)
oracle_price_data.slot += 100
assert is_oracle_valid(amm, oracle_price_data, oracle_guard_rails, slot)
assert is_oracle_valid(perp_market, oracle_price_data, oracle_guard_rails, slot)

# too volatile (>5x higher)
oracle_price_data.slot = slot + 5
oracle_price_data.price = int(113.553 * PRICE_PRECISION)
assert not is_oracle_valid(amm, oracle_price_data, oracle_guard_rails, slot)
assert not is_oracle_valid(perp_market, oracle_price_data, oracle_guard_rails, slot)

# too volatile (>5x lower)
oracle_price_data.price = int(0.553 * PRICE_PRECISION)
assert not is_oracle_valid(amm, oracle_price_data, oracle_guard_rails, slot)
assert not is_oracle_valid(perp_market, oracle_price_data, oracle_guard_rails, slot)

0 comments on commit 2eeafa2

Please sign in to comment.