Skip to content

Commit 2b26ee4

Browse files
authored
Merge pull request #1663 from Drakkar-Software/dev
Master update
2 parents 8fbe596 + 8d064eb commit 2b26ee4

File tree

4 files changed

+50
-17
lines changed

4 files changed

+50
-17
lines changed

Trading/Exchange/hollaex/hollaex_exchange.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ async def _refresh_exchange_fee_tiers(self, all_markets: list[dict]):
148148
fee_pairs = list(fees_by_tier[next(iter(fees_by_tier))]) if fees_by_tier else []
149149
self.logger.info(
150150
f"Refreshed {exchange_name} fee tiers. Sample: {sample}. {len(sample)} tiers: {list(sample)} "
151-
f"over {len(fee_pairs)} pairs: {fee_pairs}."
151+
f"over {len(fee_pairs)} pairs: {fee_pairs}. Using fee tiers "
152+
f"{self._get_fee_tiers(self.exchange_manager.exchange, not self.exchange_manager.is_backtesting).value}."
152153
)
153154

154155
@classmethod
@@ -177,7 +178,7 @@ def register_simulator_connector_fee_methods(
177178
):
178179
# only called in backtesting
179180
# overrides exchange simulator connector calculate_fees and get_fees to use fetched fees instead
180-
fee_tiers = cls._get_fee_tiers(False)
181+
fee_tiers = cls._get_fee_tiers(None, False)
181182
simulator_connector.calculate_fees = cls.simulator_connector_calculate_fees_factory(exchange_name, fee_tiers)
182183
simulator_connector.get_fees = cls.simulator_connector_get_fees_factory(exchange_name, fee_tiers)
183184

@@ -188,8 +189,9 @@ def calculate_fees(
188189
# only called in live trading
189190
is_real_trading = not self.exchange_manager.is_backtesting # consider live trading as real to use basic tier
190191
try:
192+
fee_tiers = self._get_fee_tiers(self.exchange_manager.exchange, is_real_trading)
191193
return self._calculate_fetched_fees(
192-
self.exchange_manager.exchange_name, self._get_fee_tiers(is_real_trading),
194+
self.exchange_manager.exchange_name, fee_tiers,
193195
symbol, order_type, quantity, price, taker_or_maker
194196
)
195197
except errors.MissingFeeDetailsError as err:
@@ -201,7 +203,8 @@ def get_fees(self, symbol):
201203
# only called in live trading
202204
try:
203205
is_real_trading = not self.exchange_manager.is_backtesting # consider live trading as real to use basic tier
204-
return self._get_fees(self.exchange_manager.exchange_name, self._get_fee_tiers(is_real_trading), symbol)
206+
fee_tiers = self._get_fee_tiers(self.exchange_manager.exchange, is_real_trading)
207+
return self._get_fees(self.exchange_manager.exchange_name, fee_tiers, symbol)
205208
except errors.MissingFeeDetailsError:
206209
self.logger.error(f"Missing fee details, using default value")
207210
market = self.get_market_status(symbol, with_fixer=False)
@@ -258,7 +261,14 @@ def _calculate_fetched_fees(
258261
}
259262

260263
@classmethod
261-
def _get_fee_tiers(cls, is_real_trading: bool):
264+
def _get_fee_tiers(cls, rest_exchange: typing.Optional[exchanges.RestExchange], is_real_trading: bool):
265+
if (
266+
rest_exchange
267+
and isinstance(rest_exchange, hollaex)
268+
and (fee_tiers := rest_exchange.get_configured_fee_tiers())
269+
):
270+
return fee_tiers
271+
# default to basic tier
262272
return FeeTiers.BASIC if is_real_trading else FeeTiers.VIP
263273

264274
@classmethod
@@ -320,6 +330,7 @@ class hollaex(exchanges.RestExchange):
320330

321331
BASE_REST_API = "api.hollaex.com"
322332
REST_KEY = "rest"
333+
FEE_TIERS_KEY = "fee_tiers"
323334
HAS_WEBSOCKETS_KEY = "has_websockets"
324335
REQUIRE_ORDER_FEES_FROM_TRADES = True # set True when get_order is not giving fees on closed orders and fees
325336
SUPPORT_FETCHING_CANCELLED_ORDERS = False
@@ -398,16 +409,29 @@ def init_user_inputs_from_class(cls, inputs: dict) -> None:
398409
cls.REST_KEY, commons_enums.UserInputTypes.TEXT, f"https://{cls.BASE_REST_API}", inputs,
399410
title=f"Address of the Hollaex based exchange API (similar to https://{cls.BASE_REST_API})"
400411
)
412+
cls.CLASS_UI.user_input(
413+
cls.FEE_TIERS_KEY, commons_enums.UserInputTypes.OPTIONS, FeeTiers.BASIC.value, inputs,
414+
title=f"Fee tiers to use for the exchange. Used to predict fees.",
415+
options=[tier.value for tier in FeeTiers]
416+
)
401417
cls.CLASS_UI.user_input(
402418
cls.HAS_WEBSOCKETS_KEY, commons_enums.UserInputTypes.BOOLEAN, True, inputs,
403419
title=f"Use websockets feed. To enable only when websockets are supported by the exchange."
404420
)
405421

