Skip to content
This repository was archived by the owner on Feb 3, 2026. It is now read-only.

Commit a613d9b

Browse files
committed
Trigger trading pair symbol removal when not supported in options trading
1 parent a452639 commit a613d9b

File tree

6 files changed

+56
-6
lines changed

6 files changed

+56
-6
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [2.5.6] - 2026-01-28
8+
### Updated
9+
[OHLCVUpdate] Trigger removal of unsupported traded pair when exchange trading options
10+
711
## [2.5.5] - 2026-01-27
812
### Updated
913
[API] Add include_additional_pairs get_trading_symbols

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# OctoBot-Trading [2.5.5](https://github.com/Drakkar-Software/OctoBot-Trading/blob/master/CHANGELOG.md)
1+
# OctoBot-Trading [2.5.6](https://github.com/Drakkar-Software/OctoBot-Trading/blob/master/CHANGELOG.md)
22
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/903b6b22bceb4661b608a86fea655f69)](https://app.codacy.com/gh/Drakkar-Software/OctoBot-Trading?utm_source=github.com&utm_medium=referral&utm_content=Drakkar-Software/OctoBot-Trading&utm_campaign=Badge_Grade_Dashboard)
33
[![PyPI](https://img.shields.io/pypi/v/OctoBot-Trading.svg)](https://pypi.python.org/pypi/OctoBot-Trading/)
44
[![Coverage Status](https://coveralls.io/repos/github/Drakkar-Software/OctoBot-Trading/badge.svg?branch=master)](https://coveralls.io/github/Drakkar-Software/OctoBot-Trading?branch=master)

octobot_trading/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
# License along with this library.
1616

1717
PROJECT_NAME = "OctoBot-Trading"
18-
VERSION = "2.5.5" # major.minor.revision
18+
VERSION = "2.5.6" # major.minor.revision

octobot_trading/exchange_data/ohlcv/channel/ohlcv_updater.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ async def _candle_update_loop(self, time_frame, pair):
320320
except errors.UnSupportedSymbolError as err:
321321
self.logger.warning(
322322
f"{self.channel.exchange_manager.exchange_name} is not supporting {pair} on {time_frame.value}: {err}")
323+
await self._remove_unsupported_pairs(pair)
323324
except errors.NotSupported as err:
324325
self.logger.warning(
325326
f"{self.channel.exchange_manager.exchange_name} is not supporting updates: {err}")
@@ -385,6 +386,12 @@ def _set_initialized(self, pair, time_frame, initialized):
385386
self.initialized_candles_by_tf_by_symbol[pair] = {}
386387
self.initialized_candles_by_tf_by_symbol[pair][time_frame] = initialized
387388

389+
async def _remove_unsupported_pairs(self, pair: str):
390+
# For now only remove the pair from the traded pairs if it's an option exchange
391+
if self.channel.exchange_manager.is_option:
392+
self.logger.warning(f"Removing {pair} from traded pairs...")
393+
self.channel.exchange_manager.exchange_config.remove_traded_symbols([pair])
394+
388395
async def resume(self) -> None:
389396
await super().resume()
390397
if not self.is_running:

octobot_trading/exchanges/config/exchange_config_data.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ def __init__(self, exchange_manager):
5757
# list of exchange supported pairs on which we want to collect data through updaters or websocket
5858
self.additional_traded_pairs: list[str] = []
5959

60+
# list of exchange supported pairs that have been removed from the traded_symbol_pairs or additional_traded_pairs
61+
self.removed_traded_pairs: list[str] = []
62+
6063
# list of required time frames from configuration that are available
6164
self.available_required_time_frames: list[commons_enums.TimeFrames] = []
6265

@@ -167,6 +170,11 @@ async def add_traded_symbols(self, symbols: list[str], time_frames: list[commons
167170
added_pairs=symbols, removed_pairs=[], added_time_frames=time_frames, watch_only=False
168171
)
169172

173+
async def remove_traded_symbols(self, symbols: list[str]):
174+
await self.update_traded_symbol_pairs(
175+
added_pairs=[], removed_pairs=symbols, added_time_frames=[], watch_only=False
176+
)
177+
170178
async def update_traded_symbol_pairs(
171179
self,
172180
added_pairs: list[str],
@@ -200,16 +208,16 @@ async def update_traded_symbol_pairs(
200208
and self._is_valid_symbol(symbol_pair, [])
201209
and symbol_pair not in self.traded_symbol_pairs
202210
and symbol_pair not in self.additional_traded_pairs
211+
and symbol_pair not in self.removed_traded_pairs
203212
and (not watch_only or symbol_pair not in self.watched_pairs)
204213
]
205214
removed_valid_symbol_pairs = [
206215
symbol_pair
207216
for symbol_pair in removed_pairs
208217
if symbols_util.is_symbol(symbol_pair)
209218
and self._is_valid_symbol(symbol_pair, [])
210-
and symbol_pair in self.traded_symbol_pairs
211-
and symbol_pair in self.additional_traded_pairs
212-
and (not watch_only or symbol_pair in self.watched_pairs)
219+
and (symbol_pair in self.traded_symbol_pairs or symbol_pair in self.additional_traded_pairs or (not watch_only or symbol_pair in self.watched_pairs))
220+
and symbol_pair not in self.removed_traded_pairs
213221
]
214222
new_valid_time_frames = [
215223
time_frame
@@ -268,6 +276,12 @@ async def update_traded_symbol_pairs(
268276
await channel.modify(
269277
added_pairs=new_valid_symbol_pairs, removed_pairs=removed_valid_symbol_pairs
270278
)
279+
280+
if removed_valid_symbol_pairs:
281+
self.traded_symbol_pairs = [pair for pair in self.traded_symbol_pairs if pair not in removed_valid_symbol_pairs]
282+
self.additional_traded_pairs = [pair for pair in self.additional_traded_pairs if pair not in removed_valid_symbol_pairs]
283+
self.watched_pairs = [pair for pair in self.watched_pairs if pair not in removed_valid_symbol_pairs]
284+
self.removed_traded_pairs += removed_valid_symbol_pairs
271285
except Exception as e:
272286
self._logger.exception(e, True, f"Failed to update {'watched' if watch_only else 'traded'} symbol pairs {added_pairs} and {removed_pairs} : {e}")
273287

tests/exchanges/test_exchange_config_data.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,32 @@ async def test_update_traded_symbol_pairs(self, watch_only, added_pairs, removed
336336
assert f"Ignored additional time frames for watched pairs" in logger_mock.error.call_args[0][0]
337337
else:
338338
assert logger_mock.error.call_count == 0
339-
339+
340+
# Test removed_traded_pairs
341+
if removed_pairs:
342+
# removed pairs should be tracked
343+
assert exchange_manager.exchange_config.removed_traded_pairs == removed_pairs
344+
345+
# calling again with the same pairs should not change state for removed pairs
346+
before_second_call_removed = list(exchange_manager.exchange_config.removed_traded_pairs)
347+
await exchange_manager.exchange_config.update_traded_symbol_pairs(
348+
added_pairs=removed_pairs,
349+
removed_pairs=removed_pairs,
350+
added_time_frames=added_time_frames,
351+
watch_only=watch_only,
352+
)
353+
# removed_traded_pairs should remain unchanged
354+
assert exchange_manager.exchange_config.removed_traded_pairs == before_second_call_removed
355+
for pair in removed_pairs:
356+
# removed pairs should not re-appear in additional_traded_pairs
357+
assert pair not in exchange_manager.exchange_config.additional_traded_pairs
358+
# and should not re-appear in watched_pairs for watch_only mode
359+
if watch_only:
360+
assert pair not in exchange_manager.exchange_config.watched_pairs
361+
else:
362+
# no removed pairs: tracking list must stay empty
363+
assert exchange_manager.exchange_config.removed_traded_pairs == []
364+
340365
cancel_ccxt_throttle_task()
341366
finally:
342367
await exchange_manager.stop()

0 commit comments

Comments
 (0)