Skip to content

Commit c0e3c3e

Browse files
committed
[PricesManager] fix recent trade mark price overriding exchange mark price
tmp
1 parent 658792e commit c0e3c3e

File tree

3 files changed

+42
-13
lines changed

3 files changed

+42
-13
lines changed

octobot_trading/exchange_data/prices/prices_manager.pxd

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ cdef class PricesManager(util.Initializable):
3333
cdef void _reset_prices(self)
3434
cdef void _ensure_price_validity(self)
3535
cdef bint _are_other_sources_valid(self, str mark_price_source)
36+
cdef bint _is_exchange_mark_price_valid(self)
3637
cdef int _compute_mark_price_validity_timeout(self)
3738

3839
cpdef bint set_mark_price(self, object mark_price, str mark_price_source)

octobot_trading/exchange_data/prices/prices_manager.py

+15-8
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,15 @@ def set_mark_price(self, mark_price, mark_price_source) -> bool:
6868
self._set_mark_price_value(mark_price)
6969
is_mark_price_updated = True
7070

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

8081
# set mark price value if other sources have expired
8182
elif mark_price_source in (enums.MarkPriceSources.TICKER_CLOSE_PRICE.value,
@@ -130,7 +131,13 @@ def _are_other_sources_valid(self, mark_price_source):
130131
self._is_mark_price_valid(source_mark_price[1]):
131132
return True
132133
return False
133-
134+
135+
def _is_exchange_mark_price_valid(self):
136+
if enums.MarkPriceSources.EXCHANGE_MARK_PRICE.value in self.mark_price_from_sources:
137+
return self._is_mark_price_valid(
138+
self.mark_price_from_sources[
139+
enums.MarkPriceSources.EXCHANGE_MARK_PRICE.value][1])
140+
134141
def _ensure_price_validity(self):
135142
"""
136143
Clear the event price validity event if the mark price has expired

tests/exchange_data/prices/test_prices_manager.py

+26-5
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,40 @@ async def test_set_mark_price(prices_manager):
5555
assert prices_manager.mark_price == decimal.Decimal(10)
5656
check_event_is_set(prices_manager)
5757

58-
58+
5959
async def test_set_mark_price_for_exchange_source(prices_manager):
60+
prices_manager.set_mark_price(decimal.Decimal(15), MarkPriceSources.TICKER_CLOSE_PRICE.value)
61+
assert prices_manager.mark_price == decimal.Decimal(15)
62+
check_event_is_set(prices_manager)
63+
prices_manager.set_mark_price(decimal.Decimal(30), MarkPriceSources.RECENT_TRADE_AVERAGE.value)
64+
assert prices_manager.mark_price == decimal.Decimal(15) # ignore first call
65+
check_event_is_set(prices_manager)
66+
prices_manager.set_mark_price(decimal.Decimal(30), MarkPriceSources.RECENT_TRADE_AVERAGE.value)
67+
assert prices_manager.mark_price == decimal.Decimal(30)
68+
check_event_is_set(prices_manager)
6069
prices_manager.set_mark_price(decimal.Decimal(10), MarkPriceSources.EXCHANGE_MARK_PRICE.value)
6170
assert prices_manager.mark_price == decimal.Decimal(10)
6271
check_event_is_set(prices_manager)
6372
prices_manager.set_mark_price(decimal.Decimal(25), MarkPriceSources.RECENT_TRADE_AVERAGE.value)
64-
assert prices_manager.mark_price == decimal.Decimal(10) # Drop first RT update
65-
prices_manager.set_mark_price(decimal.Decimal(30), MarkPriceSources.RECENT_TRADE_AVERAGE.value)
66-
assert prices_manager.mark_price == decimal.Decimal(30)
73+
assert prices_manager.mark_price == decimal.Decimal(10) # dont override valid exchange mark price
74+
check_event_is_set(prices_manager)
6775
prices_manager.set_mark_price(decimal.Decimal(20), MarkPriceSources.TICKER_CLOSE_PRICE.value)
68-
assert prices_manager.mark_price == decimal.Decimal(30)
76+
assert prices_manager.mark_price == decimal.Decimal(10) # dont override valid exchange mark price
77+
check_event_is_set(prices_manager)
6978
prices_manager.set_mark_price(decimal.Decimal(15), MarkPriceSources.EXCHANGE_MARK_PRICE.value)
7079
assert prices_manager.mark_price == decimal.Decimal(15)
80+
check_event_is_set(prices_manager)
81+
if not os.getenv('CYTHON_IGNORE'):
82+
prices_manager.mark_price_from_sources = {}
83+
prices_manager.set_mark_price(decimal.Decimal(10), MarkPriceSources.CANDLE_CLOSE_PRICE.value)
84+
assert prices_manager.mark_price == decimal.Decimal(10)
85+
check_event_is_set(prices_manager)
86+
prices_manager.set_mark_price(decimal.Decimal(22), MarkPriceSources.EXCHANGE_MARK_PRICE.value)
87+
assert prices_manager.mark_price == decimal.Decimal(22)
88+
check_event_is_set(prices_manager)
89+
prices_manager.set_mark_price(decimal.Decimal(15), MarkPriceSources.CANDLE_CLOSE_PRICE.value)
90+
assert prices_manager.mark_price == decimal.Decimal(22) # dont override valid exchange mark price
91+
check_event_is_set(prices_manager)
7192

7293

7394
async def test_set_mark_price_for_ticker_source_only(prices_manager):

0 commit comments

Comments
 (0)