406422
def get_additional_connector_config(self):
407423
return {
408-
ccxt_enums.ExchangeColumns.URLS.value: self.get_patched_urls(self.tentacle_config[self.REST_KEY])
424+
ccxt_enums.ExchangeColumns.URLS.value: self.get_patched_urls(self.get_api_url())
409425
}
410426

427+
def get_api_url(self):
428+
return self.tentacle_config[self.REST_KEY]
429+
430+
def get_configured_fee_tiers(self) -> typing.Optional[FeeTiers]:
431+
if tiers := self.tentacle_config.get(self.FEE_TIERS_KEY):
432+
return FeeTiers(tiers)
433+
return None
434+
411435
@classmethod
412436
def get_custom_url_config(cls, tentacle_config: dict, exchange_name: str) -> dict:
413437
if details := cls.get_exchange_details(tentacle_config, exchange_name):

Trading/Exchange/hyperliquid_websocket_feed/hyperliquid_websocket.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020

2121
class HyperliquidCCXTWebsocketConnector(exchanges.CCXTWebsocketConnector):
22+
USE_REST_CONNECTOR_ADDITIONAL_CONFIG = True
2223
EXCHANGE_FEEDS = {
2324
Feeds.TRADES: True,
2425
Feeds.KLINE: True,

Trading/Mode/market_making_trading_mode/market_making_trading.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,16 @@ async def get_forced_updater_channels(
191191
@classmethod
192192
def get_is_trading_on_exchange(cls, exchange_name, tentacles_setup_config) -> bool:
193193
"""
194-
returns True if exchange_name is not in price sources
194+
returns True if exchange_name is trading exchange or the hedging exchange
195+
"""
196+
return cls.has_trading_exchange_configuration(
197+
exchange_name, octobot_tentacles_manager.api.get_tentacle_config(tentacles_setup_config, cls)
198+
)
199+
200+
@classmethod
201+
def get_is_using_trading_mode_on_exchange(cls, exchange_name, tentacles_setup_config) -> bool:
202+
"""
203+
returns True if exchange_name is a trading exchange that is not the hedging exchange
195204
"""
196205
return cls.has_trading_exchange_configuration(
197206
exchange_name, octobot_tentacles_manager.api.get_tentacle_config(tentacles_setup_config, cls)
@@ -762,8 +771,8 @@ async def _handle_market_making_orders(
762771
outdated_orders = self._get_orders_to_cancel(sorted_orders, reference_price)
763772
if outdated_orders:
764773
self.logger.info(
765-
f"{len(outdated_orders)} outdated orders for {self.symbol} {self.exchange_manager.exchange_name}: "
766-
f"{[str(o) for o in outdated_orders]} [trigger source: {trigger_source}]"
774+
f"{len(outdated_orders)} outdated orders for {self.symbol} on {self.exchange_manager.exchange_name} (trigger_source: {trigger_source}): "
775+
f"{[str(o) for o in outdated_orders]}"
767776
)
768777

769778
# get ideal distribution
@@ -1071,12 +1080,11 @@ def _get_orders_to_cancel(
10711080
]
10721081

10731082
def _is_outdated(
1074-
self, price: decimal.Decimal, side: trading_enums.TradeOrderSide, reference_price: decimal.Decimal
1083+
self, order_price: decimal.Decimal, side: trading_enums.TradeOrderSide, reference_price: decimal.Decimal
10751084
) -> bool:
1076-
return (
1077-
(side == trading_enums.TradeOrderSide.BUY and price > reference_price)
1078-
or (side == trading_enums.TradeOrderSide.SELL and price < reference_price)
1079-
)
1085+
if side == trading_enums.TradeOrderSide.BUY:
1086+
return order_price > reference_price
1087+
return order_price < reference_price
10801088

10811089
def _sort_orders(self, open_orders: list) -> list:
10821090
"""
@@ -1292,7 +1300,7 @@ async def _get_reference_price(self) -> decimal.Decimal:
12921300
local_exchange_name, self.exchange_manager.id
12931301
):
12941302
exchange_manager = trading_api.get_exchange_manager_from_exchange_id(exchange_id)
1295-
if exchange_manager.is_trading and exchange_manager is not self.exchange_manager:
1303+
if exchange_manager.trading_modes and exchange_manager is not self.exchange_manager:
12961304
await self.sent_once_critical_notification(
12971305
"Configuration issue",
12981306
f"Multiple simultaneous trading exchanges is not supported on {self.trading_mode.get_name()}"

Trading/Mode/trading_view_signals_trading_mode/trading_view_signals_trading.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,8 @@ def is_compatible_trading_type(cls, parsed_signal: dict, trading_type: trading_e
209209

210210
def _log_error_message_if_relevant(self, parsed_data: dict, signal_data: str):
211211
# only log error messages on one TradingViewSignalsTradingMode instance to avoid logging errors multiple times
212-
all_trading_modes = trading_modes.get_trading_modes_of_this_type_on_this_matrix(self)
213-
if all_trading_modes and all_trading_modes[0] is self:
212+
if self.is_first_trading_mode_on_this_matrix():
213+
all_trading_modes = trading_modes.get_trading_modes_of_this_type_on_this_matrix(self)
214214
# Can log error message: this is the first trading mode on this matrix.
215215
# Each is notified by signals and only this one will log errors to avoid duplicating logs
216216
if not any(

0 commit comments

Comments
 (0)