|
14 | 14 | # You should have received a copy of the GNU Lesser General Public |
15 | 15 | # License along with this library. |
16 | 16 | import asyncio |
| 17 | +import copy |
17 | 18 | import decimal |
18 | 19 | import contextlib |
19 | 20 | import mock |
|
22 | 23 |
|
23 | 24 | import async_channel.util as channel_util |
24 | 25 | import octobot_commons.constants as commons_constants |
| 26 | +import octobot_commons.configuration.user_inputs as commons_user_inputs |
25 | 27 | import octobot_commons.errors as commons_errors |
26 | 28 | import octobot_commons.enums as commons_enums |
27 | 29 | import octobot_commons.asyncio_tools as asyncio_tools |
@@ -229,6 +231,58 @@ def test_does_not_mutate_original_hedging_dict(self): |
229 | 231 | assert cls.AVERAGE_PRICE_COUNTED_MINUTES not in inner |
230 | 232 |
|
231 | 233 |
|
| 234 | +@pytest.mark.parametrize( |
| 235 | + "hedging_exchange_case", |
| 236 | + ( |
| 237 | + "missing_exchange", |
| 238 | + "empty_string", |
| 239 | + "explicit_none", |
| 240 | + ), |
| 241 | +) |
| 242 | +async def test_init_user_inputs_defaults_valid_hedging_off_without_exchange(hedging_exchange_case): |
| 243 | + symbol = "BTC/USDT" |
| 244 | + cls = simple_market_making_trading.SimpleMarketMakingTradingMode |
| 245 | + real_find_parent = commons_user_inputs._find_parent_config_node |
| 246 | + |
| 247 | + # Without array_indexes, pair_settings resolves to a list and user_input skips writes; |
| 248 | + # treat the first row as the parent so init_user_inputs merges defaults into it. |
| 249 | + def find_parent_pair_settings_row(tentacle_config, parent_input_name, array_indexes): |
| 250 | + if parent_input_name == cls.CONFIG_PAIR_SETTINGS and not array_indexes: |
| 251 | + pair_settings_value = tentacle_config.get(cls.CONFIG_PAIR_SETTINGS) |
| 252 | + if isinstance(pair_settings_value, list) and pair_settings_value: |
| 253 | + return pair_settings_value[0] |
| 254 | + return real_find_parent(tentacle_config, parent_input_name, array_indexes) |
| 255 | + |
| 256 | + async with _get_tools(symbol) as (producer, consumer, exchange_manager): |
| 257 | + mode = producer.trading_mode |
| 258 | + mode.trading_config = copy.deepcopy(_get_mm_config(symbol)) |
| 259 | + with mock.patch.object( |
| 260 | + commons_user_inputs, |
| 261 | + "_find_parent_config_node", |
| 262 | + side_effect=find_parent_pair_settings_row, |
| 263 | + ): |
| 264 | + mode.init_user_inputs({}) |
| 265 | + pair_config = mode.trading_config[cls.CONFIG_PAIR_SETTINGS][0] |
| 266 | + hedging_engine_cfg = pair_config[cls.HEDGING_ENGINE] |
| 267 | + assert hedging_engine_cfg[cls.HEDGING_EXCHANGE] == "" # ensure default is set |
| 268 | + hedging_engine_cfg[cls.HEDGING_MAX_LOSS_THRESHOLD] = 10 |
| 269 | + hedging_engine_cfg[cls.LEGACY_AVERAGE_PRIVE_COUNTED_MINUTES_KEY] = 60 |
| 270 | + if hedging_exchange_case == "missing_exchange": |
| 271 | + hedging_engine_cfg.pop(cls.HEDGING_EXCHANGE, None) |
| 272 | + elif hedging_exchange_case == "empty_string": |
| 273 | + hedging_engine_cfg[cls.HEDGING_EXCHANGE] = "" |
| 274 | + elif hedging_exchange_case == "explicit_none": |
| 275 | + hedging_engine_cfg[cls.HEDGING_EXCHANGE] = None |
| 276 | + assert producer._load_symbol_trading_config() is True |
| 277 | + producer.read_config() |
| 278 | + assert producer.order_book_distribution is not None |
| 279 | + assert producer.reference_prices_by_exchange |
| 280 | + with mock.patch.object(hedging, "get_or_create_hedging_engine", mock.Mock()) as get_or_create_mock: |
| 281 | + await producer._initialize_hedging_engine() |
| 282 | + get_or_create_mock.assert_not_called() |
| 283 | + assert producer._hedging_engine is None |
| 284 | + |
| 285 | + |
232 | 286 | async def test_handle_market_making_orders_from_no_orders(): |
233 | 287 | symbol = "BTC/USDT" |
234 | 288 | async with _get_tools(symbol) as (producer, consumer, exchange_manager): |
|
0 commit comments