Skip to content

Commit 3c5a9a0

Browse files
committed
[CCXT] fix failed market fetch
1 parent 23bb134 commit 3c5a9a0

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

octobot_trading/errors.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ class NetworkError(RetriableFailedRequest):
165165
"""
166166

167167

168+
class FailedMarketStatusRequest(RetriableFailedRequest):
169+
"""
170+
Raised when an exchange fails to fetch its market status
171+
"""
172+
173+
168174
class RateLimitExceeded(OctoBotExchangeError):
169175
"""
170176
Raised upon an exchange API rate limit error

octobot_trading/exchanges/connectors/ccxt/ccxt_connector.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ def __init__(
6565
self.is_authenticated: bool = False
6666
self.rest_name: str = rest_name or self.exchange_manager.exchange_class_string
6767
self.force_authentication: bool = force_auth
68+
69+
self._force_next_market_reload: bool = False
6870

6971
# used to save exchange local elements in subclasses
7072
self.saved_data: dict[str, typing.Any] = {}
@@ -124,6 +126,31 @@ def load_user_inputs_from_class(cls, tentacles_setup_config, tentacle_config):
124126
# no user input in connector
125127
pass
126128

129+
def _ensure_successful_markets_fetch(self, client):
130+
if not client.markets:
131+
return False
132+
symbols = list[str](client.markets)
133+
if self.exchange_manager.is_future:
134+
found_future_markets = False
135+
for symbol in symbols:
136+
if commons_symbols.parse_symbol(symbol).is_future():
137+
found_future_markets = True
138+
break
139+
if not found_future_markets:
140+
raise octobot_trading.errors.FailedMarketStatusRequest(
141+
f"No future markets found for {self.exchange_manager.exchange_name} - {len(symbols)} fetched markets: {symbols}"
142+
)
143+
if not self.exchange_manager.is_future:
144+
found_spot_markets = False
145+
for symbol in symbols:
146+
if commons_symbols.parse_symbol(symbol).is_spot():
147+
found_spot_markets = True
148+
break
149+
if not found_spot_markets:
150+
raise octobot_trading.errors.FailedMarketStatusRequest(
151+
f"No spot markets found for {self.exchange_manager.exchange_name} - {len(symbols)} fetched markets: {symbols}"
152+
)
153+
127154
async def _filtered_if_necessary_load_markets(
128155
self,
129156
client,
@@ -136,9 +163,14 @@ async def _filtered_if_necessary_load_markets(
136163
await client.load_markets(reload=reload)
137164
else:
138165
await client.load_markets(reload=reload)
166+
self._ensure_successful_markets_fetch(client)
139167
self.logger.info(
140168
f"Loaded {len(client.markets) if client.markets else 0} [{self.exchange_manager.exchange_name}] markets"
141169
)
170+
except octobot_trading.errors.FailedMarketStatusRequest as err:
171+
# failed to fetch markets, force reload for next time
172+
self._force_next_market_reload = True
173+
raise err
142174
except Exception as err:
143175
# ensure this is not a proxy error, raise dedicated error if it is
144176
if proxy_error := ccxt_client_util.get_proxy_error_if_any(self, err):
@@ -163,6 +195,10 @@ async def load_symbol_markets(
163195
reload=False,
164196
market_filter: typing.Optional[typing.Callable[[dict], bool]] = None
165197
):
198+
if self._force_next_market_reload:
199+
self.logger.info(f"Forced market reload for {self.exchange_manager.exchange_name}")
200+
reload = True
201+
self._force_next_market_reload = False
166202
authenticated_cache = self.exchange_manager.exchange.requires_authentication_for_this_configuration_only()
167203
force_load_markets = reload
168204
if not force_load_markets:

0 commit comments

Comments
 (0)