Skip to content

Commit

Permalink
[PricesManager] fix recent trade mark price overriding exchange mark …
Browse files Browse the repository at this point in the history
…price

tmp
  • Loading branch information
techfreaque committed Mar 9, 2023
1 parent 658792e commit c0e3c3e
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 13 deletions.
1 change: 1 addition & 0 deletions octobot_trading/exchange_data/prices/prices_manager.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ cdef class PricesManager(util.Initializable):
cdef void _reset_prices(self)
cdef void _ensure_price_validity(self)
cdef bint _are_other_sources_valid(self, str mark_price_source)
cdef bint _is_exchange_mark_price_valid(self)
cdef int _compute_mark_price_validity_timeout(self)

cpdef bint set_mark_price(self, object mark_price, str mark_price_source)
Expand Down
23 changes: 15 additions & 8 deletions octobot_trading/exchange_data/prices/prices_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,15 @@ def set_mark_price(self, mark_price, mark_price_source) -> bool:
self._set_mark_price_value(mark_price)
is_mark_price_updated = True

# set mark price value if MarkPriceSources.RECENT_TRADE_AVERAGE.value has already been updated
# set mark price value if RECENT_TRADE_AVERAGE has already been updated and no EXCHANGE_MARK_PRICE
elif mark_price_source == enums.MarkPriceSources.RECENT_TRADE_AVERAGE.value:
if self.mark_price_from_sources.get(enums.MarkPriceSources.RECENT_TRADE_AVERAGE.value, None) is not None:
self._set_mark_price_value(mark_price)
is_mark_price_updated = True
else:
# set time at 0 to ensure invalid price but keep track of initialization
self.mark_price_from_sources[mark_price_source] = (mark_price, 0)
if not self._is_exchange_mark_price_valid():
if self.mark_price_from_sources.get(enums.MarkPriceSources.RECENT_TRADE_AVERAGE.value, None) is not None:
self._set_mark_price_value(mark_price)
is_mark_price_updated = True
else:
# set time at 0 to ensure invalid price but keep track of initialization
self.mark_price_from_sources[mark_price_source] = (mark_price, 0)

# set mark price value if other sources have expired
elif mark_price_source in (enums.MarkPriceSources.TICKER_CLOSE_PRICE.value,
Expand Down Expand Up @@ -130,7 +131,13 @@ def _are_other_sources_valid(self, mark_price_source):
self._is_mark_price_valid(source_mark_price[1]):
return True
return False


def _is_exchange_mark_price_valid(self):
if enums.MarkPriceSources.EXCHANGE_MARK_PRICE.value in self.mark_price_from_sources:
return self._is_mark_price_valid(
self.mark_price_from_sources[
enums.MarkPriceSources.EXCHANGE_MARK_PRICE.value][1])

def _ensure_price_validity(self):
"""
Clear the event price validity event if the mark price has expired
Expand Down
31 changes: 26 additions & 5 deletions tests/exchange_data/prices/test_prices_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,40 @@ async def test_set_mark_price(prices_manager):
assert prices_manager.mark_price == decimal.Decimal(10)
check_event_is_set(prices_manager)


async def test_set_mark_price_for_exchange_source(prices_manager):
prices_manager.set_mark_price(decimal.Decimal(15), MarkPriceSources.TICKER_CLOSE_PRICE.value)
assert prices_manager.mark_price == decimal.Decimal(15)
check_event_is_set(prices_manager)
prices_manager.set_mark_price(decimal.Decimal(30), MarkPriceSources.RECENT_TRADE_AVERAGE.value)
assert prices_manager.mark_price == decimal.Decimal(15) # ignore first call
check_event_is_set(prices_manager)
prices_manager.set_mark_price(decimal.Decimal(30), MarkPriceSources.RECENT_TRADE_AVERAGE.value)
assert prices_manager.mark_price == decimal.Decimal(30)
check_event_is_set(prices_manager)
prices_manager.set_mark_price(decimal.Decimal(10), MarkPriceSources.EXCHANGE_MARK_PRICE.value)
assert prices_manager.mark_price == decimal.Decimal(10)
check_event_is_set(prices_manager)
prices_manager.set_mark_price(decimal.Decimal(25), MarkPriceSources.RECENT_TRADE_AVERAGE.value)
assert prices_manager.mark_price == decimal.Decimal(10) # Drop first RT update
prices_manager.set_mark_price(decimal.Decimal(30), MarkPriceSources.RECENT_TRADE_AVERAGE.value)
assert prices_manager.mark_price == decimal.Decimal(30)
assert prices_manager.mark_price == decimal.Decimal(10) # dont override valid exchange mark price
check_event_is_set(prices_manager)
prices_manager.set_mark_price(decimal.Decimal(20), MarkPriceSources.TICKER_CLOSE_PRICE.value)
assert prices_manager.mark_price == decimal.Decimal(30)
assert prices_manager.mark_price == decimal.Decimal(10) # dont override valid exchange mark price
check_event_is_set(prices_manager)
prices_manager.set_mark_price(decimal.Decimal(15), MarkPriceSources.EXCHANGE_MARK_PRICE.value)
assert prices_manager.mark_price == decimal.Decimal(15)
check_event_is_set(prices_manager)
if not os.getenv('CYTHON_IGNORE'):
prices_manager.mark_price_from_sources = {}
prices_manager.set_mark_price(decimal.Decimal(10), MarkPriceSources.CANDLE_CLOSE_PRICE.value)
assert prices_manager.mark_price == decimal.Decimal(10)
check_event_is_set(prices_manager)
prices_manager.set_mark_price(decimal.Decimal(22), MarkPriceSources.EXCHANGE_MARK_PRICE.value)
assert prices_manager.mark_price == decimal.Decimal(22)
check_event_is_set(prices_manager)
prices_manager.set_mark_price(decimal.Decimal(15), MarkPriceSources.CANDLE_CLOSE_PRICE.value)
assert prices_manager.mark_price == decimal.Decimal(22) # dont override valid exchange mark price
check_event_is_set(prices_manager)


async def test_set_mark_price_for_ticker_source_only(prices_manager):
Expand Down

0 comments on commit c0e3c3e

Please sign in to comment.