From 3c8387ab611df10c8a327b5196f4798541f67b10 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Fri, 1 Apr 2022 20:48:13 +0900 Subject: [PATCH 001/449] Add exchange id for binance Futures --- docs/exchanges.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/exchanges.md b/docs/exchanges.md index b808096d2..420061050 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -87,7 +87,7 @@ When trading on Binance Futures market, orderbook must be used because there is Binance has been split into 2, and users must use the correct ccxt exchange ID for their exchange, otherwise API keys are not recognized. -* [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance`. +* [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance` for spot market, and use `binanceusdm` or `binancecoinm` for Futures market. * [binance.us](https://www.binance.us/) - US based users. Use exchange id: `binanceus`. ## Kraken From da0688b6aa26f6eee36acef9ede4186b48d876c6 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Sat, 2 Apr 2022 03:20:21 +0900 Subject: [PATCH 002/449] Revert "Add exchange id for binance Futures" This reverts commit 3c8387ab611df10c8a327b5196f4798541f67b10. --- docs/exchanges.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/exchanges.md b/docs/exchanges.md index 420061050..b808096d2 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -87,7 +87,7 @@ When trading on Binance Futures market, orderbook must be used because there is Binance has been split into 2, and users must use the correct ccxt exchange ID for their exchange, otherwise API keys are not recognized. -* [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance` for spot market, and use `binanceusdm` or `binancecoinm` for Futures market. +* [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance`. * [binance.us](https://www.binance.us/) - US based users. Use exchange id: `binanceus`. ## Kraken From 16b6b08227b12290d613f140d4c23db9a7a50d3f Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 14:42:41 +0300 Subject: [PATCH 003/449] Update docs to include info on new functionality. --- docs/bot-basics.md | 4 ++- docs/strategy-callbacks.md | 73 +++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/docs/bot-basics.md b/docs/bot-basics.md index e45e3d9ca..0ee585a15 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -24,7 +24,7 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and * Fetch open trades from persistence. * Calculate current list of tradable pairs. -* Download OHLCV data for the pairlist including all [informative pairs](strategy-customization.md#get-data-for-non-tradeable-pairs) +* Download OHLCV data for the pairlist including all [informative pairs](strategy-customization.md#get-data-for-non-tradeable-pairs) This step is only executed once per Candle to avoid unnecessary network traffic. * Call `bot_loop_start()` strategy callback. * Analyze strategy per pair. @@ -34,6 +34,8 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and * Check timeouts for open orders. * Calls `check_entry_timeout()` strategy callback for open entry orders. * Calls `check_exit_timeout()` strategy callback for open exit orders. +* Check readjustment request for open orders. + * Calls `readjust_entry_price()` strategy callback for open entry orders. * Verifies existing positions and eventually places exit orders. * Considers stoploss, ROI and exit-signal, `custom_exit()` and `custom_stoploss()`. * Determine exit-price based on `exit_pricing` configuration setting or by using the `custom_exit_price()` callback. diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index bd32f41c3..94b1230b3 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -16,6 +16,7 @@ Currently available callbacks: * [`confirm_trade_entry()`](#trade-entry-buy-order-confirmation) * [`confirm_trade_exit()`](#trade-exit-sell-order-confirmation) * [`adjust_trade_position()`](#adjust-trade-position) +* [`readjust_entry_price()`](#readjust-entry-price) * [`leverage()`](#leverage-callback) !!! Tip "Callback calling sequence" @@ -365,13 +366,13 @@ class AwesomeStrategy(IStrategy): # ... populate_* methods - def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float, + def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float, entry_tag: Optional[str], side: str, **kwargs) -> float: dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) new_entryprice = dataframe['bollinger_10_lowerband'].iat[-1] - + return new_entryprice def custom_exit_price(self, pair: str, trade: Trade, @@ -381,14 +382,14 @@ class AwesomeStrategy(IStrategy): dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) new_exitprice = dataframe['bollinger_10_upperband'].iat[-1] - + return new_exitprice ``` !!! Warning - Modifying entry and exit prices will only work for limit orders. Depending on the price chosen, this can result in a lot of unfilled orders. By default the maximum allowed distance between the current price and the custom price is 2%, this value can be changed in config with the `custom_price_max_distance_ratio` parameter. - **Example**: + Modifying entry and exit prices will only work for limit orders. Depending on the price chosen, this can result in a lot of unfilled orders. By default the maximum allowed distance between the current price and the custom price is 2%, this value can be changed in config with the `custom_price_max_distance_ratio` parameter. + **Example**: If the new_entryprice is 97, the proposed_rate is 100 and the `custom_price_max_distance_ratio` is set to 2%, The retained valid custom entry price will be 98, which is 2% below the current (proposed) rate. !!! Warning "Backtesting" @@ -430,7 +431,7 @@ class AwesomeStrategy(IStrategy): 'exit': 60 * 25 } - def check_entry_timeout(self, pair: str, trade: 'Trade', order: dict, + def check_entry_timeout(self, pair: str, trade: 'Trade', order: dict, current_time: datetime, **kwargs) -> bool: if trade.open_rate > 100 and trade.open_date_utc < current_time - timedelta(minutes=5): return True @@ -508,7 +509,7 @@ class AwesomeStrategy(IStrategy): # ... populate_* methods def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, - time_in_force: str, current_time: datetime, entry_tag: Optional[str], + time_in_force: str, current_time: datetime, entry_tag: Optional[str], side: str, **kwargs) -> bool: """ Called right before placing a entry order. @@ -616,35 +617,35 @@ from freqtrade.persistence import Trade class DigDeeperStrategy(IStrategy): - + position_adjustment_enable = True - + # Attempts to handle large drops with DCA. High stoploss is required. stoploss = -0.30 - + # ... populate_* methods - + # Example specific variables max_entry_position_adjustment = 3 # This number is explained a bit further down max_dca_multiplier = 5.5 - + # This is called when placing the initial order (opening trade) def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: float, max_stake: float, entry_tag: Optional[str], side: str, **kwargs) -> float: - + # We need to leave most of the funds for possible further DCA orders # This also applies to fixed stakes return proposed_stake / self.max_dca_multiplier - + def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: float, max_stake: float, **kwargs): """ Custom trade adjustment logic, returning the stake amount that a trade should be increased. This means extra buy orders with additional fees. - + :param trade: trade object. :param current_time: datetime object, containing the current datetime :param current_rate: Current buy rate. @@ -654,7 +655,7 @@ class DigDeeperStrategy(IStrategy): :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. :return float: Stake amount to adjust your trade """ - + if current_profit > -0.05: return None @@ -689,6 +690,46 @@ class DigDeeperStrategy(IStrategy): ``` +## Readjust Entry Price + +The `readjust_entry_price()` callback may be used by strategy developer to refresh/replace limit orders upon arrival of new candles. +Be aware that `custom_entry_price()` is still the one dictating initial entry limit order price target at the time of entry trigger. + +!!! Warning This mechanism will not trigger if previous orders were partially or fully filled. + +!!! Warning Entry `unfilledtimeout` mechanism takes precedence over this. Be sure to update timeout values to match your expectancy. + +```python +from freqtrade.persistence import Trade +from datetime import timedelta + +class AwesomeStrategy(IStrategy): + + # ... populate_* methods + + def readjust_entry_price(self, pair: str, current_time: datetime, proposed_rate: float, + entry_tag: Optional[str], side: str, **kwargs) -> float: + """ + Entry price readjustment logic, returning the readjusted entry price. + + :param pair: Pair that's currently analyzed + :param trade: Trade object. + :param current_time: datetime object, containing the current datetime + :param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. + :param side: 'long' or 'short' - indicating the direction of the proposed trade + :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. + :return float: New entry price value if provided + + """ + # Limit orders to use and follow SMA200 as price target for the first 10 minutes since entry trigger for BTC/USDT pair. + if pair == 'BTC/USDT' and entry_tag == 'long_sma200' and side == 'long' and (current_time - timedelta(minutes=10) > trade.open_date_utc: + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + return current_candle['sma_200'] + return proposed_rate +``` + ## Leverage Callback When trading in markets that allow leverage, this method must return the desired Leverage (Defaults to 1 -> No leverage). From e5d4f7766e507dab3e0a5171d30cb965c1961452 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 14:44:41 +0300 Subject: [PATCH 004/449] Add new cancel reason for when replacing orders. --- freqtrade/constants.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index c6a2ab5d3..cd04a71f1 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -478,6 +478,7 @@ CANCEL_REASON = { "ALL_CANCELLED": "cancelled (all unfilled and partially filled open orders cancelled)", "CANCELLED_ON_EXCHANGE": "cancelled on exchange", "FORCE_EXIT": "forcesold", + "REPLACE": "cancelled to be replaced by new limit order", } # List of pairs with their timeframes From 76c545ba0d7098e5b084041655b1e5176645a546 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 15:03:09 +0300 Subject: [PATCH 005/449] Reorganize, rename, redescribe and add new functionality --- freqtrade/freqtradebot.py | 104 +++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 29 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 57d7cac3c..cdb8a4bcf 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -22,6 +22,7 @@ from freqtrade.enums import (ExitCheckTuple, ExitType, RPCMessageType, RunMode, from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError, InvalidOrderException, PricingError) from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds +from freqtrade.exchange.exchange import timeframe_to_next_date from freqtrade.misc import safe_value_fallback, safe_value_fallback2 from freqtrade.mixins import LoggingMixin from freqtrade.persistence import Order, PairLocks, Trade, cleanup_db, init_db @@ -188,8 +189,8 @@ class FreqtradeBot(LoggingMixin): self.strategy.analyze(self.active_pair_whitelist) with self._exit_lock: - # Check and handle any timed out open orders - self.check_handle_timedout() + # Check for exchange cancelations, timeouts and user requested replace + self.manage_open_orders() # Protect from collisions with force_exit. # Without this, freqtrade my try to recreate stoploss_on_exchange orders @@ -1123,13 +1124,13 @@ class FreqtradeBot(LoggingMixin): return True return False - def check_handle_timedout(self) -> None: + def manage_open_orders(self) -> None: """ - Check if any orders are timed out and cancel if necessary - :param timeoutvalue: Number of minutes until order is considered timed out + Management of open orders on exchange. Unfilled orders might be cancelled if timeout + was met or replaced if there's a new candle and user has requested it. + Timeout setting takes priority over limit order adjustment request. :return: None """ - for trade in Trade.get_open_order_trades(): try: if not trade.open_order_id: @@ -1140,33 +1141,78 @@ class FreqtradeBot(LoggingMixin): continue fully_cancelled = self.update_trade_state(trade, trade.open_order_id, order) - is_entering = order['side'] == trade.entry_side not_closed = order['status'] == 'open' or fully_cancelled - max_timeouts = self.config.get('unfilledtimeout', {}).get('exit_timeout_count', 0) - order_obj = trade.select_order_by_order_id(trade.open_order_id) - if not_closed and (fully_cancelled or (order_obj and self.strategy.ft_check_timed_out( - trade, order_obj, datetime.now(timezone.utc))) - ): - if is_entering: - self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT']) + if not_closed: + if fully_cancelled or (order_obj and self.strategy.ft_check_timed_out( + trade, order_obj, datetime.now(timezone.utc))): + self.handle_timedout_orders(order, trade) else: - canceled = self.handle_cancel_exit( - trade, order, constants.CANCEL_REASON['TIMEOUT']) - canceled_count = trade.get_exit_order_count() - max_timeouts = self.config.get( - 'unfilledtimeout', {}).get('exit_timeout_count', 0) - if canceled and max_timeouts > 0 and canceled_count >= max_timeouts: - logger.warning(f'Emergency exiting trade {trade}, as the exit order ' - f'timed out {max_timeouts} times.') - try: - self.execute_trade_exit( - trade, order.get('price'), - exit_check=ExitCheckTuple(exit_type=ExitType.EMERGENCY_EXIT)) - except DependencyException as exception: - logger.warning( - f'Unable to emergency sell trade {trade.pair}: {exception}') + self.replace_orders(order, order_obj, trade) + + def handle_timedout_orders(self, order: Dict, trade: Trade) -> None: + """ + Check if any orders are timed out and cancel if necessary. + :param order: Order dict grabbed with exchange.fetch_order() + :param trade: Trade object. + :return: None + """ + if order['side'] == trade.entry_side: + self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT']) + else: + canceled = self.handle_cancel_exit( + trade, order, constants.CANCEL_REASON['TIMEOUT']) + canceled_count = trade.get_exit_order_count() + max_timeouts = self.config.get('unfilledtimeout', {}).get('exit_timeout_count', 0) + if canceled and max_timeouts > 0 and canceled_count >= max_timeouts: + logger.warning(f'Emergency exiting trade {trade}, as the exit order ' + f'timed out {max_timeouts} times.') + try: + self.execute_trade_exit( + trade, order['price'], + exit_check=ExitCheckTuple(exit_type=ExitType.EMERGENCY_EXIT)) + except DependencyException as exception: + logger.warning( + f'Unable to emergency sell trade {trade.pair}: {exception}') + + def replace_orders(self, order: Dict, order_obj: Optional[Order], trade: Trade) -> None: + """ + Check if any orders should be replaced and do so + :param order: Order dict grabbed with exchange.fetch_order() + :param order_obj: Order object. + :param trade: Trade object. + :return: None + """ + analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair, + self.strategy.timeframe) + latest_candle_open_date = analyzed_df.iloc[-1]['date'] if len(analyzed_df) > 0 else None + latest_candle_close_date = timeframe_to_next_date(self.strategy.timeframe, + latest_candle_open_date) + # Check if new candle + if order_obj and latest_candle_close_date.replace(tzinfo=None) > order_obj.order_date: + # New candle + proposed_rate = self.exchange.get_rate( + trade.pair, side='entry', is_short=trade.is_short, refresh=True) + adjusted_entry_price = strategy_safe_wrapper(self.strategy.readjust_entry_price, + default_retval=proposed_rate)( + pair=trade.pair, current_time=datetime.now(timezone.utc), + proposed_rate=proposed_rate, entry_tag=trade.enter_tag, + side=trade.entry_side) + # check if user has requested entry limit adjustment + if proposed_rate != adjusted_entry_price: + # cancel existing order + self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['REPLACE'], + allow_full_cancel=False) + stake = self.wallets.get_trade_stake_amount(trade.pair, self.edge) + # place new order with requested price + self.execute_entry( + pair=trade.pair, + stake_amount=stake, + price=adjusted_entry_price, + trade=trade, + is_short=trade.is_short + ) def cancel_all_open_orders(self) -> None: """ From 317c1e0746def78e37f895c1c3640f727f3f137c Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 15:03:44 +0300 Subject: [PATCH 006/449] Add option to handle_cancel_enter to prevent closing trade. --- freqtrade/freqtradebot.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index cdb8a4bcf..473ad9a8d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1234,7 +1234,10 @@ class FreqtradeBot(LoggingMixin): self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['ALL_CANCELLED']) Trade.commit() - def handle_cancel_enter(self, trade: Trade, order: Dict, reason: str) -> bool: + def handle_cancel_enter( + self, trade: Trade, order: Dict, reason: str, + allow_full_cancel: Optional[bool] = True + ) -> bool: """ Buy cancel - cancel order :return: True if order was fully cancelled @@ -1274,7 +1277,7 @@ class FreqtradeBot(LoggingMixin): if isclose(filled_amount, 0.0, abs_tol=constants.MATH_CLOSE_PREC): logger.info(f'{side} order fully cancelled. Removing {trade} from database.') # if trade is not partially completed and it's the only order, just delete the trade - if len(trade.orders) <= 1: + if len(trade.orders) <= 1 and allow_full_cancel: trade.delete() was_trade_fully_canceled = True reason += f", {constants.CANCEL_REASON['FULLY_CANCELLED']}" From f8a7fdd5edd7d590c348037d8f2376b1873cae3c Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 15:04:22 +0300 Subject: [PATCH 007/449] Add new callback to strategy interface. --- freqtrade/strategy/interface.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index ba2eb9636..aeda66d4e 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -467,6 +467,28 @@ class IStrategy(ABC, HyperStrategyMixin): """ return None + def readjust_entry_price(self, trade: Trade, pair: str, current_time: datetime, + proposed_rate: float, entry_tag: Optional[str], + side: str, **kwargs) -> float: + """ + Entry price readjustment logic, returning the readjusted entry price. + This only executes when a order was already placed, open(unfilled) and not timed out on + subsequent candles. + + For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/ + + :param pair: Pair that's currently analyzed + :param trade: Trade object. + :param current_time: datetime object, containing the current datetime + :param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. + :param side: 'long' or 'short' - indicating the direction of the proposed trade + :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. + :return float: New entry price value if provided + + """ + return proposed_rate + def leverage(self, pair: str, current_time: datetime, current_rate: float, proposed_leverage: float, max_leverage: float, side: str, **kwargs) -> float: From bf5799ef9eff2b821e6600997f2bb97d0df1d72a Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 15:07:18 +0300 Subject: [PATCH 008/449] Add new functionality to backtesting. --- freqtrade/optimize/backtesting.py | 36 ++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index cbb220e45..f91013585 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -635,7 +635,7 @@ class Backtesting: def get_valid_price_and_stake( self, pair: str, row: Tuple, propose_rate: float, stake_amount: Optional[float], direction: LongShort, current_time: datetime, entry_tag: Optional[str], - trade: Optional[LocalTrade], order_type: str + trade: Optional[LocalTrade], order_type: str, readjust_req: Optional[bool] = False ) -> Tuple[float, float, float, float]: if order_type == 'limit': @@ -645,6 +645,14 @@ class Backtesting: proposed_rate=propose_rate, entry_tag=entry_tag, side=direction, ) # default value is the open rate + if readjust_req: + propose_rate = strategy_safe_wrapper(self.strategy.readjust_entry_price, + default_retval=propose_rate)( + pair=pair, current_time=current_time, + proposed_rate=propose_rate, entry_tag=entry_tag, + side=direction + ) # default value is open rate or custom rate from before + # We can't place orders higher than current high (otherwise it'd be a stop limit buy) # which freqtrade does not support in live. if direction == "short": @@ -652,7 +660,7 @@ class Backtesting: else: propose_rate = min(propose_rate, row[HIGH_IDX]) - pos_adjust = trade is not None + pos_adjust = trade is not None and readjust_req is False leverage = trade.leverage if trade else 1.0 if not pos_adjust: try: @@ -697,17 +705,18 @@ class Backtesting: def _enter_trade(self, pair: str, row: Tuple, direction: LongShort, stake_amount: Optional[float] = None, - trade: Optional[LocalTrade] = None) -> Optional[LocalTrade]: + trade: Optional[LocalTrade] = None, + readjust_req: Optional[bool] = False) -> Optional[LocalTrade]: current_time = row[DATE_IDX].to_pydatetime() entry_tag = row[ENTER_TAG_IDX] if len(row) >= ENTER_TAG_IDX + 1 else None # let's call the custom entry price, using the open price as default price order_type = self.strategy.order_types['entry'] - pos_adjust = trade is not None + pos_adjust = trade is not None and readjust_req is False propose_rate, stake_amount, leverage, min_stake_amount = self.get_valid_price_and_stake( pair, row, row[OPEN_IDX], stake_amount, direction, current_time, entry_tag, trade, - order_type + order_type, readjust_req ) if not stake_amount: @@ -850,6 +859,21 @@ class Backtesting: self.protections.stop_per_pair(pair, current_time) self.protections.global_stop(current_time) + def check_order_replace(self, trade: LocalTrade, current_time, row: Tuple) -> None: + """ + Check if an entry order has to be replaced and do so. + Returns None. + """ + for order in [o for o in trade.orders if o.ft_is_open]: + if order.side == trade.entry_side and current_time > order.order_date_utc: + # cancel existing order + del trade.orders[trade.orders.index(order)] + + # place new order + self._enter_trade(pair=trade.pair, row=row, trade=trade, + direction='short' if trade.is_short else 'long', + readjust_req=True) + def check_order_cancel(self, trade: LocalTrade, current_time) -> bool: """ Check if an order has been canceled. @@ -949,6 +973,8 @@ class Backtesting: open_trade_count -= 1 open_trades[pair].remove(t) self.wallets.update() + else: + self.check_order_replace(t, current_time, row) # 2. Process buys. # without positionstacking, we can only have one open trade per pair. From 452f44206a448363886f5cac4c04fcd674cf845d Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 15:08:09 +0300 Subject: [PATCH 009/449] Add new callback to advanced template. --- .../subtemplates/strategy_methods_advanced.j2 | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 17dfa0873..c7e69d3e4 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -30,6 +30,27 @@ def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: """ return proposed_rate +def readjust_entry_price(self, trade: Trade, pair: str, current_time: datetime, + proposed_rate: float, entry_tag: Optional[str], + side: str, **kwargs) -> float: + """ + Entry price readjustment logic, returning the readjusted entry price. + + For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ + + When not implemented by a strategy, returns proposed_rate and orders are not replaced. + + :param pair: Pair that's currently analyzed + :param trade: Trade object. + :param current_time: datetime object, containing the current datetime + :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing. + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. + :param side: 'long' or 'short' - indicating the direction of the proposed trade + :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. + :return float: New entry price value if provided + """ + return proposed_rate + def custom_exit_price(self, pair: str, trade: 'Trade', current_time: 'datetime', proposed_rate: float, current_profit: float, **kwargs) -> float: From 237d116d8cd707a091f77aa43bfc17de88ba73f9 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 15:08:54 +0300 Subject: [PATCH 010/449] Update existing tests to use the new func name. --- tests/test_freqtradebot.py | 67 +++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 3737c7c05..724b7fd56 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2363,7 +2363,7 @@ def test_bot_loop_start_called_once(mocker, default_conf_usdt, caplog): @pytest.mark.parametrize("is_short", [False, True]) -def test_check_handle_timedout_entry_usercustom( +def test_manage_open_orders_entry_usercustom( default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, limit_sell_order_old, fee, mocker, is_short ) -> None: @@ -2395,12 +2395,12 @@ def test_check_handle_timedout_entry_usercustom( Trade.query.session.add(open_trade) # Ensure default is to return empty (so not mocked yet) - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 # Return false - trade remains open freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False) - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() nb_trades = len(trades) @@ -2408,7 +2408,7 @@ def test_check_handle_timedout_entry_usercustom( assert freqtrade.strategy.check_entry_timeout.call_count == 1 freqtrade.strategy.check_entry_timeout = MagicMock(side_effect=KeyError) - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() nb_trades = len(trades) @@ -2417,7 +2417,7 @@ def test_check_handle_timedout_entry_usercustom( freqtrade.strategy.check_entry_timeout = MagicMock(return_value=True) # Trade should be closed since the function returns true - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_wr_mock.call_count == 1 assert rpc_mock.call_count == 1 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() @@ -2427,7 +2427,7 @@ def test_check_handle_timedout_entry_usercustom( @pytest.mark.parametrize("is_short", [False, True]) -def test_check_handle_timedout_entry( +def test_manage_open_orders_entry( default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, limit_sell_order_old, fee, mocker, is_short ) -> None: @@ -2452,7 +2452,7 @@ def test_check_handle_timedout_entry( freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False) # check it does cancel buy orders over the time limit - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 1 assert rpc_mock.call_count == 1 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() @@ -2461,7 +2461,6 @@ def test_check_handle_timedout_entry( # Custom user buy-timeout is never called assert freqtrade.strategy.check_entry_timeout.call_count == 0 - @pytest.mark.parametrize("is_short", [False, True]) def test_check_handle_cancelled_buy( default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, @@ -2485,7 +2484,7 @@ def test_check_handle_cancelled_buy( Trade.query.session.add(open_trade) # check it does cancel buy orders over the time limit - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 assert rpc_mock.call_count == 1 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() @@ -2496,7 +2495,7 @@ def test_check_handle_cancelled_buy( @pytest.mark.parametrize("is_short", [False, True]) -def test_check_handle_timedout_buy_exception( +def test_manage_open_orders_buy_exception( default_conf_usdt, ticker_usdt, open_trade, is_short, fee, mocker ) -> None: rpc_mock = patch_RPCManager(mocker) @@ -2516,7 +2515,7 @@ def test_check_handle_timedout_buy_exception( Trade.query.session.add(open_trade) # check it does cancel buy orders over the time limit - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 assert rpc_mock.call_count == 0 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() @@ -2525,7 +2524,7 @@ def test_check_handle_timedout_buy_exception( @pytest.mark.parametrize("is_short", [False, True]) -def test_check_handle_timedout_exit_usercustom( +def test_manage_open_orders_exit_usercustom( default_conf_usdt, ticker_usdt, limit_sell_order_old, mocker, is_short, open_trade_usdt, caplog ) -> None: @@ -2554,13 +2553,13 @@ def test_check_handle_timedout_exit_usercustom( Trade.query.session.add(open_trade_usdt) # Ensure default is false - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 freqtrade.strategy.check_exit_timeout = MagicMock(return_value=False) freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False) # Return false - No impact - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 assert rpc_mock.call_count == 0 assert open_trade_usdt.is_open is False @@ -2570,7 +2569,7 @@ def test_check_handle_timedout_exit_usercustom( freqtrade.strategy.check_exit_timeout = MagicMock(side_effect=KeyError) freqtrade.strategy.check_entry_timeout = MagicMock(side_effect=KeyError) # Return Error - No impact - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 assert rpc_mock.call_count == 0 assert open_trade_usdt.is_open is False @@ -2580,7 +2579,7 @@ def test_check_handle_timedout_exit_usercustom( # Return True - sells! freqtrade.strategy.check_exit_timeout = MagicMock(return_value=True) freqtrade.strategy.check_entry_timeout = MagicMock(return_value=True) - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 1 assert rpc_mock.call_count == 1 assert open_trade_usdt.is_open is True @@ -2593,7 +2592,7 @@ def test_check_handle_timedout_exit_usercustom( mocker.patch('freqtrade.persistence.Trade.get_exit_order_count', return_value=1) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.execute_trade_exit', side_effect=DependencyException) - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert log_has_re('Unable to emergency sell .*', caplog) et_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.execute_trade_exit') @@ -2603,16 +2602,16 @@ def test_check_handle_timedout_exit_usercustom( # If cancelling fails - no emergency sell! with patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_exit', return_value=False): - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert et_mock.call_count == 0 - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert log_has_re('Emergency exiting trade.*', caplog) assert et_mock.call_count == 1 @pytest.mark.parametrize("is_short", [False, True]) -def test_check_handle_timedout_exit( +def test_manage_open_orders_exit( default_conf_usdt, ticker_usdt, limit_sell_order_old, mocker, is_short, open_trade_usdt ) -> None: rpc_mock = patch_RPCManager(mocker) @@ -2639,7 +2638,7 @@ def test_check_handle_timedout_exit( freqtrade.strategy.check_exit_timeout = MagicMock(return_value=False) freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False) # check it does cancel sell orders over the time limit - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 1 assert rpc_mock.call_count == 1 assert open_trade_usdt.is_open is True @@ -2675,7 +2674,7 @@ def test_check_handle_cancelled_exit( Trade.query.session.add(open_trade_usdt) # check it does cancel sell orders over the time limit - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 0 assert rpc_mock.call_count == 1 assert open_trade_usdt.is_open is True @@ -2685,7 +2684,7 @@ def test_check_handle_cancelled_exit( @pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("leverage", [1, 3, 5, 10]) -def test_check_handle_timedout_partial( +def test_manage_open_orders_partial( default_conf_usdt, ticker_usdt, limit_buy_order_old_partial, is_short, leverage, open_trade, mocker ) -> None: @@ -2711,7 +2710,7 @@ def test_check_handle_timedout_partial( # check it does cancel buy orders over the time limit # note this is for a partially-complete buy order - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 1 assert rpc_mock.call_count == 2 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() @@ -2722,7 +2721,7 @@ def test_check_handle_timedout_partial( @pytest.mark.parametrize("is_short", [False, True]) -def test_check_handle_timedout_partial_fee( +def test_manage_open_orders_partial_fee( default_conf_usdt, ticker_usdt, open_trade, caplog, fee, is_short, limit_buy_order_old_partial, trades_for_order, limit_buy_order_old_partial_canceled, mocker @@ -2754,7 +2753,7 @@ def test_check_handle_timedout_partial_fee( Trade.query.session.add(open_trade) # cancelling a half-filled order should update the amount to the bought amount # and apply fees if necessary. - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert log_has_re(r"Applying fee on amount for Trade.*", caplog) @@ -2771,7 +2770,7 @@ def test_check_handle_timedout_partial_fee( @pytest.mark.parametrize("is_short", [False, True]) -def test_check_handle_timedout_partial_except( +def test_manage_open_orders_partial_except( default_conf_usdt, ticker_usdt, open_trade, caplog, fee, is_short, limit_buy_order_old_partial, trades_for_order, limit_buy_order_old_partial_canceled, mocker @@ -2802,7 +2801,7 @@ def test_check_handle_timedout_partial_except( Trade.query.session.add(open_trade) # cancelling a half-filled order should update the amount to the bought amount # and apply fees if necessary. - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert log_has_re(r"Could not update trade amount: .*", caplog) @@ -2818,7 +2817,7 @@ def test_check_handle_timedout_partial_except( assert trades[0].fee_open == fee() -def test_check_handle_timedout_exception(default_conf_usdt, ticker_usdt, open_trade_usdt, mocker, +def test_manage_open_orders_exception(default_conf_usdt, ticker_usdt, open_trade_usdt, mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -2840,7 +2839,7 @@ def test_check_handle_timedout_exception(default_conf_usdt, ticker_usdt, open_tr Trade.query.session.add(open_trade_usdt) caplog.clear() - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ADA/USDT, amount=30.00000000, " r"is_short=False, leverage=1.0, " r"open_rate=2.00000000, open_since=" @@ -3397,7 +3396,7 @@ def test_execute_trade_exit_with_stoploss_on_exchange( assert trade trades = [trade] - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() freqtrade.exit_positions(trades) # Increase the price and sell it @@ -3449,7 +3448,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit( # Create some test data freqtrade.enter_positions() - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() trade = Trade.query.first() trades = [trade] assert trade.stoploss_order_id is None @@ -5212,7 +5211,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None: assert trade.stake_amount == 110 assert not trade.fee_updated('buy') - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() trade = Trade.query.first() assert trade @@ -5318,7 +5317,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None: MagicMock(return_value=closed_dca_order_1)) mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', MagicMock(return_value=closed_dca_order_1)) - freqtrade.check_handle_timedout() + freqtrade.manage_open_orders() # Assert trade is as expected (averaged dca) trade = Trade.query.first() From 698c25f133658ca88c5db7e00d8dbe665bb851f5 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 16 Apr 2022 15:44:07 +0300 Subject: [PATCH 011/449] Fix issues reported by flake. --- tests/test_freqtradebot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 724b7fd56..2026872de 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2461,6 +2461,7 @@ def test_manage_open_orders_entry( # Custom user buy-timeout is never called assert freqtrade.strategy.check_entry_timeout.call_count == 0 + @pytest.mark.parametrize("is_short", [False, True]) def test_check_handle_cancelled_buy( default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, @@ -2818,7 +2819,7 @@ def test_manage_open_orders_partial_except( def test_manage_open_orders_exception(default_conf_usdt, ticker_usdt, open_trade_usdt, mocker, - caplog) -> None: + caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) cancel_order_mock = MagicMock() From 17da4ca09939ae56256d7a5d71edf7ff1babbdcd Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sun, 17 Apr 2022 12:11:30 +0300 Subject: [PATCH 012/449] Use order_date_utc --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 473ad9a8d..a020754eb 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1190,7 +1190,7 @@ class FreqtradeBot(LoggingMixin): latest_candle_close_date = timeframe_to_next_date(self.strategy.timeframe, latest_candle_open_date) # Check if new candle - if order_obj and latest_candle_close_date.replace(tzinfo=None) > order_obj.order_date: + if order_obj and latest_candle_close_date > order_obj.order_date_utc: # New candle proposed_rate = self.exchange.get_rate( trade.pair, side='entry', is_short=trade.is_short, refresh=True) From 541147c801ff48b4bcc5fbd0310bf0701219419e Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 18 Apr 2022 21:13:50 +0300 Subject: [PATCH 013/449] Update documentation to match feature changes. --- docs/bot-basics.md | 2 +- docs/strategy-callbacks.md | 34 ++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/docs/bot-basics.md b/docs/bot-basics.md index 0ee585a15..abc0e7b16 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -35,7 +35,7 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and * Calls `check_entry_timeout()` strategy callback for open entry orders. * Calls `check_exit_timeout()` strategy callback for open exit orders. * Check readjustment request for open orders. - * Calls `readjust_entry_price()` strategy callback for open entry orders. + * Calls `adjust_entry_price()` strategy callback for open entry orders. * Verifies existing positions and eventually places exit orders. * Considers stoploss, ROI and exit-signal, `custom_exit()` and `custom_stoploss()`. * Determine exit-price based on `exit_pricing` configuration setting or by using the `custom_exit_price()` callback. diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 5f3e46be9..c78a2c7e5 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -16,7 +16,7 @@ Currently available callbacks: * [`confirm_trade_entry()`](#trade-entry-buy-order-confirmation) * [`confirm_trade_exit()`](#trade-exit-sell-order-confirmation) * [`adjust_trade_position()`](#adjust-trade-position) -* [`readjust_entry_price()`](#readjust-entry-price) +* [`adjust_entry_price()`](#adjust-entry-price) * [`leverage()`](#leverage-callback) !!! Tip "Callback calling sequence" @@ -389,7 +389,7 @@ class AwesomeStrategy(IStrategy): !!! Warning Modifying entry and exit prices will only work for limit orders. Depending on the price chosen, this can result in a lot of unfilled orders. By default the maximum allowed distance between the current price and the custom price is 2%, this value can be changed in config with the `custom_price_max_distance_ratio` parameter. - **Example**: + **Example**: If the new_entryprice is 97, the proposed_rate is 100 and the `custom_price_max_distance_ratio` is set to 2%, The retained valid custom entry price will be 98, which is 2% below the current (proposed) rate. !!! Warning "Backtesting" @@ -690,14 +690,16 @@ class DigDeeperStrategy(IStrategy): ``` -## Readjust Entry Price +## Adjust Entry Price -The `readjust_entry_price()` callback may be used by strategy developer to refresh/replace limit orders upon arrival of new candles. +The `adjust_entry_price()` callback may be used by strategy developer to refresh/replace limit orders upon arrival of new candles. Be aware that `custom_entry_price()` is still the one dictating initial entry limit order price target at the time of entry trigger. -!!! Warning This mechanism will not trigger if previous orders were partially or fully filled. +!!! Note "Simple Order Cancelation" + This also allows simple cancelation without an replacement order. This behavior occurs when `None` is returned. -!!! Warning Entry `unfilledtimeout` mechanism takes precedence over this. Be sure to update timeout values to match your expectancy. +!!! Warning + Entry `unfilledtimeout` mechanism takes precedence over this. Be sure to update timeout values to match your expectancy. ```python from freqtrade.persistence import Trade @@ -707,13 +709,17 @@ class AwesomeStrategy(IStrategy): # ... populate_* methods - def readjust_entry_price(self, pair: str, current_time: datetime, proposed_rate: float, - entry_tag: Optional[str], side: str, **kwargs) -> float: + def adjust_entry_price(self, trade: Trade, order: Order, pair: str, + current_time: datetime, proposed_rate: float, + entry_tag: Optional[str], side: str, **kwargs) -> float: """ - Entry price readjustment logic, returning the readjusted entry price. + Entry price re-adjustment logic, returning the user desired limit price. + This only executes when a order was already placed, still open(unfilled fully or partially) + and not timed out on subsequent candles after entry trigger. :param pair: Pair that's currently analyzed :param trade: Trade object. + :param order: Order object :param current_time: datetime object, containing the current datetime :param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. @@ -724,9 +730,13 @@ class AwesomeStrategy(IStrategy): """ # Limit orders to use and follow SMA200 as price target for the first 10 minutes since entry trigger for BTC/USDT pair. if pair == 'BTC/USDT' and entry_tag == 'long_sma200' and side == 'long' and (current_time - timedelta(minutes=10) > trade.open_date_utc: - dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) - current_candle = dataframe.iloc[-1].squeeze() - return current_candle['sma_200'] + # just cancel the order if it has been filled more than half of the ammount + if order.filled > order.remaining: + return None + else: + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + return current_candle['sma_200'] return proposed_rate ``` From 2cac1b7dcc1e026a1529787ed7889d24167a9dde Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 18 Apr 2022 21:14:35 +0300 Subject: [PATCH 014/449] Add new (user cancellation) reason. --- freqtrade/constants.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index cd04a71f1..fba6c968d 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -479,6 +479,7 @@ CANCEL_REASON = { "CANCELLED_ON_EXCHANGE": "cancelled on exchange", "FORCE_EXIT": "forcesold", "REPLACE": "cancelled to be replaced by new limit order", + "USER_CANCEL": "user requested order cancel" } # List of pairs with their timeframes From 95e009b9cbbe872333474fd39cd900fb95bb4247 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 18 Apr 2022 21:16:45 +0300 Subject: [PATCH 015/449] Update adjustment functionality and add cancelation option --- freqtrade/freqtradebot.py | 53 ++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index a020754eb..8d710a760 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1147,13 +1147,13 @@ class FreqtradeBot(LoggingMixin): if not_closed: if fully_cancelled or (order_obj and self.strategy.ft_check_timed_out( trade, order_obj, datetime.now(timezone.utc))): - self.handle_timedout_orders(order, trade) + self.handle_timedout_order(order, trade) else: - self.replace_orders(order, order_obj, trade) + self.replace_order(order, order_obj, trade) - def handle_timedout_orders(self, order: Dict, trade: Trade) -> None: + def handle_timedout_order(self, order: Dict, trade: Trade) -> None: """ - Check if any orders are timed out and cancel if necessary. + Check if current analyzed order timed out and cancel if necessary. :param order: Order dict grabbed with exchange.fetch_order() :param trade: Trade object. :return: None @@ -1176,9 +1176,11 @@ class FreqtradeBot(LoggingMixin): logger.warning( f'Unable to emergency sell trade {trade.pair}: {exception}') - def replace_orders(self, order: Dict, order_obj: Optional[Order], trade: Trade) -> None: + def replace_order(self, order: Dict, order_obj: Optional[Order], trade: Trade) -> None: """ - Check if any orders should be replaced and do so + Check if current analyzed entry order should be replaced. Analyzed order is canceled + if adjust_entry_price() returned price differs from proposed_rate. + New order is only placed if adjust_entry_price() returned price is not None. :param order: Order dict grabbed with exchange.fetch_order() :param order_obj: Order object. :param trade: Trade object. @@ -1194,25 +1196,30 @@ class FreqtradeBot(LoggingMixin): # New candle proposed_rate = self.exchange.get_rate( trade.pair, side='entry', is_short=trade.is_short, refresh=True) - adjusted_entry_price = strategy_safe_wrapper(self.strategy.readjust_entry_price, + adjusted_entry_price = strategy_safe_wrapper(self.strategy.adjust_entry_price, default_retval=proposed_rate)( - pair=trade.pair, current_time=datetime.now(timezone.utc), - proposed_rate=proposed_rate, entry_tag=trade.enter_tag, - side=trade.entry_side) - # check if user has requested entry limit adjustment + trade=trade, order=order_obj, pair=trade.pair, + current_time=datetime.now(timezone.utc), proposed_rate=proposed_rate, + entry_tag=trade.enter_tag, side=trade.entry_side) + + full_cancel = False + cancel_reason = constants.CANCEL_REASON['REPLACE'] + if not adjusted_entry_price: + full_cancel = True + cancel_reason = constants.CANCEL_REASON['USER_CANCEL'] if proposed_rate != adjusted_entry_price: - # cancel existing order - self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['REPLACE'], - allow_full_cancel=False) - stake = self.wallets.get_trade_stake_amount(trade.pair, self.edge) - # place new order with requested price - self.execute_entry( - pair=trade.pair, - stake_amount=stake, - price=adjusted_entry_price, - trade=trade, - is_short=trade.is_short - ) + # cancel existing order if new price is supplied or None + self.handle_cancel_enter(trade, order, cancel_reason, + allow_full_cancel=full_cancel) + if adjusted_entry_price: + # place new order only if new price is supplied + self.execute_entry( + pair=trade.pair, + stake_amount=(order_obj.remaining * order_obj.price), + price=adjusted_entry_price, + trade=trade, + is_short=trade.is_short + ) def cancel_all_open_orders(self) -> None: """ From 3166739ec9a1f211c72f922b8157619d56538148 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 18 Apr 2022 21:17:39 +0300 Subject: [PATCH 016/449] Update strategy callback params and description. --- freqtrade/strategy/interface.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 57fd07042..01473391a 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -467,18 +467,22 @@ class IStrategy(ABC, HyperStrategyMixin): """ return None - def readjust_entry_price(self, trade: Trade, pair: str, current_time: datetime, - proposed_rate: float, entry_tag: Optional[str], - side: str, **kwargs) -> float: + def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str, + current_time: datetime, proposed_rate: float, + entry_tag: Optional[str], side: str, **kwargs) -> float: """ - Entry price readjustment logic, returning the readjusted entry price. - This only executes when a order was already placed, open(unfilled) and not timed out on - subsequent candles. + Entry price re-adjustment logic, returning the user desired limit price. + This only executes when a order was already placed, still open(unfilled fully or partially) + and not timed out on subsequent candles after entry trigger. For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/ + When not implemented by a strategy, returns proposed_stake. + If None is returned then order gets canceled but not replaced by a new one. + :param pair: Pair that's currently analyzed :param trade: Trade object. + :param order: Order object :param current_time: datetime object, containing the current datetime :param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. From d9f838a65f23f39ea3d4b8c6ffc34d8d5e478422 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 18 Apr 2022 21:20:50 +0300 Subject: [PATCH 017/449] Update template usage to reflect changes. --- .../subtemplates/strategy_methods_advanced.j2 | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 90dbade91..db64b3e07 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -30,26 +30,31 @@ def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: """ return proposed_rate -def readjust_entry_price(self, trade: Trade, pair: str, current_time: datetime, - proposed_rate: float, entry_tag: Optional[str], - side: str, **kwargs) -> float: - """ - Entry price readjustment logic, returning the readjusted entry price. + def adjust_entry_price(self, trade: Trade, order: Order, pair: str, + current_time: datetime, proposed_rate: float, + entry_tag: Optional[str], side: str, **kwargs) -> float: + """ + Entry price re-adjustment logic, returning the user desired limit price. + This only executes when a order was already placed, still open(unfilled fully or partially) + and not timed out on subsequent candles after entry trigger. - For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ + For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ - When not implemented by a strategy, returns proposed_rate and orders are not replaced. + When not implemented by a strategy, returns proposed_stake. + If None is returned then order gets canceled but not replaced by a new one. - :param pair: Pair that's currently analyzed - :param trade: Trade object. - :param current_time: datetime object, containing the current datetime - :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing. - :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. - :param side: 'long' or 'short' - indicating the direction of the proposed trade - :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. - :return float: New entry price value if provided - """ - return proposed_rate + :param pair: Pair that's currently analyzed + :param trade: Trade object. + :param order: Order object + :param current_time: datetime object, containing the current datetime + :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing. + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. + :param side: 'long' or 'short' - indicating the direction of the proposed trade + :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. + :return float: New entry price value if provided + + """ + return proposed_rate def custom_exit_price(self, pair: str, trade: 'Trade', current_time: 'datetime', proposed_rate: float, From d24ee9032a46e59f57fdb256637a02c813ef98cd Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 18 Apr 2022 21:21:38 +0300 Subject: [PATCH 018/449] Update usage in backtest. No functional update. --- freqtrade/optimize/backtesting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index f91013585..bf666abf2 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -646,7 +646,7 @@ class Backtesting: side=direction, ) # default value is the open rate if readjust_req: - propose_rate = strategy_safe_wrapper(self.strategy.readjust_entry_price, + propose_rate = strategy_safe_wrapper(self.strategy.adjust_entry_price, default_retval=propose_rate)( pair=pair, current_time=current_time, proposed_rate=propose_rate, entry_tag=entry_tag, From 76558f284f15c50264dba74f83bc58ff756d37c8 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 19 Apr 2022 13:33:37 +0300 Subject: [PATCH 019/449] Fix user cancellation functionality. --- freqtrade/freqtradebot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 8d710a760..9febe64fe 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1284,7 +1284,8 @@ class FreqtradeBot(LoggingMixin): if isclose(filled_amount, 0.0, abs_tol=constants.MATH_CLOSE_PREC): logger.info(f'{side} order fully cancelled. Removing {trade} from database.') # if trade is not partially completed and it's the only order, just delete the trade - if len(trade.orders) <= 1 and allow_full_cancel: + open_order_count = len([order for order in trade.orders if order.status == 'open']) + if open_order_count <= 1 and allow_full_cancel: trade.delete() was_trade_fully_canceled = True reason += f", {constants.CANCEL_REASON['FULLY_CANCELLED']}" From 17650d7e6025385f8d9dbd3dbe44d097b50ce9eb Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Fri, 29 Apr 2022 00:10:17 +0300 Subject: [PATCH 020/449] Maintain existing order. Update functionality and documentation --- docs/strategy-callbacks.md | 20 ++++++--- freqtrade/freqtradebot.py | 14 +++--- freqtrade/strategy/interface.py | 12 ++--- .../subtemplates/strategy_methods_advanced.j2 | 44 ++++++++++--------- 4 files changed, 53 insertions(+), 37 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 8da8bab0f..7f86f2610 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -698,6 +698,9 @@ Be aware that `custom_entry_price()` is still the one dictating initial entry li !!! Note "Simple Order Cancelation" This also allows simple cancelation without an replacement order. This behavior occurs when `None` is returned. +!!! Note "Maintaining Order" + Maintaining existing order on exchange is facilitated. This behavior occurs when `order.price` is returned. + !!! Warning Entry `unfilledtimeout` mechanism takes precedence over this. Be sure to update timeout values to match your expectancy. @@ -709,19 +712,24 @@ class AwesomeStrategy(IStrategy): # ... populate_* methods - def adjust_entry_price(self, trade: Trade, order: Order, pair: str, - current_time: datetime, proposed_rate: float, - entry_tag: Optional[str], side: str, **kwargs) -> float: + def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str, + current_time: datetime, proposed_rate: float, current_order_rate: float, + entry_tag: Optional[str], side: str, **kwargs) -> float: """ Entry price re-adjustment logic, returning the user desired limit price. This only executes when a order was already placed, still open(unfilled fully or partially) and not timed out on subsequent candles after entry trigger. + When not implemented by a strategy, returns current_order_rate as default. + If current_order_rate is returned then the existing order is maintained. + If None is returned then order gets canceled but not replaced by a new one. + :param pair: Pair that's currently analyzed :param trade: Trade object. :param order: Order object :param current_time: datetime object, containing the current datetime - :param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. + :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing. + :param current_order_rate: Rate of the existing order in place. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param side: 'long' or 'short' - indicating the direction of the proposed trade :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. @@ -736,8 +744,10 @@ class AwesomeStrategy(IStrategy): else: dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) current_candle = dataframe.iloc[-1].squeeze() + # desired price return current_candle['sma_200'] - return proposed_rate + # default: maintain existing order + return current_order_rate ``` ## Leverage Callback diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index b55fee35f..330bfcdf0 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1165,9 +1165,10 @@ class FreqtradeBot(LoggingMixin): def replace_order(self, order: Dict, order_obj: Optional[Order], trade: Trade) -> None: """ - Check if current analyzed entry order should be replaced. Analyzed order is canceled - if adjust_entry_price() returned price differs from proposed_rate. - New order is only placed if adjust_entry_price() returned price is not None. + Check if current analyzed entry order should be replaced or simply cancelled. + To simply cancel the existing order(no replacement) adjust_entry_price() should return None + To maintain existing order adjust_entry_price() should return order_obj.price + To replace existing order adjust_entry_price() should return desired price for limit order :param order: Order dict grabbed with exchange.fetch_order() :param order_obj: Order object. :param trade: Trade object. @@ -1184,17 +1185,18 @@ class FreqtradeBot(LoggingMixin): proposed_rate = self.exchange.get_rate( trade.pair, side='entry', is_short=trade.is_short, refresh=True) adjusted_entry_price = strategy_safe_wrapper(self.strategy.adjust_entry_price, - default_retval=proposed_rate)( + default_retval=order_obj.price)( trade=trade, order=order_obj, pair=trade.pair, current_time=datetime.now(timezone.utc), proposed_rate=proposed_rate, - entry_tag=trade.enter_tag, side=trade.entry_side) + current_order_rate=order_obj.price, entry_tag=trade.enter_tag, + side=trade.entry_side) full_cancel = False cancel_reason = constants.CANCEL_REASON['REPLACE'] if not adjusted_entry_price: full_cancel = True cancel_reason = constants.CANCEL_REASON['USER_CANCEL'] - if proposed_rate != adjusted_entry_price: + if order_obj.price != adjusted_entry_price: # cancel existing order if new price is supplied or None self.handle_cancel_enter(trade, order, cancel_reason, allow_full_cancel=full_cancel) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 0a7580b6f..a472a6943 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -465,30 +465,32 @@ class IStrategy(ABC, HyperStrategyMixin): return None def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str, - current_time: datetime, proposed_rate: float, + current_time: datetime, proposed_rate: float, current_order_rate: float, entry_tag: Optional[str], side: str, **kwargs) -> float: """ Entry price re-adjustment logic, returning the user desired limit price. This only executes when a order was already placed, still open(unfilled fully or partially) and not timed out on subsequent candles after entry trigger. - For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/ + For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ - When not implemented by a strategy, returns proposed_stake. + When not implemented by a strategy, returns current_order_rate as default. + If current_order_rate is returned then the existing order is maintained. If None is returned then order gets canceled but not replaced by a new one. :param pair: Pair that's currently analyzed :param trade: Trade object. :param order: Order object :param current_time: datetime object, containing the current datetime - :param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. + :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing. + :param current_order_rate: Rate of the existing order in place. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param side: 'long' or 'short' - indicating the direction of the proposed trade :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. :return float: New entry price value if provided """ - return proposed_rate + return current_order_rate def leverage(self, pair: str, current_time: datetime, current_rate: float, proposed_leverage: float, max_leverage: float, side: str, diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 176f567c7..7f9671bb1 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -30,31 +30,33 @@ def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: """ return proposed_rate - def adjust_entry_price(self, trade: Trade, order: Order, pair: str, - current_time: datetime, proposed_rate: float, - entry_tag: Optional[str], side: str, **kwargs) -> float: - """ - Entry price re-adjustment logic, returning the user desired limit price. - This only executes when a order was already placed, still open(unfilled fully or partially) - and not timed out on subsequent candles after entry trigger. +def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str, + current_time: datetime, proposed_rate: float, current_order_rate: float, + entry_tag: Optional[str], side: str, **kwargs) -> float: + """ + Entry price re-adjustment logic, returning the user desired limit price. + This only executes when a order was already placed, still open(unfilled fully or partially) + and not timed out on subsequent candles after entry trigger. - For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ + For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ - When not implemented by a strategy, returns proposed_stake. - If None is returned then order gets canceled but not replaced by a new one. + When not implemented by a strategy, returns current_order_rate as default. + If current_order_rate is returned then the existing order is maintained. + If None is returned then order gets canceled but not replaced by a new one. - :param pair: Pair that's currently analyzed - :param trade: Trade object. - :param order: Order object - :param current_time: datetime object, containing the current datetime - :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing. - :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. - :param side: 'long' or 'short' - indicating the direction of the proposed trade - :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. - :return float: New entry price value if provided + :param pair: Pair that's currently analyzed + :param trade: Trade object. + :param order: Order object + :param current_time: datetime object, containing the current datetime + :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing. + :param current_order_rate: Rate of the existing order in place. + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. + :param side: 'long' or 'short' - indicating the direction of the proposed trade + :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. + :return float: New entry price value if provided - """ - return proposed_rate + """ + return current_order_rate def custom_exit_price(self, pair: str, trade: 'Trade', current_time: 'datetime', proposed_rate: float, From f9977c26e7f682346f875f30fd8b11a9f19cc867 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 30 Apr 2022 12:55:03 +0300 Subject: [PATCH 021/449] Full cancel only for non DCA trades. --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 330bfcdf0..49c7050c9 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1194,7 +1194,7 @@ class FreqtradeBot(LoggingMixin): full_cancel = False cancel_reason = constants.CANCEL_REASON['REPLACE'] if not adjusted_entry_price: - full_cancel = True + full_cancel = True if trade.nr_of_successful_entries == 0 else False cancel_reason = constants.CANCEL_REASON['USER_CANCEL'] if order_obj.price != adjusted_entry_price: # cancel existing order if new price is supplied or None From ad0c5d944034228f8e17ba658b3b3e1d8ff4af72 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 30 Apr 2022 13:38:17 +0300 Subject: [PATCH 022/449] Refactor entry adjustment for backtesting. --- freqtrade/optimize/backtesting.py | 73 +++++++++++++++++++------------ 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 02867d157..d567e1159 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -650,7 +650,7 @@ class Backtesting: def get_valid_price_and_stake( self, pair: str, row: Tuple, propose_rate: float, stake_amount: Optional[float], direction: LongShort, current_time: datetime, entry_tag: Optional[str], - trade: Optional[LocalTrade], order_type: str, readjust_req: Optional[bool] = False + trade: Optional[LocalTrade], order_type: str ) -> Tuple[float, float, float, float]: if order_type == 'limit': @@ -660,13 +660,6 @@ class Backtesting: proposed_rate=propose_rate, entry_tag=entry_tag, side=direction, ) # default value is the open rate - if readjust_req: - propose_rate = strategy_safe_wrapper(self.strategy.adjust_entry_price, - default_retval=propose_rate)( - pair=pair, current_time=current_time, - proposed_rate=propose_rate, entry_tag=entry_tag, - side=direction - ) # default value is open rate or custom rate from before # We can't place orders higher than current high (otherwise it'd be a stop limit buy) # which freqtrade does not support in live. @@ -675,7 +668,7 @@ class Backtesting: else: propose_rate = min(propose_rate, row[HIGH_IDX]) - pos_adjust = trade is not None and readjust_req is False + pos_adjust = trade is not None leverage = trade.leverage if trade else 1.0 if not pos_adjust: try: @@ -721,19 +714,24 @@ class Backtesting: def _enter_trade(self, pair: str, row: Tuple, direction: LongShort, stake_amount: Optional[float] = None, trade: Optional[LocalTrade] = None, - readjust_req: Optional[bool] = False) -> Optional[LocalTrade]: + requested_rate: Optional[float] = None, + requested_stake: Optional[float] = None) -> Optional[LocalTrade]: current_time = row[DATE_IDX].to_pydatetime() entry_tag = row[ENTER_TAG_IDX] if len(row) >= ENTER_TAG_IDX + 1 else None # let's call the custom entry price, using the open price as default price order_type = self.strategy.order_types['entry'] - pos_adjust = trade is not None and readjust_req is False + pos_adjust = trade is not None and requested_rate is None propose_rate, stake_amount, leverage, min_stake_amount = self.get_valid_price_and_stake( pair, row, row[OPEN_IDX], stake_amount, direction, current_time, entry_tag, trade, - order_type, readjust_req + order_type ) + # replace proposed rate if another rate was requested + propose_rate = requested_rate if requested_rate else propose_rate + stake_amount = requested_stake if requested_stake else stake_amount + if not stake_amount: # In case of pos adjust, still return the original trade # If not pos adjust, trade is None @@ -874,20 +872,36 @@ class Backtesting: self.protections.stop_per_pair(pair, current_time) self.protections.global_stop(current_time) - def check_order_replace(self, trade: LocalTrade, current_time, row: Tuple) -> None: + def check_order_replace(self, trade: LocalTrade, current_time, row: Tuple) -> bool: """ - Check if an entry order has to be replaced and do so. - Returns None. + Check if an entry order has to be replaced and do so. If user requested cancellation + and there are no filled orders in the trade will instruct caller to delete the trade. + Returns True if the trade should be deleted. """ for order in [o for o in trade.orders if o.ft_is_open]: + # only check on new candles for open entry orders if order.side == trade.entry_side and current_time > order.order_date_utc: - # cancel existing order - del trade.orders[trade.orders.index(order)] + requested_rate = strategy_safe_wrapper(self.strategy.adjust_entry_price, + default_retval=order.price)( + trade=trade, order=order, pair=trade.pair, current_time=current_time, + proposed_rate=row[OPEN_IDX], current_order_rate=order.price, + entry_tag=trade.enter_tag, side=trade.trade_direction + ) # default value is current order price - # place new order - self._enter_trade(pair=trade.pair, row=row, trade=trade, - direction='short' if trade.is_short else 'long', - readjust_req=True) + # cancel existing order whenever a new rate is requested (or None) + if requested_rate != order.price: + del trade.orders[trade.orders.index(order)] + + # place new order if None was not returned + if requested_rate: + self._enter_trade(pair=trade.pair, row=row, trade=trade, + requested_rate=requested_rate, + requested_stake=(order.remaining * order.price), + direction='short' if trade.is_short else 'long') + else: + # assumption: there can't be multiple open entry orders at any given time + return (trade.nr_of_successful_entries == 0) + return False def check_order_cancel(self, trade: LocalTrade, current_time) -> bool: """ @@ -983,15 +997,16 @@ class Backtesting: for t in list(open_trades[pair]): # 1. Cancel expired entry/exit orders. - if self.check_order_cancel(t, current_time): - # Close trade due to entry timeout expiration. + order_cancel = self.check_order_cancel(t, current_time) + # 2. Replace/cancel (user requested) entry orders. + order_replace = self.check_order_replace(t, current_time, row) + if order_cancel or order_replace: + # Close trade due to entry timeout expiration or cancellation. open_trade_count -= 1 open_trades[pair].remove(t) self.wallets.update() - else: - self.check_order_replace(t, current_time, row) - # 2. Process entries. + # 3. Process entries. # without positionstacking, we can only have one open trade per pair. # max_open_trades must be respected # don't open on the last row @@ -1014,7 +1029,7 @@ class Backtesting: open_trades[pair].append(trade) for trade in list(open_trades[pair]): - # 3. Process entry orders. + # 4. Process entry orders. order = trade.select_order(trade.entry_side, is_open=True) if order and self._get_order_filled(order.price, row): order.close_bt_order(current_time) @@ -1022,11 +1037,11 @@ class Backtesting: LocalTrade.add_bt_trade(trade) self.wallets.update() - # 4. Create exit orders (if any) + # 5. Create exit orders (if any) if not trade.open_order_id: self._get_exit_trade_entry(trade, row) # Place exit order if necessary - # 5. Process exit orders. + # 6. Process exit orders. order = trade.select_order(trade.exit_side, is_open=True) if order and self._get_order_filled(order.price, row): trade.open_order_id = None From 8c19953cdd3c1aab5143d0ef8e5c6d2a442cf382 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sun, 1 May 2022 12:08:19 +0300 Subject: [PATCH 023/449] Quick exit when order should be maintained. --- freqtrade/optimize/backtesting.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 4485d3da3..e42bfd2ea 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -890,7 +890,10 @@ class Backtesting: ) # default value is current order price # cancel existing order whenever a new rate is requested (or None) - if requested_rate != order.price: + if requested_rate == order.price: + # assumption: there can't be multiple open entry orders at any given time + return False + else: del trade.orders[trade.orders.index(order)] # place new order if None was not returned From 9d205132d0fb54df99a7f2b5d0a59520e07eab1b Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sun, 1 May 2022 12:10:11 +0300 Subject: [PATCH 024/449] Revert unintended comment change. --- freqtrade/optimize/backtesting.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index e42bfd2ea..1ee96d015 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -661,8 +661,7 @@ class Backtesting: proposed_rate=propose_rate, entry_tag=entry_tag, side=direction, ) # default value is the open rate - - # We can't place orders higher than current high (otherwise it'd be a stop limit buy) + # We can't place orders higher than current high (otherwise it'd be a stop limit entry) # which freqtrade does not support in live. if direction == "short": propose_rate = max(propose_rate, row[LOW_IDX]) From 4e43194dfeefb135e3a567659dba605bb501b10d Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sun, 1 May 2022 18:06:20 +0300 Subject: [PATCH 025/449] BT: Refactor open order management. --- freqtrade/optimize/backtesting.py | 121 ++++++++++++++++-------------- 1 file changed, 66 insertions(+), 55 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 1ee96d015..d54c0e5a9 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -872,64 +872,78 @@ class Backtesting: self.protections.stop_per_pair(pair, current_time) self.protections.global_stop(current_time) - def check_order_replace(self, trade: LocalTrade, current_time, row: Tuple) -> bool: + def manage_open_orders(self, trade: LocalTrade, current_time, row: Tuple) -> bool: """ - Check if an entry order has to be replaced and do so. If user requested cancellation - and there are no filled orders in the trade will instruct caller to delete the trade. + Check if any open order needs to be cancelled or replaced. Returns True if the trade should be deleted. """ for order in [o for o in trade.orders if o.ft_is_open]: - # only check on new candles for open entry orders - if order.side == trade.entry_side and current_time > order.order_date_utc: - requested_rate = strategy_safe_wrapper(self.strategy.adjust_entry_price, - default_retval=order.price)( - trade=trade, order=order, pair=trade.pair, current_time=current_time, - proposed_rate=row[OPEN_IDX], current_order_rate=order.price, - entry_tag=trade.enter_tag, side=trade.trade_direction - ) # default value is current order price - - # cancel existing order whenever a new rate is requested (or None) - if requested_rate == order.price: - # assumption: there can't be multiple open entry orders at any given time - return False - else: - del trade.orders[trade.orders.index(order)] - - # place new order if None was not returned - if requested_rate: - self._enter_trade(pair=trade.pair, row=row, trade=trade, - requested_rate=requested_rate, - requested_stake=(order.remaining * order.price), - direction='short' if trade.is_short else 'long') - else: - # assumption: there can't be multiple open entry orders at any given time - return (trade.nr_of_successful_entries == 0) + if self.check_order_cancel(trade, order, current_time): + # delete trade due to order timeout + return True + elif self.check_order_replace(trade, order, current_time, row): + # delete trade due to user request + return True + # default maintain trade return False - def check_order_cancel(self, trade: LocalTrade, current_time) -> bool: + def check_order_cancel(self, trade: LocalTrade, order: Order, current_time) -> bool: """ - Check if an order has been canceled. + Check if current analyzed order has to be canceled. Returns True if the trade should be Deleted (initial order was canceled). """ - for order in [o for o in trade.orders if o.ft_is_open]: - - timedout = self.strategy.ft_check_timed_out(trade, order, current_time) - if timedout: - if order.side == trade.entry_side: - self.timedout_entry_orders += 1 - if trade.nr_of_successful_entries == 0: - # Remove trade due to entry timeout expiration. - return True - else: - # Close additional entry order - del trade.orders[trade.orders.index(order)] - if order.side == trade.exit_side: - self.timedout_exit_orders += 1 - # Close exit order and retry exiting on next signal. + timedout = self.strategy.ft_check_timed_out(trade, order, current_time) + if timedout: + if order.side == trade.entry_side: + self.timedout_entry_orders += 1 + if trade.nr_of_successful_entries == 0: + # Remove trade due to entry timeout expiration. + return True + else: + # Close additional entry order del trade.orders[trade.orders.index(order)] + if order.side == trade.exit_side: + self.timedout_exit_orders += 1 + # Close exit order and retry exiting on next signal. + del trade.orders[trade.orders.index(order)] return False + def check_order_replace(self, trade: LocalTrade, order: Order, current_time, + row: Tuple) -> bool: + """ + Check if current analyzed entry order has to be replaced and do so. + If user requested cancellation and there are no filled orders in the trade will + instruct caller to delete the trade. + Returns True if the trade should be deleted. + """ + # only check on new candles for open entry orders + if order.side == trade.entry_side and current_time > order.order_date_utc: + requested_rate = strategy_safe_wrapper(self.strategy.adjust_entry_price, + default_retval=order.price)( + trade=trade, order=order, pair=trade.pair, current_time=current_time, + proposed_rate=row[OPEN_IDX], current_order_rate=order.price, + entry_tag=trade.enter_tag, side=trade.trade_direction + ) # default value is current order price + + # cancel existing order whenever a new rate is requested (or None) + if requested_rate == order.price: + # assumption: there can't be multiple open entry orders at any given time + return False + else: + del trade.orders[trade.orders.index(order)] + + # place new order if None was not returned + if requested_rate: + self._enter_trade(pair=trade.pair, row=row, trade=trade, + requested_rate=requested_rate, + requested_stake=(order.remaining * order.price), + direction='short' if trade.is_short else 'long') + else: + # assumption: there can't be multiple open entry orders at any given time + return (trade.nr_of_successful_entries == 0) + return False + def validate_row( self, data: Dict, pair: str, row_index: int, current_time: datetime) -> Optional[Tuple]: try: @@ -999,17 +1013,14 @@ class Backtesting: self.dataprovider._set_dataframe_max_index(row_index) for t in list(open_trades[pair]): - # 1. Cancel expired entry/exit orders. - order_cancel = self.check_order_cancel(t, current_time) - # 2. Replace/cancel (user requested) entry orders. - order_replace = self.check_order_replace(t, current_time, row) - if order_cancel or order_replace: - # Close trade due to entry timeout expiration or cancellation. + # 1. Manage currently open orders of active trades + if self.manage_open_orders(t, current_time, row): + # Close trade open_trade_count -= 1 open_trades[pair].remove(t) self.wallets.update() - # 3. Process entries. + # 2. Process entries. # without positionstacking, we can only have one open trade per pair. # max_open_trades must be respected # don't open on the last row @@ -1032,7 +1043,7 @@ class Backtesting: open_trades[pair].append(trade) for trade in list(open_trades[pair]): - # 4. Process entry orders. + # 3. Process entry orders. order = trade.select_order(trade.entry_side, is_open=True) if order and self._get_order_filled(order.price, row): order.close_bt_order(current_time) @@ -1040,11 +1051,11 @@ class Backtesting: LocalTrade.add_bt_trade(trade) self.wallets.update() - # 5. Create exit orders (if any) + # 4. Create exit orders (if any) if not trade.open_order_id: self._get_exit_trade_entry(trade, row) # Place exit order if necessary - # 6. Process exit orders. + # 5. Process exit orders. order = trade.select_order(trade.exit_side, is_open=True) if order and self._get_order_filled(order.price, row): trade.open_order_id = None From b83cd95a026b759814eba0ff98455d0b3ec86c0f Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 2 May 2022 18:07:48 +0300 Subject: [PATCH 026/449] Tests: add basic testcases for entry adjustment. --- tests/test_freqtradebot.py | 102 +++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index e3785e67e..e58619bc0 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2450,6 +2450,7 @@ def test_manage_open_orders_entry( Trade.query.session.add(open_trade) freqtrade.strategy.check_entry_timeout = MagicMock(return_value=False) + freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1234) # check it does cancel buy orders over the time limit freqtrade.manage_open_orders() assert cancel_order_mock.call_count == 1 @@ -2459,6 +2460,107 @@ def test_manage_open_orders_entry( assert nb_trades == 0 # Custom user buy-timeout is never called assert freqtrade.strategy.check_entry_timeout.call_count == 0 + # Entry adjustment is never called + assert freqtrade.strategy.adjust_entry_price.call_count == 0 + + +@pytest.mark.parametrize("is_short", [False, True]) +def test_adjust_entry_cancel( + default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, + limit_sell_order_old, fee, mocker, caplog, is_short +) -> None: + old_order = limit_sell_order_old if is_short else limit_buy_order_old + old_order['id'] = open_trade.open_order_id + limit_buy_cancel = deepcopy(old_order) + limit_buy_cancel['status'] = 'canceled' + cancel_order_mock = MagicMock(return_value=limit_buy_cancel) + patch_exchange(mocker) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + fetch_ticker=ticker_usdt, + fetch_order=MagicMock(return_value=old_order), + cancel_order_with_result=cancel_order_mock, + get_fee=fee + ) + freqtrade = FreqtradeBot(default_conf_usdt) + + open_trade.is_short = is_short + Trade.query.session.add(open_trade) + + # Timeout to not interfere + freqtrade.strategy.ft_check_timed_out = MagicMock(return_value=False) + + # check that order is cancelled + freqtrade.strategy.adjust_entry_price = MagicMock(return_value=None) + freqtrade.manage_open_orders() + trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() + nb_trades = len(trades) + assert nb_trades == 0 + nb_all_orders = len(Order.query.all()) + assert nb_all_orders == 0 + assert log_has_re( + f"{'Sell' if is_short else 'Buy'} order user requested order cancel*", caplog) + assert log_has_re( + f"{'Sell' if is_short else 'Buy'} order fully cancelled.*", caplog) + + # Entry adjustment is called + assert freqtrade.strategy.adjust_entry_price.call_count == 1 + + +@pytest.mark.parametrize("is_short", [False, True]) +def test_adjust_entry_maintain_replace( + default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, + limit_sell_order_old, fee, mocker, caplog, is_short +) -> None: + old_order = limit_sell_order_old if is_short else limit_buy_order_old + old_order['id'] = open_trade.open_order_id + limit_buy_cancel = deepcopy(old_order) + limit_buy_cancel['status'] = 'canceled' + cancel_order_mock = MagicMock(return_value=limit_buy_cancel) + patch_exchange(mocker) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + fetch_ticker=ticker_usdt, + fetch_order=MagicMock(return_value=old_order), + cancel_order_with_result=cancel_order_mock, + get_fee=fee + ) + freqtrade = FreqtradeBot(default_conf_usdt) + + open_trade.is_short = is_short + Trade.query.session.add(open_trade) + + # Timeout to not interfere + freqtrade.strategy.ft_check_timed_out = MagicMock(return_value=False) + + # Check that order is maintained + freqtrade.strategy.adjust_entry_price = MagicMock(return_value=old_order['price']) + freqtrade.manage_open_orders() + trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() + nb_trades = len(trades) + assert nb_trades == 1 + nb_orders = len(Order.get_open_orders()) + assert nb_orders == 1 + # Entry adjustment is called + assert freqtrade.strategy.adjust_entry_price.call_count == 1 + + # Check that order is replaced + freqtrade.get_valid_enter_price_and_stake = MagicMock(return_value={100, 10, 1}) + freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1234) + freqtrade.manage_open_orders() + trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() + nb_trades = len(trades) + assert nb_trades == 1 + nb_all_orders = len(Order.query.all()) + freqtrade.logger.warning(Order.query.all()) + assert nb_all_orders == 2 + # New order seems to be in closed status? + # nb_open_orders = len(Order.get_open_orders()) + # assert nb_open_orders == 1 + assert log_has_re( + f"{'Sell' if is_short else 'Buy'} order cancelled to be replaced*", caplog) + # Entry adjustment is called + assert freqtrade.strategy.adjust_entry_price.call_count == 1 @pytest.mark.parametrize("is_short", [False, True]) From 59397cdd19ea23171e91145b70b0fcfb7b5efc0c Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 2 May 2022 18:09:28 +0300 Subject: [PATCH 027/449] Freqtradebot: Fix full cancel logging location. --- freqtrade/freqtradebot.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 9258b7ca2..c0ccf2688 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1123,6 +1123,7 @@ class FreqtradeBot(LoggingMixin): Timeout setting takes priority over limit order adjustment request. :return: None """ + logger.warning(Order.query.all()) for trade in Trade.get_open_order_trades(): try: if not trade.open_order_id: @@ -1150,6 +1151,7 @@ class FreqtradeBot(LoggingMixin): :param trade: Trade object. :return: None """ + logger.warning("handle_timedout_order") if order['side'] == trade.entry_side: self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT']) else: @@ -1179,6 +1181,8 @@ class FreqtradeBot(LoggingMixin): :param trade: Trade object. :return: None """ + logger.warning("replace_order") + logger.warning(f"Order: {order}, Trade:{trade}") analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair, self.strategy.timeframe) latest_candle_open_date = analyzed_df.iloc[-1]['date'] if len(analyzed_df) > 0 else None @@ -1195,6 +1199,7 @@ class FreqtradeBot(LoggingMixin): current_time=datetime.now(timezone.utc), proposed_rate=proposed_rate, current_order_rate=order_obj.price, entry_tag=trade.enter_tag, side=trade.entry_side) + logger.warning(f"adjusted_entry_price: {adjusted_entry_price}") full_cancel = False cancel_reason = constants.CANCEL_REASON['REPLACE'] @@ -1276,10 +1281,10 @@ class FreqtradeBot(LoggingMixin): # Using filled to determine the filled amount filled_amount = safe_value_fallback2(corder, order, 'filled', 'filled') if isclose(filled_amount, 0.0, abs_tol=constants.MATH_CLOSE_PREC): - logger.info(f'{side} order fully cancelled. Removing {trade} from database.') # if trade is not partially completed and it's the only order, just delete the trade open_order_count = len([order for order in trade.orders if order.status == 'open']) if open_order_count <= 1 and allow_full_cancel: + logger.info(f'{side} order fully cancelled. Removing {trade} from database.') trade.delete() was_trade_fully_canceled = True reason += f", {constants.CANCEL_REASON['FULLY_CANCELLED']}" From 4c7460107381dffba06004e0cba24e1df5dad00f Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Mon, 2 May 2022 18:22:41 +0300 Subject: [PATCH 028/449] Freqtradebot: Cleanup stray debug messages. --- freqtrade/freqtradebot.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c0ccf2688..c3ddccdd8 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1123,7 +1123,6 @@ class FreqtradeBot(LoggingMixin): Timeout setting takes priority over limit order adjustment request. :return: None """ - logger.warning(Order.query.all()) for trade in Trade.get_open_order_trades(): try: if not trade.open_order_id: @@ -1151,7 +1150,6 @@ class FreqtradeBot(LoggingMixin): :param trade: Trade object. :return: None """ - logger.warning("handle_timedout_order") if order['side'] == trade.entry_side: self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT']) else: @@ -1181,8 +1179,6 @@ class FreqtradeBot(LoggingMixin): :param trade: Trade object. :return: None """ - logger.warning("replace_order") - logger.warning(f"Order: {order}, Trade:{trade}") analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair, self.strategy.timeframe) latest_candle_open_date = analyzed_df.iloc[-1]['date'] if len(analyzed_df) > 0 else None @@ -1199,7 +1195,6 @@ class FreqtradeBot(LoggingMixin): current_time=datetime.now(timezone.utc), proposed_rate=proposed_rate, current_order_rate=order_obj.price, entry_tag=trade.enter_tag, side=trade.entry_side) - logger.warning(f"adjusted_entry_price: {adjusted_entry_price}") full_cancel = False cancel_reason = constants.CANCEL_REASON['REPLACE'] From ce035a59478d730aec8dd0e7d58a5baf68128a91 Mon Sep 17 00:00:00 2001 From: Mark Regan Date: Tue, 3 May 2022 23:34:12 +0100 Subject: [PATCH 029/449] Add bot_loop_start() call in plotting.py plotting.py was missing a call to strategy.bot_loop_start() resulting in strategies using this callback to not work. Made changes and confirmed plotting now works for strategies using bot_loop_start() callback. LMK if anything else needed for PR. --- freqtrade/plot/plotting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 37758d05f..ce8f54cbd 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -634,6 +634,7 @@ def load_and_plot_trades(config: Dict[str, Any]): exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config) IStrategy.dp = DataProvider(config, exchange) strategy.bot_start() + strategy.bot_loop_start() plot_elements = init_plotscript(config, list(exchange.markets), strategy.startup_candle_count) timerange = plot_elements['timerange'] trades = plot_elements['trades'] From 5c82cce06c8c9ccaefae297001b0405f7bcaed47 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 4 May 2022 06:40:12 +0200 Subject: [PATCH 030/449] Fix new test failures --- tests/test_freqtradebot.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index e58619bc0..f6d03db6b 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2469,12 +2469,12 @@ def test_adjust_entry_cancel( default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, limit_sell_order_old, fee, mocker, caplog, is_short ) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) old_order = limit_sell_order_old if is_short else limit_buy_order_old old_order['id'] = open_trade.open_order_id limit_buy_cancel = deepcopy(old_order) limit_buy_cancel['status'] = 'canceled' cancel_order_mock = MagicMock(return_value=limit_buy_cancel) - patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker_usdt, @@ -2482,7 +2482,6 @@ def test_adjust_entry_cancel( cancel_order_with_result=cancel_order_mock, get_fee=fee ) - freqtrade = FreqtradeBot(default_conf_usdt) open_trade.is_short = is_short Trade.query.session.add(open_trade) @@ -2512,12 +2511,12 @@ def test_adjust_entry_maintain_replace( default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, limit_sell_order_old, fee, mocker, caplog, is_short ) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) old_order = limit_sell_order_old if is_short else limit_buy_order_old old_order['id'] = open_trade.open_order_id limit_buy_cancel = deepcopy(old_order) limit_buy_cancel['status'] = 'canceled' cancel_order_mock = MagicMock(return_value=limit_buy_cancel) - patch_exchange(mocker) mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker_usdt, @@ -2525,7 +2524,6 @@ def test_adjust_entry_maintain_replace( cancel_order_with_result=cancel_order_mock, get_fee=fee ) - freqtrade = FreqtradeBot(default_conf_usdt) open_trade.is_short = is_short Trade.query.session.add(open_trade) From b2f33944eccbece5dd13600a380c72ab1de4255b Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 4 May 2022 07:13:02 +0200 Subject: [PATCH 031/449] Add preliminary backtesting test --- tests/optimize/__init__.py | 2 ++ tests/optimize/test_backtest_detail.py | 24 ++++++++++++++++++++++++ tests/test_freqtradebot.py | 19 ++++++------------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/tests/optimize/__init__.py b/tests/optimize/__init__.py index fc4125a42..a3dd59004 100644 --- a/tests/optimize/__init__.py +++ b/tests/optimize/__init__.py @@ -40,6 +40,8 @@ class BTContainer(NamedTuple): custom_entry_price: Optional[float] = None custom_exit_price: Optional[float] = None leverage: float = 1.0 + timeout: Optional[int] = None + adjust_entry_price: Optional[float] = None def _get_frame_time_from_offset(offset): diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index ea13de4c8..f2e2c89ad 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -754,6 +754,21 @@ tc47 = BTContainer(data=[ trades=[] ) +# Test 48: Custom-entry-price below all candles - readjust order +tc48 = BTContainer(data=[ + # D O H L C V EL XL ES Xs BT + [0, 5000, 5050, 4950, 5000, 6172, 1, 0], + [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # timeout + [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust + [3, 5100, 5100, 4650, 4750, 6172, 0, 0], + [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], + stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.1, + timeout=1000, + custom_entry_price=4200, + adjust_entry_price=5200, + trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2, is_short=False)] +) + TESTS = [ tc0, @@ -804,6 +819,7 @@ TESTS = [ tc45, tc46, tc47, + tc48, ] @@ -817,6 +833,11 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) default_conf["timeframe"] = tests_timeframe default_conf["trailing_stop"] = data.trailing_stop default_conf["trailing_only_offset_is_reached"] = data.trailing_only_offset_is_reached + if data.timeout: + default_conf['unfilledtimeout'].update({ + 'entry': data.timeout, + 'exit': data.timeout, + }) # Only add this to configuration If it's necessary if data.trailing_stop_positive is not None: default_conf["trailing_stop_positive"] = data.trailing_stop_positive @@ -840,6 +861,9 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) backtesting.strategy.custom_entry_price = MagicMock(return_value=data.custom_entry_price) if data.custom_exit_price: backtesting.strategy.custom_exit_price = MagicMock(return_value=data.custom_exit_price) + if data.adjust_entry_price: + backtesting.strategy.adjust_entry_price = MagicMock(return_value=data.adjust_entry_price) + backtesting.strategy.use_custom_stoploss = data.use_custom_stoploss backtesting.strategy.leverage = lambda **kwargs: data.leverage caplog.set_level(logging.DEBUG) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index f6d03db6b..e19d5f36a 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2493,10 +2493,8 @@ def test_adjust_entry_cancel( freqtrade.strategy.adjust_entry_price = MagicMock(return_value=None) freqtrade.manage_open_orders() trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() - nb_trades = len(trades) - assert nb_trades == 0 - nb_all_orders = len(Order.query.all()) - assert nb_all_orders == 0 + assert len(trades) == 0 + assert len(Order.query.all()) == 0 assert log_has_re( f"{'Sell' if is_short else 'Buy'} order user requested order cancel*", caplog) assert log_has_re( @@ -2535,10 +2533,8 @@ def test_adjust_entry_maintain_replace( freqtrade.strategy.adjust_entry_price = MagicMock(return_value=old_order['price']) freqtrade.manage_open_orders() trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() - nb_trades = len(trades) - assert nb_trades == 1 - nb_orders = len(Order.get_open_orders()) - assert nb_orders == 1 + assert len(trades) == 1 + assert len(Order.get_open_orders()) == 1 # Entry adjustment is called assert freqtrade.strategy.adjust_entry_price.call_count == 1 @@ -2547,10 +2543,8 @@ def test_adjust_entry_maintain_replace( freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1234) freqtrade.manage_open_orders() trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() - nb_trades = len(trades) - assert nb_trades == 1 + assert len(trades) == 1 nb_all_orders = len(Order.query.all()) - freqtrade.logger.warning(Order.query.all()) assert nb_all_orders == 2 # New order seems to be in closed status? # nb_open_orders = len(Order.get_open_orders()) @@ -2588,8 +2582,7 @@ def test_check_handle_cancelled_buy( assert cancel_order_mock.call_count == 0 assert rpc_mock.call_count == 1 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() - nb_trades = len(trades) - assert nb_trades == 0 + assert len(trades) == 0 assert log_has_re( f"{'Sell' if is_short else 'Buy'} order cancelled on exchange for Trade.*", caplog) From dbecc097dffdb54b8b78c10ce52c99283c00d4b0 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Wed, 4 May 2022 21:34:45 +0300 Subject: [PATCH 032/449] Models:Trade: Update trade open_rate based on lastest order. --- freqtrade/persistence/models.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 299032bb4..4ed651e20 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -866,9 +866,17 @@ class LocalTrade(): return float(f"{profit_ratio:.8f}") def recalc_trade_from_orders(self): + filled_orders_count = len(self.select_filled_orders(self.entry_side)) + latest_order_in_trade = self.select_order(self.entry_side, True) + # No fills but newer order + if (filled_orders_count == 0 and latest_order_in_trade is not None and + latest_order_in_trade.id is not None): + # after ensuring there is a populated order + if latest_order_in_trade.id > 1: + self.open_rate = latest_order_in_trade.price # We need at least 2 entry orders for averaging amounts and rates. # TODO: this condition could probably be removed - if len(self.select_filled_orders(self.entry_side)) < 2: + if filled_orders_count < 2: self.stake_amount = self.amount * self.open_rate / self.leverage # Just in case, still recalc open trade value From ae01afdd0f3bd9f63b3b39d8bb22ae8a3a38830b Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Wed, 4 May 2022 22:05:53 +0300 Subject: [PATCH 033/449] Models:Trade: Fix open_rate updates. --- freqtrade/persistence/models.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 4ed651e20..62f3d7d55 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -868,12 +868,11 @@ class LocalTrade(): def recalc_trade_from_orders(self): filled_orders_count = len(self.select_filled_orders(self.entry_side)) latest_order_in_trade = self.select_order(self.entry_side, True) - # No fills but newer order + # No fills - update open_rate in case order was replaced if (filled_orders_count == 0 and latest_order_in_trade is not None and - latest_order_in_trade.id is not None): - # after ensuring there is a populated order - if latest_order_in_trade.id > 1: - self.open_rate = latest_order_in_trade.price + latest_order_in_trade.price is not None): + # after ensuring there is a populated order price + self.open_rate = latest_order_in_trade.price # We need at least 2 entry orders for averaging amounts and rates. # TODO: this condition could probably be removed if filled_orders_count < 2: From 1a37c6ff427d6a4048f7cfbf9fa33d95ab90969f Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 5 May 2022 07:04:53 +0200 Subject: [PATCH 034/449] Bump ccxt to 1.81.43 fixes bug in okx live liquidation pricing --- freqtrade/freqtradebot.py | 1 - requirements.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c52ce1b1c..4acf94c32 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1578,7 +1578,6 @@ class FreqtradeBot(LoggingMixin): # TODO: Margin will need to use interest_rate as well. # interest_rate = self.exchange.get_interest_rate() trade.set_isolated_liq(self.exchange.get_liquidation_price( - leverage=trade.leverage, pair=trade.pair, amount=trade.amount, diff --git a/requirements.txt b/requirements.txt index 709408aeb..c5459a5b2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.3 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.81.16 +ccxt==1.81.43 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.1 aiohttp==3.8.1 From 25c74e26d1a59699e8ae5e54f94d5fe0cb47a3d4 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Thu, 5 May 2022 12:18:19 +0300 Subject: [PATCH 035/449] Models:Trade: Revert trade open_rate update. --- freqtrade/persistence/models.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 62f3d7d55..d1846f9ef 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -866,16 +866,10 @@ class LocalTrade(): return float(f"{profit_ratio:.8f}") def recalc_trade_from_orders(self): - filled_orders_count = len(self.select_filled_orders(self.entry_side)) - latest_order_in_trade = self.select_order(self.entry_side, True) - # No fills - update open_rate in case order was replaced - if (filled_orders_count == 0 and latest_order_in_trade is not None and - latest_order_in_trade.price is not None): - # after ensuring there is a populated order price - self.open_rate = latest_order_in_trade.price + # We need at least 2 entry orders for averaging amounts and rates. # TODO: this condition could probably be removed - if filled_orders_count < 2: + if len(self.select_filled_orders(self.entry_side)) < 2: self.stake_amount = self.amount * self.open_rate / self.leverage # Just in case, still recalc open trade value From 2bed0eab0cc5433800ac8de8b68bb0ad2d7ca1f3 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Thu, 5 May 2022 12:19:05 +0300 Subject: [PATCH 036/449] BT: Update trade open_rate on first filled order. --- freqtrade/optimize/backtesting.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 376236747..35761c54c 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -813,6 +813,11 @@ class Backtesting: cost=stake_amount + trade.fee_open, ) if pos_adjust and self._get_order_filled(order.price, row): + # Update trade open_rate on first filled order + # this is for cases where adjust_entry_order might have replaced the + # initial order from trade opening + if len(trade.select_filled_orders(trade.entry_side)) == 1: + trade.open_rate = order.price order.close_bt_order(current_time) else: trade.open_order_id = str(self.order_id_counter) From 29f1edbde70a77c5d8bb1f367464e514cc04da37 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Thu, 5 May 2022 12:24:32 +0300 Subject: [PATCH 037/449] Cleanup. Remove stray new line. --- freqtrade/persistence/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index d1846f9ef..299032bb4 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -866,7 +866,6 @@ class LocalTrade(): return float(f"{profit_ratio:.8f}") def recalc_trade_from_orders(self): - # We need at least 2 entry orders for averaging amounts and rates. # TODO: this condition could probably be removed if len(self.select_filled_orders(self.entry_side)) < 2: From 2d9be6dacee665803b704d7dffd9814396930e4b Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 5 May 2022 19:50:16 +0200 Subject: [PATCH 038/449] move open_rate updating to close_bt_order --- freqtrade/optimize/backtesting.py | 6 ++---- freqtrade/persistence/models.py | 6 +++++- tests/optimize/test_backtest_detail.py | 26 ++++++++++++++++++++------ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 35761c54c..aadda6dbd 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -816,9 +816,7 @@ class Backtesting: # Update trade open_rate on first filled order # this is for cases where adjust_entry_order might have replaced the # initial order from trade opening - if len(trade.select_filled_orders(trade.entry_side)) == 1: - trade.open_rate = order.price - order.close_bt_order(current_time) + order.close_bt_order(current_time, trade) else: trade.open_order_id = str(self.order_id_counter) trade.orders.append(order) @@ -1052,7 +1050,7 @@ class Backtesting: # 3. Process entry orders. order = trade.select_order(trade.entry_side, is_open=True) if order and self._get_order_filled(order.price, row): - order.close_bt_order(current_time) + order.close_bt_order(current_time, trade) trade.open_order_id = None LocalTrade.add_bt_trade(trade) self.wallets.update() diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 299032bb4..c5ea34a30 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -219,11 +219,15 @@ class Order(_DECL_BASE): 'remaining': self.remaining, } - def close_bt_order(self, close_date: datetime): + def close_bt_order(self, close_date: datetime, trade: 'LocalTrade'): self.order_filled_date = close_date self.filled = self.amount self.status = 'closed' self.ft_is_open = False + if (self.ft_order_side == trade.entry_side + and len(trade.select_filled_orders(trade.entry_side)) == 1): + trade.open_rate = self.price + trade.recalc_open_trade_value() @staticmethod def update_orders(orders: List['Order'], order: Dict[str, Any]): diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index f2e2c89ad..aab864431 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -760,16 +760,29 @@ tc48 = BTContainer(data=[ [0, 5000, 5050, 4950, 5000, 6172, 1, 0], [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # timeout [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust - [3, 5100, 5100, 4650, 4750, 6172, 0, 0], + [3, 5100, 5100, 4650, 4750, 6172, 0, 1], [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], - stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.1, - timeout=1000, - custom_entry_price=4200, - adjust_entry_price=5200, - trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=2, is_short=False)] + stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.087, + use_exit_signal=True, timeout=1000, + custom_entry_price=4200, adjust_entry_price=5200, + trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=False)] ) +# Test 49: Custom-entry-price short above all candles - readjust order +tc49 = BTContainer(data=[ + # D O H L C V EL XL ES Xs BT + [0, 5000, 5050, 4950, 5000, 6172, 0, 0, 1, 0], + [1, 5000, 5200, 4951, 5000, 6172, 0, 0, 0, 0], # timeout + [2, 4900, 5250, 4900, 5100, 6172, 0, 0, 0, 0], # Order readjust + [3, 5100, 5100, 4650, 4750, 6172, 0, 0, 0, 1], + [4, 4750, 4950, 4350, 4750, 6172, 0, 0, 0, 0]], + stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.05, + use_exit_signal=True, timeout=1000, + custom_entry_price=5300, adjust_entry_price=5000, + trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=True)] +) + TESTS = [ tc0, tc1, @@ -820,6 +833,7 @@ TESTS = [ tc46, tc47, tc48, + tc49, ] From d11c44940eebc4ed413fd858b4bdb9096f2730af Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 6 May 2022 06:23:06 +0200 Subject: [PATCH 039/449] Slightly reword docs remove some Note-boxes - people tend to skip these. --- docs/bot-basics.md | 2 +- docs/strategy-callbacks.md | 17 ++++++++++------- freqtrade/optimize/backtesting.py | 3 --- freqtrade/strategy/interface.py | 2 +- .../subtemplates/strategy_methods_advanced.j2 | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/bot-basics.md b/docs/bot-basics.md index abc0e7b16..9fdbdc8a8 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -24,7 +24,7 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and * Fetch open trades from persistence. * Calculate current list of tradable pairs. -* Download OHLCV data for the pairlist including all [informative pairs](strategy-customization.md#get-data-for-non-tradeable-pairs) +* Download OHLCV data for the pairlist including all [informative pairs](strategy-customization.md#get-data-for-non-tradeable-pairs) This step is only executed once per Candle to avoid unnecessary network traffic. * Call `bot_loop_start()` strategy callback. * Analyze strategy per pair. diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 462cf604f..a58878ee7 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -719,14 +719,17 @@ class DigDeeperStrategy(IStrategy): The `adjust_entry_price()` callback may be used by strategy developer to refresh/replace limit orders upon arrival of new candles. Be aware that `custom_entry_price()` is still the one dictating initial entry limit order price target at the time of entry trigger. -!!! Note "Simple Order Cancelation" - This also allows simple cancelation without an replacement order. This behavior occurs when `None` is returned. +Orders can ba cancelled out of this callback by returning `None`. -!!! Note "Maintaining Order" - Maintaining existing order on exchange is facilitated. This behavior occurs when `order.price` is returned. +Returning `current_order_rate` will keep the order on the exchange "as is". +Returning any other price will cancel the existing order, and replace it with a new order. -!!! Warning - Entry `unfilledtimeout` mechanism takes precedence over this. Be sure to update timeout values to match your expectancy. +The trade open-date (`trade.open_date_utc`) will remain at the time of the very first order placed. +Please makes sure to be aware of this - and eventually adjust your logic in other callbacks to account for this, and use the date of the first filled order instead. + +!!! Warning "Regular timeout" + Entry `unfilledtimeout` mechanism (as well as `check_entry_timeout()`) takes precedence over this. + Entry Orders that are cancelled via the above methods will not have this callback called. Be sure to update timeout values to match your expectations. ```python from freqtrade.persistence import Trade @@ -741,7 +744,7 @@ class AwesomeStrategy(IStrategy): entry_tag: Optional[str], side: str, **kwargs) -> float: """ Entry price re-adjustment logic, returning the user desired limit price. - This only executes when a order was already placed, still open(unfilled fully or partially) + This only executes when a order was already placed, still open (unfilled fully or partially) and not timed out on subsequent candles after entry trigger. When not implemented by a strategy, returns current_order_rate as default. diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index aadda6dbd..86dcb1094 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -813,9 +813,6 @@ class Backtesting: cost=stake_amount + trade.fee_open, ) if pos_adjust and self._get_order_filled(order.price, row): - # Update trade open_rate on first filled order - # this is for cases where adjust_entry_order might have replaced the - # initial order from trade opening order.close_bt_order(current_time, trade) else: trade.open_order_id = str(self.order_id_counter) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 367097d71..26efd74a9 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -476,7 +476,7 @@ class IStrategy(ABC, HyperStrategyMixin): entry_tag: Optional[str], side: str, **kwargs) -> float: """ Entry price re-adjustment logic, returning the user desired limit price. - This only executes when a order was already placed, still open(unfilled fully or partially) + This only executes when a order was already placed, still open (unfilled fully or partially) and not timed out on subsequent candles after entry trigger. For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 7f9671bb1..014e97cc0 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -35,7 +35,7 @@ def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str, entry_tag: Optional[str], side: str, **kwargs) -> float: """ Entry price re-adjustment logic, returning the user desired limit price. - This only executes when a order was already placed, still open(unfilled fully or partially) + This only executes when a order was already placed, still open (unfilled fully or partially) and not timed out on subsequent candles after entry trigger. For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ From 5b3eaa3003ce70dfeb3d23b47ef91605742462fc Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 6 May 2022 06:30:35 +0200 Subject: [PATCH 040/449] Ensure advanced strategy template is runnable --- freqtrade/templates/base_strategy.py.j2 | 4 +++- .../subtemplates/strategy_methods_advanced.j2 | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/freqtrade/templates/base_strategy.py.j2 b/freqtrade/templates/base_strategy.py.j2 index 53237f67d..9e7e1fe50 100644 --- a/freqtrade/templates/base_strategy.py.j2 +++ b/freqtrade/templates/base_strategy.py.j2 @@ -4,7 +4,9 @@ # --- Do not remove these libs --- import numpy as np # noqa import pandas as pd # noqa -from pandas import DataFrame +from pandas import DataFrame # noqa +from datetime import datetime # noqa +from typing import Optional # noqa from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, IStrategy, IntParameter) diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 014e97cc0..317602da9 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -13,7 +13,7 @@ def bot_loop_start(self, **kwargs) -> None: pass def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: float, - entry_tag: 'Optional[str]', **kwargs) -> float: + entry_tag: Optional[str], **kwargs) -> float: """ Custom entry price logic, returning the new entry price. @@ -30,7 +30,7 @@ def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: """ return proposed_rate -def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str, +def adjust_entry_price(self, trade: 'Trade', order: 'Optional[Order]', pair: str, current_time: datetime, proposed_rate: float, current_order_rate: float, entry_tag: Optional[str], side: str, **kwargs) -> float: """ @@ -81,7 +81,7 @@ def custom_exit_price(self, pair: str, trade: 'Trade', def custom_stake_amount(self, pair: str, current_time: 'datetime', current_rate: float, proposed_stake: float, min_stake: float, max_stake: float, - side: str, entry_tag: 'Optional[str]', **kwargs) -> float: + side: str, entry_tag: Optional[str], **kwargs) -> float: """ Customize stake size for each new trade. @@ -146,7 +146,7 @@ def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', curre return None def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, - time_in_force: str, current_time: datetime, entry_tag: 'Optional[str]', + time_in_force: str, current_time: datetime, entry_tag: Optional[str], side: str, **kwargs) -> bool: """ Called right before placing a entry order. @@ -245,7 +245,7 @@ def check_exit_timeout(self, pair: str, trade: 'Trade', order: 'Order', def adjust_trade_position(self, trade: 'Trade', current_time: 'datetime', current_rate: float, current_profit: float, min_stake: float, - max_stake: float, **kwargs) -> 'Optional[float]': + max_stake: float, **kwargs) -> Optional[float]: """ Custom trade adjustment logic, returning the stake amount that a trade should be increased. This means extra buy orders with additional fees. From 182a6f475d6c0a05fd475d7b40f83afe7e7c733b Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Fri, 6 May 2022 10:13:29 +0300 Subject: [PATCH 041/449] Minor typos. --- docs/strategy-callbacks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index a58878ee7..750d5fbd0 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -719,13 +719,13 @@ class DigDeeperStrategy(IStrategy): The `adjust_entry_price()` callback may be used by strategy developer to refresh/replace limit orders upon arrival of new candles. Be aware that `custom_entry_price()` is still the one dictating initial entry limit order price target at the time of entry trigger. -Orders can ba cancelled out of this callback by returning `None`. +Orders can be cancelled out of this callback by returning `None`. Returning `current_order_rate` will keep the order on the exchange "as is". Returning any other price will cancel the existing order, and replace it with a new order. The trade open-date (`trade.open_date_utc`) will remain at the time of the very first order placed. -Please makes sure to be aware of this - and eventually adjust your logic in other callbacks to account for this, and use the date of the first filled order instead. +Please make sure to be aware of this - and eventually adjust your logic in other callbacks to account for this, and use the date of the first filled order instead. !!! Warning "Regular timeout" Entry `unfilledtimeout` mechanism (as well as `check_entry_timeout()`) takes precedence over this. From 70bac41d89a25f1cccffe730340cee5df5126e4a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 6 May 2022 06:45:22 +0200 Subject: [PATCH 042/449] Add more backtest test scenarios --- tests/optimize/test_backtest_detail.py | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index aab864431..c98330e6c 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -783,6 +783,34 @@ tc49 = BTContainer(data=[ trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=True)] ) +# Test 50: Custom-entry-price below all candles - readjust order cancels order +tc50 = BTContainer(data=[ + # D O H L C V EL XL ES Xs BT + [0, 5000, 5050, 4950, 5000, 6172, 1, 0], + [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # timeout + [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust - cancel order + [3, 5100, 5100, 4650, 4750, 6172, 0, 0], + [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], + stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.0, + use_exit_signal=True, timeout=1000, + custom_entry_price=4200, adjust_entry_price=None, + trades=[] +) + +# Test 51: Custom-entry-price below all candles - readjust order leaves order in place and timeout. +tc51 = BTContainer(data=[ + # D O H L C V EL XL ES Xs BT + [0, 5000, 5050, 4950, 5000, 6172, 1, 0], + [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # timeout + [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust - cancel order + [3, 5100, 5100, 4650, 4750, 6172, 0, 0], + [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], + stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.0, + use_exit_signal=True, timeout=1000, + custom_entry_price=4200, adjust_entry_price=4200, + trades=[] +) + TESTS = [ tc0, tc1, @@ -834,6 +862,8 @@ TESTS = [ tc47, tc48, tc49, + tc50, + tc51, ] From 108903f7f0c968f88a3b2520a8cc8e7753c4c2e1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 6 May 2022 19:49:39 +0200 Subject: [PATCH 043/449] Add DCA order adjust test --- tests/test_integration.py | 92 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/test_integration.py b/tests/test_integration.py index 8f56c1fea..020f77fed 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -351,3 +351,95 @@ def test_dca_short(default_conf_usdt, ticker_usdt, fee, mocker) -> None: assert trade.nr_of_successful_entries == 2 assert trade.nr_of_successful_exits == 1 + + +def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None: + default_conf_usdt['position_adjustment_enable'] = True + + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + fetch_ticker=ticker_usdt, + get_fee=fee, + amount_to_precision=lambda s, x, y: y, + price_to_precision=lambda s, x, y: y, + ) + mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=False) + + patch_get_signal(freqtrade) + freqtrade.strategy.custom_entry_price = lambda **kwargs: ticker_usdt['ask'] * 0.96 + + freqtrade.enter_positions() + + assert len(Trade.get_trades().all()) == 1 + trade = Trade.get_trades().first() + assert len(trade.orders) == 1 + assert trade.open_order_id is not None + assert pytest.approx(trade.stake_amount) == 60 + assert trade.open_rate == 1.96 + # No adjustment + freqtrade.process() + trade = Trade.get_trades().first() + assert len(trade.orders) == 1 + assert trade.open_order_id is not None + assert pytest.approx(trade.stake_amount) == 60 + + # Cancel order and place new one + freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1.99) + freqtrade.process() + trade = Trade.get_trades().first() + assert len(trade.orders) == 2 + assert trade.open_order_id is not None + # Open rate is not adjusted yet + assert trade.open_rate == 1.96 + + # Fill order + mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=True) + freqtrade.process() + trade = Trade.get_trades().first() + assert len(trade.orders) == 2 + assert trade.open_order_id is None + # Open rate is not adjusted yet + assert trade.open_rate == 1.99 + + # 2nd order - not filling + freqtrade.strategy.adjust_trade_position = MagicMock(return_value=120) + mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=False) + + freqtrade.process() + trade = Trade.get_trades().first() + assert len(trade.orders) == 3 + assert trade.open_order_id is not None + assert trade.open_rate == 1.99 + assert trade.orders[-1].price == 1.96 + assert trade.orders[-1].cost == 120 + + # Replace new order with diff. order at a lower price + freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1.95) + + freqtrade.process() + trade = Trade.get_trades().first() + assert len(trade.orders) == 4 + assert trade.open_order_id is not None + assert trade.open_rate == 1.99 + assert trade.orders[-1].price == 1.95 + assert pytest.approx(trade.orders[-1].cost) == 120 + + # Fill DCA order + freqtrade.strategy.adjust_trade_position = MagicMock(return_value=None) + mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=True) + freqtrade.strategy.adjust_entry_price = MagicMock(side_effect=ValueError) + + freqtrade.process() + trade = Trade.get_trades().first() + assert len(trade.orders) == 4 + assert trade.open_order_id is None + assert pytest.approx(trade.open_rate) == 1.963153456 + assert trade.orders[-1].price == 1.95 + assert pytest.approx(trade.orders[-1].cost) == 120 + assert trade.orders[-1].status == 'closed' + + assert pytest.approx(trade.amount) == 91.689215 + # Check the 2 filled orders equal the above amount + assert pytest.approx(trade.orders[1].amount) == 30.150753768 + assert pytest.approx(trade.orders[-1].amount) == 61.538461232 From 68a97a898ded42ae1aa850b5e825f946185af96f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 08:04:43 +0200 Subject: [PATCH 044/449] Disable scheduled notification in CI --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ff57b270..96575f034 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -327,7 +327,7 @@ jobs: # Discord notification can't handle schedule events if: (github.event_name != 'schedule') permissions: - repository-projects: read + repository-projects: read steps: - name: Check user permission @@ -419,7 +419,7 @@ jobs: - name: Discord notification uses: rjstone/discord-webhook-notify@v1 - if: always() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) + if: always() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) && (github.event_name != 'schedule') with: severity: info details: Deploy Succeeded! From 2da284b921bb2812454db8c612a0f0091bffc418 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 08:45:37 +0200 Subject: [PATCH 045/449] Properly type side for create_order --- freqtrade/constants.py | 1 + freqtrade/exchange/exchange.py | 4 ++-- freqtrade/exchange/okx.py | 3 ++- freqtrade/freqtradebot.py | 5 +++-- freqtrade/persistence/models.py | 4 ++-- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 53cae8a8e..ffbc57d62 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -494,3 +494,4 @@ TradeList = List[List] LongShort = Literal['long', 'short'] EntryExit = Literal['entry', 'exit'] +BuySell = Literal['buy', 'sell'] diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 08bdab265..59089b630 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -20,7 +20,7 @@ from ccxt.base.decimal_to_precision import (ROUND_DOWN, ROUND_UP, TICK_SIZE, TRU decimal_to_precision) from pandas import DataFrame -from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, +from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, BuySell, EntryExit, ListPairsWithTimeframes, PairWithTimeframe) from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list from freqtrade.enums import OPTIMIZE_MODES, CandleType, MarginMode, TradingMode @@ -962,7 +962,7 @@ class Exchange: *, pair: str, ordertype: str, - side: str, + side: BuySell, amount: float, rate: float, leverage: float, diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index fb7388ee1..3599d334b 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -3,6 +3,7 @@ from typing import Dict, List, Tuple import ccxt +from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, TradingMode from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange @@ -52,7 +53,7 @@ class Okx(Exchange): return params @retrier - def _lev_prep(self, pair: str, leverage: float, side: str): + def _lev_prep(self, pair: str, leverage: float, side: BuySell): if self.trading_mode != TradingMode.SPOT and self.margin_mode is not None: try: # TODO-lev: Test me properly (check mgnMode passed) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 4acf94c32..2a1709da3 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -13,7 +13,7 @@ from schedule import Scheduler from freqtrade import __version__, constants from freqtrade.configuration import validate_config_consistency -from freqtrade.constants import LongShort +from freqtrade.constants import BuySell, LongShort from freqtrade.data.converter import order_book_to_dataframe from freqtrade.data.dataprovider import DataProvider from freqtrade.edge import Edge @@ -594,7 +594,8 @@ class FreqtradeBot(LoggingMixin): """ time_in_force = self.strategy.order_time_in_force['entry'] - [side, name] = ['sell', 'Short'] if is_short else ['buy', 'Long'] + side: BuySell = 'sell' if is_short else 'buy' + name = 'Short' if is_short else 'Long' trade_side: LongShort = 'short' if is_short else 'long' pos_adjust = trade is not None diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 299032bb4..352079b2e 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -13,7 +13,7 @@ from sqlalchemy.orm import Query, declarative_base, relationship, scoped_session from sqlalchemy.pool import StaticPool from sqlalchemy.sql.schema import UniqueConstraint -from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, LongShort +from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, BuySell, LongShort from freqtrade.enums import ExitType, TradingMode from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.leverage import interest @@ -386,7 +386,7 @@ class LocalTrade(): return "buy" @property - def exit_side(self) -> str: + def exit_side(self) -> BuySell: if self.is_short: return "buy" else: From 6fdcf3a10a28d8b6fa426b06d0972ead3d8ae7e5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 10:56:13 +0200 Subject: [PATCH 046/449] Support both position modes on OKX --- docs/exchanges.md | 6 ++- freqtrade/exchange/exchange.py | 12 +++++- freqtrade/exchange/kraken.py | 3 ++ freqtrade/exchange/okx.py | 37 +++++++++++++++++- tests/exchange/test_exchange.py | 8 ++++ tests/exchange/test_okx.py | 66 +++++++++++++++++++++++++++++++++ 6 files changed, 129 insertions(+), 3 deletions(-) diff --git a/docs/exchanges.md b/docs/exchanges.md index 18a7af5a1..b2759893b 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -228,7 +228,11 @@ OKX requires a passphrase for each api key, you will therefore need to add this ``` !!! Warning - OKX only provides 100 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode. + OKX only provides 300 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode. + +!!! Warning "Futures - position mode" + OKX Futures has the concept of "position mode" - which can be Net or long/short (hedge mode). + Freqtrade supports both modes - but changing the mode mid-trading is not supported and will lead to exceptions and failures to place trades. ## Gate.io diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 59089b630..ce2c06ae0 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -198,6 +198,7 @@ class Exchange: if self.trading_mode != TradingMode.SPOT: self.fill_leverage_tiers() + self.additional_exchange_init() def __del__(self): """ @@ -294,6 +295,14 @@ class Exchange: """exchange ccxt precisionMode""" return self._api.precisionMode + def additional_exchange_init(self) -> None: + """ + Additional exchange initialization logic. + .api will be available at this point. + Must be overridden in child methods if required. + """ + pass + def _log_exchange_response(self, endpoint, response) -> None: """ Log exchange responses """ if self.log_responses: @@ -944,6 +953,7 @@ class Exchange: def _get_params( self, + side: BuySell, ordertype: str, leverage: float, reduceOnly: bool, @@ -973,7 +983,7 @@ class Exchange: dry_order = self.create_dry_run_order(pair, ordertype, side, amount, rate, leverage) return dry_order - params = self._get_params(ordertype, leverage, reduceOnly, time_in_force) + params = self._get_params(side, ordertype, leverage, reduceOnly, time_in_force) try: # Set the precision for amount and price(rate) as accepted by the exchange diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 94727afa6..ea9b73fab 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List, Optional, Tuple import ccxt from pandas import DataFrame +from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, TradingMode from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, OperationalException, TemporaryError) @@ -165,12 +166,14 @@ class Kraken(Exchange): def _get_params( self, + side: BuySell, ordertype: str, leverage: float, reduceOnly: bool, time_in_force: str = 'gtc' ) -> Dict: params = super()._get_params( + side=side, ordertype=ordertype, leverage=leverage, reduceOnly=reduceOnly, diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 3599d334b..56636bf21 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -35,14 +35,48 @@ class Okx(Exchange): (TradingMode.FUTURES, MarginMode.ISOLATED), ] + net_only = True + + @retrier + def additional_exchange_init(self) -> None: + """ + Additional exchange initialization logic. + .api will be available at this point. + Must be overridden in child methods if required. + """ + try: + if self.trading_mode == TradingMode.FUTURES: + accounts = self._api.fetch_accounts() + if len(accounts) > 0: + self.net_only = accounts[0].get('info', {}).get('posMode') == 'net_mode' + except ccxt.DDoSProtection as e: + raise DDosProtection(e) from e + except (ccxt.NetworkError, ccxt.ExchangeError) as e: + raise TemporaryError( + f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e + except ccxt.BaseError as e: + raise OperationalException(e) from e + + def _get_posSide(self, side: BuySell, reduceOnly: bool): + if self.net_only: + return 'net' + if not reduceOnly: + # Enter + return 'long' if side == 'buy' else 'short' + else: + # Exit + return 'long' if side == 'sell' else 'short' + def _get_params( self, + side: BuySell, ordertype: str, leverage: float, reduceOnly: bool, time_in_force: str = 'gtc', ) -> Dict: params = super()._get_params( + side=side, ordertype=ordertype, leverage=leverage, reduceOnly=reduceOnly, @@ -50,6 +84,7 @@ class Okx(Exchange): ) if self.trading_mode == TradingMode.FUTURES and self.margin_mode: params['tdMode'] = self.margin_mode.value + params['posSide'] = self._get_posSide(side, reduceOnly) return params @retrier @@ -62,7 +97,7 @@ class Okx(Exchange): symbol=pair, params={ "mgnMode": self.margin_mode.value, - # "posSide": "net"", + "posSide": self._get_posSide(side, False), }) except ccxt.DDoSProtection as e: raise DDosProtection(e) from e diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 1368bcb85..77a04ac6c 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -99,6 +99,8 @@ def test_remove_credentials(default_conf, caplog) -> None: def test_init_ccxt_kwargs(default_conf, mocker, caplog): mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency') + aei_mock = mocker.patch('freqtrade.exchange.Exchange.additional_exchange_init') + caplog.set_level(logging.INFO) conf = copy.deepcopy(default_conf) conf['exchange']['ccxt_async_config'] = {'aiohttp_trust_env': True, 'asyncio_loop': True} @@ -108,6 +110,7 @@ def test_init_ccxt_kwargs(default_conf, mocker, caplog): caplog) assert ex._api_async.aiohttp_trust_env assert not ex._api.aiohttp_trust_env + assert aei_mock.call_count == 1 # Reset logging and config caplog.clear() @@ -4758,8 +4761,10 @@ def test__get_params(mocker, default_conf, exchange_name): if exchange_name == 'okx': params2['tdMode'] = 'isolated' + params2['posSide'] = 'net' assert exchange._get_params( + side="buy", ordertype='market', reduceOnly=False, time_in_force='gtc', @@ -4767,6 +4772,7 @@ def test__get_params(mocker, default_conf, exchange_name): ) == params1 assert exchange._get_params( + side="buy", ordertype='market', reduceOnly=False, time_in_force='ioc', @@ -4774,6 +4780,7 @@ def test__get_params(mocker, default_conf, exchange_name): ) == params1 assert exchange._get_params( + side="buy", ordertype='limit', reduceOnly=False, time_in_force='gtc', @@ -4786,6 +4793,7 @@ def test__get_params(mocker, default_conf, exchange_name): exchange._params = {'test': True} assert exchange._get_params( + side="buy", ordertype='limit', reduceOnly=True, time_in_force='ioc', diff --git a/tests/exchange/test_okx.py b/tests/exchange/test_okx.py index 37c1ea974..8981b1a38 100644 --- a/tests/exchange/test_okx.py +++ b/tests/exchange/test_okx.py @@ -1,7 +1,10 @@ from unittest.mock import MagicMock, PropertyMock +import pytest + from freqtrade.enums import MarginMode, TradingMode from tests.conftest import get_patched_exchange +from tests.exchange.test_exchange import ccxt_exceptionhandlers def test_get_maintenance_ratio_and_amt_okx( @@ -170,6 +173,69 @@ def test_get_max_pair_stake_amount_okx(default_conf, mocker, leverage_tiers): assert exchange.get_max_pair_stake_amount('TTT/USDT', 1.0) == float('inf') # Not in tiers +@pytest.mark.parametrize('mode,side,reduceonly,result', [ + ('net', 'buy', False, 'net'), + ('net', 'sell', True, 'net'), + ('net', 'sell', False, 'net'), + ('net', 'buy', True, 'net'), + ('longshort', 'buy', False, 'long'), + ('longshort', 'sell', True, 'long'), + ('longshort', 'sell', False, 'short'), + ('longshort', 'buy', True, 'short'), +]) +def test__get_posSide(default_conf, mocker, mode, side, reduceonly, result): + + exchange = get_patched_exchange(mocker, default_conf, id="okx") + exchange.net_only = mode == 'net' + assert exchange._get_posSide(side, reduceonly) == result + + +def test_additional_exchange_init_okx(default_conf, mocker): + api_mock = MagicMock() + api_mock.fetch_accounts = MagicMock(return_value=[ + {'id': '2555', + 'type': '2', + 'currency': None, + 'info': {'acctLv': '2', + 'autoLoan': False, + 'ctIsoMode': 'automatic', + 'greeksType': 'PA', + 'level': 'Lv1', + 'levelTmp': '', + 'mgnIsoMode': 'automatic', + 'posMode': 'long_short_mode', + 'uid': '2555'}}]) + exchange = get_patched_exchange(mocker, default_conf, id="okx", api_mock=api_mock) + assert api_mock.fetch_accounts.call_count == 0 + exchange.trading_mode = TradingMode.FUTURES + # Default to netOnly + assert exchange.net_only + exchange.additional_exchange_init() + assert api_mock.fetch_accounts.call_count == 1 + assert not exchange.net_only + + api_mock.fetch_accounts = MagicMock(return_value=[ + {'id': '2555', + 'type': '2', + 'currency': None, + 'info': {'acctLv': '2', + 'autoLoan': False, + 'ctIsoMode': 'automatic', + 'greeksType': 'PA', + 'level': 'Lv1', + 'levelTmp': '', + 'mgnIsoMode': 'automatic', + 'posMode': 'net_mode', + 'uid': '2555'}}]) + exchange.additional_exchange_init() + assert api_mock.fetch_accounts.call_count == 1 + assert exchange.net_only + default_conf['trading_mode'] = 'futures' + default_conf['margin_mode'] = 'isolated' + ccxt_exceptionhandlers(mocker, default_conf, api_mock, 'okx', + "additional_exchange_init", "fetch_accounts") + + def test_load_leverage_tiers_okx(default_conf, mocker, markets): api_mock = MagicMock() type(api_mock).has = PropertyMock(return_value={ From 149704e748272f34dd541c2335ce76e9a7e12dac Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 11:08:54 +0200 Subject: [PATCH 047/449] Fix wrong type --- freqtrade/exchange/exchange.py | 4 ++-- freqtrade/exchange/ftx.py | 3 ++- freqtrade/exchange/kraken.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index ce2c06ae0..65b9fb628 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -946,7 +946,7 @@ class Exchange: # Order handling - def _lev_prep(self, pair: str, leverage: float, side: str): + def _lev_prep(self, pair: str, leverage: float, side: BuySell): if self.trading_mode != TradingMode.SPOT: self.set_margin_mode(pair, self.margin_mode) self._set_leverage(leverage, pair) @@ -1068,7 +1068,7 @@ class Exchange: @retrier(retries=0) def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, - side: str, leverage: float) -> Dict: + side: BuySell, leverage: float) -> Dict: """ creates a stoploss order. requires `_ft_has['stoploss_order_types']` to be set as a dict mapping limit and market diff --git a/freqtrade/exchange/ftx.py b/freqtrade/exchange/ftx.py index d2dcf84a6..65c2a53ca 100644 --- a/freqtrade/exchange/ftx.py +++ b/freqtrade/exchange/ftx.py @@ -4,6 +4,7 @@ from typing import Any, Dict, List, Tuple import ccxt +from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, TradingMode from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, OperationalException, TemporaryError) @@ -44,7 +45,7 @@ class Ftx(Exchange): @retrier(retries=0) def stoploss(self, pair: str, amount: float, stop_price: float, - order_types: Dict, side: str, leverage: float) -> Dict: + order_types: Dict, side: BuySell, leverage: float) -> Dict: """ Creates a stoploss order. depending on order_types.stoploss configuration, uses 'market' or limit order. diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index ea9b73fab..33a2c7f87 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -96,7 +96,7 @@ class Kraken(Exchange): @retrier(retries=0) def stoploss(self, pair: str, amount: float, stop_price: float, - order_types: Dict, side: str, leverage: float) -> Dict: + order_types: Dict, side: BuySell, leverage: float) -> Dict: """ Creates a stoploss market order. Stoploss market orders is the only stoploss type supported by kraken. From dc0c1bf87dcd597f2f33614e35c4f43b71bc0efc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 13:13:26 +0200 Subject: [PATCH 048/449] Only fetch accounts when authenticated. --- freqtrade/exchange/okx.py | 2 +- tests/exchange/test_ccxt_compat.py | 1 + tests/exchange/test_okx.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 56636bf21..9aeefd450 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -45,7 +45,7 @@ class Okx(Exchange): Must be overridden in child methods if required. """ try: - if self.trading_mode == TradingMode.FUTURES: + if self.trading_mode == TradingMode.FUTURES and not self._config['dry_run']: accounts = self._api.fetch_accounts() if len(accounts) > 0: self.net_only = accounts[0].get('info', {}).get('posMode') == 'net_mode' diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 2a148c388..d8832bb71 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -135,6 +135,7 @@ def exchange_futures(request, exchange_conf, class_mocker): class_mocker.patch( 'freqtrade.exchange.binance.Binance.fill_leverage_tiers') class_mocker.patch('freqtrade.exchange.exchange.Exchange.fetch_trading_fees') + class_mocker.patch('freqtrade.exchange.okx.Okx.additional_exchange_init') exchange = ExchangeResolver.load_exchange(request.param, exchange_conf, validate=True) yield exchange, request.param diff --git a/tests/exchange/test_okx.py b/tests/exchange/test_okx.py index 8981b1a38..f6bdd35ad 100644 --- a/tests/exchange/test_okx.py +++ b/tests/exchange/test_okx.py @@ -205,6 +205,7 @@ def test_additional_exchange_init_okx(default_conf, mocker): 'mgnIsoMode': 'automatic', 'posMode': 'long_short_mode', 'uid': '2555'}}]) + default_conf['dry_run'] = False exchange = get_patched_exchange(mocker, default_conf, id="okx", api_mock=api_mock) assert api_mock.fetch_accounts.call_count == 0 exchange.trading_mode = TradingMode.FUTURES From f5f599c7f062da86c26433221b302a2b0e0e2585 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 15:24:31 +0200 Subject: [PATCH 049/449] Add LowProfitPairs only_per_side option --- docs/includes/protections.md | 5 ++++- .../plugins/protections/low_profit_pairs.py | 12 +++++++++--- .../plugins/protections/stoploss_guard.py | 4 ++-- tests/plugins/test_protections.py | 18 +++++++++++------- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/docs/includes/protections.md b/docs/includes/protections.md index bb4a7eb35..d67924cfe 100644 --- a/docs/includes/protections.md +++ b/docs/includes/protections.md @@ -96,6 +96,8 @@ def protections(self): `LowProfitPairs` uses all trades for a pair within `lookback_period` in minutes (or in candles when using `lookback_period_candles`) to determine the overall profit ratio. If that ratio is below `required_profit`, that pair will be locked for `stop_duration` in minutes (or in candles when using `stop_duration_candles`). +For futures bots, setting `only_per_side` will make the bot only consider one side, and will then only lock this one side, allowing for example shorts to continue after a series of long losses. + The below example will stop trading a pair for 60 minutes if the pair does not have a required profit of 2% (and a minimum of 2 trades) within the last 6 candles. ``` python @@ -107,7 +109,8 @@ def protections(self): "lookback_period_candles": 6, "trade_limit": 2, "stop_duration": 60, - "required_profit": 0.02 + "required_profit": 0.02, + "only_per_pair": False, } ] ``` diff --git a/freqtrade/plugins/protections/low_profit_pairs.py b/freqtrade/plugins/protections/low_profit_pairs.py index 7d5d6054d..099242b8d 100644 --- a/freqtrade/plugins/protections/low_profit_pairs.py +++ b/freqtrade/plugins/protections/low_profit_pairs.py @@ -21,6 +21,7 @@ class LowProfitPairs(IProtection): self._trade_limit = protection_config.get('trade_limit', 1) self._required_profit = protection_config.get('required_profit', 0.0) + self._only_per_side = protection_config.get('only_per_side', False) def short_desc(self) -> str: """ @@ -36,7 +37,8 @@ class LowProfitPairs(IProtection): return (f'{profit} < {self._required_profit} in {self.lookback_period_str}, ' f'locking for {self.stop_duration_str}.') - def _low_profit(self, date_now: datetime, pair: str) -> Optional[ProtectionReturn]: + def _low_profit( + self, date_now: datetime, pair: str, side: LongShort) -> Optional[ProtectionReturn]: """ Evaluate recent trades for pair """ @@ -54,7 +56,10 @@ class LowProfitPairs(IProtection): # Not enough trades in the relevant period return None - profit = sum(trade.close_profit for trade in trades if trade.close_profit) + profit = sum( + trade.close_profit for trade in trades if trade.close_profit + and (not self._only_per_side or trade.trade_direction == side) + ) if profit < self._required_profit: self.log_once( f"Trading for {pair} stopped due to {profit:.2f} < {self._required_profit} " @@ -65,6 +70,7 @@ class LowProfitPairs(IProtection): lock=True, until=until, reason=self._reason(profit), + lock_side=(side if self._only_per_side else '*') ) return None @@ -86,4 +92,4 @@ class LowProfitPairs(IProtection): :return: Tuple of [bool, until, reason]. If true, this pair will be locked with until """ - return self._low_profit(date_now, pair=pair) + return self._low_profit(date_now, pair=pair, side=side) diff --git a/freqtrade/plugins/protections/stoploss_guard.py b/freqtrade/plugins/protections/stoploss_guard.py index f9fe039d6..713a2da07 100644 --- a/freqtrade/plugins/protections/stoploss_guard.py +++ b/freqtrade/plugins/protections/stoploss_guard.py @@ -38,8 +38,8 @@ class StoplossGuard(IProtection): return (f'{self._trade_limit} stoplosses in {self._lookback_period} min, ' f'locking for {self._stop_duration} min.') - def _stoploss_guard( - self, date_now: datetime, pair: Optional[str], side: str) -> Optional[ProtectionReturn]: + def _stoploss_guard(self, date_now: datetime, pair: Optional[str], + side: LongShort) -> Optional[ProtectionReturn]: """ Evaluate recent trades """ diff --git a/tests/plugins/test_protections.py b/tests/plugins/test_protections.py index b2dc99610..172e1f077 100644 --- a/tests/plugins/test_protections.py +++ b/tests/plugins/test_protections.py @@ -250,14 +250,16 @@ def test_CooldownPeriod(mocker, default_conf, fee, caplog): assert not PairLocks.is_global_lock() +@pytest.mark.parametrize('only_per_side', [False, True]) @pytest.mark.usefixtures("init_persistence") -def test_LowProfitPairs(mocker, default_conf, fee, caplog): +def test_LowProfitPairs(mocker, default_conf, fee, caplog, only_per_side): default_conf['protections'] = [{ "method": "LowProfitPairs", "lookback_period": 400, "stop_duration": 60, "trade_limit": 2, "required_profit": 0.0, + "only_per_side": only_per_side, }] freqtrade = get_patched_freqtradebot(mocker, default_conf) message = r"Trading stopped due to .*" @@ -292,10 +294,11 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog): # Add positive trade Trade.query.session.add(generate_mock_trade( 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.ROI.value, - min_ago_open=20, min_ago_close=10, profit_rate=1.15, + min_ago_open=20, min_ago_close=10, profit_rate=1.15, is_short=True )) - assert not freqtrade.protections.stop_per_pair('XRP/BTC') - assert not PairLocks.is_pair_locked('XRP/BTC') + assert freqtrade.protections.stop_per_pair('XRP/BTC') != only_per_side + assert not PairLocks.is_pair_locked('XRP/BTC', side='*') + assert PairLocks.is_pair_locked('XRP/BTC', side='long') == only_per_side Trade.query.session.add(generate_mock_trade( 'XRP/BTC', fee.return_value, False, exit_reason=ExitType.STOP_LOSS.value, @@ -303,9 +306,10 @@ def test_LowProfitPairs(mocker, default_conf, fee, caplog): )) # Locks due to 2nd trade - assert not freqtrade.protections.global_stop() - assert freqtrade.protections.stop_per_pair('XRP/BTC') - assert PairLocks.is_pair_locked('XRP/BTC') + assert freqtrade.protections.global_stop() != only_per_side + assert freqtrade.protections.stop_per_pair('XRP/BTC') != only_per_side + assert PairLocks.is_pair_locked('XRP/BTC', side='long') + assert PairLocks.is_pair_locked('XRP/BTC', side='*') != only_per_side assert not PairLocks.is_global_lock() From eca8d16c61d70e896f2f9a30049314b8df849419 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 7 May 2022 17:31:56 +0300 Subject: [PATCH 050/449] Minor fix and enhancement for TC51. --- tests/optimize/test_backtest_detail.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index c98330e6c..18b4c3621 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -786,9 +786,9 @@ tc49 = BTContainer(data=[ # Test 50: Custom-entry-price below all candles - readjust order cancels order tc50 = BTContainer(data=[ # D O H L C V EL XL ES Xs BT - [0, 5000, 5050, 4950, 5000, 6172, 1, 0], - [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # timeout - [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust - cancel order + [0, 5000, 5050, 4950, 5000, 6172, 1, 0], # Enter long - place order + [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # Order readjust - cancel order + [2, 4900, 5250, 4500, 5100, 6172, 0, 0], [3, 5100, 5100, 4650, 4750, 6172, 0, 0], [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.0, @@ -800,14 +800,14 @@ tc50 = BTContainer(data=[ # Test 51: Custom-entry-price below all candles - readjust order leaves order in place and timeout. tc51 = BTContainer(data=[ # D O H L C V EL XL ES Xs BT - [0, 5000, 5050, 4950, 5000, 6172, 1, 0], - [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # timeout - [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust - cancel order - [3, 5100, 5100, 4650, 4750, 6172, 0, 0], + [0, 5000, 5050, 4950, 5000, 6172, 1, 0], # Enter long - place order + [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # Order readjust - replace order + [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust - maintain order + [3, 5100, 5100, 4650, 4750, 6172, 0, 0], # Timeout [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.0, - use_exit_signal=True, timeout=1000, - custom_entry_price=4200, adjust_entry_price=4200, + use_exit_signal=True, timeout=60, + custom_entry_price=4200, adjust_entry_price=4100, trades=[] ) @@ -905,8 +905,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) backtesting.strategy.custom_entry_price = MagicMock(return_value=data.custom_entry_price) if data.custom_exit_price: backtesting.strategy.custom_exit_price = MagicMock(return_value=data.custom_exit_price) - if data.adjust_entry_price: - backtesting.strategy.adjust_entry_price = MagicMock(return_value=data.adjust_entry_price) + backtesting.strategy.adjust_entry_price = MagicMock(return_value=data.adjust_entry_price) backtesting.strategy.use_custom_stoploss = data.use_custom_stoploss backtesting.strategy.leverage = lambda **kwargs: data.leverage From 277e07589e5be31640411ef1a38fcb598f5cbd14 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 17:47:37 +0200 Subject: [PATCH 051/449] update/fix some comments and docs --- docs/bot-basics.md | 2 +- docs/strategy-callbacks.md | 2 +- freqtrade/optimize/backtesting.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/bot-basics.md b/docs/bot-basics.md index 9fdbdc8a8..1acbca565 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -34,7 +34,6 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and * Check timeouts for open orders. * Calls `check_entry_timeout()` strategy callback for open entry orders. * Calls `check_exit_timeout()` strategy callback for open exit orders. -* Check readjustment request for open orders. * Calls `adjust_entry_price()` strategy callback for open entry orders. * Verifies existing positions and eventually places exit orders. * Considers stoploss, ROI and exit-signal, `custom_exit()` and `custom_stoploss()`. @@ -60,6 +59,7 @@ This loop will be repeated again and again until the bot is stopped. * Calculate entry / exit signals (calls `populate_entry_trend()` and `populate_exit_trend()` once per pair). * Loops per candle simulating entry and exit points. * Check for Order timeouts, either via the `unfilledtimeout` configuration, or via `check_entry_timeout()` / `check_exit_timeout()` strategy callbacks. + * Calls `adjust_entry_price()` strategy callback for open entry orders. * Check for trade entry signals (`enter_long` / `enter_short` columns). * Confirm trade entry / exits (calls `confirm_trade_entry()` and `confirm_trade_exit()` if implemented in the strategy). * Call `custom_entry_price()` (if implemented in the strategy) to determine entry price (Prices are moved to be within the opening candle). diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 750d5fbd0..ab67a3c26 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -765,7 +765,7 @@ class AwesomeStrategy(IStrategy): """ # Limit orders to use and follow SMA200 as price target for the first 10 minutes since entry trigger for BTC/USDT pair. if pair == 'BTC/USDT' and entry_tag == 'long_sma200' and side == 'long' and (current_time - timedelta(minutes=10) > trade.open_date_utc: - # just cancel the order if it has been filled more than half of the ammount + # just cancel the order if it has been filled more than half of the amount if order.filled > order.remaining: return None else: diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 86dcb1094..45300b744 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -934,7 +934,7 @@ class Backtesting: else: del trade.orders[trade.orders.index(order)] - # place new order if None was not returned + # place new order if result was not None if requested_rate: self._enter_trade(pair=trade.pair, row=row, trade=trade, requested_rate=requested_rate, From bfc7898654c82bad60abd59a338dc270c6733253 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 7 May 2022 21:56:22 +0300 Subject: [PATCH 052/449] Report profit only on filled entries. --- freqtrade/rpc/rpc.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 12adc34d1..ba0db72ba 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -177,16 +177,20 @@ class RPC: current_rate = NAN else: current_rate = trade.close_rate - current_profit = trade.calc_profit_ratio(current_rate) - current_profit_abs = trade.calc_profit(current_rate) - current_profit_fiat: Optional[float] = None - # Calculate fiat profit - if self._fiat_converter: - current_profit_fiat = self._fiat_converter.convert_amount( - current_profit_abs, - self._freqtrade.config['stake_currency'], - self._freqtrade.config['fiat_display_currency'] - ) + if len(trade.select_filled_orders(trade.entry_side)) > 0: + logger.warning(trade.select_filled_orders(trade.entry_side)) + current_profit = trade.calc_profit_ratio(current_rate) + current_profit_abs = trade.calc_profit(current_rate) + current_profit_fiat: Optional[float] = None + # Calculate fiat profit + if self._fiat_converter: + current_profit_fiat = self._fiat_converter.convert_amount( + current_profit_abs, + self._freqtrade.config['stake_currency'], + self._freqtrade.config['fiat_display_currency'] + ) + else: + current_profit = current_profit_abs = current_profit_fiat = 0.0 # Calculate guaranteed profit (in case of trailing stop) stoploss_entry_dist = trade.calc_profit(trade.stop_loss) @@ -235,8 +239,12 @@ class RPC: trade.pair, side='exit', is_short=trade.is_short, refresh=False) except (PricingError, ExchangeError): current_rate = NAN - trade_profit = trade.calc_profit(current_rate) - profit_str = f'{trade.calc_profit_ratio(current_rate):.2%}' + if len(trade.select_filled_orders(trade.entry_side)) > 0: + trade_profit = trade.calc_profit(current_rate) + profit_str = f'{trade.calc_profit_ratio(current_rate):.2%}' + else: + trade_profit = 0.0 + profit_str = f'{0.0:.2f}' direction_str = ('S' if trade.is_short else 'L') if nonspot else '' if self._fiat_converter: fiat_profit = self._fiat_converter.convert_amount( @@ -244,7 +252,7 @@ class RPC: stake_currency, fiat_display_currency ) - if fiat_profit and not isnan(fiat_profit): + if not isnan(fiat_profit): profit_str += f" ({fiat_profit:.2f})" fiat_profit_sum = fiat_profit if isnan(fiat_profit_sum) \ else fiat_profit_sum + fiat_profit From 45b328af2eef747e700228b56dde7d236d2a7e51 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 8 May 2022 08:11:39 +0200 Subject: [PATCH 053/449] explicitly call cleanup when cleaning backtest --- freqtrade/rpc/api_server/api_backtest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/rpc/api_server/api_backtest.py b/freqtrade/rpc/api_server/api_backtest.py index 41712632b..26b100408 100644 --- a/freqtrade/rpc/api_server/api_backtest.py +++ b/freqtrade/rpc/api_server/api_backtest.py @@ -172,6 +172,7 @@ def api_delete_backtest(ws_mode=Depends(is_webserver_mode)): "status_msg": "Backtest running", } if ApiServer._bt: + ApiServer._bt.cleanup() del ApiServer._bt ApiServer._bt = None del ApiServer._bt_data From d79b90a98fa90cbf56d510275e94d044e25fda0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Sun, 8 May 2022 12:46:58 +0530 Subject: [PATCH 054/449] consistent exchange name --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d7b1dda37..03cd322a6 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -831,7 +831,7 @@ class FreqtradeBot(LoggingMixin): 'type': msg_type, 'buy_tag': trade.enter_tag, 'enter_tag': trade.enter_tag, - 'exchange': self.exchange.name.capitalize(), + 'exchange': trade.exchange.capitalize(), 'pair': trade.pair, 'leverage': trade.leverage if trade.leverage else None, 'direction': 'Short' if trade.is_short else 'Long', @@ -861,7 +861,7 @@ class FreqtradeBot(LoggingMixin): 'type': RPCMessageType.ENTRY_CANCEL, 'buy_tag': trade.enter_tag, 'enter_tag': trade.enter_tag, - 'exchange': self.exchange.name.capitalize(), + 'exchange': trade.exchange.capitalize(), 'pair': trade.pair, 'leverage': trade.leverage, 'direction': 'Short' if trade.is_short else 'Long', From f43ae0ea439d6aab7ce07daf119c0a7922824539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Sun, 8 May 2022 13:53:07 +0530 Subject: [PATCH 055/449] logged balance details --- freqtrade/wallets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index d93689a0e..9b91430e2 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -300,7 +300,8 @@ class Wallets: if min_stake_amount is not None and min_stake_amount > max_stake_amount: if self._log: - logger.warning("Minimum stake amount > available balance.") + logger.warning("Minimum stake amount > available balance." + f"{min_stake_amount} > {max_stake_amount}") return 0 if min_stake_amount is not None and stake_amount < min_stake_amount: if self._log: From 1436bc1a709d5870cb55e19dd346b2c9f26677df Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 8 May 2022 15:30:44 +0200 Subject: [PATCH 056/449] Update list-strategies command closes #6795 --- docs/utils.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/utils.md b/docs/utils.md index 5ef5646c3..6c1b26b01 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -119,6 +119,7 @@ This subcommand is useful for finding problems in your environment with loading usage: freqtrade list-strategies [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [--strategy-path PATH] [-1] [--no-color] + [--recursive-strategy-search] optional arguments: -h, --help show this help message and exit @@ -126,6 +127,9 @@ optional arguments: -1, --one-column Print output in one column. --no-color Disable colorization of hyperopt results. May be useful if you are redirecting output to a file. + --recursive-strategy-search + Recursively search for a strategy in the strategies + folder. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). @@ -134,9 +138,10 @@ Common arguments: details. -V, --version show program's version number and exit -c PATH, --config PATH - Specify configuration file (default: `config.json`). - Multiple --config options may be used. Can be set to - `-` to read config from stdin. + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. -d PATH, --datadir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH From 4a7515e66acc49bac0ff2b2d809dad9e44bec651 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 8 May 2022 16:04:06 +0200 Subject: [PATCH 057/449] Add test for 0.0 case --- freqtrade/rpc/rpc.py | 1 - tests/rpc/test_rpc.py | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index ba0db72ba..a98e3f96d 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -178,7 +178,6 @@ class RPC: else: current_rate = trade.close_rate if len(trade.select_filled_orders(trade.entry_side)) > 0: - logger.warning(trade.select_filled_orders(trade.entry_side)) current_profit = trade.calc_profit_ratio(current_rate) current_profit_abs = trade.calc_profit(current_rate) current_profit_fiat: Optional[float] = None diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index f4a2f6099..95645c8ba 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -233,9 +233,20 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: freqtradebot.state = State.RUNNING with pytest.raises(RPCException, match=r'.*no active trade*'): rpc._rpc_status_table(default_conf['stake_currency'], 'USD') - + mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=False) freqtradebot.enter_positions() + result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') + assert "Since" in headers + assert "Pair" in headers + assert 'instantly' == result[0][2] + assert 'ETH/BTC' in result[0][1] + assert '0.00' == result[0][3] + assert isnan(fiat_profit_sum) + + mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=True) + freqtradebot.process() + result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') assert "Since" in headers assert "Pair" in headers @@ -243,8 +254,8 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: assert 'ETH/BTC' in result[0][1] assert '-0.41%' == result[0][3] assert isnan(fiat_profit_sum) - # Test with fiatconvert + # Test with fiatconvert rpc._fiat_converter = CryptoToFiatConverter() result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') assert "Since" in headers From 3221726d85c97afd4ce3e01c50f761750c9799e8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 8 May 2022 17:27:07 +0200 Subject: [PATCH 058/449] Update migration to use boolean value closes #6794 --- freqtrade/persistence/migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index 03f3c3fb9..4d29b3d49 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -99,7 +99,7 @@ def migrate_trades_and_orders_table( liquidation_price = get_column_def(cols, 'liquidation_price', get_column_def(cols, 'isolated_liq', 'null')) # sqlite does not support literals for booleans - is_short = get_column_def(cols, 'is_short', '0') + is_short = get_column_def(cols, 'is_short', 'false') # Margin Properties interest_rate = get_column_def(cols, 'interest_rate', '0.0') From af1a5e044987e0a74ec31ca5a0aba00b1c668b39 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 8 May 2022 17:38:06 +0200 Subject: [PATCH 059/449] Extract base and Pairlock from models file --- freqtrade/persistence/base.py | 7 ++++ freqtrade/persistence/models.py | 69 ++---------------------------- freqtrade/persistence/pairlock.py | 70 +++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 65 deletions(-) create mode 100644 freqtrade/persistence/base.py create mode 100644 freqtrade/persistence/pairlock.py diff --git a/freqtrade/persistence/base.py b/freqtrade/persistence/base.py new file mode 100644 index 000000000..fb2d561e1 --- /dev/null +++ b/freqtrade/persistence/base.py @@ -0,0 +1,7 @@ + +from typing import Any + +from sqlalchemy.orm import declarative_base + + +_DECL_BASE: Any = declarative_base() diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index cb07a4c6c..92b754d0c 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -7,9 +7,9 @@ from decimal import Decimal from typing import Any, Dict, List, Optional from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String, - create_engine, desc, func, inspect, or_) + create_engine, desc, func, inspect) from sqlalchemy.exc import NoSuchModuleError -from sqlalchemy.orm import Query, declarative_base, relationship, scoped_session, sessionmaker +from sqlalchemy.orm import Query, relationship, scoped_session, sessionmaker from sqlalchemy.pool import StaticPool from sqlalchemy.sql.schema import UniqueConstraint @@ -17,13 +17,14 @@ from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, from freqtrade.enums import ExitType, TradingMode from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.leverage import interest +from freqtrade.persistence.base import _DECL_BASE from freqtrade.persistence.migrations import check_migrate +from freqtrade.persistence.pairlock import PairLock logger = logging.getLogger(__name__) -_DECL_BASE: Any = declarative_base() _SQL_DOCS_URL = 'http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls' @@ -1419,65 +1420,3 @@ class Trade(_DECL_BASE, LocalTrade): .group_by(Trade.pair) \ .order_by(desc('profit_sum')).first() return best_pair - - -class PairLock(_DECL_BASE): - """ - Pair Locks database model. - """ - __tablename__ = 'pairlocks' - - id = Column(Integer, primary_key=True) - - pair = Column(String(25), nullable=False, index=True) - # lock direction - long, short or * (for both) - side = Column(String(25), nullable=False, default="*") - reason = Column(String(255), nullable=True) - # Time the pair was locked (start time) - lock_time = Column(DateTime, nullable=False) - # Time until the pair is locked (end time) - lock_end_time = Column(DateTime, nullable=False, index=True) - - active = Column(Boolean, nullable=False, default=True, index=True) - - def __repr__(self): - lock_time = self.lock_time.strftime(DATETIME_PRINT_FORMAT) - lock_end_time = self.lock_end_time.strftime(DATETIME_PRINT_FORMAT) - return ( - f'PairLock(id={self.id}, pair={self.pair}, side={self.side}, lock_time={lock_time}, ' - f'lock_end_time={lock_end_time}, reason={self.reason}, active={self.active})') - - @staticmethod - def query_pair_locks(pair: Optional[str], now: datetime, side: str = '*') -> Query: - """ - Get all currently active locks for this pair - :param pair: Pair to check for. Returns all current locks if pair is empty - :param now: Datetime object (generated via datetime.now(timezone.utc)). - """ - filters = [PairLock.lock_end_time > now, - # Only active locks - PairLock.active.is_(True), ] - if pair: - filters.append(PairLock.pair == pair) - if side != '*': - filters.append(or_(PairLock.side == side, PairLock.side == '*')) - else: - filters.append(PairLock.side == '*') - - return PairLock.query.filter( - *filters - ) - - def to_json(self) -> Dict[str, Any]: - return { - 'id': self.id, - 'pair': self.pair, - 'lock_time': self.lock_time.strftime(DATETIME_PRINT_FORMAT), - 'lock_timestamp': int(self.lock_time.replace(tzinfo=timezone.utc).timestamp() * 1000), - 'lock_end_time': self.lock_end_time.strftime(DATETIME_PRINT_FORMAT), - 'lock_end_timestamp': int(self.lock_end_time.replace(tzinfo=timezone.utc - ).timestamp() * 1000), - 'reason': self.reason, - 'side': self.side, - 'active': self.active, - } diff --git a/freqtrade/persistence/pairlock.py b/freqtrade/persistence/pairlock.py new file mode 100644 index 000000000..926c641b0 --- /dev/null +++ b/freqtrade/persistence/pairlock.py @@ -0,0 +1,70 @@ +from datetime import datetime, timezone +from typing import Any, Dict, Optional + +from sqlalchemy import Boolean, Column, DateTime, Integer, String, or_ +from sqlalchemy.orm import Query + +from freqtrade.constants import DATETIME_PRINT_FORMAT +from freqtrade.persistence.base import _DECL_BASE + + +class PairLock(_DECL_BASE): + """ + Pair Locks database model. + """ + __tablename__ = 'pairlocks' + + id = Column(Integer, primary_key=True) + + pair = Column(String(25), nullable=False, index=True) + # lock direction - long, short or * (for both) + side = Column(String(25), nullable=False, default="*") + reason = Column(String(255), nullable=True) + # Time the pair was locked (start time) + lock_time = Column(DateTime, nullable=False) + # Time until the pair is locked (end time) + lock_end_time = Column(DateTime, nullable=False, index=True) + + active = Column(Boolean, nullable=False, default=True, index=True) + + def __repr__(self): + lock_time = self.lock_time.strftime(DATETIME_PRINT_FORMAT) + lock_end_time = self.lock_end_time.strftime(DATETIME_PRINT_FORMAT) + return ( + f'PairLock(id={self.id}, pair={self.pair}, side={self.side}, lock_time={lock_time}, ' + f'lock_end_time={lock_end_time}, reason={self.reason}, active={self.active})') + + @staticmethod + def query_pair_locks(pair: Optional[str], now: datetime, side: str = '*') -> Query: + """ + Get all currently active locks for this pair + :param pair: Pair to check for. Returns all current locks if pair is empty + :param now: Datetime object (generated via datetime.now(timezone.utc)). + """ + filters = [PairLock.lock_end_time > now, + # Only active locks + PairLock.active.is_(True), ] + if pair: + filters.append(PairLock.pair == pair) + if side != '*': + filters.append(or_(PairLock.side == side, PairLock.side == '*')) + else: + filters.append(PairLock.side == '*') + + return PairLock.query.filter( + *filters + ) + + def to_json(self) -> Dict[str, Any]: + return { + 'id': self.id, + 'pair': self.pair, + 'lock_time': self.lock_time.strftime(DATETIME_PRINT_FORMAT), + 'lock_timestamp': int(self.lock_time.replace(tzinfo=timezone.utc).timestamp() * 1000), + 'lock_end_time': self.lock_end_time.strftime(DATETIME_PRINT_FORMAT), + 'lock_end_timestamp': int(self.lock_end_time.replace(tzinfo=timezone.utc + ).timestamp() * 1000), + 'reason': self.reason, + 'side': self.side, + 'active': self.active, + } From b58e811b1486ae62e835cbea3e40cf88128243a0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 8 May 2022 17:45:20 +0200 Subject: [PATCH 060/449] Move trade/order Models to their own class --- freqtrade/persistence/__init__.py | 4 +- freqtrade/persistence/models.py | 1341 +------------------------ freqtrade/persistence/trade_model.py | 1346 ++++++++++++++++++++++++++ freqtrade/strategy/interface.py | 6 +- 4 files changed, 1354 insertions(+), 1343 deletions(-) create mode 100644 freqtrade/persistence/trade_model.py diff --git a/freqtrade/persistence/__init__.py b/freqtrade/persistence/__init__.py index d1fcac0ba..ab6e2f6a5 100644 --- a/freqtrade/persistence/__init__.py +++ b/freqtrade/persistence/__init__.py @@ -1,5 +1,5 @@ # flake8: noqa: F401 -from freqtrade.persistence.models import (LocalTrade, Order, Trade, clean_dry_run_db, cleanup_db, - init_db) +from freqtrade.persistence.models import clean_dry_run_db, cleanup_db, init_db from freqtrade.persistence.pairlock_middleware import PairLocks +from freqtrade.persistence.trade_model import LocalTrade, Order, Trade diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 92b754d0c..c31e50892 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -2,24 +2,17 @@ This module contains the class to persist trades into SQLite """ import logging -from datetime import datetime, timedelta, timezone -from decimal import Decimal -from typing import Any, Dict, List, Optional -from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String, - create_engine, desc, func, inspect) +from sqlalchemy import create_engine, inspect from sqlalchemy.exc import NoSuchModuleError -from sqlalchemy.orm import Query, relationship, scoped_session, sessionmaker +from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.pool import StaticPool -from sqlalchemy.sql.schema import UniqueConstraint -from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, BuySell, LongShort -from freqtrade.enums import ExitType, TradingMode -from freqtrade.exceptions import DependencyException, OperationalException -from freqtrade.leverage import interest +from freqtrade.exceptions import OperationalException from freqtrade.persistence.base import _DECL_BASE from freqtrade.persistence.migrations import check_migrate from freqtrade.persistence.pairlock import PairLock +from freqtrade.persistence.trade_model import Order, Trade logger = logging.getLogger(__name__) @@ -94,1329 +87,3 @@ def clean_dry_run_db() -> None: if 'dry_run' in trade.open_order_id: trade.open_order_id = None Trade.commit() - - -class Order(_DECL_BASE): - """ - Order database model - Keeps a record of all orders placed on the exchange - - One to many relationship with Trades: - - One trade can have many orders - - One Order can only be associated with one Trade - - Mirrors CCXT Order structure - """ - __tablename__ = 'orders' - # Uniqueness should be ensured over pair, order_id - # its likely that order_id is unique per Pair on some exchanges. - __table_args__ = (UniqueConstraint('ft_pair', 'order_id', name="_order_pair_order_id"),) - - id = Column(Integer, primary_key=True) - ft_trade_id = Column(Integer, ForeignKey('trades.id'), index=True) - - trade = relationship("Trade", back_populates="orders") - - # order_side can only be 'buy', 'sell' or 'stoploss' - ft_order_side: str = Column(String(25), nullable=False) - ft_pair: str = Column(String(25), nullable=False) - ft_is_open = Column(Boolean, nullable=False, default=True, index=True) - - order_id: str = Column(String(255), nullable=False, index=True) - status = Column(String(255), nullable=True) - symbol = Column(String(25), nullable=True) - order_type: str = Column(String(50), nullable=True) - side = Column(String(25), nullable=True) - price = Column(Float, nullable=True) - average = Column(Float, nullable=True) - amount = Column(Float, nullable=True) - filled = Column(Float, nullable=True) - remaining = Column(Float, nullable=True) - cost = Column(Float, nullable=True) - order_date = Column(DateTime, nullable=True, default=datetime.utcnow) - order_filled_date = Column(DateTime, nullable=True) - order_update_date = Column(DateTime, nullable=True) - - ft_fee_base = Column(Float, nullable=True) - - @property - def order_date_utc(self) -> datetime: - """ Order-date with UTC timezoneinfo""" - return self.order_date.replace(tzinfo=timezone.utc) - - @property - def safe_price(self) -> float: - return self.average or self.price - - @property - def safe_filled(self) -> float: - return self.filled or self.amount or 0.0 - - @property - def safe_fee_base(self) -> float: - return self.ft_fee_base or 0.0 - - @property - def safe_amount_after_fee(self) -> float: - return self.safe_filled - self.safe_fee_base - - def __repr__(self): - - return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, ' - f'side={self.side}, order_type={self.order_type}, status={self.status})') - - def update_from_ccxt_object(self, order): - """ - Update Order from ccxt response - Only updates if fields are available from ccxt - - """ - if self.order_id != str(order['id']): - raise DependencyException("Order-id's don't match") - - self.status = order.get('status', self.status) - self.symbol = order.get('symbol', self.symbol) - self.order_type = order.get('type', self.order_type) - self.side = order.get('side', self.side) - self.price = order.get('price', self.price) - self.amount = order.get('amount', self.amount) - self.filled = order.get('filled', self.filled) - self.average = order.get('average', self.average) - self.remaining = order.get('remaining', self.remaining) - self.cost = order.get('cost', self.cost) - - if 'timestamp' in order and order['timestamp'] is not None: - self.order_date = datetime.fromtimestamp(order['timestamp'] / 1000, tz=timezone.utc) - - self.ft_is_open = True - if self.status in NON_OPEN_EXCHANGE_STATES: - self.ft_is_open = False - if (order.get('filled', 0.0) or 0.0) > 0: - self.order_filled_date = datetime.now(timezone.utc) - self.order_update_date = datetime.now(timezone.utc) - - def to_json(self, entry_side: str) -> Dict[str, Any]: - return { - 'pair': self.ft_pair, - 'order_id': self.order_id, - 'status': self.status, - 'amount': self.amount, - 'average': round(self.average, 8) if self.average else 0, - 'safe_price': self.safe_price, - 'cost': self.cost if self.cost else 0, - 'filled': self.filled, - 'ft_order_side': self.ft_order_side, - 'is_open': self.ft_is_open, - 'order_date': self.order_date.strftime(DATETIME_PRINT_FORMAT) - if self.order_date else None, - 'order_timestamp': int(self.order_date.replace( - tzinfo=timezone.utc).timestamp() * 1000) if self.order_date else None, - 'order_filled_date': self.order_filled_date.strftime(DATETIME_PRINT_FORMAT) - if self.order_filled_date else None, - 'order_filled_timestamp': int(self.order_filled_date.replace( - tzinfo=timezone.utc).timestamp() * 1000) if self.order_filled_date else None, - 'order_type': self.order_type, - 'price': self.price, - 'ft_is_entry': self.ft_order_side == entry_side, - 'remaining': self.remaining, - } - - def close_bt_order(self, close_date: datetime, trade: 'LocalTrade'): - self.order_filled_date = close_date - self.filled = self.amount - self.status = 'closed' - self.ft_is_open = False - if (self.ft_order_side == trade.entry_side - and len(trade.select_filled_orders(trade.entry_side)) == 1): - trade.open_rate = self.price - trade.recalc_open_trade_value() - - @staticmethod - def update_orders(orders: List['Order'], order: Dict[str, Any]): - """ - Get all non-closed orders - useful when trying to batch-update orders - """ - if not isinstance(order, dict): - logger.warning(f"{order} is not a valid response object.") - return - - filtered_orders = [o for o in orders if o.order_id == order.get('id')] - if filtered_orders: - oobj = filtered_orders[0] - oobj.update_from_ccxt_object(order) - Order.query.session.commit() - else: - logger.warning(f"Did not find order for {order}.") - - @staticmethod - def parse_from_ccxt_object(order: Dict[str, Any], pair: str, side: str) -> 'Order': - """ - Parse an order from a ccxt object and return a new order Object. - """ - o = Order(order_id=str(order['id']), ft_order_side=side, ft_pair=pair) - - o.update_from_ccxt_object(order) - return o - - @staticmethod - def get_open_orders() -> List['Order']: - """ - Retrieve open orders from the database - :return: List of open orders - """ - return Order.query.filter(Order.ft_is_open.is_(True)).all() - - -class LocalTrade(): - """ - Trade database model. - Used in backtesting - must be aligned to Trade model! - - """ - use_db: bool = False - # Trades container for backtesting - trades: List['LocalTrade'] = [] - trades_open: List['LocalTrade'] = [] - total_profit: float = 0 - - id: int = 0 - - orders: List[Order] = [] - - exchange: str = '' - pair: str = '' - base_currency: str = '' - stake_currency: str = '' - is_open: bool = True - fee_open: float = 0.0 - fee_open_cost: Optional[float] = None - fee_open_currency: str = '' - fee_close: float = 0.0 - fee_close_cost: Optional[float] = None - fee_close_currency: str = '' - open_rate: float = 0.0 - open_rate_requested: Optional[float] = None - # open_trade_value - calculated via _calc_open_trade_value - open_trade_value: float = 0.0 - close_rate: Optional[float] = None - close_rate_requested: Optional[float] = None - close_profit: Optional[float] = None - close_profit_abs: Optional[float] = None - stake_amount: float = 0.0 - amount: float = 0.0 - amount_requested: Optional[float] = None - open_date: datetime - close_date: Optional[datetime] = None - open_order_id: Optional[str] = None - # absolute value of the stop loss - stop_loss: float = 0.0 - # percentage value of the stop loss - stop_loss_pct: float = 0.0 - # absolute value of the initial stop loss - initial_stop_loss: float = 0.0 - # percentage value of the initial stop loss - initial_stop_loss_pct: Optional[float] = None - # stoploss order id which is on exchange - stoploss_order_id: Optional[str] = None - # last update time of the stoploss order on exchange - stoploss_last_update: Optional[datetime] = None - # absolute value of the highest reached price - max_rate: float = 0.0 - # Lowest price reached - min_rate: float = 0.0 - exit_reason: str = '' - exit_order_status: str = '' - strategy: str = '' - enter_tag: Optional[str] = None - timeframe: Optional[int] = None - - trading_mode: TradingMode = TradingMode.SPOT - - # Leverage trading properties - liquidation_price: Optional[float] = None - is_short: bool = False - leverage: float = 1.0 - - # Margin trading properties - interest_rate: float = 0.0 - - # Futures properties - funding_fees: Optional[float] = None - - @property - def buy_tag(self) -> Optional[str]: - """ - Compatibility between buy_tag (old) and enter_tag (new) - Consider buy_tag deprecated - """ - return self.enter_tag - - @property - def has_no_leverage(self) -> bool: - """Returns true if this is a non-leverage, non-short trade""" - return ((self.leverage == 1.0 or self.leverage is None) and not self.is_short) - - @property - def borrowed(self) -> float: - """ - The amount of currency borrowed from the exchange for leverage trades - If a long trade, the amount is in base currency - If a short trade, the amount is in the other currency being traded - """ - if self.has_no_leverage: - return 0.0 - elif not self.is_short: - return (self.amount * self.open_rate) * ((self.leverage - 1) / self.leverage) - else: - return self.amount - - @property - def open_date_utc(self): - return self.open_date.replace(tzinfo=timezone.utc) - - @property - def close_date_utc(self): - return self.close_date.replace(tzinfo=timezone.utc) - - @property - def enter_side(self) -> str: - """ DEPRECATED, please use entry_side instead""" - # TODO: Please remove me after 2022.5 - return self.entry_side - - @property - def entry_side(self) -> str: - if self.is_short: - return "sell" - else: - return "buy" - - @property - def exit_side(self) -> BuySell: - if self.is_short: - return "buy" - else: - return "sell" - - @property - def trade_direction(self) -> LongShort: - if self.is_short: - return "short" - else: - return "long" - - @property - def safe_base_currency(self) -> str: - """ - Compatibility layer for asset - which can be empty for old trades. - """ - try: - return self.base_currency or self.pair.split('/')[0] - except IndexError: - return '' - - @property - def safe_quote_currency(self) -> str: - """ - Compatibility layer for asset - which can be empty for old trades. - """ - try: - return self.stake_currency or self.pair.split('/')[1].split(':')[0] - except IndexError: - return '' - - def __init__(self, **kwargs): - for key in kwargs: - setattr(self, key, kwargs[key]) - self.recalc_open_trade_value() - if self.trading_mode == TradingMode.MARGIN and self.interest_rate is None: - raise OperationalException( - f"{self.trading_mode.value} trading requires param interest_rate on trades") - - def __repr__(self): - open_since = self.open_date.strftime(DATETIME_PRINT_FORMAT) if self.is_open else 'closed' - - return ( - f'Trade(id={self.id}, pair={self.pair}, amount={self.amount:.8f}, ' - f'is_short={self.is_short or False}, leverage={self.leverage or 1.0}, ' - f'open_rate={self.open_rate:.8f}, open_since={open_since})' - ) - - def to_json(self) -> Dict[str, Any]: - filled_orders = self.select_filled_orders() - orders = [order.to_json(self.entry_side) for order in filled_orders] - - return { - 'trade_id': self.id, - 'pair': self.pair, - 'base_currency': self.safe_base_currency, - 'quote_currency': self.safe_quote_currency, - 'is_open': self.is_open, - 'exchange': self.exchange, - 'amount': round(self.amount, 8), - 'amount_requested': round(self.amount_requested, 8) if self.amount_requested else None, - 'stake_amount': round(self.stake_amount, 8), - 'strategy': self.strategy, - 'buy_tag': self.enter_tag, - 'enter_tag': self.enter_tag, - 'timeframe': self.timeframe, - - 'fee_open': self.fee_open, - 'fee_open_cost': self.fee_open_cost, - 'fee_open_currency': self.fee_open_currency, - 'fee_close': self.fee_close, - 'fee_close_cost': self.fee_close_cost, - 'fee_close_currency': self.fee_close_currency, - - 'open_date': self.open_date.strftime(DATETIME_PRINT_FORMAT), - 'open_timestamp': int(self.open_date.replace(tzinfo=timezone.utc).timestamp() * 1000), - 'open_rate': self.open_rate, - 'open_rate_requested': self.open_rate_requested, - 'open_trade_value': round(self.open_trade_value, 8), - - 'close_date': (self.close_date.strftime(DATETIME_PRINT_FORMAT) - if self.close_date else None), - 'close_timestamp': int(self.close_date.replace( - tzinfo=timezone.utc).timestamp() * 1000) if self.close_date else None, - 'close_rate': self.close_rate, - 'close_rate_requested': self.close_rate_requested, - 'close_profit': self.close_profit, # Deprecated - 'close_profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, - 'close_profit_abs': self.close_profit_abs, # Deprecated - - 'trade_duration_s': (int((self.close_date_utc - self.open_date_utc).total_seconds()) - if self.close_date else None), - 'trade_duration': (int((self.close_date_utc - self.open_date_utc).total_seconds() // 60) - if self.close_date else None), - - 'profit_ratio': self.close_profit, - 'profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, - 'profit_abs': self.close_profit_abs, - - 'sell_reason': self.exit_reason, # Deprecated - 'exit_reason': self.exit_reason, - 'exit_order_status': self.exit_order_status, - 'stop_loss_abs': self.stop_loss, - 'stop_loss_ratio': self.stop_loss_pct if self.stop_loss_pct else None, - 'stop_loss_pct': (self.stop_loss_pct * 100) if self.stop_loss_pct else None, - 'stoploss_order_id': self.stoploss_order_id, - 'stoploss_last_update': (self.stoploss_last_update.strftime(DATETIME_PRINT_FORMAT) - if self.stoploss_last_update else None), - 'stoploss_last_update_timestamp': int(self.stoploss_last_update.replace( - tzinfo=timezone.utc).timestamp() * 1000) if self.stoploss_last_update else None, - 'initial_stop_loss_abs': self.initial_stop_loss, - 'initial_stop_loss_ratio': (self.initial_stop_loss_pct - if self.initial_stop_loss_pct else None), - 'initial_stop_loss_pct': (self.initial_stop_loss_pct * 100 - if self.initial_stop_loss_pct else None), - 'min_rate': self.min_rate, - 'max_rate': self.max_rate, - - 'leverage': self.leverage, - 'interest_rate': self.interest_rate, - 'liquidation_price': self.liquidation_price, - 'is_short': self.is_short, - 'trading_mode': self.trading_mode, - 'funding_fees': self.funding_fees, - 'open_order_id': self.open_order_id, - 'orders': orders, - } - - @staticmethod - def reset_trades() -> None: - """ - Resets all trades. Only active for backtesting mode. - """ - LocalTrade.trades = [] - LocalTrade.trades_open = [] - LocalTrade.total_profit = 0 - - def adjust_min_max_rates(self, current_price: float, current_price_low: float) -> None: - """ - Adjust the max_rate and min_rate. - """ - self.max_rate = max(current_price, self.max_rate or self.open_rate) - self.min_rate = min(current_price_low, self.min_rate or self.open_rate) - - def set_isolated_liq(self, liquidation_price: Optional[float]): - """ - Method you should use to set self.liquidation price. - Assures stop_loss is not passed the liquidation price - """ - if not liquidation_price: - return - self.liquidation_price = liquidation_price - - def _set_stop_loss(self, stop_loss: float, percent: float): - """ - Method you should use to set self.stop_loss. - Assures stop_loss is not passed the liquidation price - """ - if self.liquidation_price is not None: - if self.is_short: - sl = min(stop_loss, self.liquidation_price) - else: - sl = max(stop_loss, self.liquidation_price) - else: - sl = stop_loss - - if not self.stop_loss: - self.initial_stop_loss = sl - self.stop_loss = sl - - self.stop_loss_pct = -1 * abs(percent) - self.stoploss_last_update = datetime.utcnow() - - def adjust_stop_loss(self, current_price: float, stoploss: float, - initial: bool = False) -> None: - """ - This adjusts the stop loss to it's most recently observed setting - :param current_price: Current rate the asset is traded - :param stoploss: Stoploss as factor (sample -0.05 -> -5% below current price). - :param initial: Called to initiate stop_loss. - Skips everything if self.stop_loss is already set. - """ - if initial and not (self.stop_loss is None or self.stop_loss == 0): - # Don't modify if called with initial and nothing to do - return - - leverage = self.leverage or 1.0 - if self.is_short: - new_loss = float(current_price * (1 + abs(stoploss / leverage))) - # If trading with leverage, don't set the stoploss below the liquidation price - if self.liquidation_price: - new_loss = min(self.liquidation_price, new_loss) - else: - new_loss = float(current_price * (1 - abs(stoploss / leverage))) - # If trading with leverage, don't set the stoploss below the liquidation price - if self.liquidation_price: - new_loss = max(self.liquidation_price, new_loss) - - # no stop loss assigned yet - if self.initial_stop_loss_pct is None: - logger.debug(f"{self.pair} - Assigning new stoploss...") - self._set_stop_loss(new_loss, stoploss) - self.initial_stop_loss = new_loss - self.initial_stop_loss_pct = -1 * abs(stoploss) - - # evaluate if the stop loss needs to be updated - else: - - higher_stop = new_loss > self.stop_loss - lower_stop = new_loss < self.stop_loss - - # stop losses only walk up, never down!, - # ? But adding more to a leveraged trade would create a lower liquidation price, - # ? decreasing the minimum stoploss - if (higher_stop and not self.is_short) or (lower_stop and self.is_short): - logger.debug(f"{self.pair} - Adjusting stoploss...") - self._set_stop_loss(new_loss, stoploss) - else: - logger.debug(f"{self.pair} - Keeping current stoploss...") - - logger.debug( - f"{self.pair} - Stoploss adjusted. current_price={current_price:.8f}, " - f"open_rate={self.open_rate:.8f}, max_rate={self.max_rate or self.open_rate:.8f}, " - f"initial_stop_loss={self.initial_stop_loss:.8f}, " - f"stop_loss={self.stop_loss:.8f}. " - f"Trailing stoploss saved us: " - f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f}.") - - def update_trade(self, order: Order) -> None: - """ - Updates this entity with amount and actual open/close rates. - :param order: order retrieved by exchange.fetch_order() - :return: None - """ - - # Ignore open and cancelled orders - if order.status == 'open' or order.safe_price is None: - return - - logger.info(f'Updating trade (id={self.id}) ...') - - if order.ft_order_side == self.entry_side: - # Update open rate and actual amount - self.open_rate = order.safe_price - self.amount = order.safe_amount_after_fee - if self.is_open: - payment = "SELL" if self.is_short else "BUY" - logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.') - self.open_order_id = None - self.recalc_trade_from_orders() - elif order.ft_order_side == self.exit_side: - if self.is_open: - payment = "BUY" if self.is_short else "SELL" - # * On margin shorts, you buy a little bit more than the amount (amount + interest) - logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.') - self.close(order.safe_price) - elif order.ft_order_side == 'stoploss': - self.stoploss_order_id = None - self.close_rate_requested = self.stop_loss - self.exit_reason = ExitType.STOPLOSS_ON_EXCHANGE.value - if self.is_open: - logger.info(f'{order.order_type.upper()} is hit for {self}.') - self.close(order.safe_price) - else: - raise ValueError(f'Unknown order type: {order.order_type}') - Trade.commit() - - def close(self, rate: float, *, show_msg: bool = True) -> None: - """ - Sets close_rate to the given rate, calculates total profit - and marks trade as closed - """ - self.close_rate = rate - self.close_date = self.close_date or datetime.utcnow() - self.close_profit = self.calc_profit_ratio() - self.close_profit_abs = self.calc_profit() - self.is_open = False - self.exit_order_status = 'closed' - self.open_order_id = None - if show_msg: - logger.info( - 'Marking %s as closed as the trade is fulfilled and found no open orders for it.', - self - ) - - def update_fee(self, fee_cost: float, fee_currency: Optional[str], fee_rate: Optional[float], - side: str) -> None: - """ - Update Fee parameters. Only acts once per side - """ - if self.entry_side == side and self.fee_open_currency is None: - self.fee_open_cost = fee_cost - self.fee_open_currency = fee_currency - if fee_rate is not None: - self.fee_open = fee_rate - # Assume close-fee will fall into the same fee category and take an educated guess - self.fee_close = fee_rate - elif self.exit_side == side and self.fee_close_currency is None: - self.fee_close_cost = fee_cost - self.fee_close_currency = fee_currency - if fee_rate is not None: - self.fee_close = fee_rate - - def fee_updated(self, side: str) -> bool: - """ - Verify if this side (buy / sell) has already been updated - """ - if self.entry_side == side: - return self.fee_open_currency is not None - elif self.exit_side == side: - return self.fee_close_currency is not None - else: - return False - - def update_order(self, order: Dict) -> None: - Order.update_orders(self.orders, order) - - def get_exit_order_count(self) -> int: - """ - Get amount of failed exiting orders - assumes full exits. - """ - return len([o for o in self.orders if o.ft_order_side == self.exit_side]) - - def _calc_open_trade_value(self) -> float: - """ - Calculate the open_rate including open_fee. - :return: Price in of the open trade incl. Fees - """ - open_trade = Decimal(self.amount) * Decimal(self.open_rate) - fees = open_trade * Decimal(self.fee_open) - if self.is_short: - return float(open_trade - fees) - else: - return float(open_trade + fees) - - def recalc_open_trade_value(self) -> None: - """ - Recalculate open_trade_value. - Must be called whenever open_rate, fee_open or is_short is changed. - """ - self.open_trade_value = self._calc_open_trade_value() - - def calculate_interest(self, interest_rate: Optional[float] = None) -> Decimal: - """ - :param interest_rate: interest_charge for borrowing this coin(optional). - If interest_rate is not set self.interest_rate will be used - """ - zero = Decimal(0.0) - # If nothing was borrowed - if self.trading_mode != TradingMode.MARGIN or self.has_no_leverage: - return zero - - open_date = self.open_date.replace(tzinfo=None) - now = (self.close_date or datetime.now(timezone.utc)).replace(tzinfo=None) - sec_per_hour = Decimal(3600) - total_seconds = Decimal((now - open_date).total_seconds()) - hours = total_seconds / sec_per_hour or zero - - rate = Decimal(interest_rate or self.interest_rate) - borrowed = Decimal(self.borrowed) - - return interest(exchange_name=self.exchange, borrowed=borrowed, rate=rate, hours=hours) - - def _calc_base_close(self, amount: Decimal, rate: Optional[float] = None, - fee: Optional[float] = None) -> Decimal: - - close_trade = Decimal(amount) * Decimal(rate or self.close_rate) # type: ignore - fees = close_trade * Decimal(fee or self.fee_close) - - if self.is_short: - return close_trade + fees - else: - return close_trade - fees - - def calc_close_trade_value(self, rate: Optional[float] = None, - fee: Optional[float] = None, - interest_rate: Optional[float] = None) -> float: - """ - Calculate the close_rate including fee - :param fee: fee to use on the close rate (optional). - If rate is not set self.fee will be used - :param rate: rate to compare with (optional). - If rate is not set self.close_rate will be used - :param interest_rate: interest_charge for borrowing this coin (optional). - If interest_rate is not set self.interest_rate will be used - :return: Price in BTC of the open trade - """ - if rate is None and not self.close_rate: - return 0.0 - - amount = Decimal(self.amount) - trading_mode = self.trading_mode or TradingMode.SPOT - - if trading_mode == TradingMode.SPOT: - return float(self._calc_base_close(amount, rate, fee)) - - elif (trading_mode == TradingMode.MARGIN): - - total_interest = self.calculate_interest(interest_rate) - - if self.is_short: - amount = amount + total_interest - return float(self._calc_base_close(amount, rate, fee)) - else: - # Currency already owned for longs, no need to purchase - return float(self._calc_base_close(amount, rate, fee) - total_interest) - - elif (trading_mode == TradingMode.FUTURES): - funding_fees = self.funding_fees or 0.0 - # Positive funding_fees -> Trade has gained from fees. - # Negative funding_fees -> Trade had to pay the fees. - if self.is_short: - return float(self._calc_base_close(amount, rate, fee)) - funding_fees - else: - return float(self._calc_base_close(amount, rate, fee)) + funding_fees - else: - raise OperationalException( - f"{self.trading_mode.value} trading is not yet available using freqtrade") - - def calc_profit(self, rate: Optional[float] = None, - fee: Optional[float] = None, - interest_rate: Optional[float] = None) -> float: - """ - Calculate the absolute profit in stake currency between Close and Open trade - :param fee: fee to use on the close rate (optional). - If fee is not set self.fee will be used - :param rate: close rate to compare with (optional). - If rate is not set self.close_rate will be used - :param interest_rate: interest_charge for borrowing this coin (optional). - If interest_rate is not set self.interest_rate will be used - :return: profit in stake currency as float - """ - close_trade_value = self.calc_close_trade_value( - rate=(rate or self.close_rate), - fee=(fee or self.fee_close), - interest_rate=(interest_rate or self.interest_rate) - ) - - if self.is_short: - profit = self.open_trade_value - close_trade_value - else: - profit = close_trade_value - self.open_trade_value - return float(f"{profit:.8f}") - - def calc_profit_ratio(self, rate: Optional[float] = None, - fee: Optional[float] = None, - interest_rate: Optional[float] = None) -> float: - """ - Calculates the profit as ratio (including fee). - :param rate: rate to compare with (optional). - If rate is not set self.close_rate will be used - :param fee: fee to use on the close rate (optional). - :param interest_rate: interest_charge for borrowing this coin (optional). - If interest_rate is not set self.interest_rate will be used - :return: profit ratio as float - """ - close_trade_value = self.calc_close_trade_value( - rate=(rate or self.close_rate), - fee=(fee or self.fee_close), - interest_rate=(interest_rate or self.interest_rate) - ) - - short_close_zero = (self.is_short and close_trade_value == 0.0) - long_close_zero = (not self.is_short and self.open_trade_value == 0.0) - leverage = self.leverage or 1.0 - - if (short_close_zero or long_close_zero): - return 0.0 - else: - if self.is_short: - profit_ratio = (1 - (close_trade_value / self.open_trade_value)) * leverage - else: - profit_ratio = ((close_trade_value / self.open_trade_value) - 1) * leverage - - return float(f"{profit_ratio:.8f}") - - def recalc_trade_from_orders(self): - # We need at least 2 entry orders for averaging amounts and rates. - # TODO: this condition could probably be removed - if len(self.select_filled_orders(self.entry_side)) < 2: - self.stake_amount = self.amount * self.open_rate / self.leverage - - # Just in case, still recalc open trade value - self.recalc_open_trade_value() - return - - total_amount = 0.0 - total_stake = 0.0 - for o in self.orders: - if (o.ft_is_open or - (o.ft_order_side != self.entry_side) or - (o.status not in NON_OPEN_EXCHANGE_STATES)): - continue - - tmp_amount = o.safe_amount_after_fee - tmp_price = o.average or o.price - if o.filled is not None: - tmp_amount = o.filled - if tmp_amount > 0.0 and tmp_price is not None: - total_amount += tmp_amount - total_stake += tmp_price * tmp_amount - - if total_amount > 0: - # Leverage not updated, as we don't allow changing leverage through DCA at the moment. - self.open_rate = total_stake / total_amount - self.stake_amount = total_stake / (self.leverage or 1.0) - self.amount = total_amount - self.fee_open_cost = self.fee_open * self.stake_amount - self.recalc_open_trade_value() - if self.stop_loss_pct is not None and self.open_rate is not None: - self.adjust_stop_loss(self.open_rate, self.stop_loss_pct) - - def select_order_by_order_id(self, order_id: str) -> Optional[Order]: - """ - Finds order object by Order id. - :param order_id: Exchange order id - """ - for o in self.orders: - if o.order_id == order_id: - return o - return None - - def select_order( - self, order_side: str = None, is_open: Optional[bool] = None) -> Optional[Order]: - """ - Finds latest order for this orderside and status - :param order_side: ft_order_side of the order (either 'buy', 'sell' or 'stoploss') - :param is_open: Only search for open orders? - :return: latest Order object if it exists, else None - """ - orders = self.orders - if order_side: - orders = [o for o in self.orders if o.ft_order_side == order_side] - if is_open is not None: - orders = [o for o in orders if o.ft_is_open == is_open] - if len(orders) > 0: - return orders[-1] - else: - return None - - def select_filled_orders(self, order_side: Optional[str] = None) -> List['Order']: - """ - Finds filled orders for this orderside. - :param order_side: Side of the order (either 'buy', 'sell', or None) - :return: array of Order objects - """ - return [o for o in self.orders if ((o.ft_order_side == order_side) or (order_side is None)) - and o.ft_is_open is False and - (o.filled or 0) > 0 and - o.status in NON_OPEN_EXCHANGE_STATES] - - @property - def nr_of_successful_entries(self) -> int: - """ - Helper function to count the number of entry orders that have been filled. - :return: int count of entry orders that have been filled for this trade. - """ - - return len(self.select_filled_orders(self.entry_side)) - - @property - def nr_of_successful_exits(self) -> int: - """ - Helper function to count the number of exit orders that have been filled. - :return: int count of exit orders that have been filled for this trade. - """ - return len(self.select_filled_orders(self.exit_side)) - - @property - def nr_of_successful_buys(self) -> int: - """ - Helper function to count the number of buy orders that have been filled. - WARNING: Please use nr_of_successful_entries for short support. - :return: int count of buy orders that have been filled for this trade. - """ - - return len(self.select_filled_orders('buy')) - - @property - def nr_of_successful_sells(self) -> int: - """ - Helper function to count the number of sell orders that have been filled. - WARNING: Please use nr_of_successful_exits for short support. - :return: int count of sell orders that have been filled for this trade. - """ - return len(self.select_filled_orders('sell')) - - @property - def sell_reason(self) -> str: - """ DEPRECATED! Please use exit_reason instead.""" - return self.exit_reason - - @staticmethod - def get_trades_proxy(*, pair: str = None, is_open: bool = None, - open_date: datetime = None, close_date: datetime = None, - ) -> List['LocalTrade']: - """ - Helper function to query Trades. - Returns a List of trades, filtered on the parameters given. - In live mode, converts the filter to a database query and returns all rows - In Backtest mode, uses filters on Trade.trades to get the result. - - :return: unsorted List[Trade] - """ - - # Offline mode - without database - if is_open is not None: - if is_open: - sel_trades = LocalTrade.trades_open - else: - sel_trades = LocalTrade.trades - - else: - # Not used during backtesting, but might be used by a strategy - sel_trades = list(LocalTrade.trades + LocalTrade.trades_open) - - if pair: - sel_trades = [trade for trade in sel_trades if trade.pair == pair] - if open_date: - sel_trades = [trade for trade in sel_trades if trade.open_date > open_date] - if close_date: - sel_trades = [trade for trade in sel_trades if trade.close_date - and trade.close_date > close_date] - - return sel_trades - - @staticmethod - def close_bt_trade(trade): - LocalTrade.trades_open.remove(trade) - LocalTrade.trades.append(trade) - LocalTrade.total_profit += trade.close_profit_abs - - @staticmethod - def add_bt_trade(trade): - if trade.is_open: - LocalTrade.trades_open.append(trade) - else: - LocalTrade.trades.append(trade) - - @staticmethod - def get_open_trades() -> List[Any]: - """ - Query trades from persistence layer - """ - return Trade.get_trades_proxy(is_open=True) - - @staticmethod - def stoploss_reinitialization(desired_stoploss): - """ - Adjust initial Stoploss to desired stoploss for all open trades. - """ - for trade in Trade.get_open_trades(): - logger.info("Found open trade: %s", trade) - - # skip case if trailing-stop changed the stoploss already. - if (trade.stop_loss == trade.initial_stop_loss - and trade.initial_stop_loss_pct != desired_stoploss): - # Stoploss value got changed - - logger.info(f"Stoploss for {trade} needs adjustment...") - # Force reset of stoploss - trade.stop_loss = None - trade.initial_stop_loss_pct = None - trade.adjust_stop_loss(trade.open_rate, desired_stoploss) - logger.info(f"New stoploss: {trade.stop_loss}.") - - -class Trade(_DECL_BASE, LocalTrade): - """ - Trade database model. - Also handles updating and querying trades - - Note: Fields must be aligned with LocalTrade class - """ - __tablename__ = 'trades' - - use_db: bool = True - - id = Column(Integer, primary_key=True) - - orders = relationship("Order", order_by="Order.id", cascade="all, delete-orphan", lazy="joined") - - exchange = Column(String(25), nullable=False) - pair = Column(String(25), nullable=False, index=True) - base_currency = Column(String(25), nullable=True) - stake_currency = Column(String(25), nullable=True) - is_open = Column(Boolean, nullable=False, default=True, index=True) - fee_open = Column(Float, nullable=False, default=0.0) - fee_open_cost = Column(Float, nullable=True) - fee_open_currency = Column(String(25), nullable=True) - fee_close = Column(Float, nullable=False, default=0.0) - fee_close_cost = Column(Float, nullable=True) - fee_close_currency = Column(String(25), nullable=True) - open_rate: float = Column(Float) - open_rate_requested = Column(Float) - # open_trade_value - calculated via _calc_open_trade_value - open_trade_value = Column(Float) - close_rate: Optional[float] = Column(Float) - close_rate_requested = Column(Float) - close_profit = Column(Float) - close_profit_abs = Column(Float) - stake_amount = Column(Float, nullable=False) - amount = Column(Float) - amount_requested = Column(Float) - open_date = Column(DateTime, nullable=False, default=datetime.utcnow) - close_date = Column(DateTime) - open_order_id = Column(String(255)) - # absolute value of the stop loss - stop_loss = Column(Float, nullable=True, default=0.0) - # percentage value of the stop loss - stop_loss_pct = Column(Float, nullable=True) - # absolute value of the initial stop loss - initial_stop_loss = Column(Float, nullable=True, default=0.0) - # percentage value of the initial stop loss - initial_stop_loss_pct = Column(Float, nullable=True) - # stoploss order id which is on exchange - stoploss_order_id = Column(String(255), nullable=True, index=True) - # last update time of the stoploss order on exchange - stoploss_last_update = Column(DateTime, nullable=True) - # absolute value of the highest reached price - max_rate = Column(Float, nullable=True, default=0.0) - # Lowest price reached - min_rate = Column(Float, nullable=True) - exit_reason = Column(String(100), nullable=True) - exit_order_status = Column(String(100), nullable=True) - strategy = Column(String(100), nullable=True) - enter_tag = Column(String(100), nullable=True) - timeframe = Column(Integer, nullable=True) - - trading_mode = Column(Enum(TradingMode), nullable=True) - - # Leverage trading properties - leverage = Column(Float, nullable=True, default=1.0) - is_short = Column(Boolean, nullable=False, default=False) - liquidation_price = Column(Float, nullable=True) - - # Margin Trading Properties - interest_rate = Column(Float, nullable=False, default=0.0) - - # Futures properties - funding_fees = Column(Float, nullable=True, default=None) - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.recalc_open_trade_value() - - def delete(self) -> None: - - for order in self.orders: - Order.query.session.delete(order) - - Trade.query.session.delete(self) - Trade.commit() - - @staticmethod - def commit(): - Trade.query.session.commit() - - @staticmethod - def get_trades_proxy(*, pair: str = None, is_open: bool = None, - open_date: datetime = None, close_date: datetime = None, - ) -> List['LocalTrade']: - """ - Helper function to query Trades.j - Returns a List of trades, filtered on the parameters given. - In live mode, converts the filter to a database query and returns all rows - In Backtest mode, uses filters on Trade.trades to get the result. - - :return: unsorted List[Trade] - """ - if Trade.use_db: - trade_filter = [] - if pair: - trade_filter.append(Trade.pair == pair) - if open_date: - trade_filter.append(Trade.open_date > open_date) - if close_date: - trade_filter.append(Trade.close_date > close_date) - if is_open is not None: - trade_filter.append(Trade.is_open.is_(is_open)) - return Trade.get_trades(trade_filter).all() - else: - return LocalTrade.get_trades_proxy( - pair=pair, is_open=is_open, - open_date=open_date, - close_date=close_date - ) - - @staticmethod - def get_trades(trade_filter=None) -> Query: - """ - Helper function to query Trades using filters. - NOTE: Not supported in Backtesting. - :param trade_filter: Optional filter to apply to trades - Can be either a Filter object, or a List of filters - e.g. `(trade_filter=[Trade.id == trade_id, Trade.is_open.is_(True),])` - e.g. `(trade_filter=Trade.id == trade_id)` - :return: unsorted query object - """ - if not Trade.use_db: - raise NotImplementedError('`Trade.get_trades()` not supported in backtesting mode.') - if trade_filter is not None: - if not isinstance(trade_filter, list): - trade_filter = [trade_filter] - return Trade.query.filter(*trade_filter) - else: - return Trade.query - - @staticmethod - def get_open_order_trades() -> List['Trade']: - """ - Returns all open trades - NOTE: Not supported in Backtesting. - """ - return Trade.get_trades(Trade.open_order_id.isnot(None)).all() - - @staticmethod - def get_open_trades_without_assigned_fees(): - """ - Returns all open trades which don't have open fees set correctly - NOTE: Not supported in Backtesting. - """ - return Trade.get_trades([Trade.fee_open_currency.is_(None), - Trade.orders.any(), - Trade.is_open.is_(True), - ]).all() - - @staticmethod - def get_closed_trades_without_assigned_fees(): - """ - Returns all closed trades which don't have fees set correctly - NOTE: Not supported in Backtesting. - """ - return Trade.get_trades([Trade.fee_close_currency.is_(None), - Trade.orders.any(), - Trade.is_open.is_(False), - ]).all() - - @staticmethod - def get_total_closed_profit() -> float: - """ - Retrieves total realized profit - """ - if Trade.use_db: - total_profit = Trade.query.with_entities( - func.sum(Trade.close_profit_abs)).filter(Trade.is_open.is_(False)).scalar() - else: - total_profit = sum( - t.close_profit_abs for t in LocalTrade.get_trades_proxy(is_open=False)) - return total_profit or 0 - - @staticmethod - def total_open_trades_stakes() -> float: - """ - Calculates total invested amount in open trades - in stake currency - """ - if Trade.use_db: - total_open_stake_amount = Trade.query.with_entities( - func.sum(Trade.stake_amount)).filter(Trade.is_open.is_(True)).scalar() - else: - total_open_stake_amount = sum( - t.stake_amount for t in LocalTrade.get_trades_proxy(is_open=True)) - return total_open_stake_amount or 0 - - @staticmethod - def get_overall_performance(minutes=None) -> List[Dict[str, Any]]: - """ - Returns List of dicts containing all Trades, including profit and trade count - NOTE: Not supported in Backtesting. - """ - filters = [Trade.is_open.is_(False)] - if minutes: - start_date = datetime.now(timezone.utc) - timedelta(minutes=minutes) - filters.append(Trade.close_date >= start_date) - pair_rates = Trade.query.with_entities( - Trade.pair, - func.sum(Trade.close_profit).label('profit_sum'), - func.sum(Trade.close_profit_abs).label('profit_sum_abs'), - func.count(Trade.pair).label('count') - ).filter(*filters)\ - .group_by(Trade.pair) \ - .order_by(desc('profit_sum_abs')) \ - .all() - return [ - { - 'pair': pair, - 'profit_ratio': profit, - 'profit': round(profit * 100, 2), # Compatibility mode - 'profit_pct': round(profit * 100, 2), - 'profit_abs': profit_abs, - 'count': count - } - for pair, profit, profit_abs, count in pair_rates - ] - - @staticmethod - def get_enter_tag_performance(pair: Optional[str]) -> List[Dict[str, Any]]: - """ - Returns List of dicts containing all Trades, based on buy tag performance - Can either be average for all pairs or a specific pair provided - NOTE: Not supported in Backtesting. - """ - - filters = [Trade.is_open.is_(False)] - if(pair is not None): - filters.append(Trade.pair == pair) - - enter_tag_perf = Trade.query.with_entities( - Trade.enter_tag, - func.sum(Trade.close_profit).label('profit_sum'), - func.sum(Trade.close_profit_abs).label('profit_sum_abs'), - func.count(Trade.pair).label('count') - ).filter(*filters)\ - .group_by(Trade.enter_tag) \ - .order_by(desc('profit_sum_abs')) \ - .all() - - return [ - { - 'enter_tag': enter_tag if enter_tag is not None else "Other", - 'profit_ratio': profit, - 'profit_pct': round(profit * 100, 2), - 'profit_abs': profit_abs, - 'count': count - } - for enter_tag, profit, profit_abs, count in enter_tag_perf - ] - - @staticmethod - def get_exit_reason_performance(pair: Optional[str]) -> List[Dict[str, Any]]: - """ - Returns List of dicts containing all Trades, based on exit reason performance - Can either be average for all pairs or a specific pair provided - NOTE: Not supported in Backtesting. - """ - - filters = [Trade.is_open.is_(False)] - if(pair is not None): - filters.append(Trade.pair == pair) - - sell_tag_perf = Trade.query.with_entities( - Trade.exit_reason, - func.sum(Trade.close_profit).label('profit_sum'), - func.sum(Trade.close_profit_abs).label('profit_sum_abs'), - func.count(Trade.pair).label('count') - ).filter(*filters)\ - .group_by(Trade.exit_reason) \ - .order_by(desc('profit_sum_abs')) \ - .all() - - return [ - { - 'exit_reason': exit_reason if exit_reason is not None else "Other", - 'profit_ratio': profit, - 'profit_pct': round(profit * 100, 2), - 'profit_abs': profit_abs, - 'count': count - } - for exit_reason, profit, profit_abs, count in sell_tag_perf - ] - - @staticmethod - def get_mix_tag_performance(pair: Optional[str]) -> List[Dict[str, Any]]: - """ - Returns List of dicts containing all Trades, based on entry_tag + exit_reason performance - Can either be average for all pairs or a specific pair provided - NOTE: Not supported in Backtesting. - """ - - filters = [Trade.is_open.is_(False)] - if(pair is not None): - filters.append(Trade.pair == pair) - - mix_tag_perf = Trade.query.with_entities( - Trade.id, - Trade.enter_tag, - Trade.exit_reason, - func.sum(Trade.close_profit).label('profit_sum'), - func.sum(Trade.close_profit_abs).label('profit_sum_abs'), - func.count(Trade.pair).label('count') - ).filter(*filters)\ - .group_by(Trade.id) \ - .order_by(desc('profit_sum_abs')) \ - .all() - - return_list: List[Dict] = [] - for id, enter_tag, exit_reason, profit, profit_abs, count in mix_tag_perf: - enter_tag = enter_tag if enter_tag is not None else "Other" - exit_reason = exit_reason if exit_reason is not None else "Other" - - if(exit_reason is not None and enter_tag is not None): - mix_tag = enter_tag + " " + exit_reason - i = 0 - if not any(item["mix_tag"] == mix_tag for item in return_list): - return_list.append({'mix_tag': mix_tag, - 'profit': profit, - 'profit_pct': round(profit * 100, 2), - 'profit_abs': profit_abs, - 'count': count}) - else: - while i < len(return_list): - if return_list[i]["mix_tag"] == mix_tag: - return_list[i] = { - 'mix_tag': mix_tag, - 'profit': profit + return_list[i]["profit"], - 'profit_pct': round(profit + return_list[i]["profit"] * 100, 2), - 'profit_abs': profit_abs + return_list[i]["profit_abs"], - 'count': 1 + return_list[i]["count"]} - i += 1 - - return return_list - - @staticmethod - def get_best_pair(start_date: datetime = datetime.fromtimestamp(0)): - """ - Get best pair with closed trade. - NOTE: Not supported in Backtesting. - :returns: Tuple containing (pair, profit_sum) - """ - best_pair = Trade.query.with_entities( - Trade.pair, func.sum(Trade.close_profit).label('profit_sum') - ).filter(Trade.is_open.is_(False) & (Trade.close_date >= start_date)) \ - .group_by(Trade.pair) \ - .order_by(desc('profit_sum')).first() - return best_pair diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py new file mode 100644 index 000000000..bb8c03dd2 --- /dev/null +++ b/freqtrade/persistence/trade_model.py @@ -0,0 +1,1346 @@ +""" +This module contains the class to persist trades into SQLite +""" +import logging +from datetime import datetime, timedelta, timezone +from decimal import Decimal +from typing import Any, Dict, List, Optional + +from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String, + UniqueConstraint, desc, func) +from sqlalchemy.orm import Query, relationship + +from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, BuySell, LongShort +from freqtrade.enums import ExitType, TradingMode +from freqtrade.exceptions import DependencyException, OperationalException +from freqtrade.leverage import interest +from freqtrade.persistence.base import _DECL_BASE + + +logger = logging.getLogger(__name__) + + +class Order(_DECL_BASE): + """ + Order database model + Keeps a record of all orders placed on the exchange + + One to many relationship with Trades: + - One trade can have many orders + - One Order can only be associated with one Trade + + Mirrors CCXT Order structure + """ + __tablename__ = 'orders' + # Uniqueness should be ensured over pair, order_id + # its likely that order_id is unique per Pair on some exchanges. + __table_args__ = (UniqueConstraint('ft_pair', 'order_id', name="_order_pair_order_id"),) + + id = Column(Integer, primary_key=True) + ft_trade_id = Column(Integer, ForeignKey('trades.id'), index=True) + + trade = relationship("Trade", back_populates="orders") + + # order_side can only be 'buy', 'sell' or 'stoploss' + ft_order_side: str = Column(String(25), nullable=False) + ft_pair: str = Column(String(25), nullable=False) + ft_is_open = Column(Boolean, nullable=False, default=True, index=True) + + order_id: str = Column(String(255), nullable=False, index=True) + status = Column(String(255), nullable=True) + symbol = Column(String(25), nullable=True) + order_type: str = Column(String(50), nullable=True) + side = Column(String(25), nullable=True) + price = Column(Float, nullable=True) + average = Column(Float, nullable=True) + amount = Column(Float, nullable=True) + filled = Column(Float, nullable=True) + remaining = Column(Float, nullable=True) + cost = Column(Float, nullable=True) + order_date = Column(DateTime, nullable=True, default=datetime.utcnow) + order_filled_date = Column(DateTime, nullable=True) + order_update_date = Column(DateTime, nullable=True) + + ft_fee_base = Column(Float, nullable=True) + + @property + def order_date_utc(self) -> datetime: + """ Order-date with UTC timezoneinfo""" + return self.order_date.replace(tzinfo=timezone.utc) + + @property + def safe_price(self) -> float: + return self.average or self.price + + @property + def safe_filled(self) -> float: + return self.filled or self.amount or 0.0 + + @property + def safe_fee_base(self) -> float: + return self.ft_fee_base or 0.0 + + @property + def safe_amount_after_fee(self) -> float: + return self.safe_filled - self.safe_fee_base + + def __repr__(self): + + return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, ' + f'side={self.side}, order_type={self.order_type}, status={self.status})') + + def update_from_ccxt_object(self, order): + """ + Update Order from ccxt response + Only updates if fields are available from ccxt - + """ + if self.order_id != str(order['id']): + raise DependencyException("Order-id's don't match") + + self.status = order.get('status', self.status) + self.symbol = order.get('symbol', self.symbol) + self.order_type = order.get('type', self.order_type) + self.side = order.get('side', self.side) + self.price = order.get('price', self.price) + self.amount = order.get('amount', self.amount) + self.filled = order.get('filled', self.filled) + self.average = order.get('average', self.average) + self.remaining = order.get('remaining', self.remaining) + self.cost = order.get('cost', self.cost) + + if 'timestamp' in order and order['timestamp'] is not None: + self.order_date = datetime.fromtimestamp(order['timestamp'] / 1000, tz=timezone.utc) + + self.ft_is_open = True + if self.status in NON_OPEN_EXCHANGE_STATES: + self.ft_is_open = False + if (order.get('filled', 0.0) or 0.0) > 0: + self.order_filled_date = datetime.now(timezone.utc) + self.order_update_date = datetime.now(timezone.utc) + + def to_json(self, entry_side: str) -> Dict[str, Any]: + return { + 'pair': self.ft_pair, + 'order_id': self.order_id, + 'status': self.status, + 'amount': self.amount, + 'average': round(self.average, 8) if self.average else 0, + 'safe_price': self.safe_price, + 'cost': self.cost if self.cost else 0, + 'filled': self.filled, + 'ft_order_side': self.ft_order_side, + 'is_open': self.ft_is_open, + 'order_date': self.order_date.strftime(DATETIME_PRINT_FORMAT) + if self.order_date else None, + 'order_timestamp': int(self.order_date.replace( + tzinfo=timezone.utc).timestamp() * 1000) if self.order_date else None, + 'order_filled_date': self.order_filled_date.strftime(DATETIME_PRINT_FORMAT) + if self.order_filled_date else None, + 'order_filled_timestamp': int(self.order_filled_date.replace( + tzinfo=timezone.utc).timestamp() * 1000) if self.order_filled_date else None, + 'order_type': self.order_type, + 'price': self.price, + 'ft_is_entry': self.ft_order_side == entry_side, + 'remaining': self.remaining, + } + + def close_bt_order(self, close_date: datetime, trade: 'LocalTrade'): + self.order_filled_date = close_date + self.filled = self.amount + self.status = 'closed' + self.ft_is_open = False + if (self.ft_order_side == trade.entry_side + and len(trade.select_filled_orders(trade.entry_side)) == 1): + trade.open_rate = self.price + trade.recalc_open_trade_value() + + @staticmethod + def update_orders(orders: List['Order'], order: Dict[str, Any]): + """ + Get all non-closed orders - useful when trying to batch-update orders + """ + if not isinstance(order, dict): + logger.warning(f"{order} is not a valid response object.") + return + + filtered_orders = [o for o in orders if o.order_id == order.get('id')] + if filtered_orders: + oobj = filtered_orders[0] + oobj.update_from_ccxt_object(order) + Order.query.session.commit() + else: + logger.warning(f"Did not find order for {order}.") + + @staticmethod + def parse_from_ccxt_object(order: Dict[str, Any], pair: str, side: str) -> 'Order': + """ + Parse an order from a ccxt object and return a new order Object. + """ + o = Order(order_id=str(order['id']), ft_order_side=side, ft_pair=pair) + + o.update_from_ccxt_object(order) + return o + + @staticmethod + def get_open_orders() -> List['Order']: + """ + Retrieve open orders from the database + :return: List of open orders + """ + return Order.query.filter(Order.ft_is_open.is_(True)).all() + + +class LocalTrade(): + """ + Trade database model. + Used in backtesting - must be aligned to Trade model! + + """ + use_db: bool = False + # Trades container for backtesting + trades: List['LocalTrade'] = [] + trades_open: List['LocalTrade'] = [] + total_profit: float = 0 + + id: int = 0 + + orders: List[Order] = [] + + exchange: str = '' + pair: str = '' + base_currency: str = '' + stake_currency: str = '' + is_open: bool = True + fee_open: float = 0.0 + fee_open_cost: Optional[float] = None + fee_open_currency: str = '' + fee_close: float = 0.0 + fee_close_cost: Optional[float] = None + fee_close_currency: str = '' + open_rate: float = 0.0 + open_rate_requested: Optional[float] = None + # open_trade_value - calculated via _calc_open_trade_value + open_trade_value: float = 0.0 + close_rate: Optional[float] = None + close_rate_requested: Optional[float] = None + close_profit: Optional[float] = None + close_profit_abs: Optional[float] = None + stake_amount: float = 0.0 + amount: float = 0.0 + amount_requested: Optional[float] = None + open_date: datetime + close_date: Optional[datetime] = None + open_order_id: Optional[str] = None + # absolute value of the stop loss + stop_loss: float = 0.0 + # percentage value of the stop loss + stop_loss_pct: float = 0.0 + # absolute value of the initial stop loss + initial_stop_loss: float = 0.0 + # percentage value of the initial stop loss + initial_stop_loss_pct: Optional[float] = None + # stoploss order id which is on exchange + stoploss_order_id: Optional[str] = None + # last update time of the stoploss order on exchange + stoploss_last_update: Optional[datetime] = None + # absolute value of the highest reached price + max_rate: float = 0.0 + # Lowest price reached + min_rate: float = 0.0 + exit_reason: str = '' + exit_order_status: str = '' + strategy: str = '' + enter_tag: Optional[str] = None + timeframe: Optional[int] = None + + trading_mode: TradingMode = TradingMode.SPOT + + # Leverage trading properties + liquidation_price: Optional[float] = None + is_short: bool = False + leverage: float = 1.0 + + # Margin trading properties + interest_rate: float = 0.0 + + # Futures properties + funding_fees: Optional[float] = None + + @property + def buy_tag(self) -> Optional[str]: + """ + Compatibility between buy_tag (old) and enter_tag (new) + Consider buy_tag deprecated + """ + return self.enter_tag + + @property + def has_no_leverage(self) -> bool: + """Returns true if this is a non-leverage, non-short trade""" + return ((self.leverage == 1.0 or self.leverage is None) and not self.is_short) + + @property + def borrowed(self) -> float: + """ + The amount of currency borrowed from the exchange for leverage trades + If a long trade, the amount is in base currency + If a short trade, the amount is in the other currency being traded + """ + if self.has_no_leverage: + return 0.0 + elif not self.is_short: + return (self.amount * self.open_rate) * ((self.leverage - 1) / self.leverage) + else: + return self.amount + + @property + def open_date_utc(self): + return self.open_date.replace(tzinfo=timezone.utc) + + @property + def close_date_utc(self): + return self.close_date.replace(tzinfo=timezone.utc) + + @property + def enter_side(self) -> str: + """ DEPRECATED, please use entry_side instead""" + # TODO: Please remove me after 2022.5 + return self.entry_side + + @property + def entry_side(self) -> str: + if self.is_short: + return "sell" + else: + return "buy" + + @property + def exit_side(self) -> BuySell: + if self.is_short: + return "buy" + else: + return "sell" + + @property + def trade_direction(self) -> LongShort: + if self.is_short: + return "short" + else: + return "long" + + @property + def safe_base_currency(self) -> str: + """ + Compatibility layer for asset - which can be empty for old trades. + """ + try: + return self.base_currency or self.pair.split('/')[0] + except IndexError: + return '' + + @property + def safe_quote_currency(self) -> str: + """ + Compatibility layer for asset - which can be empty for old trades. + """ + try: + return self.stake_currency or self.pair.split('/')[1].split(':')[0] + except IndexError: + return '' + + def __init__(self, **kwargs): + for key in kwargs: + setattr(self, key, kwargs[key]) + self.recalc_open_trade_value() + if self.trading_mode == TradingMode.MARGIN and self.interest_rate is None: + raise OperationalException( + f"{self.trading_mode.value} trading requires param interest_rate on trades") + + def __repr__(self): + open_since = self.open_date.strftime(DATETIME_PRINT_FORMAT) if self.is_open else 'closed' + + return ( + f'Trade(id={self.id}, pair={self.pair}, amount={self.amount:.8f}, ' + f'is_short={self.is_short or False}, leverage={self.leverage or 1.0}, ' + f'open_rate={self.open_rate:.8f}, open_since={open_since})' + ) + + def to_json(self) -> Dict[str, Any]: + filled_orders = self.select_filled_orders() + orders = [order.to_json(self.entry_side) for order in filled_orders] + + return { + 'trade_id': self.id, + 'pair': self.pair, + 'base_currency': self.safe_base_currency, + 'quote_currency': self.safe_quote_currency, + 'is_open': self.is_open, + 'exchange': self.exchange, + 'amount': round(self.amount, 8), + 'amount_requested': round(self.amount_requested, 8) if self.amount_requested else None, + 'stake_amount': round(self.stake_amount, 8), + 'strategy': self.strategy, + 'buy_tag': self.enter_tag, + 'enter_tag': self.enter_tag, + 'timeframe': self.timeframe, + + 'fee_open': self.fee_open, + 'fee_open_cost': self.fee_open_cost, + 'fee_open_currency': self.fee_open_currency, + 'fee_close': self.fee_close, + 'fee_close_cost': self.fee_close_cost, + 'fee_close_currency': self.fee_close_currency, + + 'open_date': self.open_date.strftime(DATETIME_PRINT_FORMAT), + 'open_timestamp': int(self.open_date.replace(tzinfo=timezone.utc).timestamp() * 1000), + 'open_rate': self.open_rate, + 'open_rate_requested': self.open_rate_requested, + 'open_trade_value': round(self.open_trade_value, 8), + + 'close_date': (self.close_date.strftime(DATETIME_PRINT_FORMAT) + if self.close_date else None), + 'close_timestamp': int(self.close_date.replace( + tzinfo=timezone.utc).timestamp() * 1000) if self.close_date else None, + 'close_rate': self.close_rate, + 'close_rate_requested': self.close_rate_requested, + 'close_profit': self.close_profit, # Deprecated + 'close_profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, + 'close_profit_abs': self.close_profit_abs, # Deprecated + + 'trade_duration_s': (int((self.close_date_utc - self.open_date_utc).total_seconds()) + if self.close_date else None), + 'trade_duration': (int((self.close_date_utc - self.open_date_utc).total_seconds() // 60) + if self.close_date else None), + + 'profit_ratio': self.close_profit, + 'profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, + 'profit_abs': self.close_profit_abs, + + 'sell_reason': self.exit_reason, # Deprecated + 'exit_reason': self.exit_reason, + 'exit_order_status': self.exit_order_status, + 'stop_loss_abs': self.stop_loss, + 'stop_loss_ratio': self.stop_loss_pct if self.stop_loss_pct else None, + 'stop_loss_pct': (self.stop_loss_pct * 100) if self.stop_loss_pct else None, + 'stoploss_order_id': self.stoploss_order_id, + 'stoploss_last_update': (self.stoploss_last_update.strftime(DATETIME_PRINT_FORMAT) + if self.stoploss_last_update else None), + 'stoploss_last_update_timestamp': int(self.stoploss_last_update.replace( + tzinfo=timezone.utc).timestamp() * 1000) if self.stoploss_last_update else None, + 'initial_stop_loss_abs': self.initial_stop_loss, + 'initial_stop_loss_ratio': (self.initial_stop_loss_pct + if self.initial_stop_loss_pct else None), + 'initial_stop_loss_pct': (self.initial_stop_loss_pct * 100 + if self.initial_stop_loss_pct else None), + 'min_rate': self.min_rate, + 'max_rate': self.max_rate, + + 'leverage': self.leverage, + 'interest_rate': self.interest_rate, + 'liquidation_price': self.liquidation_price, + 'is_short': self.is_short, + 'trading_mode': self.trading_mode, + 'funding_fees': self.funding_fees, + 'open_order_id': self.open_order_id, + 'orders': orders, + } + + @staticmethod + def reset_trades() -> None: + """ + Resets all trades. Only active for backtesting mode. + """ + LocalTrade.trades = [] + LocalTrade.trades_open = [] + LocalTrade.total_profit = 0 + + def adjust_min_max_rates(self, current_price: float, current_price_low: float) -> None: + """ + Adjust the max_rate and min_rate. + """ + self.max_rate = max(current_price, self.max_rate or self.open_rate) + self.min_rate = min(current_price_low, self.min_rate or self.open_rate) + + def set_isolated_liq(self, liquidation_price: Optional[float]): + """ + Method you should use to set self.liquidation price. + Assures stop_loss is not passed the liquidation price + """ + if not liquidation_price: + return + self.liquidation_price = liquidation_price + + def _set_stop_loss(self, stop_loss: float, percent: float): + """ + Method you should use to set self.stop_loss. + Assures stop_loss is not passed the liquidation price + """ + if self.liquidation_price is not None: + if self.is_short: + sl = min(stop_loss, self.liquidation_price) + else: + sl = max(stop_loss, self.liquidation_price) + else: + sl = stop_loss + + if not self.stop_loss: + self.initial_stop_loss = sl + self.stop_loss = sl + + self.stop_loss_pct = -1 * abs(percent) + self.stoploss_last_update = datetime.utcnow() + + def adjust_stop_loss(self, current_price: float, stoploss: float, + initial: bool = False) -> None: + """ + This adjusts the stop loss to it's most recently observed setting + :param current_price: Current rate the asset is traded + :param stoploss: Stoploss as factor (sample -0.05 -> -5% below current price). + :param initial: Called to initiate stop_loss. + Skips everything if self.stop_loss is already set. + """ + if initial and not (self.stop_loss is None or self.stop_loss == 0): + # Don't modify if called with initial and nothing to do + return + + leverage = self.leverage or 1.0 + if self.is_short: + new_loss = float(current_price * (1 + abs(stoploss / leverage))) + # If trading with leverage, don't set the stoploss below the liquidation price + if self.liquidation_price: + new_loss = min(self.liquidation_price, new_loss) + else: + new_loss = float(current_price * (1 - abs(stoploss / leverage))) + # If trading with leverage, don't set the stoploss below the liquidation price + if self.liquidation_price: + new_loss = max(self.liquidation_price, new_loss) + + # no stop loss assigned yet + if self.initial_stop_loss_pct is None: + logger.debug(f"{self.pair} - Assigning new stoploss...") + self._set_stop_loss(new_loss, stoploss) + self.initial_stop_loss = new_loss + self.initial_stop_loss_pct = -1 * abs(stoploss) + + # evaluate if the stop loss needs to be updated + else: + + higher_stop = new_loss > self.stop_loss + lower_stop = new_loss < self.stop_loss + + # stop losses only walk up, never down!, + # ? But adding more to a leveraged trade would create a lower liquidation price, + # ? decreasing the minimum stoploss + if (higher_stop and not self.is_short) or (lower_stop and self.is_short): + logger.debug(f"{self.pair} - Adjusting stoploss...") + self._set_stop_loss(new_loss, stoploss) + else: + logger.debug(f"{self.pair} - Keeping current stoploss...") + + logger.debug( + f"{self.pair} - Stoploss adjusted. current_price={current_price:.8f}, " + f"open_rate={self.open_rate:.8f}, max_rate={self.max_rate or self.open_rate:.8f}, " + f"initial_stop_loss={self.initial_stop_loss:.8f}, " + f"stop_loss={self.stop_loss:.8f}. " + f"Trailing stoploss saved us: " + f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f}.") + + def update_trade(self, order: Order) -> None: + """ + Updates this entity with amount and actual open/close rates. + :param order: order retrieved by exchange.fetch_order() + :return: None + """ + + # Ignore open and cancelled orders + if order.status == 'open' or order.safe_price is None: + return + + logger.info(f'Updating trade (id={self.id}) ...') + + if order.ft_order_side == self.entry_side: + # Update open rate and actual amount + self.open_rate = order.safe_price + self.amount = order.safe_amount_after_fee + if self.is_open: + payment = "SELL" if self.is_short else "BUY" + logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.') + self.open_order_id = None + self.recalc_trade_from_orders() + elif order.ft_order_side == self.exit_side: + if self.is_open: + payment = "BUY" if self.is_short else "SELL" + # * On margin shorts, you buy a little bit more than the amount (amount + interest) + logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.') + self.close(order.safe_price) + elif order.ft_order_side == 'stoploss': + self.stoploss_order_id = None + self.close_rate_requested = self.stop_loss + self.exit_reason = ExitType.STOPLOSS_ON_EXCHANGE.value + if self.is_open: + logger.info(f'{order.order_type.upper()} is hit for {self}.') + self.close(order.safe_price) + else: + raise ValueError(f'Unknown order type: {order.order_type}') + Trade.commit() + + def close(self, rate: float, *, show_msg: bool = True) -> None: + """ + Sets close_rate to the given rate, calculates total profit + and marks trade as closed + """ + self.close_rate = rate + self.close_date = self.close_date or datetime.utcnow() + self.close_profit = self.calc_profit_ratio() + self.close_profit_abs = self.calc_profit() + self.is_open = False + self.exit_order_status = 'closed' + self.open_order_id = None + if show_msg: + logger.info( + 'Marking %s as closed as the trade is fulfilled and found no open orders for it.', + self + ) + + def update_fee(self, fee_cost: float, fee_currency: Optional[str], fee_rate: Optional[float], + side: str) -> None: + """ + Update Fee parameters. Only acts once per side + """ + if self.entry_side == side and self.fee_open_currency is None: + self.fee_open_cost = fee_cost + self.fee_open_currency = fee_currency + if fee_rate is not None: + self.fee_open = fee_rate + # Assume close-fee will fall into the same fee category and take an educated guess + self.fee_close = fee_rate + elif self.exit_side == side and self.fee_close_currency is None: + self.fee_close_cost = fee_cost + self.fee_close_currency = fee_currency + if fee_rate is not None: + self.fee_close = fee_rate + + def fee_updated(self, side: str) -> bool: + """ + Verify if this side (buy / sell) has already been updated + """ + if self.entry_side == side: + return self.fee_open_currency is not None + elif self.exit_side == side: + return self.fee_close_currency is not None + else: + return False + + def update_order(self, order: Dict) -> None: + Order.update_orders(self.orders, order) + + def get_exit_order_count(self) -> int: + """ + Get amount of failed exiting orders + assumes full exits. + """ + return len([o for o in self.orders if o.ft_order_side == self.exit_side]) + + def _calc_open_trade_value(self) -> float: + """ + Calculate the open_rate including open_fee. + :return: Price in of the open trade incl. Fees + """ + open_trade = Decimal(self.amount) * Decimal(self.open_rate) + fees = open_trade * Decimal(self.fee_open) + if self.is_short: + return float(open_trade - fees) + else: + return float(open_trade + fees) + + def recalc_open_trade_value(self) -> None: + """ + Recalculate open_trade_value. + Must be called whenever open_rate, fee_open or is_short is changed. + """ + self.open_trade_value = self._calc_open_trade_value() + + def calculate_interest(self, interest_rate: Optional[float] = None) -> Decimal: + """ + :param interest_rate: interest_charge for borrowing this coin(optional). + If interest_rate is not set self.interest_rate will be used + """ + zero = Decimal(0.0) + # If nothing was borrowed + if self.trading_mode != TradingMode.MARGIN or self.has_no_leverage: + return zero + + open_date = self.open_date.replace(tzinfo=None) + now = (self.close_date or datetime.now(timezone.utc)).replace(tzinfo=None) + sec_per_hour = Decimal(3600) + total_seconds = Decimal((now - open_date).total_seconds()) + hours = total_seconds / sec_per_hour or zero + + rate = Decimal(interest_rate or self.interest_rate) + borrowed = Decimal(self.borrowed) + + return interest(exchange_name=self.exchange, borrowed=borrowed, rate=rate, hours=hours) + + def _calc_base_close(self, amount: Decimal, rate: Optional[float] = None, + fee: Optional[float] = None) -> Decimal: + + close_trade = Decimal(amount) * Decimal(rate or self.close_rate) # type: ignore + fees = close_trade * Decimal(fee or self.fee_close) + + if self.is_short: + return close_trade + fees + else: + return close_trade - fees + + def calc_close_trade_value(self, rate: Optional[float] = None, + fee: Optional[float] = None, + interest_rate: Optional[float] = None) -> float: + """ + Calculate the close_rate including fee + :param fee: fee to use on the close rate (optional). + If rate is not set self.fee will be used + :param rate: rate to compare with (optional). + If rate is not set self.close_rate will be used + :param interest_rate: interest_charge for borrowing this coin (optional). + If interest_rate is not set self.interest_rate will be used + :return: Price in BTC of the open trade + """ + if rate is None and not self.close_rate: + return 0.0 + + amount = Decimal(self.amount) + trading_mode = self.trading_mode or TradingMode.SPOT + + if trading_mode == TradingMode.SPOT: + return float(self._calc_base_close(amount, rate, fee)) + + elif (trading_mode == TradingMode.MARGIN): + + total_interest = self.calculate_interest(interest_rate) + + if self.is_short: + amount = amount + total_interest + return float(self._calc_base_close(amount, rate, fee)) + else: + # Currency already owned for longs, no need to purchase + return float(self._calc_base_close(amount, rate, fee) - total_interest) + + elif (trading_mode == TradingMode.FUTURES): + funding_fees = self.funding_fees or 0.0 + # Positive funding_fees -> Trade has gained from fees. + # Negative funding_fees -> Trade had to pay the fees. + if self.is_short: + return float(self._calc_base_close(amount, rate, fee)) - funding_fees + else: + return float(self._calc_base_close(amount, rate, fee)) + funding_fees + else: + raise OperationalException( + f"{self.trading_mode.value} trading is not yet available using freqtrade") + + def calc_profit(self, rate: Optional[float] = None, + fee: Optional[float] = None, + interest_rate: Optional[float] = None) -> float: + """ + Calculate the absolute profit in stake currency between Close and Open trade + :param fee: fee to use on the close rate (optional). + If fee is not set self.fee will be used + :param rate: close rate to compare with (optional). + If rate is not set self.close_rate will be used + :param interest_rate: interest_charge for borrowing this coin (optional). + If interest_rate is not set self.interest_rate will be used + :return: profit in stake currency as float + """ + close_trade_value = self.calc_close_trade_value( + rate=(rate or self.close_rate), + fee=(fee or self.fee_close), + interest_rate=(interest_rate or self.interest_rate) + ) + + if self.is_short: + profit = self.open_trade_value - close_trade_value + else: + profit = close_trade_value - self.open_trade_value + return float(f"{profit:.8f}") + + def calc_profit_ratio(self, rate: Optional[float] = None, + fee: Optional[float] = None, + interest_rate: Optional[float] = None) -> float: + """ + Calculates the profit as ratio (including fee). + :param rate: rate to compare with (optional). + If rate is not set self.close_rate will be used + :param fee: fee to use on the close rate (optional). + :param interest_rate: interest_charge for borrowing this coin (optional). + If interest_rate is not set self.interest_rate will be used + :return: profit ratio as float + """ + close_trade_value = self.calc_close_trade_value( + rate=(rate or self.close_rate), + fee=(fee or self.fee_close), + interest_rate=(interest_rate or self.interest_rate) + ) + + short_close_zero = (self.is_short and close_trade_value == 0.0) + long_close_zero = (not self.is_short and self.open_trade_value == 0.0) + leverage = self.leverage or 1.0 + + if (short_close_zero or long_close_zero): + return 0.0 + else: + if self.is_short: + profit_ratio = (1 - (close_trade_value / self.open_trade_value)) * leverage + else: + profit_ratio = ((close_trade_value / self.open_trade_value) - 1) * leverage + + return float(f"{profit_ratio:.8f}") + + def recalc_trade_from_orders(self): + # We need at least 2 entry orders for averaging amounts and rates. + # TODO: this condition could probably be removed + if len(self.select_filled_orders(self.entry_side)) < 2: + self.stake_amount = self.amount * self.open_rate / self.leverage + + # Just in case, still recalc open trade value + self.recalc_open_trade_value() + return + + total_amount = 0.0 + total_stake = 0.0 + for o in self.orders: + if (o.ft_is_open or + (o.ft_order_side != self.entry_side) or + (o.status not in NON_OPEN_EXCHANGE_STATES)): + continue + + tmp_amount = o.safe_amount_after_fee + tmp_price = o.average or o.price + if o.filled is not None: + tmp_amount = o.filled + if tmp_amount > 0.0 and tmp_price is not None: + total_amount += tmp_amount + total_stake += tmp_price * tmp_amount + + if total_amount > 0: + # Leverage not updated, as we don't allow changing leverage through DCA at the moment. + self.open_rate = total_stake / total_amount + self.stake_amount = total_stake / (self.leverage or 1.0) + self.amount = total_amount + self.fee_open_cost = self.fee_open * self.stake_amount + self.recalc_open_trade_value() + if self.stop_loss_pct is not None and self.open_rate is not None: + self.adjust_stop_loss(self.open_rate, self.stop_loss_pct) + + def select_order_by_order_id(self, order_id: str) -> Optional[Order]: + """ + Finds order object by Order id. + :param order_id: Exchange order id + """ + for o in self.orders: + if o.order_id == order_id: + return o + return None + + def select_order( + self, order_side: str = None, is_open: Optional[bool] = None) -> Optional[Order]: + """ + Finds latest order for this orderside and status + :param order_side: ft_order_side of the order (either 'buy', 'sell' or 'stoploss') + :param is_open: Only search for open orders? + :return: latest Order object if it exists, else None + """ + orders = self.orders + if order_side: + orders = [o for o in self.orders if o.ft_order_side == order_side] + if is_open is not None: + orders = [o for o in orders if o.ft_is_open == is_open] + if len(orders) > 0: + return orders[-1] + else: + return None + + def select_filled_orders(self, order_side: Optional[str] = None) -> List['Order']: + """ + Finds filled orders for this orderside. + :param order_side: Side of the order (either 'buy', 'sell', or None) + :return: array of Order objects + """ + return [o for o in self.orders if ((o.ft_order_side == order_side) or (order_side is None)) + and o.ft_is_open is False and + (o.filled or 0) > 0 and + o.status in NON_OPEN_EXCHANGE_STATES] + + @property + def nr_of_successful_entries(self) -> int: + """ + Helper function to count the number of entry orders that have been filled. + :return: int count of entry orders that have been filled for this trade. + """ + + return len(self.select_filled_orders(self.entry_side)) + + @property + def nr_of_successful_exits(self) -> int: + """ + Helper function to count the number of exit orders that have been filled. + :return: int count of exit orders that have been filled for this trade. + """ + return len(self.select_filled_orders(self.exit_side)) + + @property + def nr_of_successful_buys(self) -> int: + """ + Helper function to count the number of buy orders that have been filled. + WARNING: Please use nr_of_successful_entries for short support. + :return: int count of buy orders that have been filled for this trade. + """ + + return len(self.select_filled_orders('buy')) + + @property + def nr_of_successful_sells(self) -> int: + """ + Helper function to count the number of sell orders that have been filled. + WARNING: Please use nr_of_successful_exits for short support. + :return: int count of sell orders that have been filled for this trade. + """ + return len(self.select_filled_orders('sell')) + + @property + def sell_reason(self) -> str: + """ DEPRECATED! Please use exit_reason instead.""" + return self.exit_reason + + @staticmethod + def get_trades_proxy(*, pair: str = None, is_open: bool = None, + open_date: datetime = None, close_date: datetime = None, + ) -> List['LocalTrade']: + """ + Helper function to query Trades. + Returns a List of trades, filtered on the parameters given. + In live mode, converts the filter to a database query and returns all rows + In Backtest mode, uses filters on Trade.trades to get the result. + + :return: unsorted List[Trade] + """ + + # Offline mode - without database + if is_open is not None: + if is_open: + sel_trades = LocalTrade.trades_open + else: + sel_trades = LocalTrade.trades + + else: + # Not used during backtesting, but might be used by a strategy + sel_trades = list(LocalTrade.trades + LocalTrade.trades_open) + + if pair: + sel_trades = [trade for trade in sel_trades if trade.pair == pair] + if open_date: + sel_trades = [trade for trade in sel_trades if trade.open_date > open_date] + if close_date: + sel_trades = [trade for trade in sel_trades if trade.close_date + and trade.close_date > close_date] + + return sel_trades + + @staticmethod + def close_bt_trade(trade): + LocalTrade.trades_open.remove(trade) + LocalTrade.trades.append(trade) + LocalTrade.total_profit += trade.close_profit_abs + + @staticmethod + def add_bt_trade(trade): + if trade.is_open: + LocalTrade.trades_open.append(trade) + else: + LocalTrade.trades.append(trade) + + @staticmethod + def get_open_trades() -> List[Any]: + """ + Query trades from persistence layer + """ + return Trade.get_trades_proxy(is_open=True) + + @staticmethod + def stoploss_reinitialization(desired_stoploss): + """ + Adjust initial Stoploss to desired stoploss for all open trades. + """ + for trade in Trade.get_open_trades(): + logger.info("Found open trade: %s", trade) + + # skip case if trailing-stop changed the stoploss already. + if (trade.stop_loss == trade.initial_stop_loss + and trade.initial_stop_loss_pct != desired_stoploss): + # Stoploss value got changed + + logger.info(f"Stoploss for {trade} needs adjustment...") + # Force reset of stoploss + trade.stop_loss = None + trade.initial_stop_loss_pct = None + trade.adjust_stop_loss(trade.open_rate, desired_stoploss) + logger.info(f"New stoploss: {trade.stop_loss}.") + + +class Trade(_DECL_BASE, LocalTrade): + """ + Trade database model. + Also handles updating and querying trades + + Note: Fields must be aligned with LocalTrade class + """ + __tablename__ = 'trades' + + use_db: bool = True + + id = Column(Integer, primary_key=True) + + orders = relationship("Order", order_by="Order.id", cascade="all, delete-orphan", lazy="joined") + + exchange = Column(String(25), nullable=False) + pair = Column(String(25), nullable=False, index=True) + base_currency = Column(String(25), nullable=True) + stake_currency = Column(String(25), nullable=True) + is_open = Column(Boolean, nullable=False, default=True, index=True) + fee_open = Column(Float, nullable=False, default=0.0) + fee_open_cost = Column(Float, nullable=True) + fee_open_currency = Column(String(25), nullable=True) + fee_close = Column(Float, nullable=False, default=0.0) + fee_close_cost = Column(Float, nullable=True) + fee_close_currency = Column(String(25), nullable=True) + open_rate: float = Column(Float) + open_rate_requested = Column(Float) + # open_trade_value - calculated via _calc_open_trade_value + open_trade_value = Column(Float) + close_rate: Optional[float] = Column(Float) + close_rate_requested = Column(Float) + close_profit = Column(Float) + close_profit_abs = Column(Float) + stake_amount = Column(Float, nullable=False) + amount = Column(Float) + amount_requested = Column(Float) + open_date = Column(DateTime, nullable=False, default=datetime.utcnow) + close_date = Column(DateTime) + open_order_id = Column(String(255)) + # absolute value of the stop loss + stop_loss = Column(Float, nullable=True, default=0.0) + # percentage value of the stop loss + stop_loss_pct = Column(Float, nullable=True) + # absolute value of the initial stop loss + initial_stop_loss = Column(Float, nullable=True, default=0.0) + # percentage value of the initial stop loss + initial_stop_loss_pct = Column(Float, nullable=True) + # stoploss order id which is on exchange + stoploss_order_id = Column(String(255), nullable=True, index=True) + # last update time of the stoploss order on exchange + stoploss_last_update = Column(DateTime, nullable=True) + # absolute value of the highest reached price + max_rate = Column(Float, nullable=True, default=0.0) + # Lowest price reached + min_rate = Column(Float, nullable=True) + exit_reason = Column(String(100), nullable=True) + exit_order_status = Column(String(100), nullable=True) + strategy = Column(String(100), nullable=True) + enter_tag = Column(String(100), nullable=True) + timeframe = Column(Integer, nullable=True) + + trading_mode = Column(Enum(TradingMode), nullable=True) + + # Leverage trading properties + leverage = Column(Float, nullable=True, default=1.0) + is_short = Column(Boolean, nullable=False, default=False) + liquidation_price = Column(Float, nullable=True) + + # Margin Trading Properties + interest_rate = Column(Float, nullable=False, default=0.0) + + # Futures properties + funding_fees = Column(Float, nullable=True, default=None) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.recalc_open_trade_value() + + def delete(self) -> None: + + for order in self.orders: + Order.query.session.delete(order) + + Trade.query.session.delete(self) + Trade.commit() + + @staticmethod + def commit(): + Trade.query.session.commit() + + @staticmethod + def get_trades_proxy(*, pair: str = None, is_open: bool = None, + open_date: datetime = None, close_date: datetime = None, + ) -> List['LocalTrade']: + """ + Helper function to query Trades.j + Returns a List of trades, filtered on the parameters given. + In live mode, converts the filter to a database query and returns all rows + In Backtest mode, uses filters on Trade.trades to get the result. + + :return: unsorted List[Trade] + """ + if Trade.use_db: + trade_filter = [] + if pair: + trade_filter.append(Trade.pair == pair) + if open_date: + trade_filter.append(Trade.open_date > open_date) + if close_date: + trade_filter.append(Trade.close_date > close_date) + if is_open is not None: + trade_filter.append(Trade.is_open.is_(is_open)) + return Trade.get_trades(trade_filter).all() + else: + return LocalTrade.get_trades_proxy( + pair=pair, is_open=is_open, + open_date=open_date, + close_date=close_date + ) + + @staticmethod + def get_trades(trade_filter=None) -> Query: + """ + Helper function to query Trades using filters. + NOTE: Not supported in Backtesting. + :param trade_filter: Optional filter to apply to trades + Can be either a Filter object, or a List of filters + e.g. `(trade_filter=[Trade.id == trade_id, Trade.is_open.is_(True),])` + e.g. `(trade_filter=Trade.id == trade_id)` + :return: unsorted query object + """ + if not Trade.use_db: + raise NotImplementedError('`Trade.get_trades()` not supported in backtesting mode.') + if trade_filter is not None: + if not isinstance(trade_filter, list): + trade_filter = [trade_filter] + return Trade.query.filter(*trade_filter) + else: + return Trade.query + + @staticmethod + def get_open_order_trades() -> List['Trade']: + """ + Returns all open trades + NOTE: Not supported in Backtesting. + """ + return Trade.get_trades(Trade.open_order_id.isnot(None)).all() + + @staticmethod + def get_open_trades_without_assigned_fees(): + """ + Returns all open trades which don't have open fees set correctly + NOTE: Not supported in Backtesting. + """ + return Trade.get_trades([Trade.fee_open_currency.is_(None), + Trade.orders.any(), + Trade.is_open.is_(True), + ]).all() + + @staticmethod + def get_closed_trades_without_assigned_fees(): + """ + Returns all closed trades which don't have fees set correctly + NOTE: Not supported in Backtesting. + """ + return Trade.get_trades([Trade.fee_close_currency.is_(None), + Trade.orders.any(), + Trade.is_open.is_(False), + ]).all() + + @staticmethod + def get_total_closed_profit() -> float: + """ + Retrieves total realized profit + """ + if Trade.use_db: + total_profit = Trade.query.with_entities( + func.sum(Trade.close_profit_abs)).filter(Trade.is_open.is_(False)).scalar() + else: + total_profit = sum( + t.close_profit_abs for t in LocalTrade.get_trades_proxy(is_open=False)) + return total_profit or 0 + + @staticmethod + def total_open_trades_stakes() -> float: + """ + Calculates total invested amount in open trades + in stake currency + """ + if Trade.use_db: + total_open_stake_amount = Trade.query.with_entities( + func.sum(Trade.stake_amount)).filter(Trade.is_open.is_(True)).scalar() + else: + total_open_stake_amount = sum( + t.stake_amount for t in LocalTrade.get_trades_proxy(is_open=True)) + return total_open_stake_amount or 0 + + @staticmethod + def get_overall_performance(minutes=None) -> List[Dict[str, Any]]: + """ + Returns List of dicts containing all Trades, including profit and trade count + NOTE: Not supported in Backtesting. + """ + filters = [Trade.is_open.is_(False)] + if minutes: + start_date = datetime.now(timezone.utc) - timedelta(minutes=minutes) + filters.append(Trade.close_date >= start_date) + pair_rates = Trade.query.with_entities( + Trade.pair, + func.sum(Trade.close_profit).label('profit_sum'), + func.sum(Trade.close_profit_abs).label('profit_sum_abs'), + func.count(Trade.pair).label('count') + ).filter(*filters)\ + .group_by(Trade.pair) \ + .order_by(desc('profit_sum_abs')) \ + .all() + return [ + { + 'pair': pair, + 'profit_ratio': profit, + 'profit': round(profit * 100, 2), # Compatibility mode + 'profit_pct': round(profit * 100, 2), + 'profit_abs': profit_abs, + 'count': count + } + for pair, profit, profit_abs, count in pair_rates + ] + + @staticmethod + def get_enter_tag_performance(pair: Optional[str]) -> List[Dict[str, Any]]: + """ + Returns List of dicts containing all Trades, based on buy tag performance + Can either be average for all pairs or a specific pair provided + NOTE: Not supported in Backtesting. + """ + + filters = [Trade.is_open.is_(False)] + if(pair is not None): + filters.append(Trade.pair == pair) + + enter_tag_perf = Trade.query.with_entities( + Trade.enter_tag, + func.sum(Trade.close_profit).label('profit_sum'), + func.sum(Trade.close_profit_abs).label('profit_sum_abs'), + func.count(Trade.pair).label('count') + ).filter(*filters)\ + .group_by(Trade.enter_tag) \ + .order_by(desc('profit_sum_abs')) \ + .all() + + return [ + { + 'enter_tag': enter_tag if enter_tag is not None else "Other", + 'profit_ratio': profit, + 'profit_pct': round(profit * 100, 2), + 'profit_abs': profit_abs, + 'count': count + } + for enter_tag, profit, profit_abs, count in enter_tag_perf + ] + + @staticmethod + def get_exit_reason_performance(pair: Optional[str]) -> List[Dict[str, Any]]: + """ + Returns List of dicts containing all Trades, based on exit reason performance + Can either be average for all pairs or a specific pair provided + NOTE: Not supported in Backtesting. + """ + + filters = [Trade.is_open.is_(False)] + if(pair is not None): + filters.append(Trade.pair == pair) + + sell_tag_perf = Trade.query.with_entities( + Trade.exit_reason, + func.sum(Trade.close_profit).label('profit_sum'), + func.sum(Trade.close_profit_abs).label('profit_sum_abs'), + func.count(Trade.pair).label('count') + ).filter(*filters)\ + .group_by(Trade.exit_reason) \ + .order_by(desc('profit_sum_abs')) \ + .all() + + return [ + { + 'exit_reason': exit_reason if exit_reason is not None else "Other", + 'profit_ratio': profit, + 'profit_pct': round(profit * 100, 2), + 'profit_abs': profit_abs, + 'count': count + } + for exit_reason, profit, profit_abs, count in sell_tag_perf + ] + + @staticmethod + def get_mix_tag_performance(pair: Optional[str]) -> List[Dict[str, Any]]: + """ + Returns List of dicts containing all Trades, based on entry_tag + exit_reason performance + Can either be average for all pairs or a specific pair provided + NOTE: Not supported in Backtesting. + """ + + filters = [Trade.is_open.is_(False)] + if(pair is not None): + filters.append(Trade.pair == pair) + + mix_tag_perf = Trade.query.with_entities( + Trade.id, + Trade.enter_tag, + Trade.exit_reason, + func.sum(Trade.close_profit).label('profit_sum'), + func.sum(Trade.close_profit_abs).label('profit_sum_abs'), + func.count(Trade.pair).label('count') + ).filter(*filters)\ + .group_by(Trade.id) \ + .order_by(desc('profit_sum_abs')) \ + .all() + + return_list: List[Dict] = [] + for id, enter_tag, exit_reason, profit, profit_abs, count in mix_tag_perf: + enter_tag = enter_tag if enter_tag is not None else "Other" + exit_reason = exit_reason if exit_reason is not None else "Other" + + if(exit_reason is not None and enter_tag is not None): + mix_tag = enter_tag + " " + exit_reason + i = 0 + if not any(item["mix_tag"] == mix_tag for item in return_list): + return_list.append({'mix_tag': mix_tag, + 'profit': profit, + 'profit_pct': round(profit * 100, 2), + 'profit_abs': profit_abs, + 'count': count}) + else: + while i < len(return_list): + if return_list[i]["mix_tag"] == mix_tag: + return_list[i] = { + 'mix_tag': mix_tag, + 'profit': profit + return_list[i]["profit"], + 'profit_pct': round(profit + return_list[i]["profit"] * 100, 2), + 'profit_abs': profit_abs + return_list[i]["profit_abs"], + 'count': 1 + return_list[i]["count"]} + i += 1 + + return return_list + + @staticmethod + def get_best_pair(start_date: datetime = datetime.fromtimestamp(0)): + """ + Get best pair with closed trade. + NOTE: Not supported in Backtesting. + :returns: Tuple containing (pair, profit_sum) + """ + best_pair = Trade.query.with_entities( + Trade.pair, func.sum(Trade.close_profit).label('profit_sum') + ).filter(Trade.is_open.is_(False) & (Trade.close_date >= start_date)) \ + .group_by(Trade.pair) \ + .order_by(desc('profit_sum')).first() + return best_pair diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 26efd74a9..57afbf32a 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -15,10 +15,8 @@ from freqtrade.data.dataprovider import DataProvider from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, SignalDirection, SignalTagType, SignalType, TradingMode) from freqtrade.exceptions import OperationalException, StrategyError -from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds -from freqtrade.exchange.exchange import timeframe_to_next_date -from freqtrade.persistence import PairLocks, Trade -from freqtrade.persistence.models import LocalTrade, Order +from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date, timeframe_to_seconds +from freqtrade.persistence import LocalTrade, Order, PairLocks, Trade from freqtrade.strategy.hyper import HyperStrategyMixin from freqtrade.strategy.informative_decorator import (InformativeData, PopulateIndicators, _create_and_merge_informative_pair, From 30d6eeffd025489382170a22f779c87d72bc35ee Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 8 May 2022 17:49:13 +0200 Subject: [PATCH 061/449] Fix migration bug --- freqtrade/persistence/migrations.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index 4d29b3d49..6a77b0b9a 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -99,7 +99,10 @@ def migrate_trades_and_orders_table( liquidation_price = get_column_def(cols, 'liquidation_price', get_column_def(cols, 'isolated_liq', 'null')) # sqlite does not support literals for booleans - is_short = get_column_def(cols, 'is_short', 'false') + if engine.name == 'postgresql': + is_short = get_column_def(cols, 'is_short', 'false') + else: + is_short = get_column_def(cols, 'is_short', '0') # Margin Properties interest_rate = get_column_def(cols, 'interest_rate', '0.0') From f71b2624ab5c43a5ea8ac8d7770f506e16532a38 Mon Sep 17 00:00:00 2001 From: Luke Ingalls <45518011+lukeingalls@users.noreply.github.com> Date: Sun, 8 May 2022 10:07:22 -0700 Subject: [PATCH 062/449] then -> than --- docs/includes/pairlists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index cec5ceb19..22a252192 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -181,7 +181,7 @@ Example to remove the first 10 pairs from the pairlist: `VolumeFilter`. !!! Note - An offset larger then the total length of the incoming pairlist will result in an empty pairlist. + An offset larger than the total length of the incoming pairlist will result in an empty pairlist. #### PerformanceFilter From df48399a901db7ab3e456e8721c8dbb27b342664 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 03:10:07 +0000 Subject: [PATCH 063/449] Bump cryptography from 37.0.1 to 37.0.2 Bumps [cryptography](https://github.com/pyca/cryptography) from 37.0.1 to 37.0.2. - [Release notes](https://github.com/pyca/cryptography/releases) - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/37.0.1...37.0.2) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c5459a5b2..576ecddcb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ pandas-ta==0.3.14b ccxt==1.81.43 # Pin cryptography for now due to rust build errors with piwheels -cryptography==37.0.1 +cryptography==37.0.2 aiohttp==3.8.1 SQLAlchemy==1.4.36 python-telegram-bot==13.11 From 30cc8e92a1ffc0a51b32d70d9da073d0bc384d20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 03:10:15 +0000 Subject: [PATCH 064/449] Bump mkdocs-material from 8.2.12 to 8.2.14 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.2.12 to 8.2.14. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/8.2.12...8.2.14) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index c5a4b64b3..b26e448ea 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 -mkdocs-material==8.2.12 +mkdocs-material==8.2.14 mdx_truly_sane_lists==1.2 pymdown-extensions==9.4 jinja2==3.1.2 From 74b309cf50b05040d9f6c3af05bcabfd423c90f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 03:10:27 +0000 Subject: [PATCH 065/449] Bump jsonschema from 4.4.0 to 4.5.1 Bumps [jsonschema](https://github.com/python-jsonschema/jsonschema) from 4.4.0 to 4.5.1. - [Release notes](https://github.com/python-jsonschema/jsonschema/releases) - [Changelog](https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst) - [Commits](https://github.com/python-jsonschema/jsonschema/compare/v4.4.0...v4.5.1) --- updated-dependencies: - dependency-name: jsonschema dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c5459a5b2..294a42f81 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ arrow==1.2.2 cachetools==4.2.2 requests==2.27.1 urllib3==1.26.9 -jsonschema==4.4.0 +jsonschema==4.5.1 TA-Lib==0.4.24 technical==1.3.0 tabulate==0.8.9 From 77a22a6b1cb2c9a86cb0b52e207dc767f4511a52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 03:10:38 +0000 Subject: [PATCH 066/449] Bump fastapi from 0.75.2 to 0.76.0 Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.75.2 to 0.76.0. - [Release notes](https://github.com/tiangolo/fastapi/releases) - [Commits](https://github.com/tiangolo/fastapi/compare/0.75.2...0.76.0) --- updated-dependencies: - dependency-name: fastapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c5459a5b2..2acdc8b78 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,7 +34,7 @@ orjson==3.6.8 sdnotify==0.3.2 # API Server -fastapi==0.75.2 +fastapi==0.76.0 uvicorn==0.17.6 pyjwt==2.3.0 aiofiles==0.8.0 From 1ae74c1197120ad8ad67891eecd230cbbb662ca5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 03:11:12 +0000 Subject: [PATCH 067/449] Bump flake8-tidy-imports from 4.6.0 to 4.7.0 Bumps [flake8-tidy-imports](https://github.com/adamchainz/flake8-tidy-imports) from 4.6.0 to 4.7.0. - [Release notes](https://github.com/adamchainz/flake8-tidy-imports/releases) - [Changelog](https://github.com/adamchainz/flake8-tidy-imports/blob/main/HISTORY.rst) - [Commits](https://github.com/adamchainz/flake8-tidy-imports/compare/4.6.0...4.7.0) --- updated-dependencies: - dependency-name: flake8-tidy-imports dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 9458be1ef..1b60d3b30 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,7 +6,7 @@ coveralls==3.3.1 flake8==4.0.1 -flake8-tidy-imports==4.6.0 +flake8-tidy-imports==4.7.0 mypy==0.950 pre-commit==2.18.1 pytest==7.1.2 From 69b79cd799869c4b9c3fe75015fab4bc7faccdc8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 03:11:16 +0000 Subject: [PATCH 068/449] Bump types-python-dateutil from 2.8.14 to 2.8.15 Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.14 to 2.8.15. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-python-dateutil dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 9458be1ef..7213f52b3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -26,4 +26,4 @@ types-cachetools==5.0.1 types-filelock==3.2.5 types-requests==2.27.25 types-tabulate==0.8.8 -types-python-dateutil==2.8.14 +types-python-dateutil==2.8.15 From 0756027e33e03740ecbc918077d3275fa1f16400 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 9 May 2022 06:32:28 +0200 Subject: [PATCH 069/449] BUmp types-python-dateutil precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1185028b9..0ce5797c2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - types-filelock==3.2.5 - types-requests==2.27.25 - types-tabulate==0.8.8 - - types-python-dateutil==2.8.14 + - types-python-dateutil==2.8.15 # stages: [push] - repo: https://github.com/pycqa/isort From 5080245a73bf91c356aab5f7171423f8bf0ce6d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 04:32:48 +0000 Subject: [PATCH 070/449] Bump ccxt from 1.81.43 to 1.81.81 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.81.43 to 1.81.81. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.81.43...1.81.81) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 576ecddcb..674b1d3a2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.3 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.81.43 +ccxt==1.81.81 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From 2dd655eda09973f3357ecf9eb2d5b8589240f7e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 04:52:32 +0000 Subject: [PATCH 071/449] Bump pre-commit from 2.18.1 to 2.19.0 Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.18.1 to 2.19.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.18.1...v2.19.0) --- updated-dependencies: - dependency-name: pre-commit dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 1b60d3b30..195da7f9a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,7 +8,7 @@ coveralls==3.3.1 flake8==4.0.1 flake8-tidy-imports==4.7.0 mypy==0.950 -pre-commit==2.18.1 +pre-commit==2.19.0 pytest==7.1.2 pytest-asyncio==0.18.3 pytest-cov==3.0.0 From a5beacbdd0c4dc133ad0e8d1e8461f988412bb7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 May 2022 04:53:29 +0000 Subject: [PATCH 072/449] Bump types-tabulate from 0.8.8 to 0.8.9 Bumps [types-tabulate](https://github.com/python/typeshed) from 0.8.8 to 0.8.9. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-tabulate dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 42f32b01f..60f4da1a7 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -25,5 +25,5 @@ nbconvert==6.5.0 types-cachetools==5.0.1 types-filelock==3.2.5 types-requests==2.27.25 -types-tabulate==0.8.8 +types-tabulate==0.8.9 types-python-dateutil==2.8.15 From 35ec657ef11149890fcd6d63080ec6b3fc4da18e Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 9 May 2022 06:55:01 +0200 Subject: [PATCH 073/449] Bump types-tabulate==0.8.9 precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ce5797c2..ee909185a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - types-cachetools==5.0.1 - types-filelock==3.2.5 - types-requests==2.27.25 - - types-tabulate==0.8.8 + - types-tabulate==0.8.9 - types-python-dateutil==2.8.15 # stages: [push] From c3b0f6b64b55247ef6269a178ce46bd9cbca929a Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 9 May 2022 07:21:10 +0200 Subject: [PATCH 074/449] Add feature shell for database conversion --- freqtrade/commands/__init__.py | 1 + freqtrade/commands/arguments.py | 27 +++++++++++++++++++-------- freqtrade/commands/cli_options.py | 5 +++++ freqtrade/commands/db_commands.py | 9 +++++++++ 4 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 freqtrade/commands/db_commands.py diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 129836000..1c305c3c2 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -10,6 +10,7 @@ from freqtrade.commands.arguments import Arguments from freqtrade.commands.build_config_commands import start_new_config from freqtrade.commands.data_commands import (start_convert_data, start_convert_trades, start_download_data, start_list_data) +from freqtrade.commands.db_commands import start_db_convert from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui, start_new_strategy) from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index ff1d16590..6ec15dc22 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -82,7 +82,9 @@ ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url", "trade_source", "timeframe", "plot_auto_open", ] -ARGS_INSTALL_UI = ["erase_ui_only", 'ui_version'] +ARGS_INSTALL_DB = ["db_url", "db_url_from"] + +ARGS_INSTALL_UI = ["erase_ui_only", "ui_version"] ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"] @@ -182,13 +184,14 @@ class Arguments: from freqtrade.commands import (start_backtesting, start_backtesting_show, start_convert_data, start_convert_trades, - start_create_userdir, start_download_data, start_edge, - start_hyperopt, start_hyperopt_list, start_hyperopt_show, - start_install_ui, start_list_data, start_list_exchanges, - start_list_markets, start_list_strategies, - start_list_timeframes, start_new_config, start_new_strategy, - start_plot_dataframe, start_plot_profit, start_show_trades, - start_test_pairlist, start_trading, start_webserver) + start_create_userdir, start_db_convert, start_download_data, + start_edge, start_hyperopt, start_hyperopt_list, + start_hyperopt_show, start_install_ui, start_list_data, + start_list_exchanges, start_list_markets, + start_list_strategies, start_list_timeframes, + start_new_config, start_new_strategy, start_plot_dataframe, + start_plot_profit, start_show_trades, start_test_pairlist, + start_trading, start_webserver) subparsers = self.parser.add_subparsers(dest='command', # Use custom message when no subhandler is added @@ -374,6 +377,14 @@ class Arguments: test_pairlist_cmd.set_defaults(func=start_test_pairlist) self._build_args(optionlist=ARGS_TEST_PAIRLIST, parser=test_pairlist_cmd) + # Add db-convert subcommand + convert_db = subparsers.add_parser( + "db-convert", + help="Migrate database to different system", + ) + convert_db.set_defaults(func=start_db_convert) + self._build_args(optionlist=ARGS_INSTALL_DB, parser=convert_db) + # Add install-ui subcommand install_ui_cmd = subparsers.add_parser( 'install-ui', diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 58e208652..24ca01760 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -106,6 +106,11 @@ AVAILABLE_CLI_OPTIONS = { f'`{constants.DEFAULT_DB_DRYRUN_URL}` for Dry Run).', metavar='PATH', ), + "db_url_from": Arg( + '--db-url-from', + help='Source db url to use when migrating database systems.', + metavar='PATH', + ), "sd_notify": Arg( '--sd-notify', help='Notify systemd service manager.', diff --git a/freqtrade/commands/db_commands.py b/freqtrade/commands/db_commands.py new file mode 100644 index 000000000..c57afa1e4 --- /dev/null +++ b/freqtrade/commands/db_commands.py @@ -0,0 +1,9 @@ +from typing import Any, Dict + +from freqtrade.configuration.config_setup import setup_utils_configuration +from freqtrade.enums.runmode import RunMode + + +def start_db_convert(args: Dict[str, Any]) -> None: + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) + pass From 0958c06b84b02aca99936c8129eacbd1d068c17c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 9 May 2022 19:26:38 +0200 Subject: [PATCH 075/449] Implement database migration to other system --- freqtrade/commands/db_commands.py | 33 +++++++++++++++++++++++- freqtrade/configuration/configuration.py | 4 +++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/db_commands.py b/freqtrade/commands/db_commands.py index c57afa1e4..31e7cb8f2 100644 --- a/freqtrade/commands/db_commands.py +++ b/freqtrade/commands/db_commands.py @@ -1,9 +1,40 @@ +import logging from typing import Any, Dict from freqtrade.configuration.config_setup import setup_utils_configuration from freqtrade.enums.runmode import RunMode +logger = logging.getLogger(__name__) + + def start_db_convert(args: Dict[str, Any]) -> None: + from sqlalchemy.orm import make_transient + + from freqtrade.persistence import Trade, init_db + from freqtrade.persistence.pairlock import PairLock + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) - pass + + init_db(config['db_url'], False) + session_target = Trade._session + init_db(config['db_url_from'], False) + + # print(f"{id(sessionA)=}, {id(sessionB)=}") + trade_count = 0 + pairlock_count = 0 + for trade in Trade.get_trades(): + trade_count += 1 + make_transient(trade) + for o in trade.orders: + make_transient(o) + + session_target.add(trade) + session_target.commit() + + for pairlock in PairLock.query: + pairlock_count += 1 + make_transient(pairlock) + session_target.add(pairlock) + session_target.commit() + logger.info(f"Migrated {trade_count} Trades, and {pairlock_count} Pairlocks.") diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 80df6fb3f..0346b4205 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -147,6 +147,10 @@ class Configuration: config.update({'db_url': self.args['db_url']}) logger.info('Parameter --db-url detected ...') + self._args_to_config(config, argname='db_url_from', + logstring='Parameter --db-url-from detected ...') + + if config.get('force_entry_enable', False): logger.warning('`force_entry_enable` RPC message enabled.') From c19be34e714673161cc33259157178e6460cc208 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 9 May 2022 19:59:15 +0200 Subject: [PATCH 076/449] Add rudimentary test for db migration --- tests/commands/test_commands.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 37eeda86a..bae623418 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -14,11 +14,13 @@ from freqtrade.commands import (start_backtesting_show, start_convert_data, star start_list_exchanges, start_list_markets, start_list_strategies, start_list_timeframes, start_new_strategy, start_show_trades, start_test_pairlist, start_trading, start_webserver) +from freqtrade.commands.db_commands import start_db_convert from freqtrade.commands.deploy_commands import (clean_ui_subdir, download_and_install_ui, get_ui_download_url, read_ui_version) from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException +from freqtrade.persistence.models import init_db from tests.conftest import (CURRENT_TEST_STRATEGY, create_mock_trades, get_args, log_has, log_has_re, patch_exchange, patched_configuration_load_config_file) from tests.conftest_trades import MOCK_TRADE_COUNT @@ -1458,3 +1460,28 @@ def test_backtesting_show(mocker, testdatadir, capsys): assert sbr.call_count == 1 out, err = capsys.readouterr() assert "Pairs for Strategy" in out + + +def test_start_db_convert(mocker, fee, tmpdir, caplog): + db_src_file = Path(f"{tmpdir}/db.sqlite") + db_from = f"sqlite:///{db_src_file}" + db_target_file = Path(f"{tmpdir}/db_target.sqlite") + db_to = f"sqlite:///{db_target_file}" + args = [ + "db-convert", + "--db-url-from", + db_from, + "--db-url", + db_to, + ] + + assert not db_src_file.is_file() + init_db(db_from, False) + + create_mock_trades(fee) + assert db_src_file.is_file() + assert not db_target_file.is_file() + pargs = get_args(args) + pargs['config'] = None + start_db_convert(pargs) + assert db_target_file.is_file() From 269630e755c1483f427e4e15d1fa7f1c5f0af61c Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 10 May 2022 07:01:41 +0200 Subject: [PATCH 077/449] Add preliminary documentation for database conversion --- docs/utils.md | 21 +++++++++++++++++++++ freqtrade/commands/__init__.py | 2 +- freqtrade/commands/arguments.py | 25 ++++++++++++------------- freqtrade/commands/db_commands.py | 2 +- tests/commands/test_commands.py | 8 ++++---- 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/docs/utils.md b/docs/utils.md index 6c1b26b01..a8b8a57e3 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -554,6 +554,27 @@ Show whitelist when using a [dynamic pairlist](plugins.md#pairlists). freqtrade test-pairlist --config config.json --quote USDT BTC ``` +## Convert database + +`freqtrade convert-db` can be used to convert your database from one system to another (sqlite -> postgres, postgres -> other postgres), migrating all trades, orders and Pairlocks. + +Please refer to the [SQL cheatsheet](sql_cheatsheet.md#use-a-different-database-system) to learn about requirements for different database systems. + +``` +usage: freqtrade convert-db [-h] [--db-url PATH] [--db-url-from PATH] + +optional arguments: + -h, --help show this help message and exit + --db-url PATH Override trades database URL, this is useful in custom + deployments (default: `sqlite:///tradesv3.sqlite` for + Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for + Dry Run). + --db-url-from PATH Source db url to use when migrating database systems. +``` + +!!! Warning + Please ensure to only use this on an empty target database. Freqtrade will perform a regular migration, but may fail if entries already existed. + ## Webserver mode !!! Warning "Experimental" diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 1c305c3c2..0e637c487 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -10,7 +10,7 @@ from freqtrade.commands.arguments import Arguments from freqtrade.commands.build_config_commands import start_new_config from freqtrade.commands.data_commands import (start_convert_data, start_convert_trades, start_download_data, start_list_data) -from freqtrade.commands.db_commands import start_db_convert +from freqtrade.commands.db_commands import start_convert_db from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui, start_new_strategy) from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 6ec15dc22..815e28175 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -82,7 +82,7 @@ ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url", "trade_source", "timeframe", "plot_auto_open", ] -ARGS_INSTALL_DB = ["db_url", "db_url_from"] +ARGS_CONVERT_DB = ["db_url", "db_url_from"] ARGS_INSTALL_UI = ["erase_ui_only", "ui_version"] @@ -183,15 +183,14 @@ class Arguments: self._build_args(optionlist=['version'], parser=self.parser) from freqtrade.commands import (start_backtesting, start_backtesting_show, - start_convert_data, start_convert_trades, - start_create_userdir, start_db_convert, start_download_data, - start_edge, start_hyperopt, start_hyperopt_list, - start_hyperopt_show, start_install_ui, start_list_data, - start_list_exchanges, start_list_markets, - start_list_strategies, start_list_timeframes, - start_new_config, start_new_strategy, start_plot_dataframe, - start_plot_profit, start_show_trades, start_test_pairlist, - start_trading, start_webserver) + start_convert_data, start_convert_db, start_convert_trades, + start_create_userdir, start_download_data, start_edge, + start_hyperopt, start_hyperopt_list, start_hyperopt_show, + start_install_ui, start_list_data, start_list_exchanges, + start_list_markets, start_list_strategies, + start_list_timeframes, start_new_config, start_new_strategy, + start_plot_dataframe, start_plot_profit, start_show_trades, + start_test_pairlist, start_trading, start_webserver) subparsers = self.parser.add_subparsers(dest='command', # Use custom message when no subhandler is added @@ -379,11 +378,11 @@ class Arguments: # Add db-convert subcommand convert_db = subparsers.add_parser( - "db-convert", + "convert-db", help="Migrate database to different system", ) - convert_db.set_defaults(func=start_db_convert) - self._build_args(optionlist=ARGS_INSTALL_DB, parser=convert_db) + convert_db.set_defaults(func=start_convert_db) + self._build_args(optionlist=ARGS_CONVERT_DB, parser=convert_db) # Add install-ui subcommand install_ui_cmd = subparsers.add_parser( diff --git a/freqtrade/commands/db_commands.py b/freqtrade/commands/db_commands.py index 31e7cb8f2..a0ad882b7 100644 --- a/freqtrade/commands/db_commands.py +++ b/freqtrade/commands/db_commands.py @@ -8,7 +8,7 @@ from freqtrade.enums.runmode import RunMode logger = logging.getLogger(__name__) -def start_db_convert(args: Dict[str, Any]) -> None: +def start_convert_db(args: Dict[str, Any]) -> None: from sqlalchemy.orm import make_transient from freqtrade.persistence import Trade, init_db diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index bae623418..9545206e2 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -14,7 +14,7 @@ from freqtrade.commands import (start_backtesting_show, start_convert_data, star start_list_exchanges, start_list_markets, start_list_strategies, start_list_timeframes, start_new_strategy, start_show_trades, start_test_pairlist, start_trading, start_webserver) -from freqtrade.commands.db_commands import start_db_convert +from freqtrade.commands.db_commands import start_convert_db from freqtrade.commands.deploy_commands import (clean_ui_subdir, download_and_install_ui, get_ui_download_url, read_ui_version) from freqtrade.configuration import setup_utils_configuration @@ -1462,13 +1462,13 @@ def test_backtesting_show(mocker, testdatadir, capsys): assert "Pairs for Strategy" in out -def test_start_db_convert(mocker, fee, tmpdir, caplog): +def test_start_convert_db(mocker, fee, tmpdir, caplog): db_src_file = Path(f"{tmpdir}/db.sqlite") db_from = f"sqlite:///{db_src_file}" db_target_file = Path(f"{tmpdir}/db_target.sqlite") db_to = f"sqlite:///{db_target_file}" args = [ - "db-convert", + "convert-db", "--db-url-from", db_from, "--db-url", @@ -1483,5 +1483,5 @@ def test_start_db_convert(mocker, fee, tmpdir, caplog): assert not db_target_file.is_file() pargs = get_args(args) pargs['config'] = None - start_db_convert(pargs) + start_convert_db(pargs) assert db_target_file.is_file() From 31cce741ac383884e7839ec99ebabf3d5ac195a3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 10 May 2022 07:13:51 +0200 Subject: [PATCH 078/449] Add sequence migration --- freqtrade/commands/db_commands.py | 17 +++++++++++++++++ freqtrade/persistence/migrations.py | 5 ++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/db_commands.py b/freqtrade/commands/db_commands.py index a0ad882b7..762c3c343 100644 --- a/freqtrade/commands/db_commands.py +++ b/freqtrade/commands/db_commands.py @@ -1,8 +1,12 @@ import logging from typing import Any, Dict +from sqlalchemy import func + from freqtrade.configuration.config_setup import setup_utils_configuration from freqtrade.enums.runmode import RunMode +from freqtrade.persistence.migrations import set_sequence_ids +from freqtrade.persistence.trade_model import Order logger = logging.getLogger(__name__) @@ -19,6 +23,7 @@ def start_convert_db(args: Dict[str, Any]) -> None: init_db(config['db_url'], False) session_target = Trade._session init_db(config['db_url_from'], False) + logger.info("Starting db migration.") # print(f"{id(sessionA)=}, {id(sessionB)=}") trade_count = 0 @@ -30,6 +35,7 @@ def start_convert_db(args: Dict[str, Any]) -> None: make_transient(o) session_target.add(trade) + session_target.commit() for pairlock in PairLock.query: @@ -37,4 +43,15 @@ def start_convert_db(args: Dict[str, Any]) -> None: make_transient(pairlock) session_target.add(pairlock) session_target.commit() + + # Update sequences + max_trade_id = session_target.query(func.max(Trade.id)).scalar() + max_order_id = session_target.query(func.max(Order.id)).scalar() + max_pairlock_id = session_target.query(func.max(PairLock.id)).scalar() + + set_sequence_ids(session_target.get_bind(), + trade_id=max_trade_id, + order_id=max_order_id, + pairlock_id=max_pairlock_id) + logger.info(f"Migrated {trade_count} Trades, and {pairlock_count} Pairlocks.") diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index 6a77b0b9a..53e35d9da 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -46,7 +46,7 @@ def get_last_sequence_ids(engine, trade_back_name, order_back_name): return order_id, trade_id -def set_sequence_ids(engine, order_id, trade_id): +def set_sequence_ids(engine, order_id, trade_id, pairlock_id=None): if engine.name == 'postgresql': with engine.begin() as connection: @@ -54,6 +54,9 @@ def set_sequence_ids(engine, order_id, trade_id): connection.execute(text(f"ALTER SEQUENCE orders_id_seq RESTART WITH {order_id}")) if trade_id: connection.execute(text(f"ALTER SEQUENCE trades_id_seq RESTART WITH {trade_id}")) + if pairlock_id: + connection.execute( + text(f"ALTER SEQUENCE pairlocks_id_seq RESTART WITH {pairlock_id}")) def drop_index_on_table(engine, inspector, table_bak_name): From 044afdf7afe48447973c132ade0971bab5fa2b9f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 10 May 2022 19:17:12 +0200 Subject: [PATCH 079/449] Add better test scenario --- freqtrade/configuration/configuration.py | 1 - tests/commands/test_commands.py | 7 +++++++ tests/test_persistence.py | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 0346b4205..96b585cd1 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -150,7 +150,6 @@ class Configuration: self._args_to_config(config, argname='db_url_from', logstring='Parameter --db-url-from detected ...') - if config.get('force_entry_enable', False): logger.warning('`force_entry_enable` RPC message enabled.') diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 9545206e2..0932f4362 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,5 +1,6 @@ import json import re +from datetime import datetime from io import BytesIO from pathlib import Path from unittest.mock import MagicMock, PropertyMock @@ -21,6 +22,7 @@ from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException from freqtrade.persistence.models import init_db +from freqtrade.persistence.pairlock_middleware import PairLocks from tests.conftest import (CURRENT_TEST_STRATEGY, create_mock_trades, get_args, log_has, log_has_re, patch_exchange, patched_configuration_load_config_file) from tests.conftest_trades import MOCK_TRADE_COUNT @@ -1479,9 +1481,14 @@ def test_start_convert_db(mocker, fee, tmpdir, caplog): init_db(db_from, False) create_mock_trades(fee) + + PairLocks.timeframe = '5m' + PairLocks.lock_pair('XRP/USDT', datetime.now(), 'Random reason 125', side='long') assert db_src_file.is_file() assert not db_target_file.is_file() + pargs = get_args(args) pargs['config'] = None start_convert_db(pargs) + assert db_target_file.is_file() diff --git a/tests/test_persistence.py b/tests/test_persistence.py index b66c12086..d84415938 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -1416,14 +1416,14 @@ def test_migrate_set_sequence_ids(): engine = MagicMock() engine.begin = MagicMock() engine.name = 'postgresql' - set_sequence_ids(engine, 22, 55) + set_sequence_ids(engine, 22, 55, 5) assert engine.begin.call_count == 1 engine.reset_mock() engine.begin.reset_mock() engine.name = 'somethingelse' - set_sequence_ids(engine, 22, 55) + set_sequence_ids(engine, 22, 55, 6) assert engine.begin.call_count == 0 From f374c9da705531dc6752a0b384d9664d8b052f2a Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 11 May 2022 06:30:40 +0200 Subject: [PATCH 080/449] PR cleanup --- docs/utils.md | 2 +- freqtrade/commands/cli_options.py | 2 +- freqtrade/commands/db_commands.py | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/utils.md b/docs/utils.md index a8b8a57e3..9b799e5fc 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -569,7 +569,7 @@ optional arguments: deployments (default: `sqlite:///tradesv3.sqlite` for Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for Dry Run). - --db-url-from PATH Source db url to use when migrating database systems. + --db-url-from PATH Source db url to use when migrating a database. ``` !!! Warning diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 24ca01760..aac9f5713 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -108,7 +108,7 @@ AVAILABLE_CLI_OPTIONS = { ), "db_url_from": Arg( '--db-url-from', - help='Source db url to use when migrating database systems.', + help='Source db url to use when migrating a database.', metavar='PATH', ), "sd_notify": Arg( diff --git a/freqtrade/commands/db_commands.py b/freqtrade/commands/db_commands.py index 762c3c343..d93aafcb6 100644 --- a/freqtrade/commands/db_commands.py +++ b/freqtrade/commands/db_commands.py @@ -5,8 +5,6 @@ from sqlalchemy import func from freqtrade.configuration.config_setup import setup_utils_configuration from freqtrade.enums.runmode import RunMode -from freqtrade.persistence.migrations import set_sequence_ids -from freqtrade.persistence.trade_model import Order logger = logging.getLogger(__name__) @@ -15,7 +13,8 @@ logger = logging.getLogger(__name__) def start_convert_db(args: Dict[str, Any]) -> None: from sqlalchemy.orm import make_transient - from freqtrade.persistence import Trade, init_db + from freqtrade.persistence import Order, Trade, init_db + from freqtrade.persistence.migrations import set_sequence_ids from freqtrade.persistence.pairlock import PairLock config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) @@ -25,7 +24,6 @@ def start_convert_db(args: Dict[str, Any]) -> None: init_db(config['db_url_from'], False) logger.info("Starting db migration.") - # print(f"{id(sessionA)=}, {id(sessionB)=}") trade_count = 0 pairlock_count = 0 for trade in Trade.get_trades(): From 8a6a6ec9111d4a42d9fd1d1f60df0133bbba7747 Mon Sep 17 00:00:00 2001 From: DJCrashdummy Date: Tue, 10 May 2022 10:33:04 +0000 Subject: [PATCH 081/449] corrected minor "typo" in formatting --- docs/includes/pairlists.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index 22a252192..6acd361fe 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -44,7 +44,7 @@ It uses configuration from `exchange.pair_whitelist` and `exchange.pair_blacklis ```json "pairlists": [ {"method": "StaticPairList"} - ], +], ``` By default, only currently enabled pairs are allowed. From b2b503f043e0653e9e95a83af09329ffc7b8f645 Mon Sep 17 00:00:00 2001 From: DJCrashdummy Date: Wed, 11 May 2022 06:26:49 +0000 Subject: [PATCH 082/449] minor polish for explanation of --breakdown - corrected the command to fit the explanation - added a little explanation how to read the weekly & monthly breakdown --- docs/backtesting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 75225b654..02d1a53d1 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -466,7 +466,7 @@ You can get an overview over daily / weekly or monthly results by using the `--b To visualize daily and weekly breakdowns, you can use the following: ``` bash -freqtrade backtesting --strategy MyAwesomeStrategy --breakdown day month +freqtrade backtesting --strategy MyAwesomeStrategy --breakdown day week ``` ``` output @@ -482,7 +482,7 @@ freqtrade backtesting --strategy MyAwesomeStrategy --breakdown day month ``` -The output will show a table containing the realized absolute Profit (in stake currency) for the given timeperiod, as well as wins, draws and losses that materialized (closed) on this day. +The output will show a table containing the realized absolute Profit (in stake currency) for the given timeperiod, as well as wins, draws and losses that materialized (closed) on this day. Below that there will be a second table for the summarized values of weeks indicated by the date of the closing Sunday. The same would apply to a monthly breakdown indicated by the last day of the month. ### Backtest result caching From 1fc041d0d6387712fcd69b72e1718a1820789620 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 11 May 2022 19:39:56 +0200 Subject: [PATCH 083/449] Fix formatting issue --- freqtrade/wallets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 9b91430e2..0c2197917 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -300,7 +300,7 @@ class Wallets: if min_stake_amount is not None and min_stake_amount > max_stake_amount: if self._log: - logger.warning("Minimum stake amount > available balance." + logger.warning("Minimum stake amount > available balance. " f"{min_stake_amount} > {max_stake_amount}") return 0 if min_stake_amount is not None and stake_amount < min_stake_amount: From c299601ece12c388a20042fc508debbd89b3ca1d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 13 May 2022 07:03:18 +0200 Subject: [PATCH 084/449] Add warning about OKX futures backtesting data --- docs/exchanges.md | 5 +++-- freqtrade/exchange/okx.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/exchanges.md b/docs/exchanges.md index b2759893b..50ebf9e0a 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -228,11 +228,12 @@ OKX requires a passphrase for each api key, you will therefore need to add this ``` !!! Warning - OKX only provides 300 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode. + OKX only provides 100 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode. -!!! Warning "Futures - position mode" +!!! Warning "Futures" OKX Futures has the concept of "position mode" - which can be Net or long/short (hedge mode). Freqtrade supports both modes - but changing the mode mid-trading is not supported and will lead to exceptions and failures to place trades. + OKX also only provides MARK candles for the past ~3 months. Backtesting futures prior to that date will therefore lead to slight deviations, as funding-fees cannot be calculated correctly without this data. ## Gate.io diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 9aeefd450..654021182 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -20,7 +20,7 @@ class Okx(Exchange): """ _ft_has: Dict = { - "ohlcv_candle_limit": 300, + "ohlcv_candle_limit": 100, "mark_ohlcv_timeframe": "4h", "funding_fee_timeframe": "8h", } From 8a3c2c6cad8beef24900f1939e2fbdc7736c365d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Fri, 13 May 2022 19:32:52 +0530 Subject: [PATCH 085/449] Corrected docstring Discussed in Discord --- freqtrade/persistence/trade_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index bb8c03dd2..b1fff5cf3 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -656,7 +656,7 @@ class LocalTrade(): def recalc_open_trade_value(self) -> None: """ Recalculate open_trade_value. - Must be called whenever open_rate, fee_open or is_short is changed. + Must be called whenever open_rate, fee_open is changed. """ self.open_trade_value = self._calc_open_trade_value() From 71a80cab3a19771628e3c8b936f3479003894c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Fri, 13 May 2022 21:19:40 +0530 Subject: [PATCH 086/449] fixed variable naming style --- freqtrade/optimize/backtesting.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 45300b744..3f2c35cd5 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -538,33 +538,33 @@ class Backtesting: trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60) try: - closerate = self._get_close_rate(row, trade, exit_, trade_dur) + close_rate = self._get_close_rate(row, trade, exit_, trade_dur) except ValueError: return None - # call the custom exit price,with default value as previous closerate - current_profit = trade.calc_profit_ratio(closerate) + # call the custom exit price,with default value as previous close_rate + current_profit = trade.calc_profit_ratio(close_rate) order_type = self.strategy.order_types['exit'] if exit_.exit_type in (ExitType.EXIT_SIGNAL, ExitType.CUSTOM_EXIT): # Custom exit pricing only for exit-signals if order_type == 'limit': - closerate = strategy_safe_wrapper(self.strategy.custom_exit_price, - default_retval=closerate)( + close_rate = strategy_safe_wrapper(self.strategy.custom_exit_price, + default_retval=close_rate)( pair=trade.pair, trade=trade, current_time=exit_candle_time, - proposed_rate=closerate, current_profit=current_profit, + proposed_rate=close_rate, current_profit=current_profit, exit_tag=exit_.exit_reason) # We can't place orders lower than current low. # freqtrade does not support this in live, and the order would fill immediately if trade.is_short: - closerate = min(closerate, row[HIGH_IDX]) + close_rate = min(close_rate, row[HIGH_IDX]) else: - closerate = max(closerate, row[LOW_IDX]) + close_rate = max(close_rate, row[LOW_IDX]) # Confirm trade exit: time_in_force = self.strategy.order_time_in_force['exit'] if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)( pair=trade.pair, trade=trade, order_type='limit', amount=trade.amount, - rate=closerate, + rate=close_rate, time_in_force=time_in_force, sell_reason=exit_.exit_reason, # deprecated exit_reason=exit_.exit_reason, @@ -597,12 +597,12 @@ class Backtesting: side=trade.exit_side, order_type=order_type, status="open", - price=closerate, - average=closerate, + price=close_rate, + average=close_rate, amount=trade.amount, filled=0, remaining=trade.amount, - cost=trade.amount * closerate, + cost=trade.amount * close_rate, ) trade.orders.append(order) return trade From 9d13c8729257ddfb9e8a64daf6bd8b99a9010fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Fri, 13 May 2022 21:46:25 +0530 Subject: [PATCH 087/449] cleaned up backtesting Solves the [bug](https://github.com/freqtrade/freqtrade/runs/6425715015?check_suite_focus=true) --- tests/optimize/test_backtest_detail.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 18b4c3621..0441d4214 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -522,7 +522,7 @@ tc32 = BTContainer(data=[ trailing_stop_positive=0.03, trades=[ BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3, is_short=True) - ] +] ) # Test 33: trailing_stop should be triggered by low of next candle, without adjusting stoploss using @@ -662,7 +662,7 @@ tc41 = BTContainer(data=[ custom_entry_price=4000, trades=[ BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=1, is_short=True) - ] +] ) # Test 42: Custom-entry-price around candle low @@ -933,3 +933,5 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) assert res.open_date == _get_frame_time_from_offset(trade.open_tick) assert res.close_date == _get_frame_time_from_offset(trade.close_tick) assert res.is_short == trade.is_short + backtesting.cleanup() + del backtesting From 64670726a61e8f56593a734d86ba24c10dbbc25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Fri, 13 May 2022 21:52:26 +0530 Subject: [PATCH 088/449] flake8 fix --- freqtrade/optimize/backtesting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 3f2c35cd5..20f34a0bb 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -548,7 +548,7 @@ class Backtesting: # Custom exit pricing only for exit-signals if order_type == 'limit': close_rate = strategy_safe_wrapper(self.strategy.custom_exit_price, - default_retval=close_rate)( + default_retval=close_rate)( pair=trade.pair, trade=trade, current_time=exit_candle_time, proposed_rate=close_rate, current_profit=current_profit, From 64668b11dab7530f7606e9a9deee458689faaefe Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 09:10:38 +0200 Subject: [PATCH 089/449] add ohlcv_has_history - disabling kraken downloads --- freqtrade/commands/data_commands.py | 6 ++++++ freqtrade/exchange/exchange.py | 13 +++++++++---- freqtrade/exchange/kraken.py | 1 + tests/commands/test_commands.py | 17 +++++++++++++++++ tests/exchange/test_ccxt_compat.py | 2 +- tests/exchange/test_exchange.py | 7 +++++++ 6 files changed, 41 insertions(+), 5 deletions(-) diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index a2e2a100a..61a99782e 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -79,6 +79,12 @@ def start_download_data(args: Dict[str, Any]) -> None: data_format_trades=config['dataformat_trades'], ) else: + if not exchange._ft_has.get('ohlcv_has_history', True): + raise OperationalException( + f"Historic klines not available for {exchange.name}. " + "Please use `--dl-trades` instead for this exchange " + "(will unfortunately take a long time)." + ) pairs_not_available = refresh_backtest_ohlcv_data( exchange, pairs=expanded_pairs, timeframes=config['timeframes'], datadir=config['datadir'], timerange=timerange, diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 65b9fb628..8d74a8446 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -64,6 +64,7 @@ class Exchange: "time_in_force_parameter": "timeInForce", "ohlcv_params": {}, "ohlcv_candle_limit": 500, + "ohlcv_has_history": True, # Some exchanges (Kraken) don't provide history via ohlcv "ohlcv_partial_candle": True, "ohlcv_require_since": False, # Check https://github.com/ccxt/ccxt/issues/10767 for removal of ohlcv_volume_currency @@ -621,13 +622,17 @@ class Exchange: # Allow 5 calls to the exchange per pair required_candle_call_count = int( (candle_count / candle_limit) + (0 if candle_count % candle_limit == 0 else 1)) + if self._ft_has['ohlcv_has_history']: - if required_candle_call_count > 5: - # Only allow 5 calls per pair to somewhat limit the impact + if required_candle_call_count > 5: + # Only allow 5 calls per pair to somewhat limit the impact + raise OperationalException( + f"This strategy requires {startup_candles} candles to start, which is more than 5x " + f"the amount of candles {self.name} provides for {timeframe}.") + elif required_candle_call_count > 1: raise OperationalException( - f"This strategy requires {startup_candles} candles to start, which is more than 5x " + f"This strategy requires {startup_candles} candles to start, which is more than " f"the amount of candles {self.name} provides for {timeframe}.") - if required_candle_call_count > 1: logger.warning(f"Using {required_candle_call_count} calls to get OHLCV. " f"This can result in slower operations for the bot. Please check " diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 33a2c7f87..900f6c898 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -23,6 +23,7 @@ class Kraken(Exchange): _ft_has: Dict = { "stoploss_on_exchange": True, "ohlcv_candle_limit": 720, + "ohlcv_has_history": False, "trades_pagination": "id", "trades_pagination_arg": "since", "mark_ohlcv_timeframe": "4h", diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 0932f4362..b37edf9c7 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -835,6 +835,23 @@ def test_download_data_trades(mocker, caplog): start_download_data(pargs) +def test_download_data_data_invalid(mocker): + patch_exchange(mocker, id="kraken") + mocker.patch( + 'freqtrade.exchange.Exchange.markets', PropertyMock(return_value={}) + ) + args = [ + "download-data", + "--exchange", "kraken", + "--pairs", "ETH/BTC", "XRP/BTC", + "--days", "20", + ] + pargs = get_args(args) + pargs['config'] = None + with pytest.raises(OperationalException, match=r"Historic klines not available for .*"): + start_download_data(pargs) + + def test_start_convert_trades(mocker, caplog): convert_mock = mocker.patch('freqtrade.commands.data_commands.convert_trades_to_ohlcv', MagicMock(return_value=[])) diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index d8832bb71..ac7c8a528 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -219,7 +219,7 @@ class TestCCXTExchange(): assert len(l2['asks']) == next_limit assert len(l2['asks']) == next_limit - def test_fetch_ohlcv(self, exchange): + def test_ccxt_fetch_ohlcv(self, exchange): exchange, exchangename = exchange pair = EXCHANGES[exchangename]['pair'] timeframe = EXCHANGES[exchangename]['timeframe'] diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 77a04ac6c..ed2a7b7ee 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1084,6 +1084,13 @@ def test_validate_required_startup_candles(default_conf, mocker, caplog): with pytest.raises(OperationalException, match=r'This strategy requires 6000.*'): Exchange(default_conf) + # Emulate kraken mode + ex._ft_has['ohlcv_has_history'] = False + with pytest.raises(OperationalException, + match=r'This strategy requires 2500.*, ' + r'which is more than the amount.*'): + ex.validate_required_startup_candles(2500, '5m') + def test_exchange_has(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf) From 111b04c9e65668067646265e614326f81aa1bf1c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 09:51:44 +0200 Subject: [PATCH 090/449] Okx - conditional candle-length --- freqtrade/exchange/exchange.py | 17 ++++++++++----- freqtrade/exchange/okx.py | 28 +++++++++++++++++++++++-- tests/exchange/test_ccxt_compat.py | 33 ++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 8d74a8446..864aa36e9 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -309,12 +309,15 @@ class Exchange: if self.log_responses: logger.info(f"API {endpoint}: {response}") - def ohlcv_candle_limit(self, timeframe: str) -> int: + def ohlcv_candle_limit( + self, timeframe: str, candle_type: CandleType, since_ms: Optional[int]) -> int: """ Exchange ohlcv candle limit Uses ohlcv_candle_limit_per_timeframe if the exchange has different limits per timeframe (e.g. bittrex), otherwise falls back to ohlcv_candle_limit :param timeframe: Timeframe to check + :param candle_type: Candle-type + :param since_ms: Candle-type :return: Candle limit as integer """ return int(self._ft_has.get('ohlcv_candle_limit_per_timeframe', {}).get( @@ -616,7 +619,7 @@ class Exchange: Checks if required startup_candles is more than ohlcv_candle_limit(). Requires a grace-period of 5 candles - so a startup-period up to 494 is allowed by default. """ - candle_limit = self.ohlcv_candle_limit(timeframe) + candle_limit = self.ohlcv_candle_limit(timeframe, self._config['candle_type_def'], None) # Require one more candle - to account for the still open candle. candle_count = startup_candles + 1 # Allow 5 calls to the exchange per pair @@ -1708,7 +1711,8 @@ class Exchange: :param candle_type: Any of the enum CandleType (must match trading mode!) """ - one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe) + one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit( + timeframe, candle_type, since_ms) logger.debug( "one_call: %s msecs (%s)", one_call, @@ -1744,7 +1748,8 @@ class Exchange: if (not since_ms and (self._ft_has["ohlcv_require_since"] or self.required_candle_call_count > 1)): # Multiple calls for one pair - to get more history - one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe) + one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit( + timeframe, candle_type, since_ms) move_to = one_call * self.required_candle_call_count now = timeframe_to_next_date(timeframe) since_ms = int((now - timedelta(seconds=move_to // 1000)).timestamp() * 1000) @@ -1862,7 +1867,9 @@ class Exchange: pair, timeframe, since_ms, s ) params = deepcopy(self._ft_has.get('ohlcv_params', {})) - candle_limit = self.ohlcv_candle_limit(timeframe) + candle_limit = self.ohlcv_candle_limit( + timeframe, candle_type=candle_type, since_ms=since_ms) + if candle_type != CandleType.SPOT: params.update({'price': candle_type}) if candle_type != CandleType.FUNDING_RATE: diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 654021182..5e24997d7 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -1,13 +1,16 @@ import logging -from typing import Dict, List, Tuple +from datetime import datetime, timedelta, timezone +from typing import Dict, List, Optional, Tuple import ccxt from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, TradingMode +from freqtrade.enums.candletype import CandleType from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange from freqtrade.exchange.common import retrier +from freqtrade.exchange.exchange import timeframe_to_minutes logger = logging.getLogger(__name__) @@ -20,7 +23,7 @@ class Okx(Exchange): """ _ft_has: Dict = { - "ohlcv_candle_limit": 100, + "ohlcv_candle_limit": 300, # Warning, special case with data prior to X months "mark_ohlcv_timeframe": "4h", "funding_fee_timeframe": "8h", } @@ -37,6 +40,27 @@ class Okx(Exchange): net_only = True + def ohlcv_candle_limit( + self, timeframe: str, candle_type: CandleType, since_ms: Optional[int]) -> int: + """ + Exchange ohlcv candle limit + Uses ohlcv_candle_limit_per_timeframe if the exchange has different limits + per timeframe (e.g. bittrex), otherwise falls back to ohlcv_candle_limit + :param timeframe: Timeframe to check + :param candle_type: Candle-type + :param since_ms: Candle-type + :return: Candle limit as integer + """ + now = datetime.now(timezone.utc) + offset_mins = timeframe_to_minutes(timeframe) * self._ft_has['ohlcv_candle_limit'] + if since_ms and since_ms < ((now - timedelta(minutes=offset_mins)).timestamp() * 1000): + return 100 + if candle_type not in (CandleType.FUTURES, CandleType.SPOT): + return 100 + + return int(self._ft_has.get('ohlcv_candle_limit_per_timeframe', {}).get( + timeframe, self._ft_has.get('ohlcv_candle_limit'))) + @retrier def additional_exchange_init(self) -> None: """ diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index ac7c8a528..ea9a166f6 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -13,6 +13,7 @@ import pytest from freqtrade.enums import CandleType from freqtrade.exchange import timeframe_to_minutes, timeframe_to_prev_date +from freqtrade.exchange.exchange import timeframe_to_msecs from freqtrade.resolvers.exchange_resolver import ExchangeResolver from tests.conftest import get_default_conf_usdt @@ -236,6 +237,38 @@ class TestCCXTExchange(): now = datetime.now(timezone.utc) - timedelta(minutes=(timeframe_to_minutes(timeframe) * 2)) assert exchange.klines(pair_tf).iloc[-1]['date'] >= timeframe_to_prev_date(timeframe, now) + def test_ccxt__async_get_candle_history(self, exchange): + exchange, exchangename = exchange + # For some weired reason, this test returns random lengths for bittrex. + if not exchange._ft_has['ohlcv_has_history'] or exchangename == 'bittrex': + return + pair = EXCHANGES[exchangename]['pair'] + timeframe = EXCHANGES[exchangename]['timeframe'] + candle_type = CandleType.SPOT + timeframe_ms = timeframe_to_msecs(timeframe) + now = timeframe_to_prev_date( + timeframe, datetime.now(timezone.utc)) + for offset in (360, 120, 30, 10, 5, 2): + since = now - timedelta(days=offset) + since_ms = int(since.timestamp() * 1000) + + res = exchange.loop.run_until_complete(exchange._async_get_candle_history( + pair=pair, + timeframe=timeframe, + since_ms=since_ms, + candle_type=candle_type + ) + ) + assert res + assert res[0] == pair + assert res[1] == timeframe + assert res[2] == candle_type + candles = res[3] + candle_count = exchange.ohlcv_candle_limit(timeframe, candle_type, since_ms) * 0.9 + candle_count1 = (now.timestamp() * 1000 - since_ms) // timeframe_ms + assert len(candles) >= min(candle_count, candle_count1) + assert candles[0][0] == since_ms or (since_ms + timeframe_ms) + def test_ccxt_fetch_funding_rate_history(self, exchange_futures): exchange, exchangename = exchange_futures if not exchange: From bb1b283d9548ea58cee0d588d48e631a015f8297 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 13:27:36 +0200 Subject: [PATCH 091/449] Update some ohlcv_candle_limit calls --- freqtrade/exchange/exchange.py | 2 +- freqtrade/exchange/okx.py | 2 +- freqtrade/plugins/pairlist/AgeFilter.py | 9 +++++---- freqtrade/plugins/pairlist/VolatilityFilter.py | 6 +++--- freqtrade/plugins/pairlist/VolumePairList.py | 7 ++++--- freqtrade/plugins/pairlist/rangestabilityfilter.py | 6 +++--- tests/exchange/test_ccxt_compat.py | 3 ++- tests/exchange/test_exchange.py | 8 ++++---- 8 files changed, 23 insertions(+), 20 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 864aa36e9..d2a01f394 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -310,7 +310,7 @@ class Exchange: logger.info(f"API {endpoint}: {response}") def ohlcv_candle_limit( - self, timeframe: str, candle_type: CandleType, since_ms: Optional[int]) -> int: + self, timeframe: str, candle_type: CandleType, since_ms: Optional[int] = None) -> int: """ Exchange ohlcv candle limit Uses ohlcv_candle_limit_per_timeframe if the exchange has different limits diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 5e24997d7..6d25bb12b 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -41,7 +41,7 @@ class Okx(Exchange): net_only = True def ohlcv_candle_limit( - self, timeframe: str, candle_type: CandleType, since_ms: Optional[int]) -> int: + self, timeframe: str, candle_type: CandleType, since_ms: Optional[int] = None) -> int: """ Exchange ohlcv candle limit Uses ohlcv_candle_limit_per_timeframe if the exchange has different limits diff --git a/freqtrade/plugins/pairlist/AgeFilter.py b/freqtrade/plugins/pairlist/AgeFilter.py index bb6f75012..418c0f14e 100644 --- a/freqtrade/plugins/pairlist/AgeFilter.py +++ b/freqtrade/plugins/pairlist/AgeFilter.py @@ -32,18 +32,19 @@ class AgeFilter(IPairList): self._min_days_listed = pairlistconfig.get('min_days_listed', 10) self._max_days_listed = pairlistconfig.get('max_days_listed', None) + candle_limit = exchange.ohlcv_candle_limit('1d', self._config['candle_type_def']) if self._min_days_listed < 1: raise OperationalException("AgeFilter requires min_days_listed to be >= 1") - if self._min_days_listed > exchange.ohlcv_candle_limit('1d'): + if self._min_days_listed > candle_limit: raise OperationalException("AgeFilter requires min_days_listed to not exceed " "exchange max request size " - f"({exchange.ohlcv_candle_limit('1d')})") + f"({candle_limit})") if self._max_days_listed and self._max_days_listed <= self._min_days_listed: raise OperationalException("AgeFilter max_days_listed <= min_days_listed not permitted") - if self._max_days_listed and self._max_days_listed > exchange.ohlcv_candle_limit('1d'): + if self._max_days_listed and self._max_days_listed > candle_limit: raise OperationalException("AgeFilter requires max_days_listed to not exceed " "exchange max request size " - f"({exchange.ohlcv_candle_limit('1d')})") + f"({candle_limit})") @property def needstickers(self) -> bool: diff --git a/freqtrade/plugins/pairlist/VolatilityFilter.py b/freqtrade/plugins/pairlist/VolatilityFilter.py index 6aa857c2c..bab44bdd1 100644 --- a/freqtrade/plugins/pairlist/VolatilityFilter.py +++ b/freqtrade/plugins/pairlist/VolatilityFilter.py @@ -38,12 +38,12 @@ class VolatilityFilter(IPairList): self._pair_cache: TTLCache = TTLCache(maxsize=1000, ttl=self._refresh_period) + candle_limit = exchange.ohlcv_candle_limit('1d', self._config['candle_type_def']) if self._days < 1: raise OperationalException("VolatilityFilter requires lookback_days to be >= 1") - if self._days > exchange.ohlcv_candle_limit('1d'): + if self._days > candle_limit: raise OperationalException("VolatilityFilter requires lookback_days to not " - "exceed exchange max request size " - f"({exchange.ohlcv_candle_limit('1d')})") + f"exceed exchange max request size ({candle_limit})") @property def needstickers(self) -> bool: diff --git a/freqtrade/plugins/pairlist/VolumePairList.py b/freqtrade/plugins/pairlist/VolumePairList.py index 26e7d45be..cd16a46a3 100644 --- a/freqtrade/plugins/pairlist/VolumePairList.py +++ b/freqtrade/plugins/pairlist/VolumePairList.py @@ -84,12 +84,13 @@ class VolumePairList(IPairList): raise OperationalException( f'key {self._sort_key} not in {SORT_VALUES}') + candle_limit = exchange.ohlcv_candle_limit( + self._lookback_timeframe, self._config['candle_type_def']) if self._lookback_period < 0: raise OperationalException("VolumeFilter requires lookback_period to be >= 0") - if self._lookback_period > exchange.ohlcv_candle_limit(self._lookback_timeframe): + if self._lookback_period > candle_limit: raise OperationalException("VolumeFilter requires lookback_period to not " - "exceed exchange max request size " - f"({exchange.ohlcv_candle_limit(self._lookback_timeframe)})") + f"exceed exchange max request size ({candle_limit})") @property def needstickers(self) -> bool: diff --git a/freqtrade/plugins/pairlist/rangestabilityfilter.py b/freqtrade/plugins/pairlist/rangestabilityfilter.py index c9edfd13d..de016c3a6 100644 --- a/freqtrade/plugins/pairlist/rangestabilityfilter.py +++ b/freqtrade/plugins/pairlist/rangestabilityfilter.py @@ -33,12 +33,12 @@ class RangeStabilityFilter(IPairList): self._pair_cache: TTLCache = TTLCache(maxsize=1000, ttl=self._refresh_period) + candle_limit = exchange.ohlcv_candle_limit('1d', self._config['candle_type_def']) if self._days < 1: raise OperationalException("RangeStabilityFilter requires lookback_days to be >= 1") - if self._days > exchange.ohlcv_candle_limit('1d'): + if self._days > candle_limit: raise OperationalException("RangeStabilityFilter requires lookback_days to not " - "exceed exchange max request size " - f"({exchange.ohlcv_candle_limit('1d')})") + f"exceed exchange max request size ({candle_limit})") @property def needstickers(self) -> bool: diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index ea9a166f6..e016873cb 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -232,7 +232,8 @@ class TestCCXTExchange(): assert len(ohlcv[pair_tf]) == len(exchange.klines(pair_tf)) # assert len(exchange.klines(pair_tf)) > 200 # Assume 90% uptime ... - assert len(exchange.klines(pair_tf)) > exchange.ohlcv_candle_limit(timeframe) * 0.90 + assert len(exchange.klines(pair_tf)) > exchange.ohlcv_candle_limit( + timeframe, CandleType.SPOT) * 0.90 # Check if last-timeframe is within the last 2 intervals now = datetime.now(timezone.utc) - timedelta(minutes=(timeframe_to_minutes(timeframe) * 2)) assert exchange.klines(pair_tf).iloc[-1]['date'] >= timeframe_to_prev_date(timeframe, now) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index ed2a7b7ee..9d7b77a8e 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1882,7 +1882,7 @@ def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_ exchange._async_get_candle_history = Mock(wraps=mock_candle_hist) # one_call calculation * 1.8 should do 2 calls - since = 5 * 60 * exchange.ohlcv_candle_limit('5m') * 1.8 + since = 5 * 60 * exchange.ohlcv_candle_limit('5m', CandleType.SPOT) * 1.8 ret = exchange.get_historic_ohlcv( pair, "5m", @@ -1948,7 +1948,7 @@ def test_get_historic_ohlcv_as_df(default_conf, mocker, exchange_name, candle_ty exchange._async_get_candle_history = Mock(wraps=mock_candle_hist) # one_call calculation * 1.8 should do 2 calls - since = 5 * 60 * exchange.ohlcv_candle_limit('5m') * 1.8 + since = 5 * 60 * exchange.ohlcv_candle_limit('5m', CandleType.SPOT) * 1.8 ret = exchange.get_historic_ohlcv_as_df( pair, "5m", @@ -2002,7 +2002,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_ ) # Required candles candles = (end_ts - start_ts) / 300_000 - exp = candles // exchange.ohlcv_candle_limit('5m') + 1 + exp = candles // exchange.ohlcv_candle_limit('5m', CandleType.SPOT) + 1 # Depending on the exchange, this should be called between 1 and 6 times. assert exchange._api_async.fetch_ohlcv.call_count == exp @@ -3349,7 +3349,7 @@ def test_ohlcv_candle_limit(default_conf, mocker, exchange_name): expected = exchange._ft_has['ohlcv_candle_limit_per_timeframe'][timeframe] # This should only run for bittrex assert exchange_name == 'bittrex' - assert exchange.ohlcv_candle_limit(timeframe) == expected + assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT) == expected def test_timeframe_to_minutes(): From 2a1368d508a621a35579bed55db1d6eb841933ee Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 14:14:53 +0200 Subject: [PATCH 092/449] Offsetfilter: add number_assets parameter closes #6824 --- docs/includes/pairlists.md | 8 ++++---- freqtrade/plugins/pairlist/OffsetFilter.py | 9 ++++++++- tests/plugins/test_pairlist.py | 10 +++++++++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index 6acd361fe..0f55c1b79 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -160,17 +160,17 @@ This filter allows freqtrade to ignore pairs until they have been listed for at Offsets an incoming pairlist by a given `offset` value. -As an example it can be used in conjunction with `VolumeFilter` to remove the top X volume pairs. Or to split -a larger pairlist on two bot instances. +As an example it can be used in conjunction with `VolumeFilter` to remove the top X volume pairs. Or to split a larger pairlist on two bot instances. -Example to remove the first 10 pairs from the pairlist: +Example to remove the first 10 pairs from the pairlist, and takes the next 20 (taking items 10-30 of the initial list): ```json "pairlists": [ // ... { "method": "OffsetFilter", - "offset": 10 + "offset": 10, + "number_assets": 20 } ], ``` diff --git a/freqtrade/plugins/pairlist/OffsetFilter.py b/freqtrade/plugins/pairlist/OffsetFilter.py index 573a573a6..e0f8414ef 100644 --- a/freqtrade/plugins/pairlist/OffsetFilter.py +++ b/freqtrade/plugins/pairlist/OffsetFilter.py @@ -19,6 +19,7 @@ class OffsetFilter(IPairList): super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) self._offset = pairlistconfig.get('offset', 0) + self._number_pairs = pairlistconfig.get('number_assets', 0) if self._offset < 0: raise OperationalException("OffsetFilter requires offset to be >= 0") @@ -36,7 +37,9 @@ class OffsetFilter(IPairList): """ Short whitelist method description - used for startup-messages """ - return f"{self.name} - Offseting pairs by {self._offset}." + if self._number_pairs: + return f"{self.name} - Taking {self._number_pairs} Pairs, starting from {self._offset}." + return f"{self.name} - Offsetting pairs by {self._offset}." def filter_pairlist(self, pairlist: List[str], tickers: Dict) -> List[str]: """ @@ -50,5 +53,9 @@ class OffsetFilter(IPairList): self.log_once(f"Offset of {self._offset} is larger than " + f"pair count of {len(pairlist)}", logger.warning) pairs = pairlist[self._offset:] + if self._number_pairs: + pairs = pairs[:self._number_pairs] + self.log_once(f"Searching {len(pairs)} pairs: {pairs}", logger.info) + return pairs diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index d80f23c8a..c29e619b1 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -470,12 +470,16 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): "BTC", ['ETH/BTC', 'TKN/BTC']), # VolumePairList with no offset = unchanged pairlist ([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"}, - {"method": "OffsetFilter", "offset": 0}], + {"method": "OffsetFilter", "offset": 0, "number_assets": 0}], "USDT", ['ETH/USDT', 'NANO/USDT', 'ADAHALF/USDT', 'ADADOUBLE/USDT']), # VolumePairList with offset = 2 ([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"}, {"method": "OffsetFilter", "offset": 2}], "USDT", ['ADAHALF/USDT', 'ADADOUBLE/USDT']), + # VolumePairList with offset and limit + ([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"}, + {"method": "OffsetFilter", "offset": 1, "number_assets": 2}], + "USDT", ['NANO/USDT', 'ADAHALF/USDT']), # VolumePairList with higher offset, than total pairlist ([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"}, {"method": "OffsetFilter", "offset": 100}], @@ -1152,6 +1156,10 @@ def test_spreadfilter_invalid_data(mocker, default_conf, markets, tickers, caplo "0.01 and above 0.99 over the last days.'}]", None ), + ({"method": "OffsetFilter", "offset": 5, "number_assets": 10}, + "[{'OffsetFilter': 'OffsetFilter - Taking 10 Pairs, starting from 5.'}]", + None + ), ]) def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig, desc_expected, exception_expected): From 5767d652bf9ffb97b4498c95cff9fc0e5c1654cf Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 13:52:58 +0200 Subject: [PATCH 093/449] Add explicit test and document behavior --- freqtrade/exchange/exchange.py | 3 ++- freqtrade/exchange/okx.py | 8 +++++--- tests/exchange/test_okx.py | 27 +++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d2a01f394..86f80871b 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -630,7 +630,8 @@ class Exchange: if required_candle_call_count > 5: # Only allow 5 calls per pair to somewhat limit the impact raise OperationalException( - f"This strategy requires {startup_candles} candles to start, which is more than 5x " + f"This strategy requires {startup_candles} candles to start, " + "which is more than 5x " f"the amount of candles {self.name} provides for {timeframe}.") elif required_candle_call_count > 1: raise OperationalException( diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 6d25bb12b..c8324e62e 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -41,11 +41,13 @@ class Okx(Exchange): net_only = True def ohlcv_candle_limit( - self, timeframe: str, candle_type: CandleType, since_ms: Optional[int] = None) -> int: + self, timeframe: str, candle_type: CandleType, since_ms: Optional[int] = None) -> int: """ Exchange ohlcv candle limit - Uses ohlcv_candle_limit_per_timeframe if the exchange has different limits - per timeframe (e.g. bittrex), otherwise falls back to ohlcv_candle_limit + OKX has the following behaviour: + * 300 candles for uptodate data + * 100 candles for historic data + * 100 candles for additional candles (not futures or spot). :param timeframe: Timeframe to check :param candle_type: Candle-type :param since_ms: Candle-type diff --git a/tests/exchange/test_okx.py b/tests/exchange/test_okx.py index f6bdd35ad..2804d471a 100644 --- a/tests/exchange/test_okx.py +++ b/tests/exchange/test_okx.py @@ -1,12 +1,39 @@ +from datetime import datetime, timedelta, timezone from unittest.mock import MagicMock, PropertyMock import pytest from freqtrade.enums import MarginMode, TradingMode +from freqtrade.enums.candletype import CandleType +from freqtrade.exchange.exchange import timeframe_to_minutes from tests.conftest import get_patched_exchange from tests.exchange.test_exchange import ccxt_exceptionhandlers +def test_okx_ohlcv_candle_limit(default_conf, mocker): + exchange = get_patched_exchange(mocker, default_conf, id='okx') + timeframes = ('1m', '5m', '1h') + start_time = int(datetime(2021, 1, 1, tzinfo=timezone.utc).timestamp() * 1000) + + for timeframe in timeframes: + assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT) == 300 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES) == 300 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK) == 100 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE) == 100 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == 100 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == 100 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 100 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 100 + one_call = int((datetime.now(timezone.utc) - timedelta( + minutes=290 * timeframe_to_minutes(timeframe))).timestamp() * 1000) + assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 300 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, one_call) == 300 + one_call = int((datetime.now(timezone.utc) - timedelta( + minutes=320 * timeframe_to_minutes(timeframe))).timestamp() * 1000) + assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 100 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, one_call) == 100 + + def test_get_maintenance_ratio_and_amt_okx( default_conf, mocker, From 1c20fb7638d433e0ba703ff995c572a42ecb65ac Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 14 May 2022 16:37:04 +0300 Subject: [PATCH 094/449] Refresh open_rate and stoploss on order replacement. --- freqtrade/optimize/backtesting.py | 4 ++++ freqtrade/persistence/trade_model.py | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 45300b744..f439e4e63 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -780,6 +780,8 @@ class Backtesting: # interest_rate=interest_rate, orders=[], ) + elif trade.nr_of_successful_entries == 0: + trade.open_rate = propose_rate trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss, initial=True) @@ -940,6 +942,8 @@ class Backtesting: requested_rate=requested_rate, requested_stake=(order.remaining * order.price), direction='short' if trade.is_short else 'long') + trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss, + initial=False, refresh=True) else: # assumption: there can't be multiple open entry orders at any given time return (trade.nr_of_successful_entries == 0) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index b1fff5cf3..28cca5532 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -491,7 +491,7 @@ class LocalTrade(): self.stoploss_last_update = datetime.utcnow() def adjust_stop_loss(self, current_price: float, stoploss: float, - initial: bool = False) -> None: + initial: bool = False, refresh: bool = False) -> None: """ This adjusts the stop loss to it's most recently observed setting :param current_price: Current rate the asset is traded @@ -516,8 +516,7 @@ class LocalTrade(): new_loss = max(self.liquidation_price, new_loss) # no stop loss assigned yet - if self.initial_stop_loss_pct is None: - logger.debug(f"{self.pair} - Assigning new stoploss...") + if self.initial_stop_loss_pct is None or refresh: self._set_stop_loss(new_loss, stoploss) self.initial_stop_loss = new_loss self.initial_stop_loss_pct = -1 * abs(stoploss) From ec54b47b6e36394f5f633af0f7d5a5cdc960ccfb Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 14 May 2022 16:39:27 +0300 Subject: [PATCH 095/449] Flake fix. --- tests/optimize/test_backtest_detail.py | 35 ++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 0441d4214..4b4c446e0 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -762,7 +762,7 @@ tc48 = BTContainer(data=[ [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust [3, 5100, 5100, 4650, 4750, 6172, 0, 1], [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], - stop_loss=-0.01, roi={"0": 0.10}, profit_perc=-0.087, + stop_loss=-0.2, roi={"0": 0.10}, profit_perc=-0.087, use_exit_signal=True, timeout=1000, custom_entry_price=4200, adjust_entry_price=5200, trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=False)] @@ -777,7 +777,7 @@ tc49 = BTContainer(data=[ [2, 4900, 5250, 4900, 5100, 6172, 0, 0, 0, 0], # Order readjust [3, 5100, 5100, 4650, 4750, 6172, 0, 0, 0, 1], [4, 4750, 4950, 4350, 4750, 6172, 0, 0, 0, 0]], - stop_loss=-0.01, roi={"0": 0.10}, profit_perc=0.05, + stop_loss=-0.2, roi={"0": 0.10}, profit_perc=0.05, use_exit_signal=True, timeout=1000, custom_entry_price=5300, adjust_entry_price=5000, trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=True)] @@ -811,6 +811,35 @@ tc51 = BTContainer(data=[ trades=[] ) +# Test 52: Custom-entry-price below all candles - readjust order - stoploss +tc52 = BTContainer(data=[ + # D O H L C V EL XL ES Xs BT + [0, 5000, 5050, 4950, 5000, 6172, 1, 0], + [1, 5000, 5500, 4951, 5000, 6172, 0, 0], # enter trade (signal on last candle) + [2, 4900, 5250, 4500, 5100, 6172, 0, 0], # Order readjust + [3, 5100, 5100, 4650, 4750, 6172, 0, 0], # stoploss hit? + [4, 4750, 4950, 4350, 4750, 6172, 0, 0]], + stop_loss=-0.03, roi={"0": 0.10}, profit_perc=-0.03, + use_exit_signal=True, timeout=1000, + custom_entry_price=4200, adjust_entry_price=5200, + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2, is_short=False)] +) + + +# Test 53: Custom-entry-price short above all candles - readjust order - stoploss +tc53 = BTContainer(data=[ + # D O H L C V EL XL ES Xs BT + [0, 5000, 5050, 4950, 5000, 6172, 0, 0, 1, 0], + [1, 5000, 5200, 4951, 5000, 6172, 0, 0, 0, 0], # enter trade (signal on last candle) + [2, 4900, 5250, 4900, 5100, 6172, 0, 0, 0, 0], # Order readjust + [3, 5100, 5100, 4650, 4750, 6172, 0, 0, 0, 1], # stoploss hit? + [4, 4750, 4950, 4350, 4750, 6172, 0, 0, 0, 0]], + stop_loss=-0.03, roi={"0": 0.10}, profit_perc=-0.03, + use_exit_signal=True, timeout=1000, + custom_entry_price=5300, adjust_entry_price=5000, + trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=2, is_short=True)] +) + TESTS = [ tc0, tc1, @@ -864,6 +893,8 @@ TESTS = [ tc49, tc50, tc51, + tc52, + tc53, ] From c27e0a0a1b8837525fe93cfaa459a78c4dce8f2b Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Sat, 14 May 2022 16:56:56 +0300 Subject: [PATCH 096/449] Allow SL refresh only if no filled entry orders. --- freqtrade/persistence/trade_model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 28cca5532..bbdeeef47 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -502,6 +502,7 @@ class LocalTrade(): if initial and not (self.stop_loss is None or self.stop_loss == 0): # Don't modify if called with initial and nothing to do return + refresh = False if self.nr_of_successful_entries > 0 else refresh leverage = self.leverage or 1.0 if self.is_short: From 3b144392407501a7df9ecb32c04db6c434dbbcb3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 16:16:32 +0200 Subject: [PATCH 097/449] Slightly improve performance of order adjusts Avoind 2nd call to `get_rate()`. closes #6821 --- freqtrade/freqtradebot.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 03cd322a6..07b055309 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -536,7 +536,8 @@ class FreqtradeBot(LoggingMixin): if stake_amount is not None and stake_amount > 0.0: # We should increase our position - self.execute_entry(trade.pair, stake_amount, trade=trade, is_short=trade.is_short) + self.execute_entry(trade.pair, stake_amount, price=current_rate, + trade=trade, is_short=trade.is_short) if stake_amount is not None and stake_amount < 0.0: # We should decrease our position @@ -586,6 +587,7 @@ class FreqtradeBot(LoggingMixin): ordertype: Optional[str] = None, enter_tag: Optional[str] = None, trade: Optional[Trade] = None, + order_adjust: bool = False ) -> bool: """ Executes a limit buy for the given pair @@ -601,7 +603,7 @@ class FreqtradeBot(LoggingMixin): pos_adjust = trade is not None enter_limit_requested, stake_amount, leverage = self.get_valid_enter_price_and_stake( - pair, price, stake_amount, trade_side, enter_tag, trade) + pair, price, stake_amount, trade_side, enter_tag, trade, order_adjust) if not stake_amount: return False @@ -746,23 +748,26 @@ class FreqtradeBot(LoggingMixin): self, pair: str, price: Optional[float], stake_amount: float, trade_side: LongShort, entry_tag: Optional[str], - trade: Optional[Trade] + trade: Optional[Trade], + order_adjust: bool, ) -> Tuple[float, float, float]: if price: enter_limit_requested = price else: # Calculate price - proposed_enter_rate = self.exchange.get_rate( + enter_limit_requested = self.exchange.get_rate( pair, side='entry', is_short=(trade_side == 'short'), refresh=True) + if not order_adjust: + # Don't call custom_entry_price in order-adjust scenario custom_entry_price = strategy_safe_wrapper(self.strategy.custom_entry_price, - default_retval=proposed_enter_rate)( + default_retval=enter_limit_requested)( pair=pair, current_time=datetime.now(timezone.utc), - proposed_rate=proposed_enter_rate, entry_tag=entry_tag, + proposed_rate=enter_limit_requested, entry_tag=entry_tag, side=trade_side, ) - enter_limit_requested = self.get_valid_price(custom_entry_price, proposed_enter_rate) + enter_limit_requested = self.get_valid_price(custom_entry_price, enter_limit_requested) if not enter_limit_requested: raise PricingError('Could not determine entry price.') @@ -1212,7 +1217,8 @@ class FreqtradeBot(LoggingMixin): stake_amount=(order_obj.remaining * order_obj.price), price=adjusted_entry_price, trade=trade, - is_short=trade.is_short + is_short=trade.is_short, + order_adjust=True, ) def cancel_all_open_orders(self) -> None: From a947a1316b005c29b8a5ae58665f6f52ee884bb1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 17:42:01 +0200 Subject: [PATCH 098/449] Add test to ensure stoploss is set properly in live --- tests/test_integration.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index 020f77fed..d2ad8c981 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -372,11 +372,15 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None: freqtrade.enter_positions() assert len(Trade.get_trades().all()) == 1 - trade = Trade.get_trades().first() + trade: Trade = Trade.get_trades().first() assert len(trade.orders) == 1 assert trade.open_order_id is not None assert pytest.approx(trade.stake_amount) == 60 assert trade.open_rate == 1.96 + assert trade.stop_loss_pct is None + assert trade.stop_loss == 0.0 + assert trade.initial_stop_loss == 0.0 + assert trade.initial_stop_loss_pct is None # No adjustment freqtrade.process() trade = Trade.get_trades().first() @@ -392,6 +396,10 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None: assert trade.open_order_id is not None # Open rate is not adjusted yet assert trade.open_rate == 1.96 + assert trade.stop_loss_pct is None + assert trade.stop_loss == 0.0 + assert trade.initial_stop_loss == 0.0 + assert trade.initial_stop_loss_pct is None # Fill order mocker.patch('freqtrade.exchange.Exchange._is_dry_limit_order_filled', return_value=True) @@ -401,6 +409,10 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None: assert trade.open_order_id is None # Open rate is not adjusted yet assert trade.open_rate == 1.99 + assert trade.stop_loss_pct == -0.1 + assert trade.stop_loss == 1.99 * 0.9 + assert trade.initial_stop_loss == 1.99 * 0.9 + assert trade.initial_stop_loss_pct == -0.1 # 2nd order - not filling freqtrade.strategy.adjust_trade_position = MagicMock(return_value=120) From 116b58e97cad2b86aff5e20d97f494b5ef9abd41 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 19:30:42 +0200 Subject: [PATCH 099/449] add "date_minus_candles" method --- freqtrade/exchange/exchange.py | 24 +++++++++++++++++++++--- tests/exchange/test_exchange.py | 17 ++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 86f80871b..560da8eb2 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -2687,9 +2687,10 @@ def timeframe_to_msecs(timeframe: str) -> int: def timeframe_to_prev_date(timeframe: str, date: datetime = None) -> datetime: """ - Use Timeframe and determine last possible candle. + Use Timeframe and determine the candle start date for this date. + Does not round when given a candle start date. :param timeframe: timeframe in string format (e.g. "5m") - :param date: date to use. Defaults to utcnow() + :param date: date to use. Defaults to now(utc) :returns: date of previous candle (with utc timezone) """ if not date: @@ -2704,7 +2705,7 @@ def timeframe_to_next_date(timeframe: str, date: datetime = None) -> datetime: """ Use Timeframe and determine next candle. :param timeframe: timeframe in string format (e.g. "5m") - :param date: date to use. Defaults to utcnow() + :param date: date to use. Defaults to now(utc) :returns: date of next candle (with utc timezone) """ if not date: @@ -2714,6 +2715,23 @@ def timeframe_to_next_date(timeframe: str, date: datetime = None) -> datetime: return datetime.fromtimestamp(new_timestamp, tz=timezone.utc) +def date_minus_candles( + timeframe: str, candle_count: int, date: Optional[datetime] = None) -> datetime: + """ + subtract X candles from a date. + :param timeframe: timeframe in string format (e.g. "5m") + :param candle_count: Amount of candles to subtract. + :param date: date to use. Defaults to now(utc) + + """ + if not date: + date = datetime.now(timezone.utc) + + tf_min = timeframe_to_minutes(timeframe) + new_date = timeframe_to_prev_date(timeframe, date) - timedelta(minutes=tf_min * candle_count) + return new_date + + def market_is_active(market: Dict) -> bool: """ Return True if the market is active. diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 9d7b77a8e..9dd4e6342 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -17,9 +17,9 @@ from freqtrade.exceptions import (DDosProtection, DependencyException, InvalidOr from freqtrade.exchange import Binance, Bittrex, Exchange, Kraken from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, API_RETRY_COUNT, calculate_backoff, remove_credentials) -from freqtrade.exchange.exchange import (market_is_active, timeframe_to_minutes, timeframe_to_msecs, - timeframe_to_next_date, timeframe_to_prev_date, - timeframe_to_seconds) +from freqtrade.exchange.exchange import (date_minus_candles, market_is_active, timeframe_to_minutes, + timeframe_to_msecs, timeframe_to_next_date, + timeframe_to_prev_date, timeframe_to_seconds) from freqtrade.resolvers.exchange_resolver import ExchangeResolver from tests.conftest import get_mock_coro, get_patched_exchange, log_has, log_has_re, num_log_has_re @@ -3431,6 +3431,17 @@ def test_timeframe_to_next_date(): assert timeframe_to_next_date("5m", date) == date + timedelta(minutes=5) +def test_date_minus_candles(): + + date = datetime(2019, 8, 12, 13, 25, 0, tzinfo=timezone.utc) + + assert date_minus_candles("5m", 3, date) == date - timedelta(minutes=15) + assert date_minus_candles("5m", 5, date) == date - timedelta(minutes=25) + assert date_minus_candles("1m", 6, date) == date - timedelta(minutes=6) + assert date_minus_candles("1h", 3, date) == date - timedelta(hours=3, minutes=25) + assert date_minus_candles("1h", 3) == timeframe_to_prev_date('1h') - timedelta(hours=3) + + @pytest.mark.parametrize( "market_symbol,base,quote,exchange,spot,margin,futures,trademode,add_dict,expected_result", [ From d60d0f64d209d1013e2d32938f72bc8a94598af8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 May 2022 19:32:28 +0200 Subject: [PATCH 100/449] Revert ohlcv_candle_limit logic for okx --- freqtrade/exchange/exchange.py | 5 ++++- freqtrade/exchange/okx.py | 18 ++++++++---------- tests/exchange/test_okx.py | 3 +++ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 560da8eb2..57a7f2086 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -619,7 +619,10 @@ class Exchange: Checks if required startup_candles is more than ohlcv_candle_limit(). Requires a grace-period of 5 candles - so a startup-period up to 494 is allowed by default. """ - candle_limit = self.ohlcv_candle_limit(timeframe, self._config['candle_type_def'], None) + + candle_limit = self.ohlcv_candle_limit( + timeframe, self._config['candle_type_def'], + date_minus_candles(timeframe, startup_candles)) # Require one more candle - to account for the still open candle. candle_count = startup_candles + 1 # Allow 5 calls to the exchange per pair diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index c8324e62e..ad41984e7 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -10,7 +10,7 @@ from freqtrade.enums.candletype import CandleType from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange from freqtrade.exchange.common import retrier -from freqtrade.exchange.exchange import timeframe_to_minutes +from freqtrade.exchange.exchange import date_minus_candles logger = logging.getLogger(__name__) @@ -23,7 +23,7 @@ class Okx(Exchange): """ _ft_has: Dict = { - "ohlcv_candle_limit": 300, # Warning, special case with data prior to X months + "ohlcv_candle_limit": 100, # Warning, special case with data prior to X months "mark_ohlcv_timeframe": "4h", "funding_fee_timeframe": "8h", } @@ -53,15 +53,13 @@ class Okx(Exchange): :param since_ms: Candle-type :return: Candle limit as integer """ - now = datetime.now(timezone.utc) - offset_mins = timeframe_to_minutes(timeframe) * self._ft_has['ohlcv_candle_limit'] - if since_ms and since_ms < ((now - timedelta(minutes=offset_mins)).timestamp() * 1000): - return 100 - if candle_type not in (CandleType.FUTURES, CandleType.SPOT): - return 100 + if ( + candle_type in (CandleType.FUTURES, CandleType.SPOT) and + (not since_ms or since_ms > (date_minus_candles(timeframe, 300).timestamp() * 1000)) + ): + return 300 - return int(self._ft_has.get('ohlcv_candle_limit_per_timeframe', {}).get( - timeframe, self._ft_has.get('ohlcv_candle_limit'))) + return super().ohlcv_candle_limit(timeframe, candle_type, since_ms) @retrier def additional_exchange_init(self) -> None: diff --git a/tests/exchange/test_okx.py b/tests/exchange/test_okx.py index 2804d471a..19c09ad9e 100644 --- a/tests/exchange/test_okx.py +++ b/tests/exchange/test_okx.py @@ -20,14 +20,17 @@ def test_okx_ohlcv_candle_limit(default_conf, mocker): assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES) == 300 assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK) == 100 assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE) == 100 + assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == 100 assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == 100 assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 100 assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 100 one_call = int((datetime.now(timezone.utc) - timedelta( minutes=290 * timeframe_to_minutes(timeframe))).timestamp() * 1000) + assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 300 assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, one_call) == 300 + one_call = int((datetime.now(timezone.utc) - timedelta( minutes=320 * timeframe_to_minutes(timeframe))).timestamp() * 1000) assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 100 From 9143e9ecb15c9756b6e0f4a7f437a15cddc12385 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 May 2022 15:12:29 +0200 Subject: [PATCH 101/449] Add some safety measures for new startup_candles verification --- freqtrade/exchange/exchange.py | 3 ++- freqtrade/exchange/okx.py | 1 - tests/exchange/test_exchange.py | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 57a7f2086..a07ea3596 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -622,7 +622,8 @@ class Exchange: candle_limit = self.ohlcv_candle_limit( timeframe, self._config['candle_type_def'], - date_minus_candles(timeframe, startup_candles)) + int(date_minus_candles(timeframe, startup_candles).timestamp() * 1000) + if timeframe else None) # Require one more candle - to account for the still open candle. candle_count = startup_candles + 1 # Allow 5 calls to the exchange per pair diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index ad41984e7..c0431c7fc 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -1,5 +1,4 @@ import logging -from datetime import datetime, timedelta, timezone from typing import Dict, List, Optional, Tuple import ccxt diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 9dd4e6342..e580c82d3 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -939,6 +939,7 @@ def test_validate_timeframes_emulated_ohlcvi_2(default_conf, mocker): def test_validate_timeframes_not_in_config(default_conf, mocker): + # TODO: this test does not assert ... del default_conf["timeframe"] api_mock = MagicMock() id_mock = PropertyMock(return_value='test_exchange') @@ -954,6 +955,7 @@ def test_validate_timeframes_not_in_config(default_conf, mocker): mocker.patch('freqtrade.exchange.Exchange.validate_pairs') mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency') mocker.patch('freqtrade.exchange.Exchange.validate_pricing') + mocker.patch('freqtrade.exchange.Exchange.validate_required_startup_candles') Exchange(default_conf) From 18fd3bb3332f2d50401fa6b428d073615b02db7e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 May 2022 15:30:57 +0200 Subject: [PATCH 102/449] Update stoploss handling for entry-order adjustment --- freqtrade/optimize/backtesting.py | 6 +----- freqtrade/persistence/trade_model.py | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index f439e4e63..621812b0a 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -780,8 +780,6 @@ class Backtesting: # interest_rate=interest_rate, orders=[], ) - elif trade.nr_of_successful_entries == 0: - trade.open_rate = propose_rate trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss, initial=True) @@ -814,11 +812,11 @@ class Backtesting: remaining=amount, cost=stake_amount + trade.fee_open, ) + trade.orders.append(order) if pos_adjust and self._get_order_filled(order.price, row): order.close_bt_order(current_time, trade) else: trade.open_order_id = str(self.order_id_counter) - trade.orders.append(order) trade.recalc_trade_from_orders() return trade @@ -942,8 +940,6 @@ class Backtesting: requested_rate=requested_rate, requested_stake=(order.remaining * order.price), direction='short' if trade.is_short else 'long') - trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss, - initial=False, refresh=True) else: # assumption: there can't be multiple open entry orders at any given time return (trade.nr_of_successful_entries == 0) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index bbdeeef47..358e776e3 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -153,6 +153,7 @@ class Order(_DECL_BASE): and len(trade.select_filled_orders(trade.entry_side)) == 1): trade.open_rate = self.price trade.recalc_open_trade_value() + trade.adjust_stop_loss(trade.open_rate, trade.stop_loss_pct, refresh=True) @staticmethod def update_orders(orders: List['Order'], order: Dict[str, Any]): @@ -502,7 +503,7 @@ class LocalTrade(): if initial and not (self.stop_loss is None or self.stop_loss == 0): # Don't modify if called with initial and nothing to do return - refresh = False if self.nr_of_successful_entries > 0 else refresh + refresh = True if refresh and self.nr_of_successful_entries == 1 else False leverage = self.leverage or 1.0 if self.is_short: From 706994340f36e5336e35afe4a580015992e131b6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 May 2022 17:06:40 +0200 Subject: [PATCH 103/449] Fix bad docstring --- freqtrade/exchange/exchange.py | 2 +- freqtrade/exchange/okx.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index a07ea3596..ee804aa68 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -317,7 +317,7 @@ class Exchange: per timeframe (e.g. bittrex), otherwise falls back to ohlcv_candle_limit :param timeframe: Timeframe to check :param candle_type: Candle-type - :param since_ms: Candle-type + :param since_ms: Starting timestamp :return: Candle limit as integer """ return int(self._ft_has.get('ohlcv_candle_limit_per_timeframe', {}).get( diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index c0431c7fc..012f51080 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -49,7 +49,7 @@ class Okx(Exchange): * 100 candles for additional candles (not futures or spot). :param timeframe: Timeframe to check :param candle_type: Candle-type - :param since_ms: Candle-type + :param since_ms: Starting timestamp :return: Candle limit as integer """ if ( From a8f064a8cb4b84914820c98bc895ff6c7a0dda71 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 May 2022 17:33:00 +0200 Subject: [PATCH 104/449] Fix exit_reason assignment in live mode --- freqtrade/freqtradebot.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 07b055309..315db3ae6 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1414,6 +1414,7 @@ class FreqtradeBot(LoggingMixin): open_date=trade.open_date_utc, ) exit_type = 'exit' + exit_reason = exit_tag or exit_check.exit_reason if exit_check.exit_type in (ExitType.STOP_LOSS, ExitType.TRAILING_STOP_LOSS): exit_type = 'stoploss' @@ -1431,7 +1432,7 @@ class FreqtradeBot(LoggingMixin): pair=trade.pair, trade=trade, current_time=datetime.now(timezone.utc), proposed_rate=proposed_limit_rate, current_profit=current_profit, - exit_tag=exit_check.exit_reason) + exit_tag=exit_reason) limit = self.get_valid_price(custom_exit_price, proposed_limit_rate) @@ -1448,8 +1449,8 @@ class FreqtradeBot(LoggingMixin): if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)( pair=trade.pair, trade=trade, order_type=order_type, amount=amount, rate=limit, - time_in_force=time_in_force, exit_reason=exit_check.exit_reason, - sell_reason=exit_check.exit_reason, # sellreason -> compatibility + time_in_force=time_in_force, exit_reason=exit_reason, + sell_reason=exit_reason, # sellreason -> compatibility current_time=datetime.now(timezone.utc)): logger.info(f"User requested abortion of exiting {trade.pair}") return False @@ -1478,7 +1479,7 @@ class FreqtradeBot(LoggingMixin): trade.open_order_id = order['id'] trade.exit_order_status = '' trade.close_rate_requested = limit - trade.exit_reason = exit_tag or exit_check.exit_reason + trade.exit_reason = exit_reason # Lock pair for one candle to prevent immediate re-trading self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc), From a0b25938f472d4941b7f08986a88c0c69b356e7e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 May 2022 17:41:50 +0200 Subject: [PATCH 105/449] Fix exit_reason assignment in backtesting --- freqtrade/optimize/backtesting.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 621812b0a..64107ae18 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -535,6 +535,7 @@ class Backtesting: if exit_.exit_flag: trade.close_date = exit_candle_time + exit_reason = exit_.exit_reason trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60) try: @@ -545,6 +546,15 @@ class Backtesting: current_profit = trade.calc_profit_ratio(closerate) order_type = self.strategy.order_types['exit'] if exit_.exit_type in (ExitType.EXIT_SIGNAL, ExitType.CUSTOM_EXIT): + # Checks and adds an exit tag, after checking that the length of the + # row has the length for an exit tag column + if( + len(row) > EXIT_TAG_IDX + and row[EXIT_TAG_IDX] is not None + and len(row[EXIT_TAG_IDX]) > 0 + and exit_.exit_type in (ExitType.EXIT_SIGNAL,) + ): + exit_reason = row[EXIT_TAG_IDX] # Custom exit pricing only for exit-signals if order_type == 'limit': closerate = strategy_safe_wrapper(self.strategy.custom_exit_price, @@ -552,7 +562,7 @@ class Backtesting: pair=trade.pair, trade=trade, current_time=exit_candle_time, proposed_rate=closerate, current_profit=current_profit, - exit_tag=exit_.exit_reason) + exit_tag=exit_reason) # We can't place orders lower than current low. # freqtrade does not support this in live, and the order would fill immediately if trade.is_short: @@ -566,22 +576,12 @@ class Backtesting: pair=trade.pair, trade=trade, order_type='limit', amount=trade.amount, rate=closerate, time_in_force=time_in_force, - sell_reason=exit_.exit_reason, # deprecated - exit_reason=exit_.exit_reason, + sell_reason=exit_reason, # deprecated + exit_reason=exit_reason, current_time=exit_candle_time): return None - trade.exit_reason = exit_.exit_reason - - # Checks and adds an exit tag, after checking that the length of the - # row has the length for an exit tag column - if( - len(row) > EXIT_TAG_IDX - and row[EXIT_TAG_IDX] is not None - and len(row[EXIT_TAG_IDX]) > 0 - and exit_.exit_type in (ExitType.EXIT_SIGNAL,) - ): - trade.exit_reason = row[EXIT_TAG_IDX] + trade.exit_reason = exit_reason self.order_id_counter += 1 order = Order( From 86af3fe0e7766a3dd86701d8142aeb327bafd7d2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 May 2022 19:22:12 +0200 Subject: [PATCH 106/449] Update image versions from 3.9 to 3.10 --- .github/workflows/ci.yml | 6 +++--- Dockerfile | 2 +- docker/Dockerfile.armhf | 2 +- setup.cfg | 2 +- setup.sh | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96575f034..09946e6b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -273,7 +273,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.9 + python-version: 3.10 - name: pre-commit dependencies run: | @@ -292,7 +292,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.9 + python-version: 3.10 - name: Documentation build run: | @@ -358,7 +358,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.8 + python-version: 3.9 - name: Extract branch name shell: bash diff --git a/Dockerfile b/Dockerfile index 8f5b85698..5f7b52265 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9.9-slim-bullseye as base +FROM python:3.10.4-slim-bullseye as base # Setup env ENV LANG C.UTF-8 diff --git a/docker/Dockerfile.armhf b/docker/Dockerfile.armhf index 16f2aebcd..73fc681eb 100644 --- a/docker/Dockerfile.armhf +++ b/docker/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM python:3.9.9-slim-bullseye as base +FROM python:3.9.12-slim-bullseye as base # Setup env ENV LANG C.UTF-8 diff --git a/setup.cfg b/setup.cfg index edbd320c3..042517ec9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,7 +32,7 @@ tests_require = pytest-mock packages = find: -python_requires = >=3.6 +python_requires = >=3.8 [options.entry_points] console_scripts = diff --git a/setup.sh b/setup.sh index dcf6c02c7..bb51c3a2f 100755 --- a/setup.sh +++ b/setup.sh @@ -25,7 +25,7 @@ function check_installed_python() { exit 2 fi - for v in 9 10 8 + for v in 10 9 8 do PYTHON="python3.${v}" which $PYTHON From 008ee148890b3c396c311483340bfb698ebd925a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 15 May 2022 19:25:27 +0200 Subject: [PATCH 107/449] Improve ci to run on ubuntu 22.04 --- .github/workflows/ci.yml | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09946e6b5..d11285ba4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ ubuntu-18.04, ubuntu-20.04 ] + os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-22.04 ] python-version: ["3.8", "3.9", "3.10"] steps: @@ -70,7 +70,7 @@ jobs: if: matrix.python-version == '3.9' - name: Coveralls - if: (runner.os == 'Linux' && matrix.python-version == '3.8') + if: (runner.os == 'Linux' && matrix.python-version == '3.9') env: # Coveralls token. Not used as secret due to github not providing secrets to forked repositories COVERALLS_REPO_TOKEN: 6D1m0xupS3FgutfuGao8keFf9Hc0FpIXu @@ -157,24 +157,9 @@ jobs: pip install -e . - name: Tests - if: (runner.os != 'Linux' || matrix.python-version != '3.8') run: | pytest --random-order - - name: Tests (with cov) - if: (runner.os == 'Linux' && matrix.python-version == '3.8') - run: | - pytest --random-order --cov=freqtrade --cov-config=.coveragerc - - - name: Coveralls - if: (runner.os == 'Linux' && matrix.python-version == '3.8') - env: - # Coveralls token. Not used as secret due to github not providing secrets to forked repositories - COVERALLS_REPO_TOKEN: 6D1m0xupS3FgutfuGao8keFf9Hc0FpIXu - run: | - # Allow failure for coveralls - coveralls -v || true - - name: Backtesting run: | cp config_examples/config_bittrex.example.json config.json @@ -273,7 +258,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.10 + python-version: "3.10" - name: pre-commit dependencies run: | @@ -292,7 +277,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.10 + python-version: "3.10" - name: Documentation build run: | @@ -358,7 +343,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: 3.9 + python-version: "3.9" - name: Extract branch name shell: bash From e21f6a7787091e2c3831f872bf26aaed3df0184c Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Mon, 16 May 2022 07:28:40 +0900 Subject: [PATCH 108/449] missing newline --- freqtrade/rpc/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 1a9be4503..259d2c831 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -1417,7 +1417,7 @@ class Telegram(RPCHandler): "*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" "*/forceexit |all:* `Instantly exits the given trade or all trades, " "regardless of profit`\n" - "*/fe |all:* `Alias to /forceexit`" + "*/fe |all:* `Alias to /forceexit`\n" f"{force_enter_text if self._config.get('force_entry_enable', False) else ''}" "*/delete :* `Instantly delete the given trade in the database`\n" "*/whitelist:* `Show current whitelist` \n" From 2cb8eecf18eed273df41ee2702e54def89831b03 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Mon, 16 May 2022 07:43:36 +0900 Subject: [PATCH 109/449] add space --- freqtrade/rpc/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 259d2c831..f26de8b5c 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -1410,7 +1410,7 @@ class Telegram(RPCHandler): "Optionally takes a rate at which to sell " "(only applies to limit orders).` \n") message = ( - "_BotControl_\n" + "_Bot Control_\n" "------------\n" "*/start:* `Starts the trader`\n" "*/stop:* Stops the trader\n" From 4fc6857d8778cb423ab228750a8edb23c2cfe0c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 03:01:25 +0000 Subject: [PATCH 110/449] Bump time-machine from 2.6.0 to 2.7.0 Bumps [time-machine](https://github.com/adamchainz/time-machine) from 2.6.0 to 2.7.0. - [Release notes](https://github.com/adamchainz/time-machine/releases) - [Changelog](https://github.com/adamchainz/time-machine/blob/main/HISTORY.rst) - [Commits](https://github.com/adamchainz/time-machine/compare/2.6.0...2.7.0) --- updated-dependencies: - dependency-name: time-machine dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 60f4da1a7..58eaef3e2 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -16,7 +16,7 @@ pytest-mock==3.7.0 pytest-random-order==1.0.4 isort==5.10.1 # For datetime mocking -time-machine==2.6.0 +time-machine==2.7.0 # Convert jupyter notebooks to markdown documents nbconvert==6.5.0 From 47c116a423cabe9a0444c29be9edef465af86ecb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 03:01:28 +0000 Subject: [PATCH 111/449] Bump fastapi from 0.76.0 to 0.78.0 Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.76.0 to 0.78.0. - [Release notes](https://github.com/tiangolo/fastapi/releases) - [Commits](https://github.com/tiangolo/fastapi/compare/0.76.0...0.78.0) --- updated-dependencies: - dependency-name: fastapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index bed3a7fed..14edbe16c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,7 +34,7 @@ orjson==3.6.8 sdnotify==0.3.2 # API Server -fastapi==0.76.0 +fastapi==0.78.0 uvicorn==0.17.6 pyjwt==2.3.0 aiofiles==0.8.0 From 748055892cbc0f32a6610960ec0e58521e6b45fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 03:01:33 +0000 Subject: [PATCH 112/449] Bump plotly from 5.7.0 to 5.8.0 Bumps [plotly](https://github.com/plotly/plotly.py) from 5.7.0 to 5.8.0. - [Release notes](https://github.com/plotly/plotly.py/releases) - [Changelog](https://github.com/plotly/plotly.py/blob/master/CHANGELOG.md) - [Commits](https://github.com/plotly/plotly.py/compare/v5.7.0...v5.8.0) --- updated-dependencies: - dependency-name: plotly dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-plot.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-plot.txt b/requirements-plot.txt index d9faed301..e17efbc71 100644 --- a/requirements-plot.txt +++ b/requirements-plot.txt @@ -1,4 +1,4 @@ # Include all requirements to run the bot. -r requirements.txt -plotly==5.7.0 +plotly==5.8.0 From 9fc21686ede5c7f28f978a9198535307a2a92b14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 03:01:40 +0000 Subject: [PATCH 113/449] Bump flake8-tidy-imports from 4.7.0 to 4.8.0 Bumps [flake8-tidy-imports](https://github.com/adamchainz/flake8-tidy-imports) from 4.7.0 to 4.8.0. - [Release notes](https://github.com/adamchainz/flake8-tidy-imports/releases) - [Changelog](https://github.com/adamchainz/flake8-tidy-imports/blob/main/HISTORY.rst) - [Commits](https://github.com/adamchainz/flake8-tidy-imports/compare/4.7.0...4.8.0) --- updated-dependencies: - dependency-name: flake8-tidy-imports dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 60f4da1a7..17a505912 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,7 +6,7 @@ coveralls==3.3.1 flake8==4.0.1 -flake8-tidy-imports==4.7.0 +flake8-tidy-imports==4.8.0 mypy==0.950 pre-commit==2.19.0 pytest==7.1.2 From 9e44d697746369fa6467e053698a698365069cfb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 03:01:53 +0000 Subject: [PATCH 114/449] Bump ccxt from 1.81.81 to 1.82.61 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.81.81 to 1.82.61. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.81.81...1.82.61) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index bed3a7fed..cdd72403d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.3 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.81.81 +ccxt==1.82.61 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From a8b4066f85fdb08c254e06be91a3818e62dc1855 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 03:01:57 +0000 Subject: [PATCH 115/449] Bump mkdocs-material from 8.2.14 to 8.2.15 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.2.14 to 8.2.15. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/8.2.14...8.2.15) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index b26e448ea..3fa35d80d 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 -mkdocs-material==8.2.14 +mkdocs-material==8.2.15 mdx_truly_sane_lists==1.2 pymdown-extensions==9.4 jinja2==3.1.2 From dd1b84f938db950821d4d40e14be83e1b0faff5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 03:02:00 +0000 Subject: [PATCH 116/449] Bump filelock from 3.6.0 to 3.7.0 Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.6.0 to 3.7.0. - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.6.0...3.7.0) --- updated-dependencies: - dependency-name: filelock dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 32fc3f4b9..17a7c7b8c 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -5,5 +5,5 @@ scipy==1.8.0 scikit-learn==1.0.2 scikit-optimize==0.9.0 -filelock==3.6.0 +filelock==3.7.0 progressbar2==4.0.0 From bd65236e17f53ed19abf6a687ff0cd8d856d838f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 04:37:25 +0000 Subject: [PATCH 117/449] Bump pyjwt from 2.3.0 to 2.4.0 Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.3.0 to 2.4.0. - [Release notes](https://github.com/jpadilla/pyjwt/releases) - [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst) - [Commits](https://github.com/jpadilla/pyjwt/compare/2.3.0...2.4.0) --- updated-dependencies: - dependency-name: pyjwt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 95826b71c..90ddcd1b6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,7 +36,7 @@ sdnotify==0.3.2 # API Server fastapi==0.78.0 uvicorn==0.17.6 -pyjwt==2.3.0 +pyjwt==2.4.0 aiofiles==0.8.0 psutil==5.9.0 From f5183df0f1c6e41fb3b8d39fca18b8f829bf73d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 May 2022 04:37:41 +0000 Subject: [PATCH 118/449] Bump scikit-learn from 1.0.2 to 1.1.0 Bumps [scikit-learn](https://github.com/scikit-learn/scikit-learn) from 1.0.2 to 1.1.0. - [Release notes](https://github.com/scikit-learn/scikit-learn/releases) - [Commits](https://github.com/scikit-learn/scikit-learn/compare/1.0.2...1.1.0) --- updated-dependencies: - dependency-name: scikit-learn dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 17a7c7b8c..0b91636f1 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -3,7 +3,7 @@ # Required for hyperopt scipy==1.8.0 -scikit-learn==1.0.2 +scikit-learn==1.1.0 scikit-optimize==0.9.0 filelock==3.7.0 progressbar2==4.0.0 From 528509f809b2474218e24ac5442d889b4ca1fce9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 16 May 2022 19:18:13 +0200 Subject: [PATCH 119/449] Extract get_price_side from get_rate --- freqtrade/exchange/exchange.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index ee804aa68..156216557 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1457,6 +1457,23 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e + def _get_price_side(self, side: str, is_short: bool, conf_strategy: Dict) -> str: + price_side = conf_strategy['price_side'] + + if price_side in ('same', 'other'): + price_map = { + ('entry', 'long', 'same'): 'bid', + ('entry', 'long', 'other'): 'ask', + ('entry', 'short', 'same'): 'ask', + ('entry', 'short', 'other'): 'bid', + ('exit', 'long', 'same'): 'ask', + ('exit', 'long', 'other'): 'bid', + ('exit', 'short', 'same'): 'bid', + ('exit', 'short', 'other'): 'ask', + } + price_side = price_map[(side, 'short' if is_short else 'long', price_side)] + return price_side + def get_rate(self, pair: str, refresh: bool, side: EntryExit, is_short: bool) -> float: """ @@ -1483,20 +1500,7 @@ class Exchange: conf_strategy = self._config.get(strat_name, {}) - price_side = conf_strategy['price_side'] - - if price_side in ('same', 'other'): - price_map = { - ('entry', 'long', 'same'): 'bid', - ('entry', 'long', 'other'): 'ask', - ('entry', 'short', 'same'): 'ask', - ('entry', 'short', 'other'): 'bid', - ('exit', 'long', 'same'): 'ask', - ('exit', 'long', 'other'): 'bid', - ('exit', 'short', 'same'): 'bid', - ('exit', 'short', 'other'): 'ask', - } - price_side = price_map[(side, 'short' if is_short else 'long', price_side)] + price_side = self._get_price_side(side, is_short, conf_strategy) price_side_word = price_side.capitalize() From a793cf8f05975767432d6b12bd31307e21923eb6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 30 Mar 2022 07:10:46 +0200 Subject: [PATCH 120/449] Use ccxt's "precise" to do precise math --- freqtrade/exchange/exchange.py | 10 ++++++---- tests/exchange/test_exchange.py | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 156216557..d17c84f5c 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -16,6 +16,7 @@ import arrow import ccxt import ccxt.async_support as ccxt_async from cachetools import TTLCache +from ccxt import Precise from ccxt.base.decimal_to_precision import (ROUND_DOWN, ROUND_UP, TICK_SIZE, TRUNCATE, decimal_to_precision) from pandas import DataFrame @@ -704,10 +705,11 @@ class Exchange: # counting_mode=self.precisionMode, # )) if self.precisionMode == TICK_SIZE: - precision = self.markets[pair]['precision']['price'] - missing = price % precision - if missing != 0: - price = round(price - missing + precision, 10) + precision = Precise(str(self.markets[pair]['precision']['price'])) + price_str = Precise(str(price)) + missing = price_str.mod(precision) + if not missing.equals(Precise("0")): + price = round(float(str(price_str.sub(missing).add(precision))), 14) else: symbol_prec = self.markets[pair]['precision']['price'] big_price = price * pow(10, symbol_prec) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index e580c82d3..53e6cc3f3 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -305,6 +305,7 @@ def test_amount_to_precision( (234.53, 4, 0.5, 235.0), (0.891534, 4, 0.0001, 0.8916), (64968.89, 4, 0.01, 64968.89), + (0.000000003483, 4, 1e-12, 0.000000003483), ]) def test_price_to_precision(default_conf, mocker, price, precision_mode, precision, expected): From c8e0fc926d756f9cd5b5eff539653b2f9e332c06 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 3 Apr 2022 12:00:41 +0200 Subject: [PATCH 121/449] Update to do Builtin Precise math --- freqtrade/exchange/exchange.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d17c84f5c..8bbbf6d4d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -707,9 +707,9 @@ class Exchange: if self.precisionMode == TICK_SIZE: precision = Precise(str(self.markets[pair]['precision']['price'])) price_str = Precise(str(price)) - missing = price_str.mod(precision) - if not missing.equals(Precise("0")): - price = round(float(str(price_str.sub(missing).add(precision))), 14) + missing = price_str % precision + if not missing == Precise("0"): + price = round(float(str(price_str - missing + precision)), 14) else: symbol_prec = self.markets[pair]['precision']['price'] big_price = price * pow(10, symbol_prec) From d09b462930adf105d3f6a074d1f2b9f3d58e3ab4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 6 Apr 2022 19:46:55 +0200 Subject: [PATCH 122/449] Add rudimentary tests for Precise "builtin operator" workings --- tests/exchange/test_ccxt_precise.py | 75 +++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 tests/exchange/test_ccxt_precise.py diff --git a/tests/exchange/test_ccxt_precise.py b/tests/exchange/test_ccxt_precise.py new file mode 100644 index 000000000..026adb4c1 --- /dev/null +++ b/tests/exchange/test_ccxt_precise.py @@ -0,0 +1,75 @@ +from ccxt import Precise + + +ws = Precise('-1.123e-6') +ws = Precise('-1.123e-6') +xs = Precise('0.00000002') +ys = Precise('69696900000') +zs = Precise('0') + + +def test_precise(): + assert ys * xs == '1393.938' + assert xs * ys == '1393.938' + + assert ys + xs == '69696900000.00000002' + assert xs + ys == '69696900000.00000002' + assert xs - ys == '-69696899999.99999998' + assert ys - xs == '69696899999.99999998' + assert xs / ys == '0' + assert ys / xs == '3484845000000000000' + + assert ws * xs == '-0.00000000000002246' + assert xs * ws == '-0.00000000000002246' + + assert ws + xs == '-0.000001103' + assert xs + ws == '-0.000001103' + + assert xs - ws == '0.000001143' + assert ws - xs == '-0.000001143' + + assert xs / ws == '-0.017809439002671415' + assert ws / xs == '-56.15' + + assert zs * ws == '0' + assert zs * xs == '0' + assert zs * ys == '0' + assert ws * zs == '0' + assert xs * zs == '0' + assert ys * zs == '0' + + assert zs + ws == '-0.000001123' + assert zs + xs == '0.00000002' + assert zs + ys == '69696900000' + assert ws + zs == '-0.000001123' + assert xs + zs == '0.00000002' + assert ys + zs == '69696900000' + + assert abs(Precise('-500.1')) == '500.1' + assert abs(Precise('213')) == '213' + + assert abs(Precise('-500.1')) == '500.1' + assert -Precise('213') == '-213' + + assert Precise('10.1') % Precise('0.5') == '0.1' + assert Precise('5550') % Precise('120') == '30' + + assert Precise('-0.0') == Precise('0') + assert Precise('5.534000') == Precise('5.5340') + + assert min(Precise('-3.1415'), Precise('-2')) == '-3.1415' + + assert max(Precise('3.1415'), Precise('-2')) == '3.1415' + + assert Precise('2') > Precise('1.2345') + assert not Precise('-3.1415') > Precise('-2') + assert not Precise('3.1415') > Precise('3.1415') + assert Precise.string_gt('3.14150000000000000000001', '3.1415') + + assert Precise('3.1415') >= Precise('3.1415') + assert Precise('3.14150000000000000000001') >= Precise('3.1415') + + assert not Precise('3.1415') < Precise('3.1415') + + assert Precise('3.1415') <= Precise('3.1415') + assert Precise('3.1415') <= Precise('3.14150000000000000000001') From 9607d0427903a05334576f7ce33e3d4e92282a51 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 25 Apr 2022 09:55:35 +0200 Subject: [PATCH 123/449] Improve ccxt imports --- freqtrade/exchange/exchange.py | 4 +--- setup.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 8bbbf6d4d..d2766cd6d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -16,9 +16,7 @@ import arrow import ccxt import ccxt.async_support as ccxt_async from cachetools import TTLCache -from ccxt import Precise -from ccxt.base.decimal_to_precision import (ROUND_DOWN, ROUND_UP, TICK_SIZE, TRUNCATE, - decimal_to_precision) +from ccxt import ROUND_DOWN, ROUND_UP, TICK_SIZE, TRUNCATE, Precise, decimal_to_precision from pandas import DataFrame from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, BuySell, diff --git a/setup.py b/setup.py index c5e418d0d..fadd4629f 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ setup( ], install_requires=[ # from requirements.txt - 'ccxt>=1.79.69', + 'ccxt>=1.80.67', 'SQLAlchemy', 'python-telegram-bot>=13.4', 'arrow>=0.17.0', From a1048fb619e186d83ff83ad25ba0e02e818d6fd1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 1 May 2022 17:00:00 +0200 Subject: [PATCH 124/449] Store monthly candles as "Mo" --- freqtrade/data/history/hdf5datahandler.py | 2 +- freqtrade/data/history/idatahandler.py | 16 ++++++++++++++-- freqtrade/data/history/jsondatahandler.py | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index 23120a4ba..165685960 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -40,7 +40,7 @@ class HDF5DataHandler(IDataHandler): return [ ( cls.rebuild_pair_from_filename(match[1]), - match[2], + cls.rebuild_timeframe_from_filename(match[2]), CandleType.from_string(match[3]) ) for match in _tmp if match and len(match.groups()) > 1] diff --git a/freqtrade/data/history/idatahandler.py b/freqtrade/data/history/idatahandler.py index 2e6b070ca..bd795f480 100644 --- a/freqtrade/data/history/idatahandler.py +++ b/freqtrade/data/history/idatahandler.py @@ -26,7 +26,7 @@ logger = logging.getLogger(__name__) class IDataHandler(ABC): - _OHLCV_REGEX = r'^([a-zA-Z_-]+)\-(\d+\S)\-?([a-zA-Z_]*)?(?=\.)' + _OHLCV_REGEX = r'^([a-zA-Z_-]+)\-(\d+[a-zA-Z]{1,2})\-?([a-zA-Z_]*)?(?=\.)' def __init__(self, datadir: Path) -> None: self._datadir = datadir @@ -201,7 +201,7 @@ class IDataHandler(ABC): datadir = datadir.joinpath('futures') candle = f"-{candle_type}" filename = datadir.joinpath( - f'{pair_s}-{timeframe}{candle}.{cls._get_file_extension()}') + f'{pair_s}-{cls.timeframe_to_file(timeframe)}{candle}.{cls._get_file_extension()}') return filename @classmethod @@ -210,6 +210,18 @@ class IDataHandler(ABC): filename = datadir.joinpath(f'{pair_s}-trades.{cls._get_file_extension()}') return filename + @staticmethod + def timeframe_to_file(timeframe: str): + return timeframe.replace('M', 'Mo') + + @staticmethod + def rebuild_timeframe_from_filename(timeframe: str) -> str: + """ + converts timeframe from disk to file + Replaces mo with M (to avoid problems on case-insensitive filesystems) + """ + return re.sub('mo', 'M', timeframe, flags=re.IGNORECASE) + @staticmethod def rebuild_pair_from_filename(pair: str) -> str: """ diff --git a/freqtrade/data/history/jsondatahandler.py b/freqtrade/data/history/jsondatahandler.py index 23054ac51..fa02c770b 100644 --- a/freqtrade/data/history/jsondatahandler.py +++ b/freqtrade/data/history/jsondatahandler.py @@ -41,7 +41,7 @@ class JsonDataHandler(IDataHandler): return [ ( cls.rebuild_pair_from_filename(match[1]), - match[2], + cls.rebuild_timeframe_from_filename(match[2]), CandleType.from_string(match[3]) ) for match in _tmp if match and len(match.groups()) > 1] From 2e65a1793d086ecbdf904d74a0dc3dc3b4ddeac1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 1 May 2022 19:51:25 +0200 Subject: [PATCH 125/449] Add fallback to load 1M files as well as 1Mo files --- freqtrade/data/history/hdf5datahandler.py | 11 +++++++--- freqtrade/data/history/idatahandler.py | 7 ++++--- freqtrade/data/history/jsondatahandler.py | 12 ++++++++--- tests/data/test_history.py | 25 ++++++++++++----------- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index 165685960..6099c22bc 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -77,7 +77,8 @@ class HDF5DataHandler(IDataHandler): key = self._pair_ohlcv_key(pair, timeframe) _data = data.copy() - filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) + filename = self._pair_data_filename( + self._datadir, pair, self.timeframe_to_file(timeframe), candle_type) self.create_dir_if_needed(filename) _data.loc[:, self._columns].to_hdf( @@ -104,12 +105,16 @@ class HDF5DataHandler(IDataHandler): filename = self._pair_data_filename( self._datadir, pair, - timeframe, + self.timeframe_to_file(timeframe), candle_type=candle_type ) if not filename.exists(): - return pd.DataFrame(columns=self._columns) + # Fallback mode for 1M files + filename = self._pair_data_filename( + self._datadir, pair, timeframe, candle_type=candle_type) + if not filename.exists(): + return pd.DataFrame(columns=self._columns) where = [] if timerange: if timerange.starttype == 'date': diff --git a/freqtrade/data/history/idatahandler.py b/freqtrade/data/history/idatahandler.py index bd795f480..69d6212ee 100644 --- a/freqtrade/data/history/idatahandler.py +++ b/freqtrade/data/history/idatahandler.py @@ -98,7 +98,8 @@ class IDataHandler(ABC): :param candle_type: Any of the enum CandleType (must match trading mode!) :return: True when deleted, false if file did not exist. """ - filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) + filename = self._pair_data_filename( + self._datadir, pair, self.timeframe_to_file(timeframe), candle_type) if filename.exists(): filename.unlink() return True @@ -201,7 +202,7 @@ class IDataHandler(ABC): datadir = datadir.joinpath('futures') candle = f"-{candle_type}" filename = datadir.joinpath( - f'{pair_s}-{cls.timeframe_to_file(timeframe)}{candle}.{cls._get_file_extension()}') + f'{pair_s}-{timeframe}{candle}.{cls._get_file_extension()}') return filename @classmethod @@ -220,7 +221,7 @@ class IDataHandler(ABC): converts timeframe from disk to file Replaces mo with M (to avoid problems on case-insensitive filesystems) """ - return re.sub('mo', 'M', timeframe, flags=re.IGNORECASE) + return re.sub('1mo', '1M', timeframe, flags=re.IGNORECASE) @staticmethod def rebuild_pair_from_filename(pair: str) -> str: diff --git a/freqtrade/data/history/jsondatahandler.py b/freqtrade/data/history/jsondatahandler.py index fa02c770b..38402a113 100644 --- a/freqtrade/data/history/jsondatahandler.py +++ b/freqtrade/data/history/jsondatahandler.py @@ -77,7 +77,8 @@ class JsonDataHandler(IDataHandler): :param candle_type: Any of the enum CandleType (must match trading mode!) :return: None """ - filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) + filename = self._pair_data_filename( + self._datadir, pair, self.timeframe_to_file(timeframe), candle_type) self.create_dir_if_needed(filename) _data = data.copy() # Convert date to int @@ -103,9 +104,14 @@ class JsonDataHandler(IDataHandler): :param candle_type: Any of the enum CandleType (must match trading mode!) :return: DataFrame with ohlcv data, or empty DataFrame """ - filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type=candle_type) + filename = self._pair_data_filename( + self._datadir, pair, self.timeframe_to_file(timeframe), candle_type=candle_type) if not filename.exists(): - return DataFrame(columns=self._columns) + # Fallback mode for 1M files + filename = self._pair_data_filename( + self._datadir, pair, timeframe, candle_type=candle_type) + if not filename.exists(): + return DataFrame(columns=self._columns) try: pairdata = read_json(filename, orient='values') pairdata.columns = self._columns diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 82d4a841c..1e7d8855e 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -158,21 +158,22 @@ def test_testdata_path(testdatadir) -> None: assert str(Path('tests') / 'testdata') in str(testdatadir) -@pytest.mark.parametrize("pair,expected_result,candle_type", [ - ("ETH/BTC", 'freqtrade/hello/world/ETH_BTC-5m.json', ""), - ("Fabric Token/ETH", 'freqtrade/hello/world/Fabric_Token_ETH-5m.json', ""), - ("ETHH20", 'freqtrade/hello/world/ETHH20-5m.json', ""), - (".XBTBON2H", 'freqtrade/hello/world/_XBTBON2H-5m.json', ""), - ("ETHUSD.d", 'freqtrade/hello/world/ETHUSD_d-5m.json', ""), - ("ACC_OLD/BTC", 'freqtrade/hello/world/ACC_OLD_BTC-5m.json', ""), - ("ETH/BTC", 'freqtrade/hello/world/futures/ETH_BTC-5m-mark.json', "mark"), - ("ACC_OLD/BTC", 'freqtrade/hello/world/futures/ACC_OLD_BTC-5m-index.json', "index"), +@pytest.mark.parametrize("pair,timeframe,expected_result,candle_type", [ + ("ETH/BTC", "5m", "freqtrade/hello/world/ETH_BTC-5m.json", ""), + ("ETH/USDT", "1M", "freqtrade/hello/world/ETH_USDT-1Mo.json", ""), + ("Fabric Token/ETH", "5m", "freqtrade/hello/world/Fabric_Token_ETH-5m.json", ""), + ("ETHH20", "5m", "freqtrade/hello/world/ETHH20-5m.json", ""), + (".XBTBON2H", "5m", "freqtrade/hello/world/_XBTBON2H-5m.json", ""), + ("ETHUSD.d", "5m", "freqtrade/hello/world/ETHUSD_d-5m.json", ""), + ("ACC_OLD/BTC", "5m", "freqtrade/hello/world/ACC_OLD_BTC-5m.json", ""), + ("ETH/BTC", "5m", "freqtrade/hello/world/futures/ETH_BTC-5m-mark.json", "mark"), + ("ACC_OLD/BTC", "5m", "freqtrade/hello/world/futures/ACC_OLD_BTC-5m-index.json", "index"), ]) -def test_json_pair_data_filename(pair, expected_result, candle_type): +def test_json_pair_data_filename(pair, timeframe, expected_result, candle_type): fn = JsonDataHandler._pair_data_filename( Path('freqtrade/hello/world'), pair, - '5m', + JsonDataHandler.timeframe_to_file(timeframe), CandleType.from_string(candle_type) ) assert isinstance(fn, Path) @@ -180,7 +181,7 @@ def test_json_pair_data_filename(pair, expected_result, candle_type): fn = JsonGzDataHandler._pair_data_filename( Path('freqtrade/hello/world'), pair, - '5m', + JsonGzDataHandler.timeframe_to_file(timeframe), candle_type=CandleType.from_string(candle_type) ) assert isinstance(fn, Path) From 76637d3939994219e1ec15e1cdf7e513217536a5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 16 May 2022 19:53:01 +0200 Subject: [PATCH 126/449] Simplify timeframe-transition --- freqtrade/data/history/hdf5datahandler.py | 7 +++---- freqtrade/data/history/idatahandler.py | 9 ++++++--- freqtrade/data/history/jsondatahandler.py | 7 +++---- tests/data/test_history.py | 4 ++-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index 6099c22bc..dadc9c7e6 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -77,8 +77,7 @@ class HDF5DataHandler(IDataHandler): key = self._pair_ohlcv_key(pair, timeframe) _data = data.copy() - filename = self._pair_data_filename( - self._datadir, pair, self.timeframe_to_file(timeframe), candle_type) + filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) self.create_dir_if_needed(filename) _data.loc[:, self._columns].to_hdf( @@ -105,14 +104,14 @@ class HDF5DataHandler(IDataHandler): filename = self._pair_data_filename( self._datadir, pair, - self.timeframe_to_file(timeframe), + timeframe, candle_type=candle_type ) if not filename.exists(): # Fallback mode for 1M files filename = self._pair_data_filename( - self._datadir, pair, timeframe, candle_type=candle_type) + self._datadir, pair, timeframe, candle_type=candle_type, no_timeframe_modify=True) if not filename.exists(): return pd.DataFrame(columns=self._columns) where = [] diff --git a/freqtrade/data/history/idatahandler.py b/freqtrade/data/history/idatahandler.py index 69d6212ee..07dc7c763 100644 --- a/freqtrade/data/history/idatahandler.py +++ b/freqtrade/data/history/idatahandler.py @@ -98,8 +98,7 @@ class IDataHandler(ABC): :param candle_type: Any of the enum CandleType (must match trading mode!) :return: True when deleted, false if file did not exist. """ - filename = self._pair_data_filename( - self._datadir, pair, self.timeframe_to_file(timeframe), candle_type) + filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) if filename.exists(): filename.unlink() return True @@ -194,10 +193,14 @@ class IDataHandler(ABC): datadir: Path, pair: str, timeframe: str, - candle_type: CandleType + candle_type: CandleType, + no_timeframe_modify: bool = False ) -> Path: pair_s = misc.pair_to_filename(pair) candle = "" + if not no_timeframe_modify: + timeframe = cls.timeframe_to_file(timeframe) + if candle_type != CandleType.SPOT: datadir = datadir.joinpath('futures') candle = f"-{candle_type}" diff --git a/freqtrade/data/history/jsondatahandler.py b/freqtrade/data/history/jsondatahandler.py index 38402a113..83ec183df 100644 --- a/freqtrade/data/history/jsondatahandler.py +++ b/freqtrade/data/history/jsondatahandler.py @@ -77,8 +77,7 @@ class JsonDataHandler(IDataHandler): :param candle_type: Any of the enum CandleType (must match trading mode!) :return: None """ - filename = self._pair_data_filename( - self._datadir, pair, self.timeframe_to_file(timeframe), candle_type) + filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) self.create_dir_if_needed(filename) _data = data.copy() # Convert date to int @@ -105,11 +104,11 @@ class JsonDataHandler(IDataHandler): :return: DataFrame with ohlcv data, or empty DataFrame """ filename = self._pair_data_filename( - self._datadir, pair, self.timeframe_to_file(timeframe), candle_type=candle_type) + self._datadir, pair, timeframe, candle_type=candle_type) if not filename.exists(): # Fallback mode for 1M files filename = self._pair_data_filename( - self._datadir, pair, timeframe, candle_type=candle_type) + self._datadir, pair, timeframe, candle_type=candle_type, no_timeframe_modify=True) if not filename.exists(): return DataFrame(columns=self._columns) try: diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 1e7d8855e..9709e7ad0 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -173,7 +173,7 @@ def test_json_pair_data_filename(pair, timeframe, expected_result, candle_type): fn = JsonDataHandler._pair_data_filename( Path('freqtrade/hello/world'), pair, - JsonDataHandler.timeframe_to_file(timeframe), + timeframe, CandleType.from_string(candle_type) ) assert isinstance(fn, Path) @@ -181,7 +181,7 @@ def test_json_pair_data_filename(pair, timeframe, expected_result, candle_type): fn = JsonGzDataHandler._pair_data_filename( Path('freqtrade/hello/world'), pair, - JsonGzDataHandler.timeframe_to_file(timeframe), + timeframe, candle_type=CandleType.from_string(candle_type) ) assert isinstance(fn, Path) From fb7c0792c017f9deae8a397272ba310eca798664 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 01:41:01 +0300 Subject: [PATCH 127/449] Track trade entries canceled by user. --- freqtrade/optimize/backtesting.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 64107ae18..933cc2aea 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -297,6 +297,7 @@ class Backtesting: self.rejected_trades = 0 self.timedout_entry_orders = 0 self.timedout_exit_orders = 0 + self.canceled_trade_entries = 0 self.dataprovider.clear_cache() if enable_protections: self._load_protections(self.strategy) @@ -884,6 +885,7 @@ class Backtesting: return True elif self.check_order_replace(trade, order, current_time, row): # delete trade due to user request + self.canceled_trade_entries += 1 return True # default maintain trade return False @@ -1087,6 +1089,7 @@ class Backtesting: 'rejected_signals': self.rejected_trades, 'timedout_entry_orders': self.timedout_entry_orders, 'timedout_exit_orders': self.timedout_exit_orders, + 'canceled_trade_entries': self.canceled_trade_entries, 'final_balance': self.wallets.get_total(self.strategy.config['stake_currency']), } From f2e2e57237a3335431f48e8fdb6557729631b926 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 01:41:31 +0300 Subject: [PATCH 128/449] Report trade entries canceled by user. --- freqtrade/optimize/optimize_reports.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 42db366a1..7ee25ea73 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -468,6 +468,7 @@ def generate_strategy_stats(pairlist: List[str], 'rejected_signals': content['rejected_signals'], 'timedout_entry_orders': content['timedout_entry_orders'], 'timedout_exit_orders': content['timedout_exit_orders'], + 'canceled_trade_entries': content['canceled_trade_entries'], 'max_open_trades': max_open_trades, 'max_open_trades_setting': (config['max_open_trades'] if config['max_open_trades'] != float('inf') else -1), @@ -801,6 +802,7 @@ def text_table_add_metrics(strat_results: Dict) -> str: ('Entry/Exit Timeouts', f"{strat_results.get('timedout_entry_orders', 'N/A')} / " f"{strat_results.get('timedout_exit_orders', 'N/A')}"), + ('Canceled Trade Entries', strat_results.get('canceled_trade_entries', 'N/A')), ('', ''), # Empty line to improve readability ('Min balance', round_coin_value(strat_results['csum_min'], From 99aea454b5eaae99962718fbe1abf65cc63debb1 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 01:42:48 +0300 Subject: [PATCH 129/449] Update testcases to match reporting. --- tests/optimize/test_backtesting.py | 8 ++++++++ tests/optimize/test_hyperopt.py | 2 ++ tests/optimize/test_optimize_reports.py | 2 ++ 3 files changed, 12 insertions(+) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index c87a0ef73..5b080fb11 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -1168,6 +1168,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir): 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, }) mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', @@ -1280,6 +1281,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, }, { @@ -1289,6 +1291,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, } ]) @@ -1431,6 +1434,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, }, { @@ -1440,6 +1444,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, } ]) @@ -1534,6 +1539,7 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker, 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, }, { @@ -1543,6 +1549,7 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker, 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, } ]) @@ -1606,6 +1613,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, }) mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 75944390e..1d729190e 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -368,6 +368,7 @@ def test_hyperopt_format_results(hyperopt): 'rejected_signals': 2, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'backtest_start_time': 1619718665, 'backtest_end_time': 1619718665, } @@ -438,6 +439,7 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None: 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'final_balance': 1000, } diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index ff8d420b3..6ba03f08e 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -87,6 +87,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'backtest_start_time': Arrow.utcnow().int_timestamp, 'backtest_end_time': Arrow.utcnow().int_timestamp, 'run_id': '123', @@ -139,6 +140,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): 'rejected_signals': 20, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, 'backtest_start_time': Arrow.utcnow().int_timestamp, 'backtest_end_time': Arrow.utcnow().int_timestamp, 'run_id': '124', From a2a8e4fdc75f1a497471f1892fcd148b5052d1bc Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 02:01:27 +0300 Subject: [PATCH 130/449] Update doc BT sample report. --- docs/backtesting.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/backtesting.md b/docs/backtesting.md index 02d1a53d1..6f0ed8447 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -320,6 +320,7 @@ A backtesting result will look like that: | Avg. Duration Loser | 6:55:00 | | Rejected Entry signals | 3089 | | Entry/Exit Timeouts | 0 / 0 | +| Canceled Trade Entries | 123 | | | | | Min balance | 0.00945123 BTC | | Max balance | 0.01846651 BTC | From 905b24bd4d4de6be7bdcf81011fd7fe37bd34678 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 02:04:45 +0300 Subject: [PATCH 131/449] Update BT report detailing. --- docs/backtesting.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/backtesting.md b/docs/backtesting.md index 6f0ed8447..45c2704a0 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -417,6 +417,7 @@ It contains some useful key metrics about performance of your strategy on backte | Avg. Duration Loser | 6:55:00 | | Rejected Entry signals | 3089 | | Entry/Exit Timeouts | 0 / 0 | +| Canceled Trade Entries | 123 | | | | | Min balance | 0.00945123 BTC | | Max balance | 0.01846651 BTC | @@ -448,6 +449,7 @@ It contains some useful key metrics about performance of your strategy on backte - `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades. - `Rejected Entry signals`: Trade entry signals that could not be acted upon due to `max_open_trades` being reached. - `Entry/Exit Timeouts`: Entry/exit orders which did not fill (only applicable if custom pricing is used). +- `Canceled Trade Entries`: Number of trades that have been canceled by user request via `adjust_entry_price`. - `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period. - `Max % of account underwater`: Maximum percentage your account has decreased from the top since the simulation started. Calculated as the maximum of `(Max Balance - Current Balance) / (Max Balance)`. From 6e8f24f6a7cd634b9ce6d83ffc7871fee4efb9b8 Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 14:07:02 +0300 Subject: [PATCH 132/449] BT: track canceled/replaced orders also. --- freqtrade/optimize/backtesting.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 933cc2aea..9aee1215f 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -298,6 +298,8 @@ class Backtesting: self.timedout_entry_orders = 0 self.timedout_exit_orders = 0 self.canceled_trade_entries = 0 + self.canceled_entry_orders = 0 + self.replaced_entry_orders = 0 self.dataprovider.clear_cache() if enable_protections: self._load_protections(self.strategy) @@ -935,6 +937,7 @@ class Backtesting: return False else: del trade.orders[trade.orders.index(order)] + self.canceled_entry_orders += 1 # place new order if result was not None if requested_rate: @@ -942,6 +945,7 @@ class Backtesting: requested_rate=requested_rate, requested_stake=(order.remaining * order.price), direction='short' if trade.is_short else 'long') + self.replaced_entry_orders += 1 else: # assumption: there can't be multiple open entry orders at any given time return (trade.nr_of_successful_entries == 0) @@ -1090,6 +1094,8 @@ class Backtesting: 'timedout_entry_orders': self.timedout_entry_orders, 'timedout_exit_orders': self.timedout_exit_orders, 'canceled_trade_entries': self.canceled_trade_entries, + 'canceled_entry_orders': self.canceled_entry_orders, + 'replaced_entry_orders': self.replaced_entry_orders, 'final_balance': self.wallets.get_total(self.strategy.config['stake_currency']), } From 0585b378b3187926ca6e0980c8c67eed7dd1378d Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 14:07:42 +0300 Subject: [PATCH 133/449] BT: Report canceled/replaced orders also. --- freqtrade/optimize/optimize_reports.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 7ee25ea73..93336fa3f 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -469,6 +469,8 @@ def generate_strategy_stats(pairlist: List[str], 'timedout_entry_orders': content['timedout_entry_orders'], 'timedout_exit_orders': content['timedout_exit_orders'], 'canceled_trade_entries': content['canceled_trade_entries'], + 'canceled_entry_orders': content['canceled_entry_orders'], + 'replaced_entry_orders': content['replaced_entry_orders'], 'max_open_trades': max_open_trades, 'max_open_trades_setting': (config['max_open_trades'] if config['max_open_trades'] != float('inf') else -1), @@ -754,6 +756,12 @@ def text_table_add_metrics(strat_results: Dict) -> str: ('Drawdown End', strat_results['drawdown_end']), ]) + entry_adjustment_metrics = [ + ('Canceled Trade Entries', strat_results.get('canceled_trade_entries', 'N/A')), + ('Canceled Entry Orders', strat_results.get('canceled_entry_orders', 'N/A')), + ('Replaced Entry Orders', strat_results.get('replaced_entry_orders', 'N/A')), + ] if strat_results.get('canceled_entry_orders', 0) > 0 else [] + # Newly added fields should be ignored if they are missing in strat_results. hyperopt-show # command stores these results and newer version of freqtrade must be able to handle old # results with missing new fields. @@ -802,7 +810,7 @@ def text_table_add_metrics(strat_results: Dict) -> str: ('Entry/Exit Timeouts', f"{strat_results.get('timedout_entry_orders', 'N/A')} / " f"{strat_results.get('timedout_exit_orders', 'N/A')}"), - ('Canceled Trade Entries', strat_results.get('canceled_trade_entries', 'N/A')), + *entry_adjustment_metrics, ('', ''), # Empty line to improve readability ('Min balance', round_coin_value(strat_results['csum_min'], From bb7ffd8fbec123de522f43909603c3c80b4c899c Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 14:08:35 +0300 Subject: [PATCH 134/449] Update testcases relying on BT results. --- tests/optimize/test_backtesting.py | 16 ++++++++++++++++ tests/optimize/test_hyperopt.py | 4 ++++ tests/optimize/test_optimize_reports.py | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 5b080fb11..f169e0a35 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -1169,6 +1169,8 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir): 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, }) mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', @@ -1282,6 +1284,8 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, }, { @@ -1292,6 +1296,8 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, } ]) @@ -1435,6 +1441,8 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, }, { @@ -1445,6 +1453,8 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, } ]) @@ -1540,6 +1550,8 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, }, { @@ -1550,6 +1562,8 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker, 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, } ]) @@ -1614,6 +1628,8 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, }) mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 1d729190e..dcc1ddeea 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -369,6 +369,8 @@ def test_hyperopt_format_results(hyperopt): 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'backtest_start_time': 1619718665, 'backtest_end_time': 1619718665, } @@ -440,6 +442,8 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None: 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'final_balance': 1000, } diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 6ba03f08e..997c0436e 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -88,6 +88,8 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'backtest_start_time': Arrow.utcnow().int_timestamp, 'backtest_end_time': Arrow.utcnow().int_timestamp, 'run_id': '123', @@ -141,6 +143,8 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): 'timedout_entry_orders': 0, 'timedout_exit_orders': 0, 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, 'backtest_start_time': Arrow.utcnow().int_timestamp, 'backtest_end_time': Arrow.utcnow().int_timestamp, 'run_id': '124', From c6bf6779f874c1d5c3fe3c8065bfe01516c5a2ae Mon Sep 17 00:00:00 2001 From: eSeR1805 Date: Tue, 17 May 2022 14:09:01 +0300 Subject: [PATCH 135/449] Update docs BT sample report and details. --- docs/backtesting.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 45c2704a0..b4d9aef80 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -320,7 +320,9 @@ A backtesting result will look like that: | Avg. Duration Loser | 6:55:00 | | Rejected Entry signals | 3089 | | Entry/Exit Timeouts | 0 / 0 | -| Canceled Trade Entries | 123 | +| Canceled Trade Entries | 34 | +| Canceled Entry Orders | 123 | +| Replaced Entry Orders | 89 | | | | | Min balance | 0.00945123 BTC | | Max balance | 0.01846651 BTC | @@ -417,7 +419,9 @@ It contains some useful key metrics about performance of your strategy on backte | Avg. Duration Loser | 6:55:00 | | Rejected Entry signals | 3089 | | Entry/Exit Timeouts | 0 / 0 | -| Canceled Trade Entries | 123 | +| Canceled Trade Entries | 34 | +| Canceled Entry Orders | 123 | +| Replaced Entry Orders | 89 | | | | | Min balance | 0.00945123 BTC | | Max balance | 0.01846651 BTC | @@ -450,6 +454,8 @@ It contains some useful key metrics about performance of your strategy on backte - `Rejected Entry signals`: Trade entry signals that could not be acted upon due to `max_open_trades` being reached. - `Entry/Exit Timeouts`: Entry/exit orders which did not fill (only applicable if custom pricing is used). - `Canceled Trade Entries`: Number of trades that have been canceled by user request via `adjust_entry_price`. +- `Canceled Entry Orders`: Number of entry orders that have been canceled by user request via `adjust_entry_price`. +- `Replaced Entry Orders`: Number of entry orders that have been replaced by user request via `adjust_entry_price`. - `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period. - `Max % of account underwater`: Maximum percentage your account has decreased from the top since the simulation started. Calculated as the maximum of `(Max Balance - Current Balance) / (Max Balance)`. From bb758da9408e15eed3327f3122eb576674d3f4b1 Mon Sep 17 00:00:00 2001 From: froggleston Date: Tue, 17 May 2022 22:05:33 +0100 Subject: [PATCH 136/449] Add support for fudging unavailable funding rates, allowing backtesting of timeranges where futures candles are available, but rates are not --- docs/configuration.md | 1 + docs/leverage.md | 6 ++++++ freqtrade/data/history/history_utils.py | 7 ++++++- freqtrade/optimize/backtesting.py | 23 +++++++++++++++++++++-- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 80cd52c5b..5a6d5849a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -230,6 +230,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `dataformat_trades` | Data format to use to store historical trades data.
*Defaults to `jsongz`*.
**Datatype:** String | `position_adjustment_enable` | Enables the strategy to use position adjustments (additional buys or sells). [More information here](strategy-callbacks.md#adjust-trade-position).
[Strategy Override](#parameters-in-the-strategy).
*Defaults to `false`.*
**Datatype:** Boolean | `max_entry_position_adjustment` | Maximum additional order(s) for each open trade on top of the first entry Order. Set it to `-1` for unlimited additional orders. [More information here](strategy-callbacks.md#adjust-trade-position).
[Strategy Override](#parameters-in-the-strategy).
*Defaults to `-1`.*
**Datatype:** Positive Integer or -1 +| `futures_funding_rate` | User-specified funding rate to be used when historical funding rates are not available from the exchange. This does not overwrite real historical rates. It is recommended that this be set to 0 unless you are testing a specific coin and you understand how the funding rate will affect freqtrade's profit calculations. [More information here](configuration.md)
*Defaults to None.*
**Datatype:** Float ### Parameters in the strategy diff --git a/docs/leverage.md b/docs/leverage.md index 79d3c9842..d8a9c8032 100644 --- a/docs/leverage.md +++ b/docs/leverage.md @@ -101,6 +101,12 @@ Possible values are any floats between 0.0 and 0.99 !!! Danger "A `liquidation_buffer` of 0.0, or a low `liquidation_buffer` is likely to result in liquidations, and liquidation fees" Currently Freqtrade is able to calculate liquidation prices, but does not calculate liquidation fees. Setting your `liquidation_buffer` to 0.0, or using a low `liquidation_buffer` could result in your positions being liquidated. Freqtrade does not track liquidation fees, so liquidations will result in inaccurate profit/loss results for your bot. If you use a low `liquidation_buffer`, it is recommended to use `stoploss_on_exchange` if your exchange supports this. +## Unavailable funding rates + +For futures data, exchanges commonly provide the futures candles, the marks, and the funding rates. However, it is common that whilst candles and marks might be available, the funding rates are not. This can affect backtesting timeranges, i.e. you may only be able to test recent timeranges and not earlier, experiencing the `No data found. Terminating.` error. To get around this, add the `futures_funding_rate` config option as listed in [configuration.md](configuration.md), and it is recommended that you set this to `0`, unless you know a given specific funding rate for your pair, exchange and timerange. Setting this to anything other than `0` can have drastic effects on your profit calculations within strategy, e.g. within the `custom_exit`, `custom_stoploss`, etc functions. + +!!! This will not overwrite funding rates that are available from the exchange. + ### Developer #### Margin mode diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index eb36d2042..b589001ca 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -68,7 +68,8 @@ def load_data(datadir: Path, startup_candles: int = 0, fail_without_data: bool = False, data_format: str = 'json', - candle_type: CandleType = CandleType.SPOT + candle_type: CandleType = CandleType.SPOT, + user_futures_funding_rate = None, ) -> Dict[str, DataFrame]: """ Load ohlcv history data for a list of pairs. @@ -100,6 +101,10 @@ def load_data(datadir: Path, ) if not hist.empty: result[pair] = hist + else: + if candle_type is CandleType.FUNDING_RATE and user_futures_funding_rate is not None: + logger.warn(f"{pair} using user specified [{user_futures_funding_rate}]") + result[pair] = DataFrame(columns=["open","close","high","low","volume"]) if fail_without_data and not result: raise OperationalException("No data found. Terminating.") diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 4e604898f..49b085ca1 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -275,8 +275,27 @@ class Backtesting: if pair not in self.exchange._leverage_tiers: unavailable_pairs.append(pair) continue - self.futures_data[pair] = funding_rates_dict[pair].merge( - mark_rates_dict[pair], on='date', how="inner", suffixes=["_fund", "_mark"]) + + if (pair in mark_rates_dict + and len(funding_rates_dict[pair]) == 0 + and "futures_funding_rate" in self.config): + mark_rates_dict[pair]["open_fund"] = self.config.get('futures_funding_rate') + mark_rates_dict[pair]["close_fund"] = 0.0 + mark_rates_dict[pair]["high_fund"] = 0.0 + mark_rates_dict[pair]["low_fund"] = 0.0 + mark_rates_dict[pair]["volume_fund"] = 0.0 + mark_rates_dict[pair].rename( + columns = {'open':'open_mark', + 'close':'close_mark', + 'high':'high_mark', + 'low':'low_mark', + 'volume':'volume_mark'}, + inplace = True) + + self.futures_data[pair] = mark_rates_dict[pair] + else: + self.futures_data[pair] = mark_rates_dict[pair].merge( + funding_rates_dict[pair], on='date', how="inner", suffixes=["_fund", "_mark"]) if unavailable_pairs: raise OperationalException( From 37e4ede65c674c898193a828d72feb90a92c5ea4 Mon Sep 17 00:00:00 2001 From: froggleston Date: Tue, 17 May 2022 22:32:17 +0100 Subject: [PATCH 137/449] Fix flake issues --- docs/leverage.md | 5 +++-- freqtrade/data/history/history_utils.py | 4 ++-- freqtrade/optimize/backtesting.py | 19 ++++++++++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/leverage.md b/docs/leverage.md index d8a9c8032..0c8139ad3 100644 --- a/docs/leverage.md +++ b/docs/leverage.md @@ -105,8 +105,9 @@ Possible values are any floats between 0.0 and 0.99 For futures data, exchanges commonly provide the futures candles, the marks, and the funding rates. However, it is common that whilst candles and marks might be available, the funding rates are not. This can affect backtesting timeranges, i.e. you may only be able to test recent timeranges and not earlier, experiencing the `No data found. Terminating.` error. To get around this, add the `futures_funding_rate` config option as listed in [configuration.md](configuration.md), and it is recommended that you set this to `0`, unless you know a given specific funding rate for your pair, exchange and timerange. Setting this to anything other than `0` can have drastic effects on your profit calculations within strategy, e.g. within the `custom_exit`, `custom_stoploss`, etc functions. -!!! This will not overwrite funding rates that are available from the exchange. - +!!! Warning This will mean your backtests are inaccurate. + This will not overwrite funding rates that are available from the exchange, but bear in mind that setting a false funding rate will mean backtesting results will be inaccurate for historical timeranges where funding rates are not available. + ### Developer #### Margin mode diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index b589001ca..4600d6ab4 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -69,7 +69,7 @@ def load_data(datadir: Path, fail_without_data: bool = False, data_format: str = 'json', candle_type: CandleType = CandleType.SPOT, - user_futures_funding_rate = None, + user_futures_funding_rate: int = None, ) -> Dict[str, DataFrame]: """ Load ohlcv history data for a list of pairs. @@ -104,7 +104,7 @@ def load_data(datadir: Path, else: if candle_type is CandleType.FUNDING_RATE and user_futures_funding_rate is not None: logger.warn(f"{pair} using user specified [{user_futures_funding_rate}]") - result[pair] = DataFrame(columns=["open","close","high","low","volume"]) + result[pair] = DataFrame(columns=["open", "close", "high", "low", "volume"]) if fail_without_data and not result: raise OperationalException("No data found. Terminating.") diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 49b085ca1..8d5a5fcea 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -277,25 +277,26 @@ class Backtesting: continue if (pair in mark_rates_dict - and len(funding_rates_dict[pair]) == 0 - and "futures_funding_rate" in self.config): + and len(funding_rates_dict[pair]) == 0 + and "futures_funding_rate" in self.config): mark_rates_dict[pair]["open_fund"] = self.config.get('futures_funding_rate') mark_rates_dict[pair]["close_fund"] = 0.0 mark_rates_dict[pair]["high_fund"] = 0.0 mark_rates_dict[pair]["low_fund"] = 0.0 mark_rates_dict[pair]["volume_fund"] = 0.0 mark_rates_dict[pair].rename( - columns = {'open':'open_mark', - 'close':'close_mark', - 'high':'high_mark', - 'low':'low_mark', - 'volume':'volume_mark'}, - inplace = True) + columns={'open': 'open_mark', + 'close': 'close_mark', + 'high': 'high_mark', + 'low': 'low_mark', + 'volume': 'volume_mark'}, + inplace=True) self.futures_data[pair] = mark_rates_dict[pair] else: self.futures_data[pair] = mark_rates_dict[pair].merge( - funding_rates_dict[pair], on='date', how="inner", suffixes=["_fund", "_mark"]) + funding_rates_dict[pair], on='date', + how="inner", suffixes=["_fund", "_mark"]) if unavailable_pairs: raise OperationalException( From c41d4c4f45ba06deb2b70923469ce9dfb2701e6f Mon Sep 17 00:00:00 2001 From: froggleston Date: Tue, 17 May 2022 22:37:48 +0100 Subject: [PATCH 138/449] Fix leverage docs --- docs/leverage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/leverage.md b/docs/leverage.md index 0c8139ad3..58e7cc778 100644 --- a/docs/leverage.md +++ b/docs/leverage.md @@ -105,7 +105,7 @@ Possible values are any floats between 0.0 and 0.99 For futures data, exchanges commonly provide the futures candles, the marks, and the funding rates. However, it is common that whilst candles and marks might be available, the funding rates are not. This can affect backtesting timeranges, i.e. you may only be able to test recent timeranges and not earlier, experiencing the `No data found. Terminating.` error. To get around this, add the `futures_funding_rate` config option as listed in [configuration.md](configuration.md), and it is recommended that you set this to `0`, unless you know a given specific funding rate for your pair, exchange and timerange. Setting this to anything other than `0` can have drastic effects on your profit calculations within strategy, e.g. within the `custom_exit`, `custom_stoploss`, etc functions. -!!! Warning This will mean your backtests are inaccurate. +!!! Warning "This will mean your backtests are inaccurate." This will not overwrite funding rates that are available from the exchange, but bear in mind that setting a false funding rate will mean backtesting results will be inaccurate for historical timeranges where funding rates are not available. ### Developer From 2b61aa282a434f4011fbd5e5720270b4f6eefe35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AE=E0=AE=A9=E0=AF=8B=E0=AE=9C=E0=AF=8D=E0=AE=95?= =?UTF-8?q?=E0=AF=81=E0=AE=AE=E0=AE=BE=E0=AE=B0=E0=AF=8D=20=E0=AE=AA?= =?UTF-8?q?=E0=AE=B4=E0=AE=A9=E0=AE=BF=E0=AE=9A=E0=AF=8D=E0=AE=9A=E0=AE=BE?= =?UTF-8?q?=E0=AE=AE=E0=AE=BF?= Date: Wed, 18 May 2022 03:41:10 +0530 Subject: [PATCH 139/449] Removed None in dict.get() https://stackoverflow.com/a/12631641 Extra Changes: freqtrade\freqtradebot.py:70 freqtrade\plugins\pairlistmanager.py:31 --- freqtrade/commands/hyperopt_commands.py | 2 +- freqtrade/configuration/configuration.py | 8 ++++---- freqtrade/exchange/exchange.py | 12 ++++++------ freqtrade/freqtradebot.py | 14 +++++++------- freqtrade/optimize/backtesting.py | 4 ++-- freqtrade/optimize/hyperopt.py | 2 +- freqtrade/optimize/hyperopt_tools.py | 16 ++++++++-------- freqtrade/plugins/pairlist/AgeFilter.py | 2 +- freqtrade/plugins/pairlist/PerformanceFilter.py | 2 +- freqtrade/plugins/pairlist/PriceFilter.py | 2 +- .../plugins/pairlist/rangestabilityfilter.py | 2 +- freqtrade/plugins/pairlistmanager.py | 2 +- freqtrade/rpc/api_server/api_v1.py | 2 +- freqtrade/rpc/rpc.py | 4 ++-- freqtrade/rpc/telegram.py | 6 +++--- freqtrade/rpc/webhook.py | 14 +++++++------- freqtrade/wallets.py | 6 +++--- 17 files changed, 50 insertions(+), 50 deletions(-) diff --git a/freqtrade/commands/hyperopt_commands.py b/freqtrade/commands/hyperopt_commands.py index 344828282..19e291ea7 100755 --- a/freqtrade/commands/hyperopt_commands.py +++ b/freqtrade/commands/hyperopt_commands.py @@ -24,7 +24,7 @@ def start_hyperopt_list(args: Dict[str, Any]) -> None: print_colorized = config.get('print_colorized', False) print_json = config.get('print_json', False) - export_csv = config.get('export_csv', None) + export_csv = config.get('export_csv') no_details = config.get('hyperopt_list_no_details', False) no_header = False diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 96b585cd1..e4c7b8f9d 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -127,7 +127,7 @@ class Configuration: # Default to in-memory db for dry_run if not specified config['db_url'] = constants.DEFAULT_DB_DRYRUN_URL else: - if not config.get('db_url', None): + if not config.get('db_url'): config['db_url'] = constants.DEFAULT_DB_PROD_URL logger.info('Dry run is disabled') @@ -180,7 +180,7 @@ class Configuration: config['user_data_dir'] = create_userdata_dir(config['user_data_dir'], create_dir=False) logger.info('Using user-data directory: %s ...', config['user_data_dir']) - config.update({'datadir': create_datadir(config, self.args.get('datadir', None))}) + config.update({'datadir': create_datadir(config, self.args.get('datadir'))}) logger.info('Using data directory: %s ...', config.get('datadir')) if self.args.get('exportfilename'): @@ -219,7 +219,7 @@ class Configuration: if config.get('max_open_trades') == -1: config['max_open_trades'] = float('inf') - if self.args.get('stake_amount', None): + if self.args.get('stake_amount'): # Convert explicitly to float to support CLI argument for both unlimited and value try: self.args['stake_amount'] = float(self.args['stake_amount']) @@ -459,7 +459,7 @@ class Configuration: configuration instead of the content) """ if (argname in self.args and self.args[argname] is not None - and self.args[argname] is not False): + and self.args[argname] is not False): config.update({argname: self.args[argname]}) if logfun: diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d2766cd6d..685f86899 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -383,11 +383,11 @@ class Exchange: Ensures that Configured mode aligns to """ return ( - market.get('quote', None) is not None - and market.get('base', None) is not None + market.get('quote') is not None + and market.get('base') is not None and (self.precisionMode != TICK_SIZE # Too low precision will falsify calculations - or market.get('precision', {}).get('price', None) > 1e-11) + or market.get('precision', {}).get('price') > 1e-11) and ((self.trading_mode == TradingMode.SPOT and self.market_is_spot(market)) or (self.trading_mode == TradingMode.MARGIN and self.market_is_margin(market)) or (self.trading_mode == TradingMode.FUTURES and self.market_is_future(market))) @@ -537,7 +537,7 @@ class Exchange: # The internal info array is different for each particular market, # its contents depend on the exchange. # It can also be a string or similar ... so we need to verify that first. - elif (isinstance(self.markets[pair].get('info', None), dict) + elif (isinstance(self.markets[pair].get('info'), dict) and self.markets[pair].get('info', {}).get('prohibitedIn', False)): # Warn users about restricted pairs in whitelist. # We cannot determine reliably if Users are affected. @@ -1593,7 +1593,7 @@ class Exchange: def get_fee(self, symbol: str, type: str = '', side: str = '', amount: float = 1, price: float = 1, taker_or_maker: str = 'maker') -> float: try: - if self._config['dry_run'] and self._config.get('fee', None) is not None: + if self._config['dry_run'] and self._config.get('fee') is not None: return self._config['fee'] # validate that markets are loaded before trying to get fee if self._api.markets is None or len(self._api.markets) == 0: @@ -1654,7 +1654,7 @@ class Exchange: fee_to_quote_rate = safe_value_fallback2(tick, tick, 'last', 'ask') except ExchangeError: - fee_to_quote_rate = self._config['exchange'].get('unknown_fee_rate', None) + fee_to_quote_rate = self._config['exchange'].get('unknown_fee_rate') if not fee_to_quote_rate: return None return round((self._contracts_to_amount( diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 315db3ae6..cbd44a755 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -67,7 +67,7 @@ class FreqtradeBot(LoggingMixin): self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) - init_db(self.config.get('db_url', None), clean_open_orders=self.config['dry_run']) + init_db(self.config['db_url'], clean_open_orders=self.config['dry_run']) self.wallets = Wallets(self.config, self.exchange) @@ -638,7 +638,7 @@ class FreqtradeBot(LoggingMixin): ) order_obj = Order.parse_from_ccxt_object(order, pair, side) order_id = order['id'] - order_status = order.get('status', None) + order_status = order.get('status') logger.info(f"Order #{order_id} was created for {pair} and status is {order_status}.") # we assume the order is executed at the price requested @@ -845,7 +845,7 @@ class FreqtradeBot(LoggingMixin): 'order_type': order_type, 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], - 'fiat_currency': self.config.get('fiat_display_currency', None), + 'fiat_currency': self.config.get('fiat_display_currency'), 'amount': safe_value_fallback(order, 'filled', 'amount') or trade.amount, 'open_date': trade.open_date or datetime.utcnow(), 'current_rate': current_rate, @@ -874,7 +874,7 @@ class FreqtradeBot(LoggingMixin): 'order_type': order_type, 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], - 'fiat_currency': self.config.get('fiat_display_currency', None), + 'fiat_currency': self.config.get('fiat_display_currency'), 'amount': trade.amount, 'open_date': trade.open_date, 'current_rate': current_rate, @@ -1529,7 +1529,7 @@ class FreqtradeBot(LoggingMixin): 'open_date': trade.open_date, 'close_date': trade.close_date or datetime.utcnow(), 'stake_currency': self.config['stake_currency'], - 'fiat_currency': self.config.get('fiat_display_currency', None), + 'fiat_currency': self.config.get('fiat_display_currency'), } if 'fiat_display_currency' in self.config: @@ -1578,7 +1578,7 @@ class FreqtradeBot(LoggingMixin): 'open_date': trade.open_date, 'close_date': trade.close_date or datetime.now(timezone.utc), 'stake_currency': self.config['stake_currency'], - 'fiat_currency': self.config.get('fiat_display_currency', None), + 'fiat_currency': self.config.get('fiat_display_currency'), 'reason': reason, } @@ -1640,7 +1640,7 @@ class FreqtradeBot(LoggingMixin): if order['status'] in constants.NON_OPEN_EXCHANGE_STATES: # If a entry order was closed, force update on stoploss on exchange - if order.get('side', None) == trade.entry_side: + if order.get('side') == trade.entry_side: trade = self.cancel_stoploss_on_exchange(trade) # TODO: Margin will need to use interest_rate as well. # interest_rate = self.exchange.get_interest_rate() diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 4e604898f..f1ccd3b51 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -87,7 +87,7 @@ class Backtesting: self.exchange = ExchangeResolver.load_exchange(self._exchange_name, self.config) self.dataprovider = DataProvider(self.config, self.exchange) - if self.config.get('strategy_list', None): + if self.config.get('strategy_list'): for strat in list(self.config['strategy_list']): stratconf = deepcopy(self.config) stratconf['strategy'] = strat @@ -123,7 +123,7 @@ class Backtesting: if len(self.pairlists.whitelist) == 0: raise OperationalException("No pair in whitelist.") - if config.get('fee', None) is not None: + if config.get('fee') is not None: self.fee = config['fee'] else: self.fee = self.exchange.get_fee(symbol=self.pairlists.whitelist[0]) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 1dafb483c..a267ca4ac 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -455,7 +455,7 @@ class Hyperopt: return self.opt.ask(n_points=n_points), [False for _ in range(n_points)] def start(self) -> None: - self.random_state = self._set_random_state(self.config.get('hyperopt_random_state', None)) + self.random_state = self._set_random_state(self.config.get('hyperopt_random_state')) logger.info(f"Using optimizer random state: {self.random_state}") self.hyperopt_table_header = -1 # Initialize spaces ... diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 0421e6e38..ab6ef013b 100755 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -127,14 +127,14 @@ class HyperoptTools(): 'only_profitable': config.get('hyperopt_list_profitable', False), 'filter_min_trades': config.get('hyperopt_list_min_trades', 0), 'filter_max_trades': config.get('hyperopt_list_max_trades', 0), - 'filter_min_avg_time': config.get('hyperopt_list_min_avg_time', None), - 'filter_max_avg_time': config.get('hyperopt_list_max_avg_time', None), - 'filter_min_avg_profit': config.get('hyperopt_list_min_avg_profit', None), - 'filter_max_avg_profit': config.get('hyperopt_list_max_avg_profit', None), - 'filter_min_total_profit': config.get('hyperopt_list_min_total_profit', None), - 'filter_max_total_profit': config.get('hyperopt_list_max_total_profit', None), - 'filter_min_objective': config.get('hyperopt_list_min_objective', None), - 'filter_max_objective': config.get('hyperopt_list_max_objective', None), + 'filter_min_avg_time': config.get('hyperopt_list_min_avg_time'), + 'filter_max_avg_time': config.get('hyperopt_list_max_avg_time'), + 'filter_min_avg_profit': config.get('hyperopt_list_min_avg_profit'), + 'filter_max_avg_profit': config.get('hyperopt_list_max_avg_profit'), + 'filter_min_total_profit': config.get('hyperopt_list_min_total_profit'), + 'filter_max_total_profit': config.get('hyperopt_list_max_total_profit'), + 'filter_min_objective': config.get('hyperopt_list_min_objective'), + 'filter_max_objective': config.get('hyperopt_list_max_objective'), } if not HyperoptTools._test_hyperopt_results_exist(results_file): # No file found. diff --git a/freqtrade/plugins/pairlist/AgeFilter.py b/freqtrade/plugins/pairlist/AgeFilter.py index 418c0f14e..786f32e88 100644 --- a/freqtrade/plugins/pairlist/AgeFilter.py +++ b/freqtrade/plugins/pairlist/AgeFilter.py @@ -30,7 +30,7 @@ class AgeFilter(IPairList): self._symbolsCheckFailed = PeriodicCache(maxsize=1000, ttl=86_400) self._min_days_listed = pairlistconfig.get('min_days_listed', 10) - self._max_days_listed = pairlistconfig.get('max_days_listed', None) + self._max_days_listed = pairlistconfig.get('max_days_listed') candle_limit = exchange.ohlcv_candle_limit('1d', self._config['candle_type_def']) if self._min_days_listed < 1: diff --git a/freqtrade/plugins/pairlist/PerformanceFilter.py b/freqtrade/plugins/pairlist/PerformanceFilter.py index 5b02a47ab..8e0b407c3 100644 --- a/freqtrade/plugins/pairlist/PerformanceFilter.py +++ b/freqtrade/plugins/pairlist/PerformanceFilter.py @@ -21,7 +21,7 @@ class PerformanceFilter(IPairList): super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) self._minutes = pairlistconfig.get('minutes', 0) - self._min_profit = pairlistconfig.get('min_profit', None) + self._min_profit = pairlistconfig.get('min_profit') @property def needstickers(self) -> bool: diff --git a/freqtrade/plugins/pairlist/PriceFilter.py b/freqtrade/plugins/pairlist/PriceFilter.py index 009789eaf..4c5db52b1 100644 --- a/freqtrade/plugins/pairlist/PriceFilter.py +++ b/freqtrade/plugins/pairlist/PriceFilter.py @@ -70,7 +70,7 @@ class PriceFilter(IPairList): :param ticker: ticker dict as returned from ccxt.fetch_tickers() :return: True if the pair can stay, false if it should be removed """ - if ticker.get('last', None) is None or ticker.get('last') == 0: + if ticker.get('last') is None or ticker.get('last') == 0: self.log_once(f"Removed {pair} from whitelist, because " "ticker['last'] is empty (Usually no trade in the last 24h).", logger.info) diff --git a/freqtrade/plugins/pairlist/rangestabilityfilter.py b/freqtrade/plugins/pairlist/rangestabilityfilter.py index de016c3a6..f3e7bc0d6 100644 --- a/freqtrade/plugins/pairlist/rangestabilityfilter.py +++ b/freqtrade/plugins/pairlist/rangestabilityfilter.py @@ -27,7 +27,7 @@ class RangeStabilityFilter(IPairList): self._days = pairlistconfig.get('lookback_days', 10) self._min_rate_of_change = pairlistconfig.get('min_rate_of_change', 0.01) - self._max_rate_of_change = pairlistconfig.get('max_rate_of_change', None) + self._max_rate_of_change = pairlistconfig.get('max_rate_of_change') self._refresh_period = pairlistconfig.get('refresh_period', 1440) self._def_candletype = self._config['candle_type_def'] diff --git a/freqtrade/plugins/pairlistmanager.py b/freqtrade/plugins/pairlistmanager.py index 2ae67a157..3ddad4a5e 100644 --- a/freqtrade/plugins/pairlistmanager.py +++ b/freqtrade/plugins/pairlistmanager.py @@ -28,7 +28,7 @@ class PairListManager(LoggingMixin): self._blacklist = self._config['exchange'].get('pair_blacklist', []) self._pairlist_handlers: List[IPairList] = [] self._tickers_needed = False - for pairlist_handler_config in self._config.get('pairlists', None): + for pairlist_handler_config in self._config.get('pairlists', []): pairlist_handler = PairListResolver.load_pairlist( pairlist_handler_config['method'], exchange=exchange, diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index a8b9873d7..c8299a153 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -281,7 +281,7 @@ def get_strategy(strategy: str, config=Depends(get_config)): def list_available_pairs(timeframe: Optional[str] = None, stake_currency: Optional[str] = None, candletype: Optional[CandleType] = None, config=Depends(get_config)): - dh = get_datahandler(config['datadir'], config.get('dataformat_ohlcv', None)) + dh = get_datahandler(config['datadir'], config.get('dataformat_ohlcv')) trading_mode: TradingMode = config.get('trading_mode', TradingMode.SPOT) pair_interval = dh.ohlcv_get_available_data(config['datadir'], trading_mode) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index a98e3f96d..4c03b8bd4 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -96,7 +96,7 @@ class RPC: """ self._freqtrade = freqtrade self._config: Dict[str, Any] = freqtrade.config - if self._config.get('fiat_display_currency', None): + if self._config.get('fiat_display_currency'): self._fiat_converter = CryptoToFiatConverter() @staticmethod @@ -600,7 +600,7 @@ class RPC: else: try: pair = self._freqtrade.exchange.get_valid_pair_combination(coin, stake_currency) - rate = tickers.get(pair, {}).get('last', None) + rate = tickers.get(pair, {}).get('last') if rate: if pair.startswith(stake_currency) and not pair.endswith(stake_currency): rate = 1.0 / rate diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index f26de8b5c..81fb206cc 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -241,7 +241,7 @@ class Telegram(RPCHandler): f" {entry_side['entered'] if is_fill else entry_side['enter']} {msg['pair']}" f" (#{msg['trade_id']})\n" ) - message += f"*Enter Tag:* `{msg['enter_tag']}`\n" if msg.get('enter_tag', None) else "" + message += f"*Enter Tag:* `{msg['enter_tag']}`\n" if msg.get('enter_tag') else "" message += f"*Amount:* `{msg['amount']:.8f}`\n" if msg.get('leverage') and msg.get('leverage', 1.0) != 1.0: message += f"*Leverage:* `{msg['leverage']}`\n" @@ -254,7 +254,7 @@ class Telegram(RPCHandler): message += f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}" - if msg.get('fiat_currency', None): + if msg.get('fiat_currency'): message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" message += ")`" @@ -270,7 +270,7 @@ class Telegram(RPCHandler): msg['enter_tag'] = msg['enter_tag'] if "enter_tag" in msg.keys() else None msg['emoji'] = self._get_sell_emoji(msg) msg['leverage_text'] = (f"*Leverage:* `{msg['leverage']:.1f}`\n" - if msg.get('leverage', None) and msg.get('leverage', 1.0) != 1.0 + if msg.get('leverage') and msg.get('leverage', 1.0) != 1.0 else "") # Check if all sell properties are available. diff --git a/freqtrade/rpc/webhook.py b/freqtrade/rpc/webhook.py index a2edcbc85..1b39a29b7 100644 --- a/freqtrade/rpc/webhook.py +++ b/freqtrade/rpc/webhook.py @@ -45,21 +45,21 @@ class Webhook(RPCHandler): try: whconfig = self._config['webhook'] if msg['type'] in [RPCMessageType.ENTRY]: - valuedict = whconfig.get('webhookentry', None) + valuedict = whconfig.get('webhookentry') elif msg['type'] in [RPCMessageType.ENTRY_CANCEL]: - valuedict = whconfig.get('webhookentrycancel', None) + valuedict = whconfig.get('webhookentrycancel') elif msg['type'] in [RPCMessageType.ENTRY_FILL]: - valuedict = whconfig.get('webhookentryfill', None) + valuedict = whconfig.get('webhookentryfill') elif msg['type'] == RPCMessageType.EXIT: - valuedict = whconfig.get('webhookexit', None) + valuedict = whconfig.get('webhookexit') elif msg['type'] == RPCMessageType.EXIT_FILL: - valuedict = whconfig.get('webhookexitfill', None) + valuedict = whconfig.get('webhookexitfill') elif msg['type'] == RPCMessageType.EXIT_CANCEL: - valuedict = whconfig.get('webhookexitcancel', None) + valuedict = whconfig.get('webhookexitcancel') elif msg['type'] in (RPCMessageType.STATUS, RPCMessageType.STARTUP, RPCMessageType.WARNING): - valuedict = whconfig.get('webhookstatus', None) + valuedict = whconfig.get('webhookstatus') else: raise NotImplementedError('Unknown message type: {}'.format(msg['type'])) if not valuedict: diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 0c2197917..14e5a6743 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -131,9 +131,9 @@ class Wallets: if isinstance(balances[currency], dict): self._wallets[currency] = Wallet( currency, - balances[currency].get('free', None), - balances[currency].get('used', None), - balances[currency].get('total', None) + balances[currency].get('free'), + balances[currency].get('used'), + balances[currency].get('total') ) # Remove currencies no longer in get_balances output for currency in deepcopy(self._wallets): From d5486f17d8ad8261f109ccb400ecc59eac9affa8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 18 May 2022 10:57:19 +0200 Subject: [PATCH 140/449] Update Test to use StrategyV3 --- tests/optimize/test_backtesting_adjust_position.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/optimize/test_backtesting_adjust_position.py b/tests/optimize/test_backtesting_adjust_position.py index 5babfb548..94505e3ce 100644 --- a/tests/optimize/test_backtesting_adjust_position.py +++ b/tests/optimize/test_backtesting_adjust_position.py @@ -22,7 +22,7 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) -> default_conf.update({ "stake_amount": 100.0, "dry_run_wallet": 1000.0, - "strategy": "StrategyTestV2" + "strategy": "StrategyTestV3" }) backtesting = Backtesting(default_conf) backtesting._set_strategy(backtesting.strategylist[0]) From 736f9f4972add41a066bfc23705d1664915aa9b4 Mon Sep 17 00:00:00 2001 From: froggleston Date: Wed, 18 May 2022 12:47:37 +0100 Subject: [PATCH 141/449] Fix docs and add outer join support for merging funding rates across full timerange --- docs/configuration.md | 2 +- freqtrade/optimize/backtesting.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 5a6d5849a..4a05ad3d4 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -230,7 +230,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `dataformat_trades` | Data format to use to store historical trades data.
*Defaults to `jsongz`*.
**Datatype:** String | `position_adjustment_enable` | Enables the strategy to use position adjustments (additional buys or sells). [More information here](strategy-callbacks.md#adjust-trade-position).
[Strategy Override](#parameters-in-the-strategy).
*Defaults to `false`.*
**Datatype:** Boolean | `max_entry_position_adjustment` | Maximum additional order(s) for each open trade on top of the first entry Order. Set it to `-1` for unlimited additional orders. [More information here](strategy-callbacks.md#adjust-trade-position).
[Strategy Override](#parameters-in-the-strategy).
*Defaults to `-1`.*
**Datatype:** Positive Integer or -1 -| `futures_funding_rate` | User-specified funding rate to be used when historical funding rates are not available from the exchange. This does not overwrite real historical rates. It is recommended that this be set to 0 unless you are testing a specific coin and you understand how the funding rate will affect freqtrade's profit calculations. [More information here](configuration.md)
*Defaults to None.*
**Datatype:** Float +| `futures_funding_rate` | User-specified funding rate to be used when historical funding rates are not available from the exchange. This does not overwrite real historical rates. It is recommended that this be set to 0 unless you are testing a specific coin and you understand how the funding rate will affect freqtrade's profit calculations. [More information here](leverage.md)
*Defaults to None.*
**Datatype:** Float ### Parameters in the strategy diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 8d5a5fcea..78faf65be 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -294,9 +294,15 @@ class Backtesting: self.futures_data[pair] = mark_rates_dict[pair] else: - self.futures_data[pair] = mark_rates_dict[pair].merge( - funding_rates_dict[pair], on='date', - how="inner", suffixes=["_fund", "_mark"]) + if "futures_funding_rate" in self.config: + self.futures_data[pair] = mark_rates_dict[pair].merge( + funding_rates_dict[pair], on='date', + how="outer", suffixes=["_fund", "_mark"]).fillna( + self.config.get('futures_funding_rate')) + else: + self.futures_data[pair] = mark_rates_dict[pair].merge( + funding_rates_dict[pair], on='date', + how="inner", suffixes=["_fund", "_mark"]) if unavailable_pairs: raise OperationalException( From 363098d32dcb729f4b6f3e3e2aadae492c97138e Mon Sep 17 00:00:00 2001 From: froggleston Date: Wed, 18 May 2022 12:56:43 +0100 Subject: [PATCH 142/449] Fix reversed makr/funding_rate columns --- freqtrade/optimize/backtesting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 78faf65be..a80266b2c 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -297,12 +297,12 @@ class Backtesting: if "futures_funding_rate" in self.config: self.futures_data[pair] = mark_rates_dict[pair].merge( funding_rates_dict[pair], on='date', - how="outer", suffixes=["_fund", "_mark"]).fillna( + how="outer", suffixes=["_mark", "_fund"]).fillna( self.config.get('futures_funding_rate')) else: self.futures_data[pair] = mark_rates_dict[pair].merge( funding_rates_dict[pair], on='date', - how="inner", suffixes=["_fund", "_mark"]) + how="inner", suffixes=["_mark", "_fund"]) if unavailable_pairs: raise OperationalException( From 0a95ef6ab2e0cf369143f7af6be6ee0d2c3d15a5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 19 May 2022 06:42:38 +0200 Subject: [PATCH 143/449] Don't reset open orders in dry-run on restart --- freqtrade/exchange/exchange.py | 6 ++++ freqtrade/persistence/models.py | 15 --------- freqtrade/persistence/trade_model.py | 27 +++++++++++++++ tests/test_persistence.py | 50 ---------------------------- 4 files changed, 33 insertions(+), 65 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d2766cd6d..4ee9d3f63 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -953,6 +953,12 @@ class Exchange: order = self.check_dry_limit_order_filled(order) return order except KeyError as e: + from freqtrade.persistence import Order + order = Order.order_by_id(order_id) + if order: + x = order.to_ccxt_object() + self._dry_run_open_orders[order_id] = x + return x # Gracefully handle errors with dry-run orders. raise InvalidOrderException( f'Tried to get an invalid dry-run-order (id: {order_id}). Message: {e}') from e diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index c31e50892..1e0a70784 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -64,10 +64,6 @@ def init_db(db_url: str, clean_open_orders: bool = False) -> None: _DECL_BASE.metadata.create_all(engine) check_migrate(engine, decl_base=_DECL_BASE, previous_tables=previous_tables) - # Clean dry_run DB if the db is not in-memory - if clean_open_orders and db_url != 'sqlite://': - clean_dry_run_db() - def cleanup_db() -> None: """ @@ -76,14 +72,3 @@ def cleanup_db() -> None: """ Trade.commit() - -def clean_dry_run_db() -> None: - """ - Remove open_order_id from a Dry_run DB - :return: None - """ - for trade in Trade.query.filter(Trade.open_order_id.isnot(None)).all(): - # Check we are updating only a dry_run order not a prod one - if 'dry_run' in trade.open_order_id: - trade.open_order_id = None - Trade.commit() diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 358e776e3..57aeda76c 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -118,6 +118,25 @@ class Order(_DECL_BASE): self.order_filled_date = datetime.now(timezone.utc) self.order_update_date = datetime.now(timezone.utc) + def to_ccxt_object(self) -> Dict[str, Any]: + return { + 'id': self.order_id, + 'symbol': self.ft_pair, + 'price': self.price, + 'average': self.average, + 'amount': self.amount, + 'cost': self.cost, + 'type': self.order_type, + 'side': self.ft_order_side, + 'filled': self.filled, + 'remaining': self.remaining, + 'datetime': self.order_date_utc.strftime('%Y-%m-%dT%H:%M:%S.%3f'), + 'timestamp': int(self.order_date_utc.timestamp() * 1000), + 'status': self.status, + 'fee': None, + 'info': {}, + } + def to_json(self, entry_side: str) -> Dict[str, Any]: return { 'pair': self.ft_pair, @@ -190,6 +209,14 @@ class Order(_DECL_BASE): """ return Order.query.filter(Order.ft_is_open.is_(True)).all() + @staticmethod + def order_by_id(order_id: str) -> Optional['Order']: + """ + Retrieve order based on order_id + :return: Order or None + """ + return Order.query.filter(Order.order_id == order_id).first() + class LocalTrade(): """ diff --git a/tests/test_persistence.py b/tests/test_persistence.py index d84415938..8d033663e 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -1129,56 +1129,6 @@ def test_calc_profit( assert pytest.approx(trade.calc_profit_ratio(rate=close_rate)) == round(profit_ratio, 8) -@pytest.mark.usefixtures("init_persistence") -def test_clean_dry_run_db(default_conf, fee): - - # Simulate dry_run entries - trade = Trade( - pair='ADA/USDT', - stake_amount=0.001, - amount=123.0, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.123, - exchange='binance', - open_order_id='dry_run_buy_12345' - ) - Trade.query.session.add(trade) - - trade = Trade( - pair='ETC/BTC', - stake_amount=0.001, - amount=123.0, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.123, - exchange='binance', - open_order_id='dry_run_sell_12345' - ) - Trade.query.session.add(trade) - - # Simulate prod entry - trade = Trade( - pair='ETC/BTC', - stake_amount=0.001, - amount=123.0, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_rate=0.123, - exchange='binance', - open_order_id='prod_buy_12345' - ) - Trade.query.session.add(trade) - - # We have 3 entries: 2 dry_run, 1 prod - assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 3 - - clean_dry_run_db() - - # We have now only the prod - assert len(Trade.query.filter(Trade.open_order_id.isnot(None)).all()) == 1 - - def test_migrate_new(mocker, default_conf, fee, caplog): """ Test Database migration (starting with new pairformat) From a3d9384bc0665a06c25400948ad4b45fdc2e55c1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 19 May 2022 06:45:20 +0200 Subject: [PATCH 144/449] Remove clean-dry-run code --- freqtrade/commands/db_commands.py | 4 ++-- freqtrade/commands/list_commands.py | 2 +- freqtrade/data/btanalysis.py | 2 +- freqtrade/freqtradebot.py | 2 +- freqtrade/persistence/__init__.py | 2 +- freqtrade/persistence/models.py | 4 +--- tests/commands/test_commands.py | 2 +- tests/conftest.py | 2 +- tests/test_persistence.py | 20 ++++++++++---------- 9 files changed, 19 insertions(+), 21 deletions(-) diff --git a/freqtrade/commands/db_commands.py b/freqtrade/commands/db_commands.py index d93aafcb6..618b5cb6e 100644 --- a/freqtrade/commands/db_commands.py +++ b/freqtrade/commands/db_commands.py @@ -19,9 +19,9 @@ def start_convert_db(args: Dict[str, Any]) -> None: config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) - init_db(config['db_url'], False) + init_db(config['db_url']) session_target = Trade._session - init_db(config['db_url_from'], False) + init_db(config['db_url_from']) logger.info("Starting db migration.") trade_count = 0 diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index 2a5223917..eb761eeec 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -212,7 +212,7 @@ def start_show_trades(args: Dict[str, Any]) -> None: raise OperationalException("--db-url is required for this command.") logger.info(f'Using DB: "{parse_db_uri_for_logging(config["db_url"])}"') - init_db(config['db_url'], clean_open_orders=False) + init_db(config['db_url']) tfilter = [] if config.get('trade_ids'): diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index e29d9ebe4..fef432576 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -353,7 +353,7 @@ def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataF Can also serve as protection to load the correct result. :return: Dataframe containing Trades """ - init_db(db_url, clean_open_orders=False) + init_db(db_url) filters = [] if strategy: diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 315db3ae6..da35c12ff 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -67,7 +67,7 @@ class FreqtradeBot(LoggingMixin): self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) - init_db(self.config.get('db_url', None), clean_open_orders=self.config['dry_run']) + init_db(self.config.get('db_url', None)) self.wallets = Wallets(self.config, self.exchange) diff --git a/freqtrade/persistence/__init__.py b/freqtrade/persistence/__init__.py index ab6e2f6a5..f4e7470a7 100644 --- a/freqtrade/persistence/__init__.py +++ b/freqtrade/persistence/__init__.py @@ -1,5 +1,5 @@ # flake8: noqa: F401 -from freqtrade.persistence.models import clean_dry_run_db, cleanup_db, init_db +from freqtrade.persistence.models import cleanup_db, init_db from freqtrade.persistence.pairlock_middleware import PairLocks from freqtrade.persistence.trade_model import LocalTrade, Order, Trade diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 1e0a70784..154f2590a 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -21,14 +21,12 @@ logger = logging.getLogger(__name__) _SQL_DOCS_URL = 'http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls' -def init_db(db_url: str, clean_open_orders: bool = False) -> None: +def init_db(db_url: str) -> None: """ Initializes this module with the given config, registers all known command handlers and starts polling for message updates :param db_url: Database to use - :param clean_open_orders: Remove open orders from the database. - Useful for dry-run or if all orders have been reset on the exchange. :return: None """ kwargs = {} diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index b37edf9c7..d6e80675e 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1495,7 +1495,7 @@ def test_start_convert_db(mocker, fee, tmpdir, caplog): ] assert not db_src_file.is_file() - init_db(db_from, False) + init_db(db_from) create_mock_trades(fee) diff --git a/tests/conftest.py b/tests/conftest.py index cc07de1de..8719c70f4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -384,7 +384,7 @@ def patch_coingekko(mocker) -> None: @pytest.fixture(scope='function') def init_persistence(default_conf): - init_db(default_conf['db_url'], default_conf['dry_run']) + init_db(default_conf['db_url']) @pytest.fixture(scope="function") diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 8d033663e..ef17c4d1c 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -13,7 +13,7 @@ from sqlalchemy import create_engine, text from freqtrade import constants from freqtrade.enums import TradingMode from freqtrade.exceptions import DependencyException, OperationalException -from freqtrade.persistence import LocalTrade, Order, Trade, clean_dry_run_db, init_db +from freqtrade.persistence import LocalTrade, Order, Trade, init_db from freqtrade.persistence.migrations import get_last_sequence_ids, set_sequence_ids from freqtrade.persistence.models import PairLock from tests.conftest import create_mock_trades, create_mock_trades_with_leverage, log_has, log_has_re @@ -24,7 +24,7 @@ spot, margin, futures = TradingMode.SPOT, TradingMode.MARGIN, TradingMode.FUTURE def test_init_create_session(default_conf): # Check if init create a session - init_db(default_conf['db_url'], default_conf['dry_run']) + init_db(default_conf['db_url']) assert hasattr(Trade, '_session') assert 'scoped_session' in type(Trade._session).__name__ @@ -36,7 +36,7 @@ def test_init_custom_db_url(default_conf, tmpdir): default_conf.update({'db_url': f'sqlite:///{filename}'}) - init_db(default_conf['db_url'], default_conf['dry_run']) + init_db(default_conf['db_url']) assert Path(filename).is_file() r = Trade._session.execute(text("PRAGMA journal_mode")) assert r.first() == ('wal',) @@ -45,10 +45,10 @@ def test_init_custom_db_url(default_conf, tmpdir): def test_init_invalid_db_url(): # Update path to a value other than default, but still in-memory with pytest.raises(OperationalException, match=r'.*no valid database URL*'): - init_db('unknown:///some.url', True) + init_db('unknown:///some.url') with pytest.raises(OperationalException, match=r'Bad db-url.*For in-memory database, pl.*'): - init_db('sqlite:///', True) + init_db('sqlite:///') def test_init_prod_db(default_conf, mocker): @@ -57,7 +57,7 @@ def test_init_prod_db(default_conf, mocker): create_engine_mock = mocker.patch('freqtrade.persistence.models.create_engine', MagicMock()) - init_db(default_conf['db_url'], default_conf['dry_run']) + init_db(default_conf['db_url']) assert create_engine_mock.call_count == 1 assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:///tradesv3.sqlite' @@ -70,7 +70,7 @@ def test_init_dryrun_db(default_conf, tmpdir): 'db_url': f'sqlite:///{filename}' }) - init_db(default_conf['db_url'], default_conf['dry_run']) + init_db(default_conf['db_url']) assert Path(filename).is_file() @@ -1260,7 +1260,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): connection.execute(text("create table trades_bak1 as select * from trades")) # Run init to test migration - init_db(default_conf['db_url'], default_conf['dry_run']) + init_db(default_conf['db_url']) assert len(Trade.query.filter(Trade.id == 1).all()) == 1 trade = Trade.query.filter(Trade.id == 1).first() @@ -1343,7 +1343,7 @@ def test_migrate_too_old(mocker, default_conf, fee, caplog): # Run init to test migration with pytest.raises(OperationalException, match=r'Your database seems to be very old'): - init_db(default_conf['db_url'], default_conf['dry_run']) + init_db(default_conf['db_url']) def test_migrate_get_last_sequence_ids(): @@ -1417,7 +1417,7 @@ def test_migrate_pairlocks(mocker, default_conf, fee, caplog): connection.execute(text(create_index2)) connection.execute(text(create_index3)) - init_db(default_conf['db_url'], default_conf['dry_run']) + init_db(default_conf['db_url']) assert len(PairLock.query.all()) == 2 assert len(PairLock.query.filter(PairLock.pair == '*').all()) == 1 From 5e18e51ce0ca1a36ef1d73f31f0d09a194a254dc Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 19 May 2022 06:56:38 +0200 Subject: [PATCH 145/449] Fix some tests --- tests/test_freqtradebot.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index e19d5f36a..d2df4e6a5 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3044,6 +3044,7 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order trade.entry_side = "buy" trade.open_rate = 200 trade.entry_side = "buy" + trade.open_order_id = "open_order_noop" l_order['filled'] = 0.0 l_order['status'] = 'open' reason = CANCEL_REASON['TIMEOUT'] @@ -4786,9 +4787,6 @@ def test_startup_update_open_orders(mocker, default_conf_usdt, fee, caplog, is_s freqtrade.config['dry_run'] = False freqtrade.startup_update_open_orders() - assert log_has_re(r"Error updating Order .*", caplog) - caplog.clear() - assert len(Order.get_open_orders()) == 3 matching_buy_order = mock_order_4(is_short=is_short) matching_buy_order.update({ @@ -4799,6 +4797,11 @@ def test_startup_update_open_orders(mocker, default_conf_usdt, fee, caplog, is_s # Only stoploss and sell orders are kept open assert len(Order.get_open_orders()) == 2 + caplog.clear() + mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=InvalidOrderException) + freqtrade.startup_update_open_orders() + assert log_has_re(r"Error updating Order .*", caplog) + @pytest.mark.usefixtures("init_persistence") @pytest.mark.parametrize("is_short", [False, True]) From 56a73575a13bccf5fddc8fa4d9f85ac7d28ee214 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 19 May 2022 19:29:39 +0200 Subject: [PATCH 146/449] Add explicit test for order_to_ccxt --- freqtrade/persistence/trade_model.py | 2 +- tests/conftest.py | 1 + tests/test_persistence.py | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 57aeda76c..d2abb48d6 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -130,7 +130,7 @@ class Order(_DECL_BASE): 'side': self.ft_order_side, 'filled': self.filled, 'remaining': self.remaining, - 'datetime': self.order_date_utc.strftime('%Y-%m-%dT%H:%M:%S.%3f'), + 'datetime': self.order_date_utc.strftime('%Y-%m-%dT%H:%M:%S.%f'), 'timestamp': int(self.order_date_utc.timestamp() * 1000), 'status': self.status, 'fee': None, diff --git a/tests/conftest.py b/tests/conftest.py index 8719c70f4..02738b0e9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1616,6 +1616,7 @@ def limit_buy_order_open(): 'datetime': arrow.utcnow().isoformat(), 'price': 0.00001099, 'amount': 90.99181073, + 'average': None, 'filled': 0.0, 'cost': 0.0009999, 'remaining': 90.99181073, diff --git a/tests/test_persistence.py b/tests/test_persistence.py index ef17c4d1c..be19a3f5f 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -2671,3 +2671,21 @@ def test_select_filled_orders(fee): orders = trades[4].select_filled_orders('sell') assert orders is not None assert len(orders) == 0 + + +@pytest.mark.usefixtures("init_persistence") +def test_order_to_ccxt(limit_buy_order_open): + + order = Order.parse_from_ccxt_object(limit_buy_order_open, 'mocked', 'buy') + order.query.session.add(order) + Order.query.session.commit() + + order_resp = Order.order_by_id(limit_buy_order_open['id']) + assert order_resp + + raw_order = order_resp.to_ccxt_object() + del raw_order['fee'] + del raw_order['datetime'] + del raw_order['info'] + del limit_buy_order_open['datetime'] + assert raw_order == limit_buy_order_open From 219363fffb37e972ca426ce3b87fa3c1b959577e Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 19 May 2022 19:53:23 +0200 Subject: [PATCH 147/449] Check for both ask and bid in SpreadFilter closes #6865 --- freqtrade/plugins/pairlist/SpreadFilter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/plugins/pairlist/SpreadFilter.py b/freqtrade/plugins/pairlist/SpreadFilter.py index d1f88d2a5..43856b451 100644 --- a/freqtrade/plugins/pairlist/SpreadFilter.py +++ b/freqtrade/plugins/pairlist/SpreadFilter.py @@ -50,7 +50,7 @@ class SpreadFilter(IPairList): :param ticker: ticker dict as returned from ccxt.fetch_tickers() :return: True if the pair can stay, false if it should be removed """ - if 'bid' in ticker and 'ask' in ticker and ticker['ask']: + if 'bid' in ticker and 'ask' in ticker and ticker['ask'] and ticker['bid']: spread = 1 - ticker['bid'] / ticker['ask'] if spread > self._max_spread_ratio: self.log_once(f"Removed {pair} from whitelist, because spread " From 46ea135b6bf4e3b5f2e54e0c951ba40dde7cf9f2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 19 May 2022 19:42:00 +0200 Subject: [PATCH 148/449] Update dry-run considerations --- docs/configuration.md | 2 +- freqtrade/persistence/models.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 80cd52c5b..7dc907b9f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -583,7 +583,7 @@ Once you will be happy with your bot performance running in the Dry-run mode, yo * Market orders fill based on orderbook volume the moment the order is placed. * Limit orders fill once the price reaches the defined level - or time out based on `unfilledtimeout` settings. * In combination with `stoploss_on_exchange`, the stop_loss price is assumed to be filled. -* Open orders (not trades, which are stored in the database) are reset on bot restart. +* Open orders (not trades, which are stored in the database) are kept open after bot restarts, with the assumption that they were not filled while being offline. ## Switch to production mode diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 154f2590a..86d2f9f9c 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -69,4 +69,3 @@ def cleanup_db() -> None: :return: None """ Trade.commit() - From 2cf17e04be3d6cbd5444f6fb2f4e03c90ab3d022 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 20 May 2022 06:26:16 +0200 Subject: [PATCH 149/449] Init persistence for tests that use dry-run orders --- tests/exchange/test_exchange.py | 3 +++ tests/exchange/test_ftx.py | 1 + tests/exchange/test_gateio.py | 1 + 3 files changed, 5 insertions(+) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 53e6cc3f3..07b2147d5 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2808,6 +2808,7 @@ def test_get_historic_trades_notsupported(default_conf, mocker, caplog, exchange until=trades_history[-1][0]) +@pytest.mark.usefixtures("init_persistence") @pytest.mark.parametrize("exchange_name", EXCHANGES) def test_cancel_order_dry_run(default_conf, mocker, exchange_name): default_conf['dry_run'] = True @@ -2973,6 +2974,7 @@ def test_cancel_stoploss_order_with_result(default_conf, mocker, exchange_name): exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=123) +@pytest.mark.usefixtures("init_persistence") @pytest.mark.parametrize("exchange_name", EXCHANGES) def test_fetch_order(default_conf, mocker, exchange_name, caplog): default_conf['dry_run'] = True @@ -3025,6 +3027,7 @@ def test_fetch_order(default_conf, mocker, exchange_name, caplog): order_id='_', pair='TKN/BTC') +@pytest.mark.usefixtures("init_persistence") @pytest.mark.parametrize("exchange_name", EXCHANGES) def test_fetch_stoploss_order(default_conf, mocker, exchange_name): # Don't test FTX here - that needs a separate test diff --git a/tests/exchange/test_ftx.py b/tests/exchange/test_ftx.py index 0f16d4433..5a83b964a 100644 --- a/tests/exchange/test_ftx.py +++ b/tests/exchange/test_ftx.py @@ -174,6 +174,7 @@ def test_stoploss_adjust_ftx(mocker, default_conf, sl1, sl2, sl3, side): assert not exchange.stoploss_adjust(sl3, order, side=side) +@pytest.mark.usefixtures("init_persistence") def test_fetch_stoploss_order_ftx(default_conf, mocker, limit_sell_order, limit_buy_order): default_conf['dry_run'] = True order = MagicMock() diff --git a/tests/exchange/test_gateio.py b/tests/exchange/test_gateio.py index ad30a7d86..92f8186a6 100644 --- a/tests/exchange/test_gateio.py +++ b/tests/exchange/test_gateio.py @@ -34,6 +34,7 @@ def test_validate_order_types_gateio(default_conf, mocker): ExchangeResolver.load_exchange('gateio', default_conf, True) +@pytest.mark.usefixtures("init_persistence") def test_fetch_stoploss_order_gateio(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf, id='gateio') From b3acfb3c6f5bf76b12cca14d2cb5985596b7ea4e Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 20 May 2022 06:55:51 +0200 Subject: [PATCH 150/449] Bump ccxt to 1.83.12 closes #6849 --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 90ddcd1b6..a3c4c3dca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.3 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.82.61 +ccxt==1.83.12 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 diff --git a/setup.py b/setup.py index fadd4629f..7aa56bf81 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ setup( ], install_requires=[ # from requirements.txt - 'ccxt>=1.80.67', + 'ccxt>=1.83.12', 'SQLAlchemy', 'python-telegram-bot>=13.4', 'arrow>=0.17.0', From 843bf0631e661dc93be9741255831c06a76c39ce Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 30 Apr 2022 14:57:15 +0200 Subject: [PATCH 151/449] Remove Sponsored Promotions --- README.md | 4 ---- docs/index.md | 4 ---- 2 files changed, 8 deletions(-) diff --git a/README.md b/README.md index cad39f9ac..6c3c8fe25 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,6 @@ Freqtrade is a free and open source crypto trading bot written in Python. It is ![freqtrade](https://raw.githubusercontent.com/freqtrade/freqtrade/develop/docs/assets/freqtrade-screenshot.png) -## Sponsored promotion - -[![tokenbot-promo](https://raw.githubusercontent.com/freqtrade/freqtrade/develop/docs/assets/TokenBot-Freqtrade-banner.png)](https://tokenbot.com/?utm_source=github&utm_medium=freqtrade&utm_campaign=algodevs) - ## Disclaimer This software is for educational purposes only. Do not risk money which diff --git a/docs/index.md b/docs/index.md index e0a88a381..16c4ded94 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,10 +22,6 @@ Freqtrade is a free and open source crypto trading bot written in Python. It is ![freqtrade screenshot](assets/freqtrade-screenshot.png) -## Sponsored promotion - -[![tokenbot-promo](assets/TokenBot-Freqtrade-banner.png)](https://tokenbot.com/?utm_source=github&utm_medium=freqtrade&utm_campaign=algodevs) - ## Features - Develop your Strategy: Write your strategy in python, using [pandas](https://pandas.pydata.org/). Example strategies to inspire you are available in the [strategy repository](https://github.com/freqtrade/freqtrade-strategies). From c3e3188c6a66682fb7b9511b8615f0e5fa5087c6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 20 May 2022 11:30:25 +0200 Subject: [PATCH 152/449] Rename variable --- freqtrade/exchange/exchange.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 4ee9d3f63..06a30c99b 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -956,9 +956,9 @@ class Exchange: from freqtrade.persistence import Order order = Order.order_by_id(order_id) if order: - x = order.to_ccxt_object() - self._dry_run_open_orders[order_id] = x - return x + ccxt_order = order.to_ccxt_object() + self._dry_run_open_orders[order_id] = ccxt_order + return ccxt_order # Gracefully handle errors with dry-run orders. raise InvalidOrderException( f'Tried to get an invalid dry-run-order (id: {order_id}). Message: {e}') from e From c499a92f57cccf520f3d6f19941857af87fac5aa Mon Sep 17 00:00:00 2001 From: froggleston Date: Fri, 20 May 2022 11:48:53 +0100 Subject: [PATCH 153/449] Remove surplus mark columns, and make fillna on funding rate only --- freqtrade/optimize/backtesting.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index a80266b2c..99bddbf8a 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -280,10 +280,6 @@ class Backtesting: and len(funding_rates_dict[pair]) == 0 and "futures_funding_rate" in self.config): mark_rates_dict[pair]["open_fund"] = self.config.get('futures_funding_rate') - mark_rates_dict[pair]["close_fund"] = 0.0 - mark_rates_dict[pair]["high_fund"] = 0.0 - mark_rates_dict[pair]["low_fund"] = 0.0 - mark_rates_dict[pair]["volume_fund"] = 0.0 mark_rates_dict[pair].rename( columns={'open': 'open_mark', 'close': 'close_mark', @@ -297,7 +293,7 @@ class Backtesting: if "futures_funding_rate" in self.config: self.futures_data[pair] = mark_rates_dict[pair].merge( funding_rates_dict[pair], on='date', - how="outer", suffixes=["_mark", "_fund"]).fillna( + how="outer", suffixes=["_mark", "_fund"])['open_fund'].fillna( self.config.get('futures_funding_rate')) else: self.futures_data[pair] = mark_rates_dict[pair].merge( From 0e158b66b0e089f12f79a1217cce431ec3fc7a4f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 May 2022 08:26:44 +0200 Subject: [PATCH 154/449] Update docs link --- docs/configuration.md | 2 +- docs/leverage.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 4a05ad3d4..949cac91d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -230,7 +230,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `dataformat_trades` | Data format to use to store historical trades data.
*Defaults to `jsongz`*.
**Datatype:** String | `position_adjustment_enable` | Enables the strategy to use position adjustments (additional buys or sells). [More information here](strategy-callbacks.md#adjust-trade-position).
[Strategy Override](#parameters-in-the-strategy).
*Defaults to `false`.*
**Datatype:** Boolean | `max_entry_position_adjustment` | Maximum additional order(s) for each open trade on top of the first entry Order. Set it to `-1` for unlimited additional orders. [More information here](strategy-callbacks.md#adjust-trade-position).
[Strategy Override](#parameters-in-the-strategy).
*Defaults to `-1`.*
**Datatype:** Positive Integer or -1 -| `futures_funding_rate` | User-specified funding rate to be used when historical funding rates are not available from the exchange. This does not overwrite real historical rates. It is recommended that this be set to 0 unless you are testing a specific coin and you understand how the funding rate will affect freqtrade's profit calculations. [More information here](leverage.md)
*Defaults to None.*
**Datatype:** Float +| `futures_funding_rate` | User-specified funding rate to be used when historical funding rates are not available from the exchange. This does not overwrite real historical rates. It is recommended that this be set to 0 unless you are testing a specific coin and you understand how the funding rate will affect freqtrade's profit calculations. [More information here](leverage.md#unavailable-funding-rates)
*Defaults to None.*
**Datatype:** Float ### Parameters in the strategy diff --git a/docs/leverage.md b/docs/leverage.md index 58e7cc778..2ee6f8444 100644 --- a/docs/leverage.md +++ b/docs/leverage.md @@ -107,7 +107,7 @@ For futures data, exchanges commonly provide the futures candles, the marks, and !!! Warning "This will mean your backtests are inaccurate." This will not overwrite funding rates that are available from the exchange, but bear in mind that setting a false funding rate will mean backtesting results will be inaccurate for historical timeranges where funding rates are not available. - + ### Developer #### Margin mode From 6bd5535d6c3476d36bafdf73d02926c562546fc6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 May 2022 08:31:34 +0200 Subject: [PATCH 155/449] Use exchange method to combine funding and mark candles --- freqtrade/exchange/exchange.py | 2 +- freqtrade/optimize/backtesting.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d2766cd6d..65d9909c6 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -2420,7 +2420,7 @@ class Exchange: :param mark_rates: Dataframe containing Mark rates (Type mark_ohlcv_price) """ - return funding_rates.merge(mark_rates, on='date', how="inner", suffixes=["_fund", "_mark"]) + return mark_rates.merge(funding_rates, on='date', how="inner", suffixes=["_mark", "_fund"]) def calculate_funding_fees( self, diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 99bddbf8a..3041136a3 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -296,9 +296,10 @@ class Backtesting: how="outer", suffixes=["_mark", "_fund"])['open_fund'].fillna( self.config.get('futures_funding_rate')) else: - self.futures_data[pair] = mark_rates_dict[pair].merge( - funding_rates_dict[pair], on='date', - how="inner", suffixes=["_mark", "_fund"]) + self.futures_data[pair] = self.exchange.combine_funding_and_mark( + funding_rates=funding_rates_dict[pair], + mark_rates=mark_rates_dict[pair] + ) if unavailable_pairs: raise OperationalException( From 2df42a3035902028dfbe50839cd685be78f2e0c9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 May 2022 08:50:39 +0200 Subject: [PATCH 156/449] Move "funding fillup" logic to exchange class --- freqtrade/exchange/exchange.py | 23 +++++++++++++++++++++-- freqtrade/optimize/backtesting.py | 29 +++++------------------------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 65d9909c6..9372c77b7 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -2413,14 +2413,33 @@ class Exchange: ) @staticmethod - def combine_funding_and_mark(funding_rates: DataFrame, mark_rates: DataFrame) -> DataFrame: + def combine_funding_and_mark(funding_rates: DataFrame, mark_rates: DataFrame, + futures_funding_rate: Optional[int] = None) -> DataFrame: """ Combine funding-rates and mark-rates dataframes :param funding_rates: Dataframe containing Funding rates (Type FUNDING_RATE) :param mark_rates: Dataframe containing Mark rates (Type mark_ohlcv_price) + :param futures_funding_rate: Fake funding rate to use if funding_rates are not available """ + if futures_funding_rate is None: + return mark_rates.merge( + funding_rates, on='date', how="inner", suffixes=["_mark", "_fund"]) + else: + if len(funding_rates) == 0: + # No funding rate candles - full fillup with fallback variable + mark_rates['open_fund'] = futures_funding_rate + return mark_rates.rename( + columns={'open': 'open_mark', + 'close': 'close_mark', + 'high': 'high_mark', + 'low': 'low_mark', + 'volume': 'volume_mark'}) - return mark_rates.merge(funding_rates, on='date', how="inner", suffixes=["_mark", "_fund"]) + else: + # Fill up missing funding_rate candles with fallback value + return mark_rates.merge( + funding_rates, on='date', how="outer", suffixes=["_mark", "_fund"] + )['open_fund'].fillna(futures_funding_rate) def calculate_funding_fees( self, diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 3041136a3..2c34e29b0 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -276,30 +276,11 @@ class Backtesting: unavailable_pairs.append(pair) continue - if (pair in mark_rates_dict - and len(funding_rates_dict[pair]) == 0 - and "futures_funding_rate" in self.config): - mark_rates_dict[pair]["open_fund"] = self.config.get('futures_funding_rate') - mark_rates_dict[pair].rename( - columns={'open': 'open_mark', - 'close': 'close_mark', - 'high': 'high_mark', - 'low': 'low_mark', - 'volume': 'volume_mark'}, - inplace=True) - - self.futures_data[pair] = mark_rates_dict[pair] - else: - if "futures_funding_rate" in self.config: - self.futures_data[pair] = mark_rates_dict[pair].merge( - funding_rates_dict[pair], on='date', - how="outer", suffixes=["_mark", "_fund"])['open_fund'].fillna( - self.config.get('futures_funding_rate')) - else: - self.futures_data[pair] = self.exchange.combine_funding_and_mark( - funding_rates=funding_rates_dict[pair], - mark_rates=mark_rates_dict[pair] - ) + self.futures_data[pair] = self.exchange.combine_funding_and_mark( + funding_rates=funding_rates_dict[pair], + mark_rates=mark_rates_dict[pair], + futures_funding_rate=self.config.get('futures_funding_rate'), + ) if unavailable_pairs: raise OperationalException( From 0d388b561bca0af4f2b0ee958632cea3b61824f2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 May 2022 09:03:30 +0200 Subject: [PATCH 157/449] Add test for "combine_funding_and_mark", fix bug --- freqtrade/exchange/exchange.py | 6 ++-- tests/exchange/test_exchange.py | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 9372c77b7..d30c5fc2f 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -2437,9 +2437,11 @@ class Exchange: else: # Fill up missing funding_rate candles with fallback value - return mark_rates.merge( + combined = mark_rates.merge( funding_rates, on='date', how="outer", suffixes=["_mark", "_fund"] - )['open_fund'].fillna(futures_funding_rate) + ) + combined['open_fund'] = combined['open_fund'].fillna(futures_funding_rate) + return combined def calculate_funding_fees( self, diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 53e6cc3f3..37f4dedbe 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3912,6 +3912,70 @@ def test_calculate_funding_fees( ) == kraken_fee +@pytest.mark.parametrize( + 'mark_price,funding_rate,futures_funding_rate', [ + (1000, 0.001, None), + (1000, 0.001, 0.01), + (1000, 0.001, 0.0), + (1000, 0.001, -0.01), + ]) +def test_combine_funding_and_mark( + default_conf, + mocker, + funding_rate, + mark_price, + futures_funding_rate, +): + exchange = get_patched_exchange(mocker, default_conf) + prior2_date = timeframe_to_prev_date('1h', datetime.now(timezone.utc) - timedelta(hours=2)) + prior_date = timeframe_to_prev_date('1h', datetime.now(timezone.utc) - timedelta(hours=1)) + trade_date = timeframe_to_prev_date('1h', datetime.now(timezone.utc)) + funding_rates = DataFrame([ + {'date': prior2_date, 'open': funding_rate}, + {'date': prior_date, 'open': funding_rate}, + {'date': trade_date, 'open': funding_rate}, + ]) + mark_rates = DataFrame([ + {'date': prior2_date, 'open': mark_price}, + {'date': prior_date, 'open': mark_price}, + {'date': trade_date, 'open': mark_price}, + ]) + + df = exchange.combine_funding_and_mark(funding_rates, mark_rates, futures_funding_rate) + assert 'open_mark' in df.columns + assert 'open_fund' in df.columns + assert len(df) == 3 + + funding_rates = DataFrame([ + {'date': trade_date, 'open': funding_rate}, + ]) + mark_rates = DataFrame([ + {'date': prior2_date, 'open': mark_price}, + {'date': prior_date, 'open': mark_price}, + {'date': trade_date, 'open': mark_price}, + ]) + df = exchange.combine_funding_and_mark(funding_rates, mark_rates, futures_funding_rate) + + if futures_funding_rate is not None: + assert len(df) == 3 + assert df.iloc[0]['open_fund'] == futures_funding_rate + assert df.iloc[1]['open_fund'] == futures_funding_rate + assert df.iloc[2]['open_fund'] == funding_rate + else: + assert len(df) == 1 + + # Empty funding rates + funding_rates = DataFrame([], columns=['date', 'open']) + df = exchange.combine_funding_and_mark(funding_rates, mark_rates, futures_funding_rate) + if futures_funding_rate is not None: + assert len(df) == 3 + assert df.iloc[0]['open_fund'] == futures_funding_rate + assert df.iloc[1]['open_fund'] == futures_funding_rate + assert df.iloc[2]['open_fund'] == futures_funding_rate + else: + assert len(df) == 0 + + def test_get_or_calculate_liquidation_price(mocker, default_conf): api_mock = MagicMock() From 963cc17c18c171d34f51add0a344a9c7633dbc56 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 May 2022 16:05:00 +0200 Subject: [PATCH 158/449] Update leveraged tiers --- .../exchange/binance_leverage_tiers.json | 15933 ++++++++-------- tests/conftest.py | 255 +- 2 files changed, 8283 insertions(+), 7905 deletions(-) diff --git a/freqtrade/exchange/binance_leverage_tiers.json b/freqtrade/exchange/binance_leverage_tiers.json index ddffe1250..9292509bf 100644 --- a/freqtrade/exchange/binance_leverage_tiers.json +++ b/freqtrade/exchange/binance_leverage_tiers.json @@ -1,91 +1,195 @@ { "RAY/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "API3/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -93,106 +197,113 @@ ], "SUSHI/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 50000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "2000000", + "notionalCap": "50000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -200,91 +311,97 @@ ], "CVC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -292,91 +409,97 @@ ], "BTS/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -384,91 +507,97 @@ ], "HOT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -476,91 +605,97 @@ ], "ZRX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -568,91 +703,97 @@ ], "QTUM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -660,91 +801,97 @@ ], "IOTA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -752,151 +899,161 @@ ], "BTC/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.004, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.004", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.005, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.005", "cum": "50.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "3", "initialLeverage": "20", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.01", "cum": "1300.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 7500000, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 7500000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "7500000", - "minNotional": "1000000", + "notionalCap": "7500000", + "notionalFloor": "1000000", "maintMarginRatio": "0.025", "cum": "16300.0" } }, { - "tier": 5, - "minNotional": 7500000, - "maxNotional": 40000000, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 7500000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 6, + "maxLeverage": 6.0, "info": { "bracket": "5", "initialLeverage": "6", - "maxNotional": "40000000", - "minNotional": "7500000", + "notionalCap": "40000000", + "notionalFloor": "7500000", "maintMarginRatio": "0.05", "cum": "203800.0" } }, { - "tier": 6, - "minNotional": 40000000, - "maxNotional": 100000000, + "tier": 6.0, + "currency": "BUSD", + "minNotional": 40000000.0, + "maxNotional": 100000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "maxNotional": "100000000", - "minNotional": "40000000", + "notionalCap": "100000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.1", "cum": "2203800.0" } }, { - "tier": 7, - "minNotional": 100000000, - "maxNotional": 200000000, + "tier": 7.0, + "currency": "BUSD", + "minNotional": 100000000.0, + "maxNotional": 200000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "maxNotional": "200000000", - "minNotional": "100000000", + "notionalCap": "200000000", + "notionalFloor": "100000000", "maintMarginRatio": "0.125", "cum": "4703800.0" } }, { - "tier": 8, - "minNotional": 200000000, - "maxNotional": 400000000, + "tier": 8.0, + "currency": "BUSD", + "minNotional": 200000000.0, + "maxNotional": 400000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "maxNotional": "400000000", - "minNotional": "200000000", + "notionalCap": "400000000", + "notionalFloor": "200000000", "maintMarginRatio": "0.15", "cum": "9703800.0" } }, { - "tier": 9, - "minNotional": 400000000, - "maxNotional": 600000000, + "tier": 9.0, + "currency": "BUSD", + "minNotional": 400000000.0, + "maxNotional": 600000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "maxNotional": "600000000", - "minNotional": "400000000", + "notionalCap": "600000000", + "notionalFloor": "400000000", "maintMarginRatio": "0.25", "cum": "4.97038E7" } }, { - "tier": 10, - "minNotional": 600000000, - "maxNotional": 1000000000, + "tier": 10.0, + "currency": "BUSD", + "minNotional": 600000000.0, + "maxNotional": 1000000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "maxNotional": "1000000000", - "minNotional": "600000000", + "notionalCap": "1000000000", + "notionalFloor": "600000000", "maintMarginRatio": "0.5", "cum": "1.997038E8" } @@ -904,91 +1061,97 @@ ], "WAVES/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -996,136 +1159,145 @@ ], "ADA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -1133,183 +1305,97 @@ ], "LIT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "NU/USDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20, - "info": { - "bracket": "2", - "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "3", - "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "4", - "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2, - "info": { - "bracket": "5", - "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "6", - "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -1317,136 +1403,145 @@ ], "XTZ/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -1454,136 +1549,145 @@ ], "BNB/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -1591,183 +1695,293 @@ ], "AKRO/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.012, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.012", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "65.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "690.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5690.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11940.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386940.0" } } ], - "HNT/USDT": [ + "DAR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "HNT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -1775,136 +1989,145 @@ ], "ETC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -1912,136 +2135,145 @@ ], "XMR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -2049,91 +2281,97 @@ ], "YFI/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -2141,365 +2379,259 @@ ], "FTT/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 100000, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "maxNotional": "100000", - "minNotional": "0", + "notionalCap": "100000", + "notionalFloor": "0", "maintMarginRatio": "0.025", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 100000, - "maxNotional": 500000, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "maxNotional": "500000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.05", "cum": "2500.0" } }, { - "tier": 3, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "3", "initialLeverage": "5", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.1", "cum": "27500.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "4", "initialLeverage": "3", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.15", "cum": "77500.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.25", "cum": "277500.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "5000000", + "notionalCap": "30000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.5", "cum": "1527500.0" } } ], - "BTCUSDT_210326": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, - "info": { - "bracket": "1", - "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50, - "info": { - "bracket": "2", - "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "3", - "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "4", - "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "5", - "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "6", - "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "7", - "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 9223372036854776000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "8", - "initialLeverage": "2", - "maxNotional": "9223372036854775807", - "minNotional": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - } - ], "ETH/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.005, - "maxLeverage": 100, + "maxLeverage": 100.0, "info": { "bracket": "1", "initialLeverage": "100", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.005", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 100000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "2", "initialLeverage": "75", - "maxNotional": "100000", - "minNotional": "10000", + "notionalCap": "100000", + "notionalFloor": "10000", "maintMarginRatio": "0.0065", "cum": "15.0" } }, { - "tier": 3, - "minNotional": 100000, - "maxNotional": 500000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "3", "initialLeverage": "50", - "maxNotional": "500000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.01", "cum": "365.0" } }, { - "tier": 4, - "minNotional": 500000, - "maxNotional": 1500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "maxNotional": "1500000", - "minNotional": "500000", + "notionalCap": "1500000", + "notionalFloor": "500000", "maintMarginRatio": "0.02", "cum": "5365.0" } }, { - "tier": 5, - "minNotional": 1500000, - "maxNotional": 4000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "maxNotional": "4000000", - "minNotional": "1500000", + "notionalCap": "4000000", + "notionalFloor": "1500000", "maintMarginRatio": "0.05", "cum": "50365.0" } }, { - "tier": 6, - "minNotional": 4000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "maxNotional": "10000000", - "minNotional": "4000000", + "notionalCap": "10000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.1", "cum": "250365.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.125", "cum": "500365.0" } }, { - "tier": 8, - "minNotional": 20000000, - "maxNotional": 40000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "maxNotional": "40000000", - "minNotional": "20000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.15", "cum": "1000365.0" } }, { - "tier": 9, - "minNotional": 40000000, - "maxNotional": 150000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 40000000.0, + "maxNotional": 150000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "maxNotional": "150000000", - "minNotional": "40000000", + "notionalCap": "150000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.25", "cum": "5000365.0" } }, { - "tier": 10, - "minNotional": 150000000, - "maxNotional": 500000000, + "tier": 10.0, + "currency": "USDT", + "minNotional": 150000000.0, + "maxNotional": 500000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "maxNotional": "500000000", - "minNotional": "150000000", + "notionalCap": "500000000", + "notionalFloor": "150000000", "maintMarginRatio": "0.5", "cum": "4.2500365E7" } @@ -2507,106 +2639,113 @@ ], "ALICE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -2614,91 +2753,195 @@ ], "ALPHA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "WOO/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -2706,91 +2949,97 @@ ], "SFP/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -2798,91 +3047,97 @@ ], "REEF/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -2890,91 +3145,97 @@ ], "BAT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -2982,106 +3243,113 @@ ], "DOGE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "7000.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "57000.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "107000.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.25", "cum": "732000.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 50000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "10000000", + "notionalCap": "50000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", "cum": "3232000.0" } @@ -3089,136 +3357,145 @@ ], "TRX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -3226,275 +3503,195 @@ ], "RLC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "DOTECOUSDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.012, - "maxLeverage": 20, - "info": { - "bracket": "1", - "initialLeverage": "20", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.012", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.025", - "cum": "65.0" - } - }, - { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.05", - "cum": "690.0" - } - }, - { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "250000", - "minNotional": "100000", - "maintMarginRatio": "0.1", - "cum": "5690.0" - } - }, - { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2, - "info": { - "bracket": "5", - "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.125", - "cum": "11940.0" - } - }, - { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 9223372036854776000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "6", - "initialLeverage": "1", - "maxNotional": "9223372036854775807", - "minNotional": "1000000", - "maintMarginRatio": "0.5", - "cum": "386940.0" - } - } - ], "BTCSTUSDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 9223372036854776000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 9.223372036854776e+18, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "9223372036854775807", - "minNotional": "1000000", + "notionalCap": "9223372036854775807", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -3502,91 +3699,97 @@ ], "STORJ/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -3594,275 +3797,195 @@ ], "SNX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "ETHUSDT_210625": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 250000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.05", - "cum": "7500.0" - } - }, - { - "tier": 3, - "minNotional": 1000000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", - "maintMarginRatio": "0.1", - "cum": "57500.0" - } - }, - { - "tier": 4, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.125", - "cum": "107500.0" - } - }, - { - "tier": 5, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "5", - "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.15", - "cum": "232500.0" - } - }, - { - "tier": 6, - "minNotional": 10000000, - "maxNotional": 9223372036854776000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "6", - "initialLeverage": "2", - "maxNotional": "9223372036854775807", - "minNotional": "10000000", - "maintMarginRatio": "0.25", - "cum": "1232500.0" - } - } - ], "1000XEC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -3870,457 +3993,505 @@ ], "AUDIO/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], + "NEAR/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], "XLM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } } ], - "BTCBUSD_210129": [ + "APE/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.004, - "maxLeverage": 20, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.004", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.005, - "maxLeverage": 15, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "15", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.005", - "cum": "5.0" + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 10, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "3", - "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.01", - "cum": "130.0" + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 500000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 7, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, "info": { "bracket": "4", - "initialLeverage": "7", - "maxNotional": "500000", - "minNotional": "100000", - "maintMarginRatio": "0.025", - "cum": "1630.0" + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 6, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, "info": { "bracket": "5", - "initialLeverage": "6", - "maxNotional": "2000000", - "minNotional": "500000", - "maintMarginRatio": "0.05", - "cum": "14130.0" - } - }, - { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "6", - "initialLeverage": "5", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.1", - "cum": "114130.0" - } - }, - { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "7", - "initialLeverage": "4", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.125", - "cum": "239130.0" - } - }, - { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "8", - "initialLeverage": "3", - "maxNotional": "20000000", - "minNotional": "10000000", - "maintMarginRatio": "0.15", - "cum": "489130.0" - } - }, - { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 9223372036854776000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "9", - "initialLeverage": "2", - "maxNotional": "9223372036854775807", - "minNotional": "20000000", - "maintMarginRatio": "0.25", - "cum": "2489130.0" + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" } } ], "IOTX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -4328,91 +4499,97 @@ ], "NEO/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -4420,91 +4597,97 @@ ], "UNFI/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -4512,106 +4695,113 @@ ], "SAND/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -4619,91 +4809,97 @@ ], "DASH/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -4711,91 +4907,97 @@ ], "KAVA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -4803,183 +5005,309 @@ ], "RUNE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "CTK/USDT": [ + "APE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.5", + "cum": "654500.0" + } + } + ], + "CTK/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -4987,136 +5315,145 @@ ], "LINK/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -5124,106 +5461,227 @@ ], "CELR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.5", + "cum": "654500.0" + } + } + ], + "BNX/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "50000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -5231,91 +5689,97 @@ ], "RSR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -5323,91 +5787,97 @@ ], "ADA/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 100000, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "maxNotional": "100000", - "minNotional": "0", + "notionalCap": "100000", + "notionalFloor": "0", "maintMarginRatio": "0.025", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 100000, - "maxNotional": 500000, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "maxNotional": "500000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.05", "cum": "2500.0" } }, { - "tier": 3, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "3", "initialLeverage": "5", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.1", "cum": "27500.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "4", "initialLeverage": "3", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.15", "cum": "77500.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.25", "cum": "277500.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "5000000", + "notionalCap": "30000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.5", "cum": "1527500.0" } @@ -5415,91 +5885,97 @@ ], "DGB/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -5507,91 +5983,97 @@ ], "SKL/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -5599,91 +6081,97 @@ ], "REN/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -5691,91 +6179,195 @@ ], "LPT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "JASMY/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -5783,91 +6375,97 @@ ], "TOMO/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -5875,91 +6473,97 @@ ], "MTL/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -5967,136 +6571,145 @@ ], "LTC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -6104,91 +6717,97 @@ ], "DODO/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -6196,91 +6815,97 @@ ], "EGLD/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 50000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "1000000", + "notionalCap": "50000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -6288,91 +6913,97 @@ ], "KSM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -6380,275 +7011,195 @@ ], "BNB/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 100000, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "maxNotional": "100000", - "minNotional": "0", + "notionalCap": "100000", + "notionalFloor": "0", "maintMarginRatio": "0.025", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 100000, - "maxNotional": 500000, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "maxNotional": "500000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.05", "cum": "2500.0" } }, { - "tier": 3, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "3", "initialLeverage": "5", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.1", "cum": "27500.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "4", "initialLeverage": "3", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.15", "cum": "77500.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.25", "cum": "277500.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "5000000", + "notionalCap": "30000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.5", "cum": "1527500.0" } } ], - "BTCUSDT_210625": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 250000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.05", - "cum": "7500.0" - } - }, - { - "tier": 3, - "minNotional": 1000000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", - "maintMarginRatio": "0.1", - "cum": "57500.0" - } - }, - { - "tier": 4, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.125", - "cum": "107500.0" - } - }, - { - "tier": 5, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "5", - "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.15", - "cum": "232500.0" - } - }, - { - "tier": 6, - "minNotional": 10000000, - "maxNotional": 9223372036854776000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "6", - "initialLeverage": "2", - "maxNotional": "9223372036854775807", - "minNotional": "10000000", - "maintMarginRatio": "0.25", - "cum": "1232500.0" - } - } - ], "ONT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -6656,198 +7207,309 @@ ], "VET/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } } ], - "TRB/USDT": [ + "IMX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "TRB/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -6855,198 +7517,309 @@ ], "MANA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } } ], - "COTI/USDT": [ + "FLOW/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "COTI/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -7054,581 +7827,571 @@ ], "CHR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "ETHUSDT_210924": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 250000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.05", - "cum": "7500.0" - } - }, - { - "tier": 3, - "minNotional": 1000000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", - "maintMarginRatio": "0.1", - "cum": "57500.0" - } - }, - { - "tier": 4, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.125", - "cum": "107500.0" - } - }, - { - "tier": 5, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "5", - "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.15", - "cum": "232500.0" - } - }, - { - "tier": 6, - "minNotional": 10000000, - "maxNotional": 20000000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "6", - "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", - "maintMarginRatio": "0.25", - "cum": "1232500.0" - } - }, - { - "tier": 7, - "minNotional": 20000000, - "maxNotional": 50000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "7", - "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", - "maintMarginRatio": "0.5", - "cum": "6232500.0" - } - } - ], "BAKE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], + "AVAX/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], "GRT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "ETHUSDT_220325": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 375000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "375000", - "minNotional": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 375000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "2000000", - "minNotional": "375000", - "maintMarginRatio": "0.05", - "cum": "11250.0" - } - }, - { - "tier": 3, - "minNotional": 2000000, - "maxNotional": 4000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "4000000", - "minNotional": "2000000", - "maintMarginRatio": "0.1", - "cum": "111250.0" - } - }, - { - "tier": 4, - "minNotional": 4000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "10000000", - "minNotional": "4000000", - "maintMarginRatio": "0.125", - "cum": "211250.0" - } - }, - { - "tier": 5, - "minNotional": 10000000, - "maxNotional": 20000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "5", - "initialLeverage": "3", - "maxNotional": "20000000", - "minNotional": "10000000", - "maintMarginRatio": "0.15", - "cum": "461250.0" - } - }, - { - "tier": 6, - "minNotional": 20000000, - "maxNotional": 40000000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "6", - "initialLeverage": "2", - "maxNotional": "40000000", - "minNotional": "20000000", - "maintMarginRatio": "0.25", - "cum": "2461250.0" - } - }, - { - "tier": 7, - "minNotional": 40000000, - "maxNotional": 400000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "7", - "initialLeverage": "1", - "maxNotional": "400000000", - "minNotional": "40000000", - "maintMarginRatio": "0.5", - "cum": "1.246125E7" - } - } - ], "FLM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "GAL/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -7636,91 +8399,97 @@ ], "MASK/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -7728,335 +8497,243 @@ ], "EOS/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } } ], - "ETHUSDT_211231": [ + "OGN/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 375000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "375000", - "minNotional": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 375000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "2000000", - "minNotional": "375000", - "maintMarginRatio": "0.05", - "cum": "11250.0" - } - }, - { - "tier": 3, - "minNotional": 2000000, - "maxNotional": 4000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "4000000", - "minNotional": "2000000", - "maintMarginRatio": "0.1", - "cum": "111250.0" - } - }, - { - "tier": 4, - "minNotional": 4000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "10000000", - "minNotional": "4000000", - "maintMarginRatio": "0.125", - "cum": "211250.0" - } - }, - { - "tier": 5, - "minNotional": 10000000, - "maxNotional": 20000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "5", - "initialLeverage": "3", - "maxNotional": "20000000", - "minNotional": "10000000", - "maintMarginRatio": "0.15", - "cum": "461250.0" - } - }, - { - "tier": 6, - "minNotional": 20000000, - "maxNotional": 40000000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "6", - "initialLeverage": "2", - "maxNotional": "40000000", - "minNotional": "20000000", - "maintMarginRatio": "0.25", - "cum": "2461250.0" - } - }, - { - "tier": 7, - "minNotional": 40000000, - "maxNotional": 400000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "7", - "initialLeverage": "1", - "maxNotional": "400000000", - "minNotional": "40000000", - "maintMarginRatio": "0.5", - "cum": "1.246125E7" - } - } - ], - "OGN/USDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50, - "info": { - "bracket": "1", - "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -8064,183 +8741,309 @@ ], "SC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], + "ETHUSDT_220624": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 375000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "375000", + "notionalFloor": "0", + "maintMarginRatio": "0.02", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 375000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "2000000", + "notionalFloor": "375000", + "maintMarginRatio": "0.05", + "cum": "11250.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "4000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.1", + "cum": "111250.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "4", + "initialLeverage": "4", + "notionalCap": "10000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.125", + "cum": "211250.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "5", + "initialLeverage": "3", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.15", + "cum": "461250.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 40000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "40000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.25", + "cum": "2461250.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 40000000.0, + "maxNotional": 400000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "400000000", + "notionalFloor": "40000000", + "maintMarginRatio": "0.5", + "cum": "1.246125E7" + } + } + ], "BAL/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -8248,489 +9051,195 @@ ], "STMX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "BTTUSDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20, - "info": { - "bracket": "2", - "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "3", - "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "4", - "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2, - "info": { - "bracket": "5", - "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "6", - "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "LUNA/USDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50, - "info": { - "bracket": "1", - "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "2", - "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", - "maintMarginRatio": "0.02", - "cum": "500.0" - } - }, - { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "3", - "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.05", - "cum": "8000.0" - } - }, - { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "4", - "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", - "maintMarginRatio": "0.1", - "cum": "58000.0" - } - }, - { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "5", - "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.125", - "cum": "108000.0" - } - }, - { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.1665, - "maxLeverage": 3, - "info": { - "bracket": "6", - "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.1665", - "cum": "315500.0" - } - }, - { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 15000000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "7", - "initialLeverage": "2", - "maxNotional": "15000000", - "minNotional": "10000000", - "maintMarginRatio": "0.25", - "cum": "1150500.0" - } - }, - { - "tier": 8, - "minNotional": 15000000, - "maxNotional": 50000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "8", - "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "15000000", - "maintMarginRatio": "0.5", - "cum": "4900500.0" - } - } - ], "DENT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "1000BTTC/USDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20, - "info": { - "bracket": "2", - "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "3", - "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "4", - "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2, - "info": { - "bracket": "5", - "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "6", - "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -8738,91 +9247,97 @@ ], "KNC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -8830,91 +9345,97 @@ ], "SRM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -8922,106 +9443,113 @@ ], "ENJ/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -9029,91 +9557,97 @@ ], "C98/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -9121,91 +9655,97 @@ ], "ZEN/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -9213,106 +9753,113 @@ ], "ATOM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -9320,106 +9867,113 @@ ], "NEAR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -9427,91 +9981,97 @@ ], "SOL/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 100000, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "maxNotional": "100000", - "minNotional": "0", + "notionalCap": "100000", + "notionalFloor": "0", "maintMarginRatio": "0.025", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 100000, - "maxNotional": 500000, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "maxNotional": "500000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.05", "cum": "2500.0" } }, { - "tier": 3, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "3", "initialLeverage": "5", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.1", "cum": "27500.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "4", "initialLeverage": "3", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.15", "cum": "77500.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.25", "cum": "277500.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "5000000", + "notionalCap": "30000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.5", "cum": "1527500.0" } @@ -9519,91 +10079,97 @@ ], "ENS/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -9611,136 +10177,145 @@ ], "BCH/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } @@ -9748,91 +10323,97 @@ ], "ATA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -9840,91 +10421,97 @@ ], "IOST/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -9932,91 +10519,97 @@ ], "HBAR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -10024,106 +10617,113 @@ ], "ZEC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -10131,106 +10731,113 @@ ], "1000SHIB/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -10238,91 +10845,97 @@ ], "TLM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -10330,183 +10943,97 @@ ], "ANT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BZRXUSDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20, - "info": { - "bracket": "2", - "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "3", - "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "4", - "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2, - "info": { - "bracket": "5", - "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "6", - "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -10514,151 +11041,161 @@ ], "ETH/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 25000, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.004, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "25000", - "minNotional": "0", + "notionalCap": "25000", + "notionalFloor": "0", "maintMarginRatio": "0.004", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.005, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.005", "cum": "25.0" } }, { - "tier": 3, - "minNotional": 100000, - "maxNotional": 500000, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "3", "initialLeverage": "20", - "maxNotional": "500000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.01", "cum": "525.0" } }, { - "tier": 4, - "minNotional": 500000, - "maxNotional": 1500000, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1500000", - "minNotional": "500000", + "notionalCap": "1500000", + "notionalFloor": "500000", "maintMarginRatio": "0.025", "cum": "8025.0" } }, { - "tier": 5, - "minNotional": 1500000, - "maxNotional": 4000000, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1500000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 6, + "maxLeverage": 6.0, "info": { "bracket": "5", "initialLeverage": "6", - "maxNotional": "4000000", - "minNotional": "1500000", + "notionalCap": "4000000", + "notionalFloor": "1500000", "maintMarginRatio": "0.05", "cum": "45525.0" } }, { - "tier": 6, - "minNotional": 4000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "BUSD", + "minNotional": 4000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "maxNotional": "10000000", - "minNotional": "4000000", + "notionalCap": "10000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.1", "cum": "245525.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 7.0, + "currency": "BUSD", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.125", "cum": "495525.0" } }, { - "tier": 8, - "minNotional": 20000000, - "maxNotional": 40000000, + "tier": 8.0, + "currency": "BUSD", + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "maxNotional": "40000000", - "minNotional": "20000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.15", "cum": "995525.0" } }, { - "tier": 9, - "minNotional": 40000000, - "maxNotional": 150000000, + "tier": 9.0, + "currency": "BUSD", + "minNotional": 40000000.0, + "maxNotional": 150000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "maxNotional": "150000000", - "minNotional": "40000000", + "notionalCap": "150000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.25", "cum": "4995525.0" } }, { - "tier": 10, - "minNotional": 150000000, - "maxNotional": 500000000, + "tier": 10.0, + "currency": "BUSD", + "minNotional": 150000000.0, + "maxNotional": 500000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "maxNotional": "500000000", - "minNotional": "150000000", + "notionalCap": "500000000", + "notionalFloor": "150000000", "maintMarginRatio": "0.5", "cum": "4.2495525E7" } @@ -10666,106 +11203,113 @@ ], "GALA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -10773,121 +11317,129 @@ ], "AAVE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "500.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8000.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58000.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108000.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1665, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "6", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1665", "cum": "315500.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1150500.0" } }, { - "tier": 8, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6150500.0" } @@ -10895,91 +11447,97 @@ ], "GTC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -10987,106 +11545,113 @@ ], "ALGO/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -11094,305 +11659,211 @@ ], "ICP/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "BTCUSDT_210924": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 250000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.05", - "cum": "7500.0" - } - }, - { - "tier": 3, - "minNotional": 1000000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", - "maintMarginRatio": "0.1", - "cum": "57500.0" - } - }, - { - "tier": 4, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.125", - "cum": "107500.0" - } - }, - { - "tier": 5, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "5", - "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.15", - "cum": "232500.0" - } - }, - { - "tier": 6, - "minNotional": 10000000, - "maxNotional": 20000000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "6", - "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", - "maintMarginRatio": "0.25", - "cum": "1232500.0" - } - }, - { - "tier": 7, - "minNotional": 20000000, - "maxNotional": 50000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "7", - "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", - "maintMarginRatio": "0.5", - "cum": "6232500.0" - } - } - ], "LRC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -11400,305 +11871,211 @@ ], "AVAX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "4500.0" + "cum": "7000.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "17000.0" + "cum": "57000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 750000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "750000", - "minNotional": "500000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", - "cum": "29500.0" + "cum": "107000.0" } }, { - "tier": 6, - "minNotional": 750000, - "maxNotional": 1000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "750000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.25", - "cum": "123250.0" + "cum": "732000.0" } }, { - "tier": 7, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "50000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "373250.0" - } - } - ], - "BTCUSDT_220325": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 375000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "375000", - "minNotional": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 375000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "2000000", - "minNotional": "375000", - "maintMarginRatio": "0.05", - "cum": "11250.0" - } - }, - { - "tier": 3, - "minNotional": 2000000, - "maxNotional": 4000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "4000000", - "minNotional": "2000000", - "maintMarginRatio": "0.1", - "cum": "111250.0" - } - }, - { - "tier": 4, - "minNotional": 4000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "10000000", - "minNotional": "4000000", - "maintMarginRatio": "0.125", - "cum": "211250.0" - } - }, - { - "tier": 5, - "minNotional": 10000000, - "maxNotional": 20000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "5", - "initialLeverage": "3", - "maxNotional": "20000000", - "minNotional": "10000000", - "maintMarginRatio": "0.15", - "cum": "461250.0" - } - }, - { - "tier": 6, - "minNotional": 20000000, - "maxNotional": 40000000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "6", - "initialLeverage": "2", - "maxNotional": "40000000", - "minNotional": "20000000", - "maintMarginRatio": "0.25", - "cum": "2461250.0" - } - }, - { - "tier": 7, - "minNotional": 40000000, - "maxNotional": 400000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "7", - "initialLeverage": "1", - "maxNotional": "400000000", - "minNotional": "40000000", - "maintMarginRatio": "0.5", - "cum": "1.246125E7" + "cum": "3232000.0" } } ], "ARPA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -11706,91 +12083,97 @@ ], "CELO/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -11798,91 +12181,97 @@ ], "ROSE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -11890,106 +12279,113 @@ ], "MATIC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 750000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 750000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "750000", - "minNotional": "500000", + "notionalCap": "750000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 750000, - "maxNotional": 1000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "750000", + "notionalCap": "1000000", + "notionalFloor": "750000", "maintMarginRatio": "0.25", "cum": "123250.0" } }, { - "tier": 7, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "373250.0" } @@ -11997,91 +12393,97 @@ ], "1INCH/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.012, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.012", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "65.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "690.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5690.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11940.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 100000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 100000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "100000000", - "minNotional": "1000000", + "notionalCap": "100000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386940.0" } @@ -12089,91 +12491,97 @@ ], "MKR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -12181,91 +12589,97 @@ ], "PEOPLE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -12273,121 +12687,129 @@ ], "THETA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "500.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8000.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58000.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108000.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1665, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "6", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1665", "cum": "315500.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1150500.0" } }, { - "tier": 8, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6150500.0" } @@ -12395,335 +12817,227 @@ ], "UNI/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "500.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8000.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58000.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108000.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1665, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "6", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1665", "cum": "315500.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1150500.0" } }, { - "tier": 8, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6150500.0" } } ], - "ETHUSDT_210326": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, - "info": { - "bracket": "1", - "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50, - "info": { - "bracket": "2", - "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "3", - "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "4", - "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "5", - "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "6", - "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "7", - "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 9223372036854776000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "8", - "initialLeverage": "2", - "maxNotional": "9223372036854775807", - "minNotional": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - } - ], "LINA/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -12731,91 +13045,97 @@ ], "AR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -12823,91 +13143,97 @@ ], "RVN/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -12915,121 +13241,129 @@ ], "FIL/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "500.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8000.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58000.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108000.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1665, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "6", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1665", "cum": "315500.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1150500.0" } }, { - "tier": 8, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6150500.0" } @@ -13037,91 +13371,97 @@ ], "NKN/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -13129,91 +13469,97 @@ ], "KLAY/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -13221,91 +13567,97 @@ ], "DEFI/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -13313,91 +13665,97 @@ ], "COMP/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -13405,91 +13763,97 @@ ], "BTCDOM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -13497,106 +13861,113 @@ ], "SOL/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "7000.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "57000.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "107000.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.25", "cum": "732000.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 50000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "10000000", + "notionalCap": "50000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", "cum": "3232000.0" } @@ -13604,243 +13975,259 @@ ], "BTC/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.004, - "maxLeverage": 125, + "maxLeverage": 125.0, "info": { "bracket": "1", "initialLeverage": "125", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.004", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.005, - "maxLeverage": 100, + "maxLeverage": 100.0, "info": { "bracket": "2", "initialLeverage": "100", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.005", "cum": "50.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "3", "initialLeverage": "50", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.01", "cum": "1300.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 7500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "maxNotional": "7500000", - "minNotional": "1000000", + "notionalCap": "10000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.025", "cum": "16300.0" } }, { - "tier": 5, - "minNotional": 7500000, - "maxNotional": 40000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "maxNotional": "40000000", - "minNotional": "7500000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.05", - "cum": "203800.0" + "cum": "266300.0" } }, { - "tier": 6, - "minNotional": 40000000, - "maxNotional": 100000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "maxNotional": "100000000", - "minNotional": "40000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.1", - "cum": "2203800.0" + "cum": "1266300.0" } }, { - "tier": 7, - "minNotional": 100000000, - "maxNotional": 200000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 50000000.0, + "maxNotional": 100000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "maxNotional": "200000000", - "minNotional": "100000000", + "notionalCap": "100000000", + "notionalFloor": "50000000", "maintMarginRatio": "0.125", - "cum": "4703800.0" + "cum": "2516300.0" } }, { - "tier": 8, - "minNotional": 200000000, - "maxNotional": 400000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 100000000.0, + "maxNotional": 200000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "maxNotional": "400000000", - "minNotional": "200000000", + "notionalCap": "200000000", + "notionalFloor": "100000000", "maintMarginRatio": "0.15", - "cum": "9703800.0" + "cum": "5016300.0" } }, { - "tier": 9, - "minNotional": 400000000, - "maxNotional": 600000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 200000000.0, + "maxNotional": 300000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "maxNotional": "600000000", - "minNotional": "400000000", + "notionalCap": "300000000", + "notionalFloor": "200000000", "maintMarginRatio": "0.25", - "cum": "4.97038E7" + "cum": "2.50163E7" } }, { - "tier": 10, - "minNotional": 600000000, - "maxNotional": 1000000000, + "tier": 10.0, + "currency": "USDT", + "minNotional": 300000000.0, + "maxNotional": 9.223372036854776e+18, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "maxNotional": "1000000000", - "minNotional": "600000000", + "notionalCap": "9223372036854775807", + "notionalFloor": "300000000", "maintMarginRatio": "0.5", - "cum": "1.997038E8" + "cum": "1.000163E8" } } ], "OMG/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.024, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.024", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "5.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "630.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5630.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11880.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "10000000", - "minNotional": "1000000", + "notionalCap": "10000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386880.0" } @@ -13848,91 +14235,97 @@ ], "ICX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -13940,810 +14333,521 @@ ], "BLZ/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "BTCUSDT_211231": [ + "GMT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 375000, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25, - "info": { - "bracket": "1", - "initialLeverage": "25", - "maxNotional": "375000", - "minNotional": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 375000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "2", - "initialLeverage": "10", - "maxNotional": "2000000", - "minNotional": "375000", - "maintMarginRatio": "0.05", - "cum": "11250.0" - } - }, - { - "tier": 3, - "minNotional": 2000000, - "maxNotional": 4000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "3", - "initialLeverage": "5", - "maxNotional": "4000000", - "minNotional": "2000000", - "maintMarginRatio": "0.1", - "cum": "111250.0" - } - }, - { - "tier": 4, - "minNotional": 4000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "4", - "initialLeverage": "4", - "maxNotional": "10000000", - "minNotional": "4000000", - "maintMarginRatio": "0.125", - "cum": "211250.0" - } - }, - { - "tier": 5, - "minNotional": 10000000, - "maxNotional": 20000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "5", - "initialLeverage": "3", - "maxNotional": "20000000", - "minNotional": "10000000", - "maintMarginRatio": "0.15", - "cum": "461250.0" - } - }, - { - "tier": 6, - "minNotional": 20000000, - "maxNotional": 40000000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "6", - "initialLeverage": "2", - "maxNotional": "40000000", - "minNotional": "20000000", - "maintMarginRatio": "0.25", - "cum": "2461250.0" - } - }, - { - "tier": 7, - "minNotional": 40000000, - "maxNotional": 400000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "7", - "initialLeverage": "1", - "maxNotional": "400000000", - "minNotional": "40000000", - "maintMarginRatio": "0.5", - "cum": "1.246125E7" - } - } - ], - "FTM/USDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 750000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "750000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 750000, - "maxNotional": 1000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "750000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", - "cum": "123250.0" + "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", - "cum": "373250.0" + "cum": "654500.0" } } ], - "YFII/USDT": [ + "FTM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "750.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "7000.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "57000.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "107000.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, "info": { "bracket": "6", - "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "KEEP/USDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50, - "info": { - "bracket": "1", - "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20, - "info": { - "bracket": "2", - "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "3", - "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "4", - "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2, - "info": { - "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.25", + "cum": "732000.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "50000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "3232000.0" } } ], "BAND/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "BTCBUSD_210226": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.004, - "maxLeverage": 20, - "info": { - "bracket": "1", - "initialLeverage": "20", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.004", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.005, - "maxLeverage": 15, - "info": { - "bracket": "2", - "initialLeverage": "15", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.005", - "cum": "5.0" - } - }, - { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 10, - "info": { - "bracket": "3", - "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.01", - "cum": "130.0" - } - }, - { - "tier": 4, - "minNotional": 100000, - "maxNotional": 500000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 7, - "info": { - "bracket": "4", - "initialLeverage": "7", - "maxNotional": "500000", - "minNotional": "100000", - "maintMarginRatio": "0.025", - "cum": "1630.0" - } - }, - { - "tier": 5, - "minNotional": 500000, - "maxNotional": 2000000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 6, - "info": { - "bracket": "5", - "initialLeverage": "6", - "maxNotional": "2000000", - "minNotional": "500000", - "maintMarginRatio": "0.05", - "cum": "14130.0" - } - }, - { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "6", - "initialLeverage": "5", - "maxNotional": "5000000", - "minNotional": "2000000", - "maintMarginRatio": "0.1", - "cum": "114130.0" - } - }, - { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4, - "info": { - "bracket": "7", - "initialLeverage": "4", - "maxNotional": "10000000", - "minNotional": "5000000", - "maintMarginRatio": "0.125", - "cum": "239130.0" - } - }, - { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3, - "info": { - "bracket": "8", - "initialLeverage": "3", - "maxNotional": "20000000", - "minNotional": "10000000", - "maintMarginRatio": "0.15", - "cum": "489130.0" - } - }, - { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 9223372036854776000, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2, - "info": { - "bracket": "9", - "initialLeverage": "2", - "maxNotional": "9223372036854775807", - "minNotional": "20000000", - "maintMarginRatio": "0.25", - "cum": "2489130.0" - } - } - ], "XRP/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 100000, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "maxNotional": "100000", - "minNotional": "0", + "notionalCap": "100000", + "notionalFloor": "0", "maintMarginRatio": "0.025", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 100000, - "maxNotional": 500000, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "maxNotional": "500000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.05", "cum": "2500.0" } }, { - "tier": 3, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "3", "initialLeverage": "5", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.1", "cum": "27500.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "4", "initialLeverage": "3", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.15", "cum": "77500.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.25", "cum": "277500.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "5000000", + "notionalCap": "30000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.5", "cum": "1527500.0" } @@ -14751,91 +14855,97 @@ ], "DOGE/BUSD": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 100000, + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "maxNotional": "100000", - "minNotional": "0", + "notionalCap": "100000", + "notionalFloor": "0", "maintMarginRatio": "0.025", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 100000, - "maxNotional": 500000, + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "maxNotional": "500000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.05", "cum": "2500.0" } }, { - "tier": 3, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "3", "initialLeverage": "5", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.1", "cum": "27500.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "4", "initialLeverage": "3", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.15", "cum": "77500.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.25", "cum": "277500.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "5000000", + "notionalCap": "30000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.5", "cum": "1527500.0" } @@ -14843,228 +14953,341 @@ ], "XRP/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 20000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "20000000", - "minNotional": "10000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 20000000, - "maxNotional": 50000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "20000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6233035.0" } } ], - "SXP/USDT": [ + "FTT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "SXP/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -15072,106 +15295,113 @@ ], "CRV/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -15179,91 +15409,97 @@ ], "BEL/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -15271,136 +15507,145 @@ ], "DOT/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 10000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 75, + "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "maxNotional": "10000", - "minNotional": "0", + "notionalCap": "10000", + "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 10000, - "maxNotional": 50000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "10000", + "notionalCap": "50000", + "notionalFloor": "10000", "maintMarginRatio": "0.01", "cum": "35.0" } }, { - "tier": 3, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "535.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8035.0" } }, { - "tier": 5, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58035.0" } }, { - "tier": 6, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108035.0" } }, { - "tier": 7, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.15, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "7", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.15", "cum": "233035.0" } }, { - "tier": 8, - "minNotional": 10000000, - "maxNotional": 50000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "maxNotional": "50000000", - "minNotional": "10000000", + "notionalCap": "50000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1233035.0" } }, { - "tier": 9, - "minNotional": 50000000, - "maxNotional": 100000000, + "tier": 9.0, + "currency": "USDT", + "minNotional": 50000000.0, + "maxNotional": 100000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "maxNotional": "100000000", - "minNotional": "50000000", + "notionalCap": "100000000", + "notionalFloor": "50000000", "maintMarginRatio": "0.5", "cum": "1.3733035E7" } @@ -15408,198 +15653,293 @@ ], "XEM/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], + "GMT/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], "ONE/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 2000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "2000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } @@ -15607,213 +15947,243 @@ ], "ZIL/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "750.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, "info": { "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "654500.0" } } ], "AXS/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 250000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "maxNotional": "250000", - "minNotional": "50000", + "notionalCap": "250000", + "notionalFloor": "50000", "maintMarginRatio": "0.02", "cum": "500.0" } }, { - "tier": 3, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.05", "cum": "8000.0" } }, { - "tier": 4, - "minNotional": 1000000, - "maxNotional": 2000000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "2000000", - "minNotional": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", "cum": "58000.0" } }, { - "tier": 5, - "minNotional": 2000000, - "maxNotional": 5000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "5000000", - "minNotional": "2000000", + "notionalCap": "5000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", "cum": "108000.0" } }, { - "tier": 6, - "minNotional": 5000000, - "maxNotional": 10000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1665, - "maxLeverage": 3, + "maxLeverage": 3.0, "info": { "bracket": "6", "initialLeverage": "3", - "maxNotional": "10000000", - "minNotional": "5000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1665", "cum": "315500.0" } }, { - "tier": 7, - "minNotional": 10000000, - "maxNotional": 15000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 15000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "maxNotional": "15000000", - "minNotional": "10000000", + "notionalCap": "15000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", "cum": "1150500.0" } }, { - "tier": 8, - "minNotional": 15000000, - "maxNotional": 50000000, + "tier": 8.0, + "currency": "USDT", + "minNotional": 15000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "maxNotional": "50000000", - "minNotional": "15000000", + "notionalCap": "50000000", + "notionalFloor": "15000000", "maintMarginRatio": "0.5", "cum": "4900500.0" } @@ -15821,106 +16191,113 @@ ], "DYDX/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 50000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "50000", - "minNotional": "0", + "notionalCap": "50000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 50000, - "maxNotional": 150000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "150000", - "minNotional": "50000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" } }, { - "tier": 3, - "minNotional": 150000, - "maxNotional": 250000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "250000", - "minNotional": "150000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", "cum": "4500.0" } }, { - "tier": 4, - "minNotional": 250000, - "maxNotional": 500000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "500000", - "minNotional": "250000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", "cum": "17000.0" } }, { - "tier": 5, - "minNotional": 500000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4, + "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "maxNotional": "1000000", - "minNotional": "500000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", "cum": "29500.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 4000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.25, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "maxNotional": "4000000", - "minNotional": "1000000", + "notionalCap": "4000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "154500.0" } }, { - "tier": 7, - "minNotional": 4000000, - "maxNotional": 30000000, + "tier": 7.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "4000000", + "notionalCap": "30000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.5", "cum": "1154500.0" } @@ -15928,91 +16305,97 @@ ], "OCEAN/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } @@ -16020,275 +16403,195 @@ ], "CHZ/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.012, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.012", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "65.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "690.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5690.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11940.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386940.0" } } ], - "LENDUSDT": [ - { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50, - "info": { - "bracket": "1", - "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20, - "info": { - "bracket": "2", - "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10, - "info": { - "bracket": "3", - "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5, - "info": { - "bracket": "4", - "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2, - "info": { - "bracket": "5", - "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 9223372036854776000, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1, - "info": { - "bracket": "6", - "initialLeverage": "1", - "maxNotional": "9223372036854775807", - "minNotional": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], "ANKR/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.012, - "maxLeverage": 50, + "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.012", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "65.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "690.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5690.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11940.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386940.0" } @@ -16296,183 +16599,309 @@ ], "DUSK/USDT": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "CTSI/USDT": [ + "BTCUSDT_220624": [ { - "tier": 1, - "minNotional": 0, - "maxNotional": 5000, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25, + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 375000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "1", "initialLeverage": "25", - "maxNotional": "5000", - "minNotional": "0", + "notionalCap": "375000", + "notionalFloor": "0", + "maintMarginRatio": "0.02", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 375000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "2000000", + "notionalFloor": "375000", + "maintMarginRatio": "0.05", + "cum": "11250.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "4000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.1", + "cum": "111250.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "4", + "initialLeverage": "4", + "notionalCap": "10000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.125", + "cum": "211250.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "5", + "initialLeverage": "3", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.15", + "cum": "461250.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 40000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "40000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.25", + "cum": "2461250.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 40000000.0, + "maxNotional": 400000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "400000000", + "notionalFloor": "40000000", + "maintMarginRatio": "0.5", + "cum": "1.246125E7" + } + } + ], + "CTSI/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" } }, { - "tier": 2, - "minNotional": 5000, - "maxNotional": 25000, + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20, + "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "maxNotional": "25000", - "minNotional": "5000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", "cum": "75.0" } }, { - "tier": 3, - "minNotional": 25000, - "maxNotional": 100000, + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10, + "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "maxNotional": "100000", - "minNotional": "25000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" } }, { - "tier": 4, - "minNotional": 100000, - "maxNotional": 250000, + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5, + "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "maxNotional": "250000", - "minNotional": "100000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", "cum": "5700.0" } }, { - "tier": 5, - "minNotional": 250000, - "maxNotional": 1000000, + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2, + "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "maxNotional": "1000000", - "minNotional": "250000", + "notionalCap": "1000000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11950.0" } }, { - "tier": 6, - "minNotional": 1000000, - "maxNotional": 30000000, + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, - "maxLeverage": 1, + "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "maxNotional": "30000000", - "minNotional": "1000000", + "notionalCap": "30000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } diff --git a/tests/conftest.py b/tests/conftest.py index cc07de1de..3fe7ad2b0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3058,43 +3058,37 @@ def leverage_tiers(): 'mmr': 0.01, 'lev': 50, 'maintAmt': 0.0 - }, - { + }, { 'min': 50000, 'max': 150000, 'mmr': 0.025, 'lev': 20, 'maintAmt': 750.0 - }, - { + }, { 'min': 150000, 'max': 250000, 'mmr': 0.05, 'lev': 10, 'maintAmt': 4500.0 - }, - { + }, { 'min': 250000, 'max': 500000, 'mmr': 0.1, 'lev': 5, 'maintAmt': 17000.0 - }, - { + }, { 'min': 500000, 'max': 1000000, 'mmr': 0.125, 'lev': 4, 'maintAmt': 29500.0 - }, - { + }, { 'min': 1000000, 'max': 2000000, 'mmr': 0.25, 'lev': 2, 'maintAmt': 154500.0 - }, - { + }, { 'min': 2000000, 'max': 30000000, 'mmr': 0.5, @@ -3109,36 +3103,31 @@ def leverage_tiers(): 'mmr': 0.012, 'lev': 50, 'maintAmt': 0.0 - }, - { + }, { 'min': 5000, 'max': 25000, 'mmr': 0.025, 'lev': 20, 'maintAmt': 65.0 - }, - { + }, { 'min': 25000, 'max': 100000, 'mmr': 0.05, 'lev': 10, 'maintAmt': 690.0 - }, - { + }, { 'min': 100000, 'max': 250000, 'mmr': 0.1, 'lev': 5, 'maintAmt': 5690.0 - }, - { + }, { 'min': 250000, 'max': 1000000, 'mmr': 0.125, 'lev': 2, 'maintAmt': 11940.0 - }, - { + }, { 'min': 1000000, 'max': 100000000, 'mmr': 0.5, @@ -3153,50 +3142,43 @@ def leverage_tiers(): 'mmr': 0.01, 'lev': 50, 'maintAmt': 0.0 - }, - { + }, { 'min': 50000, 'max': 250000, 'mmr': 0.02, 'lev': 25, 'maintAmt': 500.0 - }, - { + }, { 'min': 250000, 'max': 1000000, 'mmr': 0.05, 'lev': 10, 'maintAmt': 8000.0 - }, - { + }, { 'min': 1000000, 'max': 2000000, 'mmr': 0.1, 'lev': 5, 'maintAmt': 58000.0 - }, - { + }, { 'min': 2000000, 'max': 5000000, 'mmr': 0.125, 'lev': 4, 'maintAmt': 108000.0 - }, - { + }, { 'min': 5000000, 'max': 10000000, 'mmr': 0.1665, 'lev': 3, 'maintAmt': 315500.0 - }, - { + }, { 'min': 10000000, 'max': 20000000, 'mmr': 0.25, 'lev': 2, 'maintAmt': 1150500.0 - }, - { + }, { "min": 20000000, "max": 50000000, "mmr": 0.5, @@ -3211,36 +3193,31 @@ def leverage_tiers(): "mmr": 0.025, "lev": 20, "maintAmt": 0.0 - }, - { + }, { "min": 100000, "max": 500000, "mmr": 0.05, "lev": 10, "maintAmt": 2500.0 - }, - { + }, { "min": 500000, "max": 1000000, "mmr": 0.1, "lev": 5, "maintAmt": 27500.0 - }, - { + }, { "min": 1000000, "max": 2000000, "mmr": 0.15, "lev": 3, "maintAmt": 77500.0 - }, - { + }, { "min": 2000000, "max": 5000000, "mmr": 0.25, "lev": 2, "maintAmt": 277500.0 - }, - { + }, { "min": 5000000, "max": 30000000, "mmr": 0.5, @@ -3255,36 +3232,31 @@ def leverage_tiers(): "mmr": 0.025, "lev": 20, "maintAmt": 0.0 - }, - { + }, { "min": 100000, # stake = 10000.0 "max": 500000, # max_stake = 50000.0 "mmr": 0.05, "lev": 10, "maintAmt": 2500.0 - }, - { + }, { "min": 500000, # stake = 100000.0 "max": 1000000, # max_stake = 200000.0 "mmr": 0.1, "lev": 5, "maintAmt": 27500.0 - }, - { + }, { "min": 1000000, # stake = 333333.3333333333 "max": 2000000, # max_stake = 666666.6666666666 "mmr": 0.15, "lev": 3, "maintAmt": 77500.0 - }, - { + }, { "min": 2000000, # stake = 1000000.0 "max": 5000000, # max_stake = 2500000.0 "mmr": 0.25, "lev": 2, "maintAmt": 277500.0 - }, - { + }, { "min": 5000000, # stake = 5000000.0 "max": 30000000, # max_stake = 30000000.0 "mmr": 0.5, @@ -3299,57 +3271,49 @@ def leverage_tiers(): "mmr": 0.0065, "lev": 75, "maintAmt": 0.0 - }, - { + }, { "min": 10000, # stake = 200.0 "max": 50000, # max_stake = 1000.0 "mmr": 0.01, "lev": 50, "maintAmt": 35.0 - }, - { + }, { "min": 50000, # stake = 2000.0 "max": 250000, # max_stake = 10000.0 "mmr": 0.02, "lev": 25, "maintAmt": 535.0 - }, - { + }, { "min": 250000, # stake = 25000.0 "max": 1000000, # max_stake = 100000.0 "mmr": 0.05, "lev": 10, "maintAmt": 8035.0 - }, - { + }, { "min": 1000000, # stake = 200000.0 "max": 2000000, # max_stake = 400000.0 "mmr": 0.1, "lev": 5, "maintAmt": 58035.0 - }, - { + }, { "min": 2000000, # stake = 500000.0 "max": 5000000, # max_stake = 1250000.0 "mmr": 0.125, "lev": 4, "maintAmt": 108035.0 - }, - { + }, { "min": 5000000, # stake = 1666666.6666666667 "max": 10000000, # max_stake = 3333333.3333333335 "mmr": 0.15, "lev": 3, "maintAmt": 233035.0 - }, - { + }, { "min": 10000000, # stake = 5000000.0 "max": 20000000, # max_stake = 10000000.0 "mmr": 0.25, "lev": 2, "maintAmt": 1233035.0 - }, - { + }, { "min": 20000000, # stake = 20000000.0 "max": 50000000, # max_stake = 50000000.0 "mmr": 0.5, @@ -3359,75 +3323,66 @@ def leverage_tiers(): ], 'BTC/USDT': [ { - "min": 0, # stake = 0.0 - "max": 50000, # max_stake = 400.0 - "mmr": 0.004, - "lev": 125, - "maintAmt": 0.0 - }, - { - "min": 50000, # stake = 500.0 - "max": 250000, # max_stake = 2500.0 - "mmr": 0.005, - "lev": 100, - "maintAmt": 50.0 - }, - { - "min": 250000, # stake = 5000.0 - "max": 1000000, # max_stake = 20000.0 - "mmr": 0.01, - "lev": 50, - "maintAmt": 1300.0 - }, - { - "min": 1000000, # stake = 50000.0 - "max": 7500000, # max_stake = 375000.0 - "mmr": 0.025, - "lev": 20, - "maintAmt": 16300.0 - }, - { - "min": 7500000, # stake = 750000.0 - "max": 40000000, # max_stake = 4000000.0 - "mmr": 0.05, - "lev": 10, - "maintAmt": 203800.0 - }, - { - "min": 40000000, # stake = 8000000.0 - "max": 100000000, # max_stake = 20000000.0 - "mmr": 0.1, - "lev": 5, - "maintAmt": 2203800.0 - }, - { - "min": 100000000, # stake = 25000000.0 - "max": 200000000, # max_stake = 50000000.0 - "mmr": 0.125, - "lev": 4, - "maintAmt": 4703800.0 - }, - { - "min": 200000000, # stake = 66666666.666666664 - "max": 400000000, # max_stake = 133333333.33333333 - "mmr": 0.15, - "lev": 3, - "maintAmt": 9703800.0 - }, - { - "min": 400000000, # stake = 200000000.0 - "max": 600000000, # max_stake = 300000000.0 - "mmr": 0.25, - "lev": 2, - "maintAmt": 4.97038E7 - }, - { - "min": 600000000, # stake = 600000000.0 - "max": 1000000000, # max_stake = 1000000000.0 - "mmr": 0.5, - "lev": 1, - "maintAmt": 1.997038E8 - }, + 'min': 0.0, + 'max': 50000.0, + 'mmr': 0.004, + 'lev': 125.0, + 'maintAmt': 0.0 + }, { + 'min': 50000.0, + 'max': 250000.0, + 'mmr': 0.005, + 'lev': 100.0, + 'maintAmt': 50.0 + }, { + 'min': 250000.0, + 'max': 1000000.0, + 'mmr': 0.01, + 'lev': 50.0, + 'maintAmt': 1300.0 + }, { + 'min': 1000000.0, + 'max': 10000000.0, + 'mmr': 0.025, + 'lev': 20.0, + 'maintAmt': 16300.0 + }, { + 'min': 10000000.0, + 'max': 20000000.0, + 'mmr': 0.05, + 'lev': 10.0, + 'maintAmt': 266300.0 + }, { + 'min': 20000000.0, + 'max': 50000000.0, + 'mmr': 0.1, + 'lev': 5.0, + 'maintAmt': 1266300.0 + }, { + 'min': 50000000.0, + 'max': 100000000.0, + 'mmr': 0.125, + 'lev': 4.0, + 'maintAmt': 2516300.0 + }, { + 'min': 100000000.0, + 'max': 200000000.0, + 'mmr': 0.15, + 'lev': 3.0, + 'maintAmt': 5016300.0 + }, { + 'min': 200000000.0, + 'max': 300000000.0, + 'mmr': 0.25, + 'lev': 2.0, + 'maintAmt': 25016300.0 + }, { + 'min': 300000000.0, + 'max': 9.223372036854776e+18, + 'mmr': 0.5, + 'lev': 1.0, + 'maintAmt': 100016300.0 + } ], "ZEC/USDT": [ { @@ -3436,43 +3391,37 @@ def leverage_tiers(): 'mmr': 0.01, 'lev': 50, 'maintAmt': 0.0 - }, - { + }, { 'min': 50000, 'max': 150000, 'mmr': 0.025, 'lev': 20, 'maintAmt': 750.0 - }, - { + }, { 'min': 150000, 'max': 250000, 'mmr': 0.05, 'lev': 10, 'maintAmt': 4500.0 - }, - { + }, { 'min': 250000, 'max': 500000, 'mmr': 0.1, 'lev': 5, 'maintAmt': 17000.0 - }, - { + }, { 'min': 500000, 'max': 1000000, 'mmr': 0.125, 'lev': 4, 'maintAmt': 29500.0 - }, - { + }, { 'min': 1000000, 'max': 2000000, 'mmr': 0.25, 'lev': 2, 'maintAmt': 154500.0 - }, - { + }, { 'min': 2000000, 'max': 30000000, 'mmr': 0.5, From 97abcf4b320d9ee514f99392e52187b155437a61 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 May 2022 16:10:00 +0200 Subject: [PATCH 159/449] Add documentation for leverage_tiers update --- docs/developer.md | 26 +++++++++++++++++++ .../exchange/binance_leverage_tiers.json | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/developer.md b/docs/developer.md index 185bfc92e..ce7fb37e1 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -314,6 +314,32 @@ The output will show the last entry from the Exchange as well as the current UTC If the day shows the same day, then the last candle can be assumed as incomplete and should be dropped (leave the setting `"ohlcv_partial_candle"` from the exchange-class untouched / True). Otherwise, set `"ohlcv_partial_candle"` to `False` to not drop Candles (shown in the example above). Another way is to run this command multiple times in a row and observe if the volume is changing (while the date remains the same). +### Update binance cached leverage tiers + +Updating leveraged tiers should be done regularly - and requires an authenticated account with futures enabled. + +``` python +import ccxt +import json +from pathlib import Path + +exchange = ccxt.binance({ + 'apiKey': '', + 'secret': '' + 'options': {'defaultType': 'future'} + }) +_ = exchange.load_markets() + +lev_tiers = exchange.fetch_leverage_tiers() + +# Assumes this is running in the root of the repository. +file = Path('freqtrade/exchange/binance_leverage_tiers.json') +json.dump(lev_tiers, file.open('w'), indent=2) + +``` + +This file should then be contributed upstream, so others can benefit from this, too. + ## Updating example notebooks To keep the jupyter notebooks aligned with the documentation, the following should be ran after updating a example notebook. diff --git a/freqtrade/exchange/binance_leverage_tiers.json b/freqtrade/exchange/binance_leverage_tiers.json index 9292509bf..126b3b62f 100644 --- a/freqtrade/exchange/binance_leverage_tiers.json +++ b/freqtrade/exchange/binance_leverage_tiers.json @@ -16907,4 +16907,4 @@ } } ] -} +} \ No newline at end of file From 681ef131741315a0c82d4a461577758eab9ff868 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 May 2022 16:23:29 +0200 Subject: [PATCH 160/449] Relax dry-run leverage test-case to simplify future updates --- tests/conftest.py | 255 ++++++++++++++++++++------------- tests/exchange/test_binance.py | 6 +- 2 files changed, 155 insertions(+), 106 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 3fe7ad2b0..cc07de1de 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3058,37 +3058,43 @@ def leverage_tiers(): 'mmr': 0.01, 'lev': 50, 'maintAmt': 0.0 - }, { + }, + { 'min': 50000, 'max': 150000, 'mmr': 0.025, 'lev': 20, 'maintAmt': 750.0 - }, { + }, + { 'min': 150000, 'max': 250000, 'mmr': 0.05, 'lev': 10, 'maintAmt': 4500.0 - }, { + }, + { 'min': 250000, 'max': 500000, 'mmr': 0.1, 'lev': 5, 'maintAmt': 17000.0 - }, { + }, + { 'min': 500000, 'max': 1000000, 'mmr': 0.125, 'lev': 4, 'maintAmt': 29500.0 - }, { + }, + { 'min': 1000000, 'max': 2000000, 'mmr': 0.25, 'lev': 2, 'maintAmt': 154500.0 - }, { + }, + { 'min': 2000000, 'max': 30000000, 'mmr': 0.5, @@ -3103,31 +3109,36 @@ def leverage_tiers(): 'mmr': 0.012, 'lev': 50, 'maintAmt': 0.0 - }, { + }, + { 'min': 5000, 'max': 25000, 'mmr': 0.025, 'lev': 20, 'maintAmt': 65.0 - }, { + }, + { 'min': 25000, 'max': 100000, 'mmr': 0.05, 'lev': 10, 'maintAmt': 690.0 - }, { + }, + { 'min': 100000, 'max': 250000, 'mmr': 0.1, 'lev': 5, 'maintAmt': 5690.0 - }, { + }, + { 'min': 250000, 'max': 1000000, 'mmr': 0.125, 'lev': 2, 'maintAmt': 11940.0 - }, { + }, + { 'min': 1000000, 'max': 100000000, 'mmr': 0.5, @@ -3142,43 +3153,50 @@ def leverage_tiers(): 'mmr': 0.01, 'lev': 50, 'maintAmt': 0.0 - }, { + }, + { 'min': 50000, 'max': 250000, 'mmr': 0.02, 'lev': 25, 'maintAmt': 500.0 - }, { + }, + { 'min': 250000, 'max': 1000000, 'mmr': 0.05, 'lev': 10, 'maintAmt': 8000.0 - }, { + }, + { 'min': 1000000, 'max': 2000000, 'mmr': 0.1, 'lev': 5, 'maintAmt': 58000.0 - }, { + }, + { 'min': 2000000, 'max': 5000000, 'mmr': 0.125, 'lev': 4, 'maintAmt': 108000.0 - }, { + }, + { 'min': 5000000, 'max': 10000000, 'mmr': 0.1665, 'lev': 3, 'maintAmt': 315500.0 - }, { + }, + { 'min': 10000000, 'max': 20000000, 'mmr': 0.25, 'lev': 2, 'maintAmt': 1150500.0 - }, { + }, + { "min": 20000000, "max": 50000000, "mmr": 0.5, @@ -3193,31 +3211,36 @@ def leverage_tiers(): "mmr": 0.025, "lev": 20, "maintAmt": 0.0 - }, { + }, + { "min": 100000, "max": 500000, "mmr": 0.05, "lev": 10, "maintAmt": 2500.0 - }, { + }, + { "min": 500000, "max": 1000000, "mmr": 0.1, "lev": 5, "maintAmt": 27500.0 - }, { + }, + { "min": 1000000, "max": 2000000, "mmr": 0.15, "lev": 3, "maintAmt": 77500.0 - }, { + }, + { "min": 2000000, "max": 5000000, "mmr": 0.25, "lev": 2, "maintAmt": 277500.0 - }, { + }, + { "min": 5000000, "max": 30000000, "mmr": 0.5, @@ -3232,31 +3255,36 @@ def leverage_tiers(): "mmr": 0.025, "lev": 20, "maintAmt": 0.0 - }, { + }, + { "min": 100000, # stake = 10000.0 "max": 500000, # max_stake = 50000.0 "mmr": 0.05, "lev": 10, "maintAmt": 2500.0 - }, { + }, + { "min": 500000, # stake = 100000.0 "max": 1000000, # max_stake = 200000.0 "mmr": 0.1, "lev": 5, "maintAmt": 27500.0 - }, { + }, + { "min": 1000000, # stake = 333333.3333333333 "max": 2000000, # max_stake = 666666.6666666666 "mmr": 0.15, "lev": 3, "maintAmt": 77500.0 - }, { + }, + { "min": 2000000, # stake = 1000000.0 "max": 5000000, # max_stake = 2500000.0 "mmr": 0.25, "lev": 2, "maintAmt": 277500.0 - }, { + }, + { "min": 5000000, # stake = 5000000.0 "max": 30000000, # max_stake = 30000000.0 "mmr": 0.5, @@ -3271,49 +3299,57 @@ def leverage_tiers(): "mmr": 0.0065, "lev": 75, "maintAmt": 0.0 - }, { + }, + { "min": 10000, # stake = 200.0 "max": 50000, # max_stake = 1000.0 "mmr": 0.01, "lev": 50, "maintAmt": 35.0 - }, { + }, + { "min": 50000, # stake = 2000.0 "max": 250000, # max_stake = 10000.0 "mmr": 0.02, "lev": 25, "maintAmt": 535.0 - }, { + }, + { "min": 250000, # stake = 25000.0 "max": 1000000, # max_stake = 100000.0 "mmr": 0.05, "lev": 10, "maintAmt": 8035.0 - }, { + }, + { "min": 1000000, # stake = 200000.0 "max": 2000000, # max_stake = 400000.0 "mmr": 0.1, "lev": 5, "maintAmt": 58035.0 - }, { + }, + { "min": 2000000, # stake = 500000.0 "max": 5000000, # max_stake = 1250000.0 "mmr": 0.125, "lev": 4, "maintAmt": 108035.0 - }, { + }, + { "min": 5000000, # stake = 1666666.6666666667 "max": 10000000, # max_stake = 3333333.3333333335 "mmr": 0.15, "lev": 3, "maintAmt": 233035.0 - }, { + }, + { "min": 10000000, # stake = 5000000.0 "max": 20000000, # max_stake = 10000000.0 "mmr": 0.25, "lev": 2, "maintAmt": 1233035.0 - }, { + }, + { "min": 20000000, # stake = 20000000.0 "max": 50000000, # max_stake = 50000000.0 "mmr": 0.5, @@ -3323,66 +3359,75 @@ def leverage_tiers(): ], 'BTC/USDT': [ { - 'min': 0.0, - 'max': 50000.0, - 'mmr': 0.004, - 'lev': 125.0, - 'maintAmt': 0.0 - }, { - 'min': 50000.0, - 'max': 250000.0, - 'mmr': 0.005, - 'lev': 100.0, - 'maintAmt': 50.0 - }, { - 'min': 250000.0, - 'max': 1000000.0, - 'mmr': 0.01, - 'lev': 50.0, - 'maintAmt': 1300.0 - }, { - 'min': 1000000.0, - 'max': 10000000.0, - 'mmr': 0.025, - 'lev': 20.0, - 'maintAmt': 16300.0 - }, { - 'min': 10000000.0, - 'max': 20000000.0, - 'mmr': 0.05, - 'lev': 10.0, - 'maintAmt': 266300.0 - }, { - 'min': 20000000.0, - 'max': 50000000.0, - 'mmr': 0.1, - 'lev': 5.0, - 'maintAmt': 1266300.0 - }, { - 'min': 50000000.0, - 'max': 100000000.0, - 'mmr': 0.125, - 'lev': 4.0, - 'maintAmt': 2516300.0 - }, { - 'min': 100000000.0, - 'max': 200000000.0, - 'mmr': 0.15, - 'lev': 3.0, - 'maintAmt': 5016300.0 - }, { - 'min': 200000000.0, - 'max': 300000000.0, - 'mmr': 0.25, - 'lev': 2.0, - 'maintAmt': 25016300.0 - }, { - 'min': 300000000.0, - 'max': 9.223372036854776e+18, - 'mmr': 0.5, - 'lev': 1.0, - 'maintAmt': 100016300.0 - } + "min": 0, # stake = 0.0 + "max": 50000, # max_stake = 400.0 + "mmr": 0.004, + "lev": 125, + "maintAmt": 0.0 + }, + { + "min": 50000, # stake = 500.0 + "max": 250000, # max_stake = 2500.0 + "mmr": 0.005, + "lev": 100, + "maintAmt": 50.0 + }, + { + "min": 250000, # stake = 5000.0 + "max": 1000000, # max_stake = 20000.0 + "mmr": 0.01, + "lev": 50, + "maintAmt": 1300.0 + }, + { + "min": 1000000, # stake = 50000.0 + "max": 7500000, # max_stake = 375000.0 + "mmr": 0.025, + "lev": 20, + "maintAmt": 16300.0 + }, + { + "min": 7500000, # stake = 750000.0 + "max": 40000000, # max_stake = 4000000.0 + "mmr": 0.05, + "lev": 10, + "maintAmt": 203800.0 + }, + { + "min": 40000000, # stake = 8000000.0 + "max": 100000000, # max_stake = 20000000.0 + "mmr": 0.1, + "lev": 5, + "maintAmt": 2203800.0 + }, + { + "min": 100000000, # stake = 25000000.0 + "max": 200000000, # max_stake = 50000000.0 + "mmr": 0.125, + "lev": 4, + "maintAmt": 4703800.0 + }, + { + "min": 200000000, # stake = 66666666.666666664 + "max": 400000000, # max_stake = 133333333.33333333 + "mmr": 0.15, + "lev": 3, + "maintAmt": 9703800.0 + }, + { + "min": 400000000, # stake = 200000000.0 + "max": 600000000, # max_stake = 300000000.0 + "mmr": 0.25, + "lev": 2, + "maintAmt": 4.97038E7 + }, + { + "min": 600000000, # stake = 600000000.0 + "max": 1000000000, # max_stake = 1000000000.0 + "mmr": 0.5, + "lev": 1, + "maintAmt": 1.997038E8 + }, ], "ZEC/USDT": [ { @@ -3391,37 +3436,43 @@ def leverage_tiers(): 'mmr': 0.01, 'lev': 50, 'maintAmt': 0.0 - }, { + }, + { 'min': 50000, 'max': 150000, 'mmr': 0.025, 'lev': 20, 'maintAmt': 750.0 - }, { + }, + { 'min': 150000, 'max': 250000, 'mmr': 0.05, 'lev': 10, 'maintAmt': 4500.0 - }, { + }, + { 'min': 250000, 'max': 500000, 'mmr': 0.1, 'lev': 5, 'maintAmt': 17000.0 - }, { + }, + { 'min': 500000, 'max': 1000000, 'mmr': 0.125, 'lev': 4, 'maintAmt': 29500.0 - }, { + }, + { 'min': 1000000, 'max': 2000000, 'mmr': 0.25, 'lev': 2, 'maintAmt': 154500.0 - }, { + }, + { 'min': 2000000, 'max': 30000000, 'mmr': 0.5, diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index 5c8d7d3b0..e00fa289a 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -490,11 +490,9 @@ def test_fill_leverage_tiers_binance_dryrun(default_conf, mocker, leverage_tiers default_conf['margin_mode'] = MarginMode.ISOLATED exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance") exchange.fill_leverage_tiers() - - leverage_tiers = leverage_tiers - + assert len(exchange._leverage_tiers.keys()) > 100 for key, value in leverage_tiers.items(): - assert exchange._leverage_tiers[key] == value + assert isinstance(exchange._leverage_tiers[key], list) def test__set_leverage_binance(mocker, default_conf): From f006978caf8d10df218c8643d4ed7f1c795b94ca Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 21 May 2022 17:35:49 +0200 Subject: [PATCH 161/449] Be more explicit in default value --- freqtrade/optimize/backtesting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 2c34e29b0..3a3660c39 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -279,7 +279,7 @@ class Backtesting: self.futures_data[pair] = self.exchange.combine_funding_and_mark( funding_rates=funding_rates_dict[pair], mark_rates=mark_rates_dict[pair], - futures_funding_rate=self.config.get('futures_funding_rate'), + futures_funding_rate=self.config.get('futures_funding_rate', None), ) if unavailable_pairs: From ea8fda0deef5801a18af2fce788da30ae16b8cff Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 08:36:28 +0200 Subject: [PATCH 162/449] Slightly improve test --- tests/exchange/test_binance.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index e00fa289a..324be9962 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -492,7 +492,9 @@ def test_fill_leverage_tiers_binance_dryrun(default_conf, mocker, leverage_tiers exchange.fill_leverage_tiers() assert len(exchange._leverage_tiers.keys()) > 100 for key, value in leverage_tiers.items(): - assert isinstance(exchange._leverage_tiers[key], list) + v = exchange._leverage_tiers[key] + assert isinstance(v, list) + assert len(v) == len(value) def test__set_leverage_binance(mocker, default_conf): From 26d394ca744a8215238174b0f12f3dbe61fd24a7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 08:54:27 +0200 Subject: [PATCH 163/449] Add liquidation Price to api response --- freqtrade/rpc/api_server/api_schemas.py | 1 + tests/rpc/test_rpc_apiserver.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index d78ea8b78..f21334bc6 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -256,6 +256,7 @@ class TradeSchema(BaseModel): leverage: Optional[float] interest_rate: Optional[float] + liquidation_price: Optional[float] funding_fees: Optional[float] trading_mode: Optional[TradingMode] diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index ac2f1c3ec..03ba895a1 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -972,6 +972,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets, is_short, 'exchange': 'binance', 'leverage': 1.0, 'interest_rate': 0.0, + 'liquidation_price': None, 'funding_fees': None, 'trading_mode': ANY, 'orders': [ANY], @@ -1175,6 +1176,7 @@ def test_api_force_entry(botclient, mocker, fee, endpoint): 'exchange': 'binance', 'leverage': None, 'interest_rate': None, + 'liquidation_price': None, 'funding_fees': None, 'trading_mode': 'spot', 'orders': [], From 1315d024372d2d284f5b8fbd84f420104bf1220c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 09:01:46 +0200 Subject: [PATCH 164/449] Fix startup sending "longed" messages for open stoplosses --- freqtrade/freqtradebot.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index da35c12ff..3dccb45e4 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -299,7 +299,8 @@ class FreqtradeBot(LoggingMixin): fo = self.exchange.fetch_order_or_stoploss_order(order.order_id, order.ft_pair, order.ft_order_side == 'stoploss') - self.update_trade_state(order.trade, order.order_id, fo) + self.update_trade_state(order.trade, order.order_id, fo, + stoploss_order=(order.ft_order_side == 'stoploss')) except ExchangeError as e: @@ -1663,7 +1664,7 @@ class FreqtradeBot(LoggingMixin): if send_msg and not stoploss_order and not trade.open_order_id: self._notify_exit(trade, '', True) self.handle_protections(trade.pair, trade.trade_direction) - elif send_msg and not trade.open_order_id: + elif send_msg and not trade.open_order_id and not stoploss_order: # Enter fill self._notify_enter(trade, order, fill=True) From bdb904e7147650be3634f15dc3875545f6e5374b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 10:15:58 +0200 Subject: [PATCH 165/449] Should_exit should return all sell signals --- freqtrade/freqtradebot.py | 15 ++++++++------- freqtrade/optimize/backtesting.py | 14 +++++++++++--- freqtrade/strategy/interface.py | 16 +++++++--------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3dccb45e4..4ae55e31c 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1106,7 +1106,7 @@ class FreqtradeBot(LoggingMixin): """ Check and execute trade exit """ - should_exit: ExitCheckTuple = self.strategy.should_exit( + exits: List[ExitCheckTuple] = self.strategy.should_exit( trade, exit_rate, datetime.now(timezone.utc), @@ -1114,12 +1114,13 @@ class FreqtradeBot(LoggingMixin): exit_=exit_, force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0 ) - - if should_exit.exit_flag: - logger.info(f'Exit for {trade.pair} detected. Reason: {should_exit.exit_type}' - f'Tag: {exit_tag if exit_tag is not None else "None"}') - self.execute_trade_exit(trade, exit_rate, should_exit, exit_tag=exit_tag) - return True + for should_exit in exits: + if should_exit.exit_flag: + logger.info(f'Exit for {trade.pair} detected. Reason: {should_exit.exit_type}' + f'Tag: {exit_tag if exit_tag is not None else "None"}') + exited = self.execute_trade_exit(trade, exit_rate, should_exit, exit_tag=exit_tag) + if exited: + return True return False def manage_open_orders(self) -> None: diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 4e604898f..4286f5b95 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -527,15 +527,23 @@ class Backtesting: if check_adjust_entry: trade = self._get_adjust_trade_entry_for_candle(trade, row) - exit_candle_time: datetime = row[DATE_IDX].to_pydatetime() enter = row[SHORT_IDX] if trade.is_short else row[LONG_IDX] exit_sig = row[ESHORT_IDX] if trade.is_short else row[ELONG_IDX] - exit_ = self.strategy.should_exit( - trade, row[OPEN_IDX], exit_candle_time, # type: ignore + exits = self.strategy.should_exit( + trade, row[OPEN_IDX], row[DATE_IDX].to_pydatetime(), # type: ignore enter=enter, exit_=exit_sig, low=row[LOW_IDX], high=row[HIGH_IDX] ) + for exit_ in exits: + t = self._get_exit_for_signal(trade, row, exit_) + if t: + return t + return None + def _get_exit_for_signal(self, trade: LocalTrade, row: Tuple, + exit_: ExitCheckTuple) -> Optional[LocalTrade]: + + exit_candle_time: datetime = row[DATE_IDX].to_pydatetime() if exit_.exit_flag: trade.close_date = exit_candle_time exit_reason = exit_.exit_reason diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 57afbf32a..15627722c 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -878,16 +878,16 @@ class IStrategy(ABC, HyperStrategyMixin): def should_exit(self, trade: Trade, rate: float, current_time: datetime, *, enter: bool, exit_: bool, low: float = None, high: float = None, - force_stoploss: float = 0) -> ExitCheckTuple: + force_stoploss: float = 0) -> List[ExitCheckTuple]: """ This function evaluates if one of the conditions required to trigger an exit order has been reached, which can either be a stop-loss, ROI or exit-signal. :param low: Only used during backtesting to simulate (long)stoploss/(short)ROI :param high: Only used during backtesting, to simulate (short)stoploss/(long)ROI :param force_stoploss: Externally provided stoploss - :return: True if trade should be exited, False otherwise + :return: List of exit reasons - or empty list. """ - + exits: List[ExitCheckTuple] = [] current_rate = rate current_profit = trade.calc_profit_ratio(current_rate) @@ -938,7 +938,7 @@ class IStrategy(ABC, HyperStrategyMixin): logger.debug(f"{trade.pair} - Sell signal received. " f"exit_type=ExitType.{exit_signal.name}" + (f", custom_reason={custom_reason}" if custom_reason else "")) - return ExitCheckTuple(exit_type=exit_signal, exit_reason=custom_reason) + exits.append(ExitCheckTuple(exit_type=exit_signal, exit_reason=custom_reason)) # Sequence: # Exit-signal @@ -946,16 +946,14 @@ class IStrategy(ABC, HyperStrategyMixin): # Stoploss if roi_reached and stoplossflag.exit_type != ExitType.STOP_LOSS: logger.debug(f"{trade.pair} - Required profit reached. exit_type=ExitType.ROI") - return ExitCheckTuple(exit_type=ExitType.ROI) + exits.append(ExitCheckTuple(exit_type=ExitType.ROI)) if stoplossflag.exit_flag: logger.debug(f"{trade.pair} - Stoploss hit. exit_type={stoplossflag.exit_type}") - return stoplossflag + exits.append(stoplossflag) - # This one is noisy, commented out... - # logger.debug(f"{trade.pair} - No exit signal.") - return ExitCheckTuple(exit_type=ExitType.NONE) + return exits def stop_loss_reached(self, current_rate: float, trade: Trade, current_time: datetime, current_profit: float, From b7388557a9418c2ec8cb1310a2aea6e41acc5366 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 10:20:01 +0200 Subject: [PATCH 166/449] Update interface tests --- tests/strategy/test_interface.py | 21 ++++++++++----------- tests/test_integration.py | 14 +++++++------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 6e57a3182..55cfcaf98 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -495,34 +495,33 @@ def test_custom_exit(default_conf, fee, caplog) -> None: enter=False, exit_=False, low=None, high=None) - assert res.exit_flag is False - assert res.exit_type == ExitType.NONE + assert res == [] strategy.custom_exit = MagicMock(return_value=True) res = strategy.should_exit(trade, 1, now, enter=False, exit_=False, low=None, high=None) - assert res.exit_flag is True - assert res.exit_type == ExitType.CUSTOM_EXIT - assert res.exit_reason == 'custom_exit' + assert res[0].exit_flag is True + assert res[0].exit_type == ExitType.CUSTOM_EXIT + assert res[0].exit_reason == 'custom_exit' strategy.custom_exit = MagicMock(return_value='hello world') res = strategy.should_exit(trade, 1, now, enter=False, exit_=False, low=None, high=None) - assert res.exit_type == ExitType.CUSTOM_EXIT - assert res.exit_flag is True - assert res.exit_reason == 'hello world' + assert res[0].exit_type == ExitType.CUSTOM_EXIT + assert res[0].exit_flag is True + assert res[0].exit_reason == 'hello world' caplog.clear() strategy.custom_exit = MagicMock(return_value='h' * 100) res = strategy.should_exit(trade, 1, now, enter=False, exit_=False, low=None, high=None) - assert res.exit_type == ExitType.CUSTOM_EXIT - assert res.exit_flag is True - assert res.exit_reason == 'h' * 64 + assert res[0].exit_type == ExitType.CUSTOM_EXIT + assert res[0].exit_flag is True + assert res[0].exit_reason == 'h' * 64 assert log_has_re('Custom exit reason returned from custom_exit is too long.*', caplog) diff --git a/tests/test_integration.py b/tests/test_integration.py index d2ad8c981..83f54becb 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -52,8 +52,8 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, side_effect=[stoploss_order_closed, stoploss_order_open, stoploss_order_open]) # Sell 3rd trade (not called for the first trade) should_sell_mock = MagicMock(side_effect=[ - ExitCheckTuple(exit_type=ExitType.NONE), - ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL)] + [], + [ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL)]] ) cancel_order_mock = MagicMock() mocker.patch('freqtrade.exchange.Binance.stoploss', stoploss) @@ -160,11 +160,11 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, mocker, balance_rati _notify_exit=MagicMock(), ) should_sell_mock = MagicMock(side_effect=[ - ExitCheckTuple(exit_type=ExitType.NONE), - ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL), - ExitCheckTuple(exit_type=ExitType.NONE), - ExitCheckTuple(exit_type=ExitType.NONE), - ExitCheckTuple(exit_type=ExitType.NONE)] + [], + [ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL)], + [], + [], + []] ) mocker.patch("freqtrade.strategy.interface.IStrategy.should_exit", should_sell_mock) From ce3bfd59f5e92f2b5f56848d76763fe17b76ad07 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 10:31:29 +0200 Subject: [PATCH 167/449] Add explicit should_sell test --- freqtrade/enums/exitchecktuple.py | 3 ++ tests/strategy/test_interface.py | 74 +++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/freqtrade/enums/exitchecktuple.py b/freqtrade/enums/exitchecktuple.py index c245a05da..580b4e21c 100644 --- a/freqtrade/enums/exitchecktuple.py +++ b/freqtrade/enums/exitchecktuple.py @@ -15,3 +15,6 @@ class ExitCheckTuple: @property def exit_flag(self): return self.exit_type != ExitType.NONE + + def __eq__(self, other): + return self.exit_type == other.exit_type and self.exit_reason == other.exit_reason diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 55cfcaf98..8bdea852a 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -525,6 +525,80 @@ def test_custom_exit(default_conf, fee, caplog) -> None: assert log_has_re('Custom exit reason returned from custom_exit is too long.*', caplog) +def test_should_sell(default_conf, fee, caplog) -> None: + + strategy = StrategyResolver.load_strategy(default_conf) + trade = Trade( + pair='ETH/BTC', + stake_amount=0.01, + amount=1, + open_date=arrow.utcnow().shift(hours=-1).datetime, + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='binance', + open_rate=1, + ) + now = arrow.utcnow().datetime + res = strategy.should_exit(trade, 1, now, + enter=False, exit_=False, + low=None, high=None) + + assert res == [] + strategy.min_roi_reached = MagicMock(return_value=True) + + res = strategy.should_exit(trade, 1, now, + enter=False, exit_=False, + low=None, high=None) + assert len(res) == 1 + assert res == [ExitCheckTuple(exit_type=ExitType.ROI)] + + strategy.min_roi_reached = MagicMock(return_value=True) + strategy.stop_loss_reached = MagicMock( + return_value=ExitCheckTuple(exit_type=ExitType.STOP_LOSS)) + + res = strategy.should_exit(trade, 1, now, + enter=False, exit_=False, + low=None, high=None) + assert len(res) == 2 + assert res == [ + ExitCheckTuple(exit_type=ExitType.ROI), + ExitCheckTuple(exit_type=ExitType.STOP_LOSS), + ] + + strategy.custom_exit = MagicMock(return_value='hello world') + + res = strategy.should_exit(trade, 1, now, + enter=False, exit_=False, + low=None, high=None) + assert len(res) == 3 + assert res == [ + ExitCheckTuple(exit_type=ExitType.CUSTOM_EXIT, exit_reason='hello world'), + ExitCheckTuple(exit_type=ExitType.ROI), + ExitCheckTuple(exit_type=ExitType.STOP_LOSS), + ] + + # Regular exit signal + res = strategy.should_exit(trade, 1, now, + enter=False, exit_=True, + low=None, high=None) + assert len(res) == 3 + assert res == [ + ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL), + ExitCheckTuple(exit_type=ExitType.ROI), + ExitCheckTuple(exit_type=ExitType.STOP_LOSS), + ] + + # Regular exit signal, no ROI + strategy.min_roi_reached = MagicMock(return_value=False) + res = strategy.should_exit(trade, 1, now, + enter=False, exit_=True, + low=None, high=None) + assert len(res) == 2 + assert res == [ + ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL), + ExitCheckTuple(exit_type=ExitType.STOP_LOSS), + ] + @pytest.mark.parametrize('side', TRADE_SIDES) def test_leverage_callback(default_conf, side) -> None: default_conf['strategy'] = 'StrategyTestV2' From 3692fcd3d5c56ca546496ac5b9bd65e899fa92f4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 11:01:18 +0200 Subject: [PATCH 168/449] Improve exit signal sequence --- freqtrade/enums/exitchecktuple.py | 3 +++ freqtrade/strategy/interface.py | 15 +++++++++++---- tests/strategy/test_interface.py | 15 +++++++++------ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/freqtrade/enums/exitchecktuple.py b/freqtrade/enums/exitchecktuple.py index 580b4e21c..cb6411caf 100644 --- a/freqtrade/enums/exitchecktuple.py +++ b/freqtrade/enums/exitchecktuple.py @@ -18,3 +18,6 @@ class ExitCheckTuple: def __eq__(self, other): return self.exit_type == other.exit_type and self.exit_reason == other.exit_reason + + def __repr__(self): + return f"ExitCheckTuple({self.exit_type}, {self.exit_reason})" diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 15627722c..69a3f9742 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -942,15 +942,22 @@ class IStrategy(ABC, HyperStrategyMixin): # Sequence: # Exit-signal - # ROI (if not stoploss) # Stoploss - if roi_reached and stoplossflag.exit_type != ExitType.STOP_LOSS: + # ROI + # Trailing stoploss + + if stoplossflag.exit_type == ExitType.STOP_LOSS: + + logger.debug(f"{trade.pair} - Stoploss hit. exit_type={stoplossflag.exit_type}") + exits.append(stoplossflag) + + if roi_reached: logger.debug(f"{trade.pair} - Required profit reached. exit_type=ExitType.ROI") exits.append(ExitCheckTuple(exit_type=ExitType.ROI)) - if stoplossflag.exit_flag: + if stoplossflag.exit_type == ExitType.TRAILING_STOP_LOSS: - logger.debug(f"{trade.pair} - Stoploss hit. exit_type={stoplossflag.exit_type}") + logger.debug(f"{trade.pair} - Trailing stoploss hit.") exits.append(stoplossflag) return exits diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 8bdea852a..2cedea962 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -525,7 +525,7 @@ def test_custom_exit(default_conf, fee, caplog) -> None: assert log_has_re('Custom exit reason returned from custom_exit is too long.*', caplog) -def test_should_sell(default_conf, fee, caplog) -> None: +def test_should_sell(default_conf, fee) -> None: strategy = StrategyResolver.load_strategy(default_conf) trade = Trade( @@ -561,22 +561,24 @@ def test_should_sell(default_conf, fee, caplog) -> None: low=None, high=None) assert len(res) == 2 assert res == [ - ExitCheckTuple(exit_type=ExitType.ROI), ExitCheckTuple(exit_type=ExitType.STOP_LOSS), + ExitCheckTuple(exit_type=ExitType.ROI), ] strategy.custom_exit = MagicMock(return_value='hello world') - + # custom-exit and exit-signal is first res = strategy.should_exit(trade, 1, now, enter=False, exit_=False, low=None, high=None) assert len(res) == 3 assert res == [ ExitCheckTuple(exit_type=ExitType.CUSTOM_EXIT, exit_reason='hello world'), - ExitCheckTuple(exit_type=ExitType.ROI), ExitCheckTuple(exit_type=ExitType.STOP_LOSS), + ExitCheckTuple(exit_type=ExitType.ROI), ] + strategy.stop_loss_reached = MagicMock( + return_value=ExitCheckTuple(exit_type=ExitType.TRAILING_STOP_LOSS)) # Regular exit signal res = strategy.should_exit(trade, 1, now, enter=False, exit_=True, @@ -585,7 +587,7 @@ def test_should_sell(default_conf, fee, caplog) -> None: assert res == [ ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL), ExitCheckTuple(exit_type=ExitType.ROI), - ExitCheckTuple(exit_type=ExitType.STOP_LOSS), + ExitCheckTuple(exit_type=ExitType.TRAILING_STOP_LOSS), ] # Regular exit signal, no ROI @@ -596,9 +598,10 @@ def test_should_sell(default_conf, fee, caplog) -> None: assert len(res) == 2 assert res == [ ExitCheckTuple(exit_type=ExitType.EXIT_SIGNAL), - ExitCheckTuple(exit_type=ExitType.STOP_LOSS), + ExitCheckTuple(exit_type=ExitType.TRAILING_STOP_LOSS), ] + @pytest.mark.parametrize('side', TRADE_SIDES) def test_leverage_callback(default_conf, side) -> None: default_conf['strategy'] = 'StrategyTestV2' From 938a66511a4fcd9961c8e55334979e4fe7e15fe5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 11:28:11 +0200 Subject: [PATCH 169/449] Update Documentation for new confirm_trade_exit behavior --- docs/backtesting.md | 3 ++- docs/strategy-callbacks.md | 11 +++++++++++ freqtrade/freqtradebot.py | 6 +++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index b4d9aef80..76718d206 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -530,8 +530,9 @@ Since backtesting lacks some detailed information about what happens within a ca - Exit-reason does not explain if a trade was positive or negative, just what triggered the exit (this can look odd if negative ROI values are used) - Evaluation sequence (if multiple signals happen on the same candle) - Exit-signal - - ROI (if not stoploss) - Stoploss + - ROI + - Trailing stoploss Taking these assumptions, backtesting tries to mirror real trading as closely as possible. However, backtesting will **never** replace running a strategy in dry-run mode. Also, keep in mind that past results don't guarantee future success. diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index ab67a3c26..7f3249c88 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -563,6 +563,14 @@ class AwesomeStrategy(IStrategy): `confirm_trade_exit()` can be used to abort a trade exit (sell) at the latest second (maybe because the price is not what we expect). +`confirm_trade_exit()` may be called multiple times within one iteration for the same trade if different exit-reasons apply. +The exit-reasons (if applicable) will be in the following sequence: + +* `exit_signal` / `custom_exit` +* `stop_loss` +* `roi` +* `trailing_stop_loss` + ``` python from freqtrade.persistence import Trade @@ -605,6 +613,9 @@ class AwesomeStrategy(IStrategy): ``` +!!! Warning + `confirm_trade_exit()` can prevent stoploss exits, causing significant losses as this would ignore stoploss exits. + ## Adjust trade position The `position_adjustment_enable` strategy property enables the usage of `adjust_trade_position()` callback in the strategy. diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 4ae55e31c..08f5474fd 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1117,7 +1117,7 @@ class FreqtradeBot(LoggingMixin): for should_exit in exits: if should_exit.exit_flag: logger.info(f'Exit for {trade.pair} detected. Reason: {should_exit.exit_type}' - f'Tag: {exit_tag if exit_tag is not None else "None"}') + f'{f" Tag: {exit_tag}" if exit_tag is not None else ""}') exited = self.execute_trade_exit(trade, exit_rate, should_exit, exit_tag=exit_tag) if exited: return True @@ -1407,7 +1407,7 @@ class FreqtradeBot(LoggingMixin): :param trade: Trade instance :param limit: limit rate for the sell order :param exit_check: CheckTuple with signal and reason - :return: True if it succeeds (supported) False (not supported) + :return: True if it succeeds False """ trade.funding_fees = self.exchange.get_funding_fees( pair=trade.pair, @@ -1454,7 +1454,7 @@ class FreqtradeBot(LoggingMixin): time_in_force=time_in_force, exit_reason=exit_reason, sell_reason=exit_reason, # sellreason -> compatibility current_time=datetime.now(timezone.utc)): - logger.info(f"User requested abortion of exiting {trade.pair}") + logger.info(f"User requested abortion of {trade.pair} exit.") return False try: From 0b5544ef9e521055196e5e3e2ddfc331156432e0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 19:16:31 +0200 Subject: [PATCH 170/449] Stoploss fill should fill as "filled" notification Closes #6873 --- freqtrade/constants.py | 4 ++-- freqtrade/freqtradebot.py | 2 +- tests/test_freqtradebot.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 372472db8..9fbd70e42 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -302,12 +302,12 @@ CONF_SCHEMA = { 'exit_fill': { 'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS, - 'default': 'off' + 'default': 'on' }, 'protection_trigger': { 'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS, - 'default': 'off' + 'default': 'on' }, 'protection_trigger_global': { 'type': 'string', diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3dccb45e4..a8e1fa31f 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1019,7 +1019,7 @@ class FreqtradeBot(LoggingMixin): # Lock pair for one candle to prevent immediate rebuys self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc), reason='Auto lock') - self._notify_exit(trade, "stoploss") + self._notify_exit(trade, "stoploss", True) return True if trade.open_order_id or not trade.is_open: diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index d2df4e6a5..23ef4ffc2 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3582,7 +3582,7 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit( assert rpc_mock.call_count == 3 assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.ENTRY assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.ENTRY_FILL - assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.EXIT + assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.EXIT_FILL @pytest.mark.parametrize( From e3beaae8be8f1603da4b255d3d09de8fdd4627d5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 22 May 2022 19:32:32 +0200 Subject: [PATCH 171/449] update hyperopt typing --- freqtrade/optimize/hyperopt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 1dafb483c..d1697709b 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -27,8 +27,7 @@ from freqtrade.misc import deep_merge_dicts, file_dump_json, plural from freqtrade.optimize.backtesting import Backtesting # Import IHyperOpt and IHyperOptLoss to allow unpickling classes from these modules from freqtrade.optimize.hyperopt_auto import HyperOptAuto -from freqtrade.optimize.hyperopt_interface import IHyperOpt # noqa: F401 -from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss # noqa: F401 +from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss from freqtrade.optimize.hyperopt_tools import HyperoptTools, hyperopt_serializer from freqtrade.optimize.optimize_reports import generate_strategy_stats from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver @@ -62,7 +61,6 @@ class Hyperopt: hyperopt = Hyperopt(config) hyperopt.start() """ - custom_hyperopt: IHyperOpt def __init__(self, config: Dict[str, Any]) -> None: self.buy_space: List[Dimension] = [] @@ -77,6 +75,7 @@ class Hyperopt: self.backtesting = Backtesting(self.config) self.pairlist = self.backtesting.pairlists.whitelist + self.custom_hyperopt: HyperOptAuto if not self.config.get('hyperopt'): self.custom_hyperopt = HyperOptAuto(self.config) @@ -88,7 +87,8 @@ class Hyperopt: self.backtesting._set_strategy(self.backtesting.strategylist[0]) self.custom_hyperopt.strategy = self.backtesting.strategy - self.custom_hyperoptloss = HyperOptLossResolver.load_hyperoptloss(self.config) + self.custom_hyperoptloss: IHyperOptLoss = HyperOptLossResolver.load_hyperoptloss( + self.config) self.calculate_loss = self.custom_hyperoptloss.hyperopt_loss_function time_now = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") strategy = str(self.config['strategy']) From 27019339b5b3cb4cc48fd834755d432489f29ac4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 03:01:15 +0000 Subject: [PATCH 172/449] Bump ccxt from 1.83.12 to 1.83.62 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.83.12 to 1.83.62. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.83.12...1.83.62) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a3c4c3dca..ea7b36865 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.3 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.83.12 +ccxt==1.83.62 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From f819fafa1cc2f6f2f45586f6c3ac8bde685ca815 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 03:01:20 +0000 Subject: [PATCH 173/449] Bump psutil from 5.9.0 to 5.9.1 Bumps [psutil](https://github.com/giampaolo/psutil) from 5.9.0 to 5.9.1. - [Release notes](https://github.com/giampaolo/psutil/releases) - [Changelog](https://github.com/giampaolo/psutil/blob/master/HISTORY.rst) - [Commits](https://github.com/giampaolo/psutil/compare/release-5.9.0...release-5.9.1) --- updated-dependencies: - dependency-name: psutil dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a3c4c3dca..2b5639c2a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,7 +38,7 @@ fastapi==0.78.0 uvicorn==0.17.6 pyjwt==2.4.0 aiofiles==0.8.0 -psutil==5.9.0 +psutil==5.9.1 # Support for colorized terminal output colorama==0.4.4 From 40f63ae51c1ce9f727557f20b696c5fd8efacec1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 03:01:30 +0000 Subject: [PATCH 174/449] Bump scipy from 1.8.0 to 1.8.1 Bumps [scipy](https://github.com/scipy/scipy) from 1.8.0 to 1.8.1. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.8.0...v1.8.1) --- updated-dependencies: - dependency-name: scipy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 0b91636f1..5370e0899 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -2,7 +2,7 @@ -r requirements.txt # Required for hyperopt -scipy==1.8.0 +scipy==1.8.1 scikit-learn==1.1.0 scikit-optimize==0.9.0 filelock==3.7.0 From ff9dcfe789bceb33e893536a8147d8a7daff29a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 03:01:32 +0000 Subject: [PATCH 175/449] Bump types-python-dateutil from 2.8.15 to 2.8.16 Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.15 to 2.8.16. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-python-dateutil dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index c7167cc8b..7c8d732f3 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -26,4 +26,4 @@ types-cachetools==5.0.1 types-filelock==3.2.5 types-requests==2.27.25 types-tabulate==0.8.9 -types-python-dateutil==2.8.15 +types-python-dateutil==2.8.16 From 34657639f8eb33db512e5382bebfa16f361649f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 03:01:46 +0000 Subject: [PATCH 176/449] Bump numpy from 1.22.3 to 1.22.4 Bumps [numpy](https://github.com/numpy/numpy) from 1.22.3 to 1.22.4. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst.txt) - [Commits](https://github.com/numpy/numpy/compare/v1.22.3...v1.22.4) --- updated-dependencies: - dependency-name: numpy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a3c4c3dca..b970a1fca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy==1.22.3 +numpy==1.22.4 pandas==1.4.2 pandas-ta==0.3.14b From 7f5650699ebf446fdc7cc41f7f6d6033ee2a85d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 03:01:48 +0000 Subject: [PATCH 177/449] Bump types-requests from 2.27.25 to 2.27.27 Bumps [types-requests](https://github.com/python/typeshed) from 2.27.25 to 2.27.27. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index c7167cc8b..27a7c4432 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -24,6 +24,6 @@ nbconvert==6.5.0 # mypy types types-cachetools==5.0.1 types-filelock==3.2.5 -types-requests==2.27.25 +types-requests==2.27.27 types-tabulate==0.8.9 types-python-dateutil==2.8.15 From 66497c28e8fe26107e09a5ba253a463ceeb3c118 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 23 May 2022 06:28:11 +0200 Subject: [PATCH 178/449] Bump pre-commit requests types --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee909185a..3954c0dec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: additional_dependencies: - types-cachetools==5.0.1 - types-filelock==3.2.5 - - types-requests==2.27.25 + - types-requests==2.27.27 - types-tabulate==0.8.9 - types-python-dateutil==2.8.15 # stages: [push] From 596aeec6527f06e37e938a0d381b5faa67a928dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 04:33:43 +0000 Subject: [PATCH 179/449] Bump scikit-learn from 1.1.0 to 1.1.1 Bumps [scikit-learn](https://github.com/scikit-learn/scikit-learn) from 1.1.0 to 1.1.1. - [Release notes](https://github.com/scikit-learn/scikit-learn/releases) - [Commits](https://github.com/scikit-learn/scikit-learn/compare/1.1.0...1.1.1) --- updated-dependencies: - dependency-name: scikit-learn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 5370e0899..b8762214a 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -3,7 +3,7 @@ # Required for hyperopt scipy==1.8.1 -scikit-learn==1.1.0 +scikit-learn==1.1.1 scikit-optimize==0.9.0 filelock==3.7.0 progressbar2==4.0.0 From cc3ec279c21c321b2665c59cd12d4e770dbce27d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 23 May 2022 06:57:49 +0200 Subject: [PATCH 180/449] Bump dateutil types precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee909185a..8078bdda3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - types-filelock==3.2.5 - types-requests==2.27.25 - types-tabulate==0.8.9 - - types-python-dateutil==2.8.15 + - types-python-dateutil==2.8.16 # stages: [push] - repo: https://github.com/pycqa/isort From b88dfe42978a310b87ec098157f4505a566c4527 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 May 2022 06:32:06 +0000 Subject: [PATCH 181/449] Bump types-filelock from 3.2.5 to 3.2.6 Bumps [types-filelock](https://github.com/python/typeshed) from 3.2.5 to 3.2.6. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-filelock dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 0f5d31636..e863238bd 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -23,7 +23,7 @@ nbconvert==6.5.0 # mypy types types-cachetools==5.0.1 -types-filelock==3.2.5 +types-filelock==3.2.6 types-requests==2.27.27 types-tabulate==0.8.9 types-python-dateutil==2.8.16 From 34b1231df307da98e4c1beed0ab0a7b3489e85b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 23 May 2022 08:32:46 +0200 Subject: [PATCH 182/449] Bump filelock-precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4893a3da9..d59010154 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: exclude: build_helpers additional_dependencies: - types-cachetools==5.0.1 - - types-filelock==3.2.5 + - types-filelock==3.2.6 - types-requests==2.27.27 - types-tabulate==0.8.9 - types-python-dateutil==2.8.16 From 5c4014ee624f3e8e5c16a2036e7d8a4e680a69e4 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Mon, 23 May 2022 10:24:58 +0200 Subject: [PATCH 183/449] Change default value of process_only_new_candles to True since False is an uncommon usecase for expert strategy devs --- docs/configuration.md | 2 +- freqtrade/strategy/interface.py | 2 +- freqtrade/templates/base_strategy.py.j2 | 2 +- freqtrade/templates/sample_strategy.py | 2 +- tests/strategy/test_strategy_loading.py | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 43151f51c..0f3069478 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -140,7 +140,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `dry_run` | **Required.** Define if the bot must be in Dry Run or production mode.
*Defaults to `true`.*
**Datatype:** Boolean | `dry_run_wallet` | Define the starting amount in stake currency for the simulated wallet used by the bot running in Dry Run mode.
*Defaults to `1000`.*
**Datatype:** Float | `cancel_open_orders_on_exit` | Cancel open orders when the `/stop` RPC command is issued, `Ctrl+C` is pressed or the bot dies unexpectedly. When set to `true`, this allows you to use `/stop` to cancel unfilled and partially filled orders in the event of a market crash. It does not impact open positions.
*Defaults to `false`.*
**Datatype:** Boolean -| `process_only_new_candles` | Enable processing of indicators only when new candles arrive. If false each loop populates the indicators, this will mean the same candle is processed many times creating system load but can be useful of your strategy depends on tick data not only candle. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `false`.*
**Datatype:** Boolean +| `process_only_new_candles` | Enable processing of indicators only when new candles arrive. If false each loop populates the indicators, this will mean the same candle is processed many times creating system load but can be useful of your strategy depends on tick data not only candle. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `true`.*
**Datatype:** Boolean | `minimal_roi` | **Required.** Set the threshold as ratio the bot will use to exit a trade. [More information below](#understand-minimal_roi). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** Dict | `stoploss` | **Required.** Value as ratio of the stoploss used by the bot. More details in the [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** Float (as ratio) | `trailing_stop` | Enables trailing stoploss (based on `stoploss` in either configuration or strategy file). More details in the [stoploss documentation](stoploss.md#trailing-stop-loss). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** Boolean diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 57afbf32a..473e58e6a 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -82,7 +82,7 @@ class IStrategy(ABC, HyperStrategyMixin): } # run "populate_indicators" only for new candle - process_only_new_candles: bool = False + process_only_new_candles: bool = True use_exit_signal: bool exit_profit_only: bool diff --git a/freqtrade/templates/base_strategy.py.j2 b/freqtrade/templates/base_strategy.py.j2 index 9e7e1fe50..d393574d9 100644 --- a/freqtrade/templates/base_strategy.py.j2 +++ b/freqtrade/templates/base_strategy.py.j2 @@ -64,7 +64,7 @@ class {{ strategy }}(IStrategy): # trailing_stop_positive_offset = 0.0 # Disabled / not configured # Run "populate_indicators()" only for new candle. - process_only_new_candles = False + process_only_new_candles = True # These values can be overridden in the config. use_exit_signal = True diff --git a/freqtrade/templates/sample_strategy.py b/freqtrade/templates/sample_strategy.py index f0ae6c10d..1b375714a 100644 --- a/freqtrade/templates/sample_strategy.py +++ b/freqtrade/templates/sample_strategy.py @@ -62,7 +62,7 @@ class SampleStrategy(IStrategy): timeframe = '5m' # Run "populate_indicators()" only for new candle. - process_only_new_candles = False + process_only_new_candles = True # These values can be overridden in the config. use_exit_signal = True diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index 3ed1eb0ce..919a4bd00 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -224,12 +224,12 @@ def test_strategy_override_process_only_new_candles(caplog, default_conf): default_conf.update({ 'strategy': CURRENT_TEST_STRATEGY, - 'process_only_new_candles': True + 'process_only_new_candles': False }) strategy = StrategyResolver.load_strategy(default_conf) - assert strategy.process_only_new_candles - assert log_has("Override strategy 'process_only_new_candles' with value in config file: True.", + assert not strategy.process_only_new_candles + assert log_has("Override strategy 'process_only_new_candles' with value in config file: False.", caplog) From 42ae8ba6fbf4007535afc85f467cfda5ccfaeed3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 23 May 2022 20:18:09 +0200 Subject: [PATCH 184/449] Refactor hyperopt parameters to separate file --- freqtrade/strategy/__init__.py | 4 +- freqtrade/strategy/hyper.py | 284 +----------------------------- freqtrade/strategy/parameters.py | 287 +++++++++++++++++++++++++++++++ tests/optimize/test_hyperopt.py | 2 +- tests/strategy/test_interface.py | 4 +- 5 files changed, 296 insertions(+), 285 deletions(-) create mode 100644 freqtrade/strategy/parameters.py diff --git a/freqtrade/strategy/__init__.py b/freqtrade/strategy/__init__.py index 2ea0ad2b4..2d23bcd4d 100644 --- a/freqtrade/strategy/__init__.py +++ b/freqtrade/strategy/__init__.py @@ -1,9 +1,9 @@ # flake8: noqa: F401 from freqtrade.exchange import (timeframe_to_minutes, timeframe_to_msecs, timeframe_to_next_date, timeframe_to_prev_date, timeframe_to_seconds) -from freqtrade.strategy.hyper import (BooleanParameter, CategoricalParameter, DecimalParameter, - IntParameter, RealParameter) from freqtrade.strategy.informative_decorator import informative from freqtrade.strategy.interface import IStrategy +from freqtrade.strategy.parameters import (BooleanParameter, CategoricalParameter, DecimalParameter, + IntParameter, RealParameter) from freqtrade.strategy.strategy_helper import (merge_informative_pair, stoploss_from_absolute, stoploss_from_open) diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index 278954bb2..15f5be483 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -3,295 +3,19 @@ IHyperStrategy interface, hyperoptable Parameter class. This module defines a base class for auto-hyperoptable strategies. """ import logging -from abc import ABC, abstractmethod -from contextlib import suppress from pathlib import Path -from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple, Union - -from freqtrade.misc import deep_merge_dicts, json_load -from freqtrade.optimize.hyperopt_tools import HyperoptTools - - -with suppress(ImportError): - from skopt.space import Integer, Real, Categorical - from freqtrade.optimize.space import SKDecimal +from typing import Any, Dict, Iterator, List, Tuple from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException +from freqtrade.misc import deep_merge_dicts, json_load +from freqtrade.optimize.hyperopt_tools import HyperoptTools +from freqtrade.strategy.parameters import BaseParameter logger = logging.getLogger(__name__) -class BaseParameter(ABC): - """ - Defines a parameter that can be optimized by hyperopt. - """ - category: Optional[str] - default: Any - value: Any - in_space: bool = False - name: str - - def __init__(self, *, default: Any, space: Optional[str] = None, - optimize: bool = True, load: bool = True, **kwargs): - """ - Initialize hyperopt-optimizable parameter. - :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if - parameter field - name is prefixed with 'buy_' or 'sell_'. - :param optimize: Include parameter in hyperopt optimizations. - :param load: Load parameter value from {space}_params. - :param kwargs: Extra parameters to skopt.space.(Integer|Real|Categorical). - """ - if 'name' in kwargs: - raise OperationalException( - 'Name is determined by parameter field name and can not be specified manually.') - self.category = space - self._space_params = kwargs - self.value = default - self.optimize = optimize - self.load = load - - def __repr__(self): - return f'{self.__class__.__name__}({self.value})' - - @abstractmethod - def get_space(self, name: str) -> Union['Integer', 'Real', 'SKDecimal', 'Categorical']: - """ - Get-space - will be used by Hyperopt to get the hyperopt Space - """ - - -class NumericParameter(BaseParameter): - """ Internal parameter used for Numeric purposes """ - float_or_int = Union[int, float] - default: float_or_int - value: float_or_int - - def __init__(self, low: Union[float_or_int, Sequence[float_or_int]], - high: Optional[float_or_int] = None, *, default: float_or_int, - space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): - """ - Initialize hyperopt-optimizable numeric parameter. - Cannot be instantiated, but provides the validation for other numeric parameters - :param low: Lower end (inclusive) of optimization space or [low, high]. - :param high: Upper end (inclusive) of optimization space. - Must be none of entire range is passed first parameter. - :param default: A default value. - :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if - parameter fieldname is prefixed with 'buy_' or 'sell_'. - :param optimize: Include parameter in hyperopt optimizations. - :param load: Load parameter value from {space}_params. - :param kwargs: Extra parameters to skopt.space.*. - """ - if high is not None and isinstance(low, Sequence): - raise OperationalException(f'{self.__class__.__name__} space invalid.') - if high is None or isinstance(low, Sequence): - if not isinstance(low, Sequence) or len(low) != 2: - raise OperationalException(f'{self.__class__.__name__} space must be [low, high]') - self.low, self.high = low - else: - self.low = low - self.high = high - - super().__init__(default=default, space=space, optimize=optimize, - load=load, **kwargs) - - -class IntParameter(NumericParameter): - default: int - value: int - - def __init__(self, low: Union[int, Sequence[int]], high: Optional[int] = None, *, default: int, - space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): - """ - Initialize hyperopt-optimizable integer parameter. - :param low: Lower end (inclusive) of optimization space or [low, high]. - :param high: Upper end (inclusive) of optimization space. - Must be none of entire range is passed first parameter. - :param default: A default value. - :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if - parameter fieldname is prefixed with 'buy_' or 'sell_'. - :param optimize: Include parameter in hyperopt optimizations. - :param load: Load parameter value from {space}_params. - :param kwargs: Extra parameters to skopt.space.Integer. - """ - - super().__init__(low=low, high=high, default=default, space=space, optimize=optimize, - load=load, **kwargs) - - def get_space(self, name: str) -> 'Integer': - """ - Create skopt optimization space. - :param name: A name of parameter field. - """ - return Integer(low=self.low, high=self.high, name=name, **self._space_params) - - @property - def range(self): - """ - Get each value in this space as list. - Returns a List from low to high (inclusive) in Hyperopt mode. - Returns a List with 1 item (`value`) in "non-hyperopt" mode, to avoid - calculating 100ds of indicators. - """ - if self.in_space and self.optimize: - # Scikit-optimize ranges are "inclusive", while python's "range" is exclusive - return range(self.low, self.high + 1) - else: - return range(self.value, self.value + 1) - - -class RealParameter(NumericParameter): - default: float - value: float - - def __init__(self, low: Union[float, Sequence[float]], high: Optional[float] = None, *, - default: float, space: Optional[str] = None, optimize: bool = True, - load: bool = True, **kwargs): - """ - Initialize hyperopt-optimizable floating point parameter with unlimited precision. - :param low: Lower end (inclusive) of optimization space or [low, high]. - :param high: Upper end (inclusive) of optimization space. - Must be none if entire range is passed first parameter. - :param default: A default value. - :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if - parameter fieldname is prefixed with 'buy_' or 'sell_'. - :param optimize: Include parameter in hyperopt optimizations. - :param load: Load parameter value from {space}_params. - :param kwargs: Extra parameters to skopt.space.Real. - """ - super().__init__(low=low, high=high, default=default, space=space, optimize=optimize, - load=load, **kwargs) - - def get_space(self, name: str) -> 'Real': - """ - Create skopt optimization space. - :param name: A name of parameter field. - """ - return Real(low=self.low, high=self.high, name=name, **self._space_params) - - -class DecimalParameter(NumericParameter): - default: float - value: float - - def __init__(self, low: Union[float, Sequence[float]], high: Optional[float] = None, *, - default: float, decimals: int = 3, space: Optional[str] = None, - optimize: bool = True, load: bool = True, **kwargs): - """ - Initialize hyperopt-optimizable decimal parameter with a limited precision. - :param low: Lower end (inclusive) of optimization space or [low, high]. - :param high: Upper end (inclusive) of optimization space. - Must be none if entire range is passed first parameter. - :param default: A default value. - :param decimals: A number of decimals after floating point to be included in testing. - :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if - parameter fieldname is prefixed with 'buy_' or 'sell_'. - :param optimize: Include parameter in hyperopt optimizations. - :param load: Load parameter value from {space}_params. - :param kwargs: Extra parameters to skopt.space.Integer. - """ - self._decimals = decimals - default = round(default, self._decimals) - - super().__init__(low=low, high=high, default=default, space=space, optimize=optimize, - load=load, **kwargs) - - def get_space(self, name: str) -> 'SKDecimal': - """ - Create skopt optimization space. - :param name: A name of parameter field. - """ - return SKDecimal(low=self.low, high=self.high, decimals=self._decimals, name=name, - **self._space_params) - - @property - def range(self): - """ - Get each value in this space as list. - Returns a List from low to high (inclusive) in Hyperopt mode. - Returns a List with 1 item (`value`) in "non-hyperopt" mode, to avoid - calculating 100ds of indicators. - """ - if self.in_space and self.optimize: - low = int(self.low * pow(10, self._decimals)) - high = int(self.high * pow(10, self._decimals)) + 1 - return [round(n * pow(0.1, self._decimals), self._decimals) for n in range(low, high)] - else: - return [self.value] - - -class CategoricalParameter(BaseParameter): - default: Any - value: Any - opt_range: Sequence[Any] - - def __init__(self, categories: Sequence[Any], *, default: Optional[Any] = None, - space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): - """ - Initialize hyperopt-optimizable parameter. - :param categories: Optimization space, [a, b, ...]. - :param default: A default value. If not specified, first item from specified space will be - used. - :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if - parameter field - name is prefixed with 'buy_' or 'sell_'. - :param optimize: Include parameter in hyperopt optimizations. - :param load: Load parameter value from {space}_params. - :param kwargs: Extra parameters to skopt.space.Categorical. - """ - if len(categories) < 2: - raise OperationalException( - 'CategoricalParameter space must be [a, b, ...] (at least two parameters)') - self.opt_range = categories - super().__init__(default=default, space=space, optimize=optimize, - load=load, **kwargs) - - def get_space(self, name: str) -> 'Categorical': - """ - Create skopt optimization space. - :param name: A name of parameter field. - """ - return Categorical(self.opt_range, name=name, **self._space_params) - - @property - def range(self): - """ - Get each value in this space as list. - Returns a List of categories in Hyperopt mode. - Returns a List with 1 item (`value`) in "non-hyperopt" mode, to avoid - calculating 100ds of indicators. - """ - if self.in_space and self.optimize: - return self.opt_range - else: - return [self.value] - - -class BooleanParameter(CategoricalParameter): - - def __init__(self, *, default: Optional[Any] = None, - space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): - """ - Initialize hyperopt-optimizable Boolean Parameter. - It's a shortcut to `CategoricalParameter([True, False])`. - :param default: A default value. If not specified, first item from specified space will be - used. - :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if - parameter field - name is prefixed with 'buy_' or 'sell_'. - :param optimize: Include parameter in hyperopt optimizations. - :param load: Load parameter value from {space}_params. - :param kwargs: Extra parameters to skopt.space.Categorical. - """ - - categories = [True, False] - super().__init__(categories=categories, default=default, space=space, optimize=optimize, - load=load, **kwargs) - - class HyperStrategyMixin: """ A helper base class which allows HyperOptAuto class to reuse implementations of buy/sell diff --git a/freqtrade/strategy/parameters.py b/freqtrade/strategy/parameters.py new file mode 100644 index 000000000..02706690d --- /dev/null +++ b/freqtrade/strategy/parameters.py @@ -0,0 +1,287 @@ +""" +IHyperStrategy interface, hyperoptable Parameter class. +This module defines a base class for auto-hyperoptable strategies. +""" +import logging +from abc import ABC, abstractmethod +from contextlib import suppress +from typing import Any, Optional, Sequence, Union + + +with suppress(ImportError): + from skopt.space import Integer, Real, Categorical + from freqtrade.optimize.space import SKDecimal + +from freqtrade.exceptions import OperationalException + + +logger = logging.getLogger(__name__) + + +class BaseParameter(ABC): + """ + Defines a parameter that can be optimized by hyperopt. + """ + category: Optional[str] + default: Any + value: Any + in_space: bool = False + name: str + + def __init__(self, *, default: Any, space: Optional[str] = None, + optimize: bool = True, load: bool = True, **kwargs): + """ + Initialize hyperopt-optimizable parameter. + :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if + parameter field + name is prefixed with 'buy_' or 'sell_'. + :param optimize: Include parameter in hyperopt optimizations. + :param load: Load parameter value from {space}_params. + :param kwargs: Extra parameters to skopt.space.(Integer|Real|Categorical). + """ + if 'name' in kwargs: + raise OperationalException( + 'Name is determined by parameter field name and can not be specified manually.') + self.category = space + self._space_params = kwargs + self.value = default + self.optimize = optimize + self.load = load + + def __repr__(self): + return f'{self.__class__.__name__}({self.value})' + + @abstractmethod + def get_space(self, name: str) -> Union['Integer', 'Real', 'SKDecimal', 'Categorical']: + """ + Get-space - will be used by Hyperopt to get the hyperopt Space + """ + + +class NumericParameter(BaseParameter): + """ Internal parameter used for Numeric purposes """ + float_or_int = Union[int, float] + default: float_or_int + value: float_or_int + + def __init__(self, low: Union[float_or_int, Sequence[float_or_int]], + high: Optional[float_or_int] = None, *, default: float_or_int, + space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): + """ + Initialize hyperopt-optimizable numeric parameter. + Cannot be instantiated, but provides the validation for other numeric parameters + :param low: Lower end (inclusive) of optimization space or [low, high]. + :param high: Upper end (inclusive) of optimization space. + Must be none of entire range is passed first parameter. + :param default: A default value. + :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if + parameter fieldname is prefixed with 'buy_' or 'sell_'. + :param optimize: Include parameter in hyperopt optimizations. + :param load: Load parameter value from {space}_params. + :param kwargs: Extra parameters to skopt.space.*. + """ + if high is not None and isinstance(low, Sequence): + raise OperationalException(f'{self.__class__.__name__} space invalid.') + if high is None or isinstance(low, Sequence): + if not isinstance(low, Sequence) or len(low) != 2: + raise OperationalException(f'{self.__class__.__name__} space must be [low, high]') + self.low, self.high = low + else: + self.low = low + self.high = high + + super().__init__(default=default, space=space, optimize=optimize, + load=load, **kwargs) + + +class IntParameter(NumericParameter): + default: int + value: int + + def __init__(self, low: Union[int, Sequence[int]], high: Optional[int] = None, *, default: int, + space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): + """ + Initialize hyperopt-optimizable integer parameter. + :param low: Lower end (inclusive) of optimization space or [low, high]. + :param high: Upper end (inclusive) of optimization space. + Must be none of entire range is passed first parameter. + :param default: A default value. + :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if + parameter fieldname is prefixed with 'buy_' or 'sell_'. + :param optimize: Include parameter in hyperopt optimizations. + :param load: Load parameter value from {space}_params. + :param kwargs: Extra parameters to skopt.space.Integer. + """ + + super().__init__(low=low, high=high, default=default, space=space, optimize=optimize, + load=load, **kwargs) + + def get_space(self, name: str) -> 'Integer': + """ + Create skopt optimization space. + :param name: A name of parameter field. + """ + return Integer(low=self.low, high=self.high, name=name, **self._space_params) + + @property + def range(self): + """ + Get each value in this space as list. + Returns a List from low to high (inclusive) in Hyperopt mode. + Returns a List with 1 item (`value`) in "non-hyperopt" mode, to avoid + calculating 100ds of indicators. + """ + if self.in_space and self.optimize: + # Scikit-optimize ranges are "inclusive", while python's "range" is exclusive + return range(self.low, self.high + 1) + else: + return range(self.value, self.value + 1) + + +class RealParameter(NumericParameter): + default: float + value: float + + def __init__(self, low: Union[float, Sequence[float]], high: Optional[float] = None, *, + default: float, space: Optional[str] = None, optimize: bool = True, + load: bool = True, **kwargs): + """ + Initialize hyperopt-optimizable floating point parameter with unlimited precision. + :param low: Lower end (inclusive) of optimization space or [low, high]. + :param high: Upper end (inclusive) of optimization space. + Must be none if entire range is passed first parameter. + :param default: A default value. + :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if + parameter fieldname is prefixed with 'buy_' or 'sell_'. + :param optimize: Include parameter in hyperopt optimizations. + :param load: Load parameter value from {space}_params. + :param kwargs: Extra parameters to skopt.space.Real. + """ + super().__init__(low=low, high=high, default=default, space=space, optimize=optimize, + load=load, **kwargs) + + def get_space(self, name: str) -> 'Real': + """ + Create skopt optimization space. + :param name: A name of parameter field. + """ + return Real(low=self.low, high=self.high, name=name, **self._space_params) + + +class DecimalParameter(NumericParameter): + default: float + value: float + + def __init__(self, low: Union[float, Sequence[float]], high: Optional[float] = None, *, + default: float, decimals: int = 3, space: Optional[str] = None, + optimize: bool = True, load: bool = True, **kwargs): + """ + Initialize hyperopt-optimizable decimal parameter with a limited precision. + :param low: Lower end (inclusive) of optimization space or [low, high]. + :param high: Upper end (inclusive) of optimization space. + Must be none if entire range is passed first parameter. + :param default: A default value. + :param decimals: A number of decimals after floating point to be included in testing. + :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if + parameter fieldname is prefixed with 'buy_' or 'sell_'. + :param optimize: Include parameter in hyperopt optimizations. + :param load: Load parameter value from {space}_params. + :param kwargs: Extra parameters to skopt.space.Integer. + """ + self._decimals = decimals + default = round(default, self._decimals) + + super().__init__(low=low, high=high, default=default, space=space, optimize=optimize, + load=load, **kwargs) + + def get_space(self, name: str) -> 'SKDecimal': + """ + Create skopt optimization space. + :param name: A name of parameter field. + """ + return SKDecimal(low=self.low, high=self.high, decimals=self._decimals, name=name, + **self._space_params) + + @property + def range(self): + """ + Get each value in this space as list. + Returns a List from low to high (inclusive) in Hyperopt mode. + Returns a List with 1 item (`value`) in "non-hyperopt" mode, to avoid + calculating 100ds of indicators. + """ + if self.in_space and self.optimize: + low = int(self.low * pow(10, self._decimals)) + high = int(self.high * pow(10, self._decimals)) + 1 + return [round(n * pow(0.1, self._decimals), self._decimals) for n in range(low, high)] + else: + return [self.value] + + +class CategoricalParameter(BaseParameter): + default: Any + value: Any + opt_range: Sequence[Any] + + def __init__(self, categories: Sequence[Any], *, default: Optional[Any] = None, + space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): + """ + Initialize hyperopt-optimizable parameter. + :param categories: Optimization space, [a, b, ...]. + :param default: A default value. If not specified, first item from specified space will be + used. + :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if + parameter field + name is prefixed with 'buy_' or 'sell_'. + :param optimize: Include parameter in hyperopt optimizations. + :param load: Load parameter value from {space}_params. + :param kwargs: Extra parameters to skopt.space.Categorical. + """ + if len(categories) < 2: + raise OperationalException( + 'CategoricalParameter space must be [a, b, ...] (at least two parameters)') + self.opt_range = categories + super().__init__(default=default, space=space, optimize=optimize, + load=load, **kwargs) + + def get_space(self, name: str) -> 'Categorical': + """ + Create skopt optimization space. + :param name: A name of parameter field. + """ + return Categorical(self.opt_range, name=name, **self._space_params) + + @property + def range(self): + """ + Get each value in this space as list. + Returns a List of categories in Hyperopt mode. + Returns a List with 1 item (`value`) in "non-hyperopt" mode, to avoid + calculating 100ds of indicators. + """ + if self.in_space and self.optimize: + return self.opt_range + else: + return [self.value] + + +class BooleanParameter(CategoricalParameter): + + def __init__(self, *, default: Optional[Any] = None, + space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): + """ + Initialize hyperopt-optimizable Boolean Parameter. + It's a shortcut to `CategoricalParameter([True, False])`. + :param default: A default value. If not specified, first item from specified space will be + used. + :param space: A parameter category. Can be 'buy' or 'sell'. This parameter is optional if + parameter field + name is prefixed with 'buy_' or 'sell_'. + :param optimize: Include parameter in hyperopt optimizations. + :param load: Load parameter value from {space}_params. + :param kwargs: Extra parameters to skopt.space.Categorical. + """ + + categories = [True, False] + super().__init__(categories=categories, default=default, space=space, optimize=optimize, + load=load, **kwargs) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index dcc1ddeea..8522894f7 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -17,7 +17,7 @@ from freqtrade.optimize.hyperopt_auto import HyperOptAuto from freqtrade.optimize.hyperopt_tools import HyperoptTools from freqtrade.optimize.optimize_reports import generate_strategy_stats from freqtrade.optimize.space import SKDecimal -from freqtrade.strategy.hyper import IntParameter +from freqtrade.strategy import IntParameter from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, log_has, log_has_re, patch_exchange, patched_configuration_load_config_file) diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 6e57a3182..ee1a381da 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -16,8 +16,8 @@ from freqtrade.exceptions import OperationalException, StrategyError from freqtrade.optimize.space import SKDecimal from freqtrade.persistence import PairLocks, Trade from freqtrade.resolvers import StrategyResolver -from freqtrade.strategy.hyper import (BaseParameter, BooleanParameter, CategoricalParameter, - DecimalParameter, IntParameter, RealParameter) +from freqtrade.strategy.parameters import (BaseParameter, BooleanParameter, CategoricalParameter, + DecimalParameter, IntParameter, RealParameter) from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from tests.conftest import CURRENT_TEST_STRATEGY, TRADE_SIDES, log_has, log_has_re From 07ec3b27fe03bdb5587ffdfaddf8fc605cbe77fe Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 15 Apr 2022 15:48:37 +0200 Subject: [PATCH 185/449] Add typing information to retrier decorator --- freqtrade/exchange/common.py | 21 ++++++++++++++++++--- freqtrade/exchange/exchange.py | 4 ++-- freqtrade/exchange/ftx.py | 4 ++-- freqtrade/exchange/gateio.py | 4 ++-- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index 4355662a8..a9f03ba1a 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -2,6 +2,7 @@ import asyncio import logging import time from functools import wraps +from typing import Any, Callable, Optional, TypeVar, cast, overload from freqtrade.exceptions import DDosProtection, RetryableOrderError, TemporaryError from freqtrade.mixins import LoggingMixin @@ -133,8 +134,22 @@ def retrier_async(f): return wrapper -def retrier(_func=None, retries=API_RETRY_COUNT): - def decorator(f): +F = TypeVar('F', bound=Callable[..., Any]) + + +# Type shenanigans +@overload +def retrier(_func: F) -> F: + ... + + +@overload +def retrier(*, retries=API_RETRY_COUNT) -> Callable[[F], F]: + ... + + +def retrier(_func: Optional[F] = None, *, retries=API_RETRY_COUNT): + def decorator(f: F) -> F: @wraps(f) def wrapper(*args, **kwargs): count = kwargs.pop('count', retries) @@ -155,7 +170,7 @@ def retrier(_func=None, retries=API_RETRY_COUNT): else: logger.warning(msg + 'Giving up.') raise ex - return wrapper + return cast(F, wrapper) # Support both @retrier and @retrier(retries=2) syntax if _func is None: return decorator diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 2fa397300..b25886868 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1164,7 +1164,7 @@ class Exchange: raise OperationalException(e) from e @retrier(retries=API_FETCH_ORDER_RETRY_COUNT) - def fetch_order(self, order_id: str, pair: str, params={}) -> Dict: + def fetch_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: if self._config['dry_run']: return self.fetch_dry_run_order(order_id) try: @@ -1212,7 +1212,7 @@ class Exchange: and order.get('filled') == 0.0) @retrier - def cancel_order(self, order_id: str, pair: str, params={}) -> Dict: + def cancel_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: if self._config['dry_run']: try: order = self.fetch_dry_run_order(order_id) diff --git a/freqtrade/exchange/ftx.py b/freqtrade/exchange/ftx.py index 65c2a53ca..9ee6894f1 100644 --- a/freqtrade/exchange/ftx.py +++ b/freqtrade/exchange/ftx.py @@ -104,7 +104,7 @@ class Ftx(Exchange): raise OperationalException(e) from e @retrier(retries=API_FETCH_ORDER_RETRY_COUNT) - def fetch_stoploss_order(self, order_id: str, pair: str) -> Dict: + def fetch_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: if self._config['dry_run']: return self.fetch_dry_run_order(order_id) @@ -145,7 +145,7 @@ class Ftx(Exchange): raise OperationalException(e) from e @retrier - def cancel_stoploss_order(self, order_id: str, pair: str) -> Dict: + def cancel_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: if self._config['dry_run']: return {} try: diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index 609cf4901..4147e8290 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -71,14 +71,14 @@ class Gateio(Exchange): } return trades - def fetch_stoploss_order(self, order_id: str, pair: str, params={}) -> Dict: + def fetch_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: return self.fetch_order( order_id=order_id, pair=pair, params={'stop': True} ) - def cancel_stoploss_order(self, order_id: str, pair: str, params={}) -> Dict: + def cancel_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: return self.cancel_order( order_id=order_id, pair=pair, From 7f4161ff782857f648f5a55efe8bf5be30b15688 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Apr 2022 06:53:38 +0200 Subject: [PATCH 186/449] Add typehints to strategy wrapper --- freqtrade/strategy/strategy_wrapper.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/freqtrade/strategy/strategy_wrapper.py b/freqtrade/strategy/strategy_wrapper.py index 9aead8395..8cb0bde15 100644 --- a/freqtrade/strategy/strategy_wrapper.py +++ b/freqtrade/strategy/strategy_wrapper.py @@ -1,5 +1,7 @@ import logging from copy import deepcopy +from functools import wraps +from typing import Any, Callable, TypeVar, cast from freqtrade.exceptions import StrategyError @@ -7,12 +9,16 @@ from freqtrade.exceptions import StrategyError logger = logging.getLogger(__name__) -def strategy_safe_wrapper(f, message: str = "", default_retval=None, supress_error=False): +F = TypeVar('F', bound=Callable[..., Any]) + + +def strategy_safe_wrapper(f: F, message: str = "", default_retval=None, supress_error=False) -> F: """ Wrapper around user-provided methods and functions. Caches all exceptions and returns either the default_retval (if it's not None) or raises a StrategyError exception, which then needs to be handled by the calling method. """ + @wraps(f) def wrapper(*args, **kwargs): try: if 'trade' in kwargs: @@ -37,4 +43,4 @@ def strategy_safe_wrapper(f, message: str = "", default_retval=None, supress_err raise StrategyError(str(error)) from error return default_retval - return wrapper + return cast(F, wrapper) From 502404c0cc3c36faafb0039b9e19aaed9fd3c5c8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 11:30:45 +0200 Subject: [PATCH 187/449] Use pyproject.toml instead of setup.cfg --- pyproject.toml | 11 +++++++++++ setup.cfg | 10 ---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e8d5ed47e..935874ab8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,17 @@ skip_glob = ["**/.env*", "**/env/*", "**/.venv/*", "**/docs/*", "**/user_data/*" [tool.pytest.ini_options] asyncio_mode = "auto" +[tool.mypy] +ignore_missing_imports = true +warn_unused_ignores = true +exclude = [ + '^build_helpers\.py$' +] + +[[tool.mypy.overrides]] +module = "tests.*" +ignore_errors = true + [build-system] requires = ["setuptools >= 46.4.0", "wheel"] build-backend = "setuptools.build_meta" diff --git a/setup.cfg b/setup.cfg index 042517ec9..d711534d9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,13 +50,3 @@ exclude = .eggs, user_data, -[mypy] -ignore_missing_imports = True -warn_unused_ignores = True -exclude = (?x)( - ^build_helpers\.py$ - ) - - -[mypy-tests.*] -ignore_errors = True From 3f68c3b68e8d23d1f5d7c42264c73af0670b9d65 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 11:41:57 +0200 Subject: [PATCH 188/449] Update some types --- freqtrade/configuration/check_exchange.py | 2 +- freqtrade/exchange/exchange.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/freqtrade/configuration/check_exchange.py b/freqtrade/configuration/check_exchange.py index fa1f47f9b..2be13ce4f 100644 --- a/freqtrade/configuration/check_exchange.py +++ b/freqtrade/configuration/check_exchange.py @@ -27,7 +27,7 @@ def check_exchange(config: Dict[str, Any], check_for_bad: bool = True) -> bool: return True logger.info("Checking exchange...") - exchange = config.get('exchange', {}).get('name').lower() + exchange = config.get('exchange', {}).get('name', '').lower() if not exchange: raise OperationalException( f'This command requires a configured exchange. You should either use ' diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index b25886868..1044ad652 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -92,8 +92,8 @@ class Exchange: it does basic validation whether the specified exchange and pairs are valid. :return: None """ - self._api: ccxt.Exchange = None - self._api_async: ccxt_async.Exchange = None + self._api: ccxt.Exchange + self._api_async: ccxt_async.Exchange self._markets: Dict = {} self._trading_fees: Dict[str, Any] = {} self._leverage_tiers: Dict[str, List[Dict]] = {} @@ -291,7 +291,7 @@ class Exchange: return self._markets @property - def precisionMode(self) -> str: + def precisionMode(self) -> int: """exchange ccxt precisionMode""" return self._api.precisionMode @@ -322,7 +322,7 @@ class Exchange: return int(self._ft_has.get('ohlcv_candle_limit_per_timeframe', {}).get( timeframe, self._ft_has.get('ohlcv_candle_limit'))) - def get_markets(self, base_currencies: List[str] = None, quote_currencies: List[str] = None, + def get_markets(self, base_currencies: List[str] = [], quote_currencies: List[str] = [], spot_only: bool = False, margin_only: bool = False, futures_only: bool = False, tradable_only: bool = True, active_only: bool = False) -> Dict[str, Any]: @@ -1718,7 +1718,7 @@ class Exchange: async def _async_get_historic_ohlcv(self, pair: str, timeframe: str, since_ms: int, candle_type: CandleType, is_new_pair: bool = False, raise_: bool = False, - until_ms: int = None + until_ms: Optional[int] = None ) -> Tuple[str, str, str, List]: """ Download historic ohlcv @@ -1779,7 +1779,7 @@ class Exchange: def refresh_latest_ohlcv(self, pair_list: ListPairsWithTimeframes, *, since_ms: Optional[int] = None, cache: bool = True, - drop_incomplete: bool = None + drop_incomplete: Optional[bool] = None ) -> Dict[PairWithTimeframe, DataFrame]: """ Refresh in-memory OHLCV asynchronously and set `_klines` with the result From f1a72e448a49c0774a84202942575815ea948189 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 11:55:49 +0200 Subject: [PATCH 189/449] Align interfaces and strategy templates --- docs/strategy-callbacks.md | 4 ++-- docs/strategy_migration.md | 4 ++-- freqtrade/strategy/interface.py | 7 ++++--- freqtrade/templates/base_strategy.py.j2 | 2 +- .../subtemplates/strategy_methods_advanced.j2 | 10 +++++----- tests/strategy/strats/strategy_test_v2.py | 4 +++- tests/strategy/strats/strategy_test_v3.py | 4 +++- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index ab67a3c26..63bd4f958 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -656,7 +656,7 @@ class DigDeeperStrategy(IStrategy): # This is called when placing the initial order (opening trade) def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, - proposed_stake: float, min_stake: float, max_stake: float, + proposed_stake: float, min_stake: Optional[float], max_stake: float, entry_tag: Optional[str], side: str, **kwargs) -> float: # We need to leave most of the funds for possible further DCA orders @@ -664,7 +664,7 @@ class DigDeeperStrategy(IStrategy): return proposed_stake / self.max_dca_multiplier def adjust_trade_position(self, trade: Trade, current_time: datetime, - current_rate: float, current_profit: float, min_stake: float, + current_rate: float, current_profit: float, min_stake: Optional[float], max_stake: float, **kwargs): """ Custom trade adjustment logic, returning the stake amount that a trade should be increased. diff --git a/docs/strategy_migration.md b/docs/strategy_migration.md index 458e80d0e..471ffa601 100644 --- a/docs/strategy_migration.md +++ b/docs/strategy_migration.md @@ -199,7 +199,7 @@ New string argument `side` - which can be either `"long"` or `"short"`. ``` python hl_lines="4" class AwesomeStrategy(IStrategy): def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, - proposed_stake: float, min_stake: float, max_stake: float, + proposed_stake: float, min_stake: Optional[float], max_stake: float, entry_tag: Optional[str], **kwargs) -> float: # ... return proposed_stake @@ -208,7 +208,7 @@ class AwesomeStrategy(IStrategy): ``` python hl_lines="4" class AwesomeStrategy(IStrategy): def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, - proposed_stake: float, min_stake: float, max_stake: float, + proposed_stake: float, min_stake: Optional[float], max_stake: float, entry_tag: Optional[str], side: str, **kwargs) -> float: # ... return proposed_stake diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 57afbf32a..44f7466ec 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -429,7 +429,7 @@ class IStrategy(ABC, HyperStrategyMixin): return self.custom_sell(pair, trade, current_time, current_rate, current_profit, **kwargs) def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, - proposed_stake: float, min_stake: float, max_stake: float, + proposed_stake: float, min_stake: Optional[float], max_stake: float, entry_tag: Optional[str], side: str, **kwargs) -> float: """ Customize stake size for each new trade. @@ -447,8 +447,9 @@ class IStrategy(ABC, HyperStrategyMixin): return proposed_stake def adjust_trade_position(self, trade: Trade, current_time: datetime, - current_rate: float, current_profit: float, min_stake: float, - max_stake: float, **kwargs) -> Optional[float]: + current_rate: float, current_profit: float, + min_stake: Optional[float], max_stake: float, + **kwargs) -> Optional[float]: """ Custom trade adjustment logic, returning the stake amount that a trade should be increased. This means extra buy orders with additional fees. diff --git a/freqtrade/templates/base_strategy.py.j2 b/freqtrade/templates/base_strategy.py.j2 index 9e7e1fe50..8c7594322 100644 --- a/freqtrade/templates/base_strategy.py.j2 +++ b/freqtrade/templates/base_strategy.py.j2 @@ -6,7 +6,7 @@ import numpy as np # noqa import pandas as pd # noqa from pandas import DataFrame # noqa from datetime import datetime # noqa -from typing import Optional # noqa +from typing import Optional, Union # noqa from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, IStrategy, IntParameter) diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 317602da9..3854efd85 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -13,7 +13,7 @@ def bot_loop_start(self, **kwargs) -> None: pass def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: float, - entry_tag: Optional[str], **kwargs) -> float: + entry_tag: 'Optional[str]', side: str, **kwargs) -> float: """ Custom entry price logic, returning the new entry price. @@ -80,8 +80,8 @@ def custom_exit_price(self, pair: str, trade: 'Trade', return proposed_rate def custom_stake_amount(self, pair: str, current_time: 'datetime', current_rate: float, - proposed_stake: float, min_stake: float, max_stake: float, - side: str, entry_tag: Optional[str], **kwargs) -> float: + proposed_stake: float, min_stake: Optional[float], max_stake: float, + entry_tag: 'Optional[str]', side: str, **kwargs) -> float: """ Customize stake size for each new trade. @@ -244,8 +244,8 @@ def check_exit_timeout(self, pair: str, trade: 'Trade', order: 'Order', return False def adjust_trade_position(self, trade: 'Trade', current_time: 'datetime', - current_rate: float, current_profit: float, min_stake: float, - max_stake: float, **kwargs) -> Optional[float]: + current_rate: float, current_profit: float, min_stake: Optional[float], + max_stake: float, **kwargs) -> 'Optional[float]': """ Custom trade adjustment logic, returning the stake amount that a trade should be increased. This means extra buy orders with additional fees. diff --git a/tests/strategy/strats/strategy_test_v2.py b/tests/strategy/strats/strategy_test_v2.py index 85ff856e1..46181ac7e 100644 --- a/tests/strategy/strats/strategy_test_v2.py +++ b/tests/strategy/strats/strategy_test_v2.py @@ -1,6 +1,7 @@ # pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement from datetime import datetime +from typing import Optional import talib.abstract as ta from pandas import DataFrame @@ -151,7 +152,8 @@ class StrategyTestV2(IStrategy): return dataframe def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, - current_profit: float, min_stake: float, max_stake: float, **kwargs): + current_profit: float, + min_stake: Optional[float], max_stake: float, **kwargs): if current_profit < -0.0075: orders = trade.select_filled_orders('buy') diff --git a/tests/strategy/strats/strategy_test_v3.py b/tests/strategy/strats/strategy_test_v3.py index df83d3663..340001ef2 100644 --- a/tests/strategy/strats/strategy_test_v3.py +++ b/tests/strategy/strats/strategy_test_v3.py @@ -1,6 +1,7 @@ # pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement from datetime import datetime +from typing import Optional import talib.abstract as ta from pandas import DataFrame @@ -185,7 +186,8 @@ class StrategyTestV3(IStrategy): return 3.0 def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, - current_profit: float, min_stake: float, max_stake: float, **kwargs): + current_profit: float, + min_stake: Optional[float], max_stake: float, **kwargs): if current_profit < -0.0075: orders = trade.select_filled_orders(trade.entry_side) From 0a713faca84c5039b9245ab6d25ba22c1b4d112e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 7 May 2022 14:53:51 +0200 Subject: [PATCH 190/449] Fix some type errors --- freqtrade/optimize/backtesting.py | 22 ++++++++++++++++------ freqtrade/strategy/interface.py | 17 +++++++++-------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 3a3660c39..19922ee57 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -500,7 +500,8 @@ class Backtesting: stake_available = self.wallets.get_available_stake_amount() stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position, default_retval=None)( - trade=trade, current_time=row[DATE_IDX].to_pydatetime(), current_rate=row[OPEN_IDX], + trade=trade, # type: ignore[arg-type] + current_time=row[DATE_IDX].to_pydatetime(), current_rate=row[OPEN_IDX], current_profit=current_profit, min_stake=min_stake, max_stake=min(max_stake, stake_available)) @@ -566,7 +567,8 @@ class Backtesting: if order_type == 'limit': close_rate = strategy_safe_wrapper(self.strategy.custom_exit_price, default_retval=close_rate)( - pair=trade.pair, trade=trade, + pair=trade.pair, + trade=trade, # type: ignore[arg-type] current_time=exit_candle_time, proposed_rate=close_rate, current_profit=current_profit, exit_tag=exit_reason) @@ -580,7 +582,10 @@ class Backtesting: time_in_force = self.strategy.order_time_in_force['exit'] if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)( - pair=trade.pair, trade=trade, order_type='limit', amount=trade.amount, + pair=trade.pair, + trade=trade, # type: ignore[arg-type] + order_type='limit', + amount=trade.amount, rate=close_rate, time_in_force=time_in_force, sell_reason=exit_reason, # deprecated @@ -656,7 +661,7 @@ class Backtesting: return self._get_exit_trade_entry_for_candle(trade, row) def get_valid_price_and_stake( - self, pair: str, row: Tuple, propose_rate: float, stake_amount: Optional[float], + self, pair: str, row: Tuple, propose_rate: float, stake_amount_inp: Optional[float], direction: LongShort, current_time: datetime, entry_tag: Optional[str], trade: Optional[LocalTrade], order_type: str ) -> Tuple[float, float, float, float]: @@ -694,6 +699,8 @@ class Backtesting: ) if self._can_short else 1.0 # Cap leverage between 1.0 and max_leverage. leverage = min(max(leverage, 1.0), max_leverage) + elif stake_amount_inp is not None: + stake_amount = stake_amount_inp min_stake_amount = self.exchange.get_min_pair_stake_amount( pair, propose_rate, -0.05, leverage=leverage) or 0 @@ -901,7 +908,9 @@ class Backtesting: Check if current analyzed order has to be canceled. Returns True if the trade should be Deleted (initial order was canceled). """ - timedout = self.strategy.ft_check_timed_out(trade, order, current_time) + timedout = self.strategy.ft_check_timed_out( + trade, # type: ignore[arg-type] + order, current_time) if timedout: if order.side == trade.entry_side: self.timedout_entry_orders += 1 @@ -930,7 +939,8 @@ class Backtesting: if order.side == trade.entry_side and current_time > order.order_date_utc: requested_rate = strategy_safe_wrapper(self.strategy.adjust_entry_price, default_retval=order.price)( - trade=trade, order=order, pair=trade.pair, current_time=current_time, + trade=trade, # type: ignore[arg-type] + order=order, pair=trade.pair, current_time=current_time, proposed_rate=row[OPEN_IDX], current_order_rate=order.price, entry_tag=trade.enter_tag, side=trade.trade_direction ) # default value is current order price diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 44f7466ec..002a7aca5 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -16,7 +16,7 @@ from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, SignalDirecti SignalType, TradingMode) from freqtrade.exceptions import OperationalException, StrategyError from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date, timeframe_to_seconds -from freqtrade.persistence import LocalTrade, Order, PairLocks, Trade +from freqtrade.persistence import Order, PairLocks, Trade from freqtrade.strategy.hyper import HyperStrategyMixin from freqtrade.strategy.informative_decorator import (InformativeData, PopulateIndicators, _create_and_merge_informative_pair, @@ -918,19 +918,20 @@ class IStrategy(ABC, HyperStrategyMixin): if exit_ and not enter: exit_signal = ExitType.EXIT_SIGNAL else: - custom_reason = strategy_safe_wrapper(self.custom_exit, default_retval=False)( + reason_cust = strategy_safe_wrapper(self.custom_exit, default_retval=False)( pair=trade.pair, trade=trade, current_time=current_time, current_rate=current_rate, current_profit=current_profit) - if custom_reason: + if reason_cust: exit_signal = ExitType.CUSTOM_EXIT - if isinstance(custom_reason, str): - if len(custom_reason) > CUSTOM_EXIT_MAX_LENGTH: + if isinstance(reason_cust, str): + custom_reason = reason_cust + if len(reason_cust) > CUSTOM_EXIT_MAX_LENGTH: logger.warning(f'Custom exit reason returned from ' f'custom_exit is too long and was trimmed' f'to {CUSTOM_EXIT_MAX_LENGTH} characters.') - custom_reason = custom_reason[:CUSTOM_EXIT_MAX_LENGTH] + custom_reason = reason_cust[:CUSTOM_EXIT_MAX_LENGTH] else: - custom_reason = None + custom_reason = '' if ( exit_signal == ExitType.CUSTOM_EXIT or (exit_signal == ExitType.EXIT_SIGNAL @@ -1071,7 +1072,7 @@ class IStrategy(ABC, HyperStrategyMixin): else: return current_profit > roi - def ft_check_timed_out(self, trade: LocalTrade, order: Order, + def ft_check_timed_out(self, trade: Trade, order: Order, current_time: datetime) -> bool: """ FT Internal method. From 904f094b806d9a7ee68034ca86c531f7fa83b876 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 May 2022 06:45:56 +0200 Subject: [PATCH 191/449] Don't reassign method, but implement it properly --- freqtrade/data/history/history_utils.py | 1 + freqtrade/exchange/exchange.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index 4600d6ab4..bead59814 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -282,6 +282,7 @@ def refresh_backtest_ohlcv_data(exchange: Exchange, pairs: List[str], timeframes pairs_not_available = [] data_handler = get_datahandler(datadir, data_format) candle_type = CandleType.get_default(trading_mode) + process = '' for idx, pair in enumerate(pairs, start=1): if pair not in exchange.markets: pairs_not_available.append(pair) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 1044ad652..6ef61f227 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1186,8 +1186,8 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - # Assign method to fetch_stoploss_order to allow easy overriding in other classes - fetch_stoploss_order = fetch_order + def fetch_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: + return self.fetch_order(order_id, pair, params) def fetch_order_or_stoploss_order(self, order_id: str, pair: str, stoploss_order: bool = False) -> Dict: @@ -1238,8 +1238,8 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - # Assign method to cancel_stoploss_order to allow easy overriding in other classes - cancel_stoploss_order = cancel_order + def cancel_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: + return self.cancel_order(order_id, pair, params) def is_cancel_order_result_suitable(self, corder) -> bool: if not isinstance(corder, dict): From 9488e8992dea615420b4712be52774b8995bec5e Mon Sep 17 00:00:00 2001 From: froggleston Date: Sun, 22 May 2022 23:24:52 +0100 Subject: [PATCH 192/449] First commit for integrating buy_reasons into FT --- freqtrade/commands/__init__.py | 1 + freqtrade/commands/arguments.py | 14 +- freqtrade/commands/cli_options.py | 31 +++ freqtrade/configuration/configuration.py | 15 ++ freqtrade/data/entryexitanalysis.py | 258 +++++++++++++++++++++++ 5 files changed, 317 insertions(+), 2 deletions(-) create mode 100755 freqtrade/data/entryexitanalysis.py diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 0e637c487..d93ed1e09 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -6,6 +6,7 @@ Contains all start-commands, subcommands and CLI Interface creation. Note: Be careful with file-scoped imports in these subfiles. as they are parsed on startup, nothing containing optional modules should be loaded. """ +from freqtrade.commands.analyze_commands import start_analysis_entries_exits from freqtrade.commands.arguments import Arguments from freqtrade.commands.build_config_commands import start_new_config from freqtrade.commands.data_commands import (start_convert_data, start_convert_trades, diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 815e28175..4dd0141fa 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -101,6 +101,9 @@ ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperop "print_json", "hyperoptexportfilename", "hyperopt_show_no_header", "disableparamexport", "backtest_breakdown"] +ARGS_ANALYZE_ENTRIES_EXITS = ["analysis_groups", "enter_reason_list", + "exit_reason_list", "indicator_list"] + NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes", "list-markets", "list-pairs", "list-strategies", "list-data", "hyperopt-list", "hyperopt-show", "backtest-filter", @@ -182,8 +185,9 @@ class Arguments: self.parser = argparse.ArgumentParser(description='Free, open source crypto trading bot') self._build_args(optionlist=['version'], parser=self.parser) - from freqtrade.commands import (start_backtesting, start_backtesting_show, - start_convert_data, start_convert_db, start_convert_trades, + from freqtrade.commands import (start_analysis_entries_exits, start_backtesting, + start_backtesting_show, start_convert_data, + start_convert_db, start_convert_trades, start_create_userdir, start_download_data, start_edge, start_hyperopt, start_hyperopt_list, start_hyperopt_show, start_install_ui, start_list_data, start_list_exchanges, @@ -415,3 +419,9 @@ class Arguments: parents=[_common_parser]) webserver_cmd.set_defaults(func=start_webserver) self._build_args(optionlist=ARGS_WEBSERVER, parser=webserver_cmd) + + # Add backtesting analysis subcommand + analysis_cmd = subparsers.add_parser('analysis', help='Analysis module.', + parents=[_common_parser, _strategy_parser]) + analysis_cmd.set_defaults(func=start_analysis_entries_exits) + self._build_args(optionlist=ARGS_ANALYZE_ENTRIES_EXITS, parser=analysis_cmd) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index aac9f5713..f925bd699 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -614,4 +614,35 @@ AVAILABLE_CLI_OPTIONS = { "that do not contain any parameters."), action="store_true", ), + "analysis_groups": Arg( + "--analysis_groups", + help=("grouping output - ", + "0: simple wins/losses by enter tag, ", + "1: by enter_tag, ", + "2: by enter_tag and exit_tag, ", + "3: by pair and enter_tag, ", + "4: by pair, enter_ and exit_tag (this can get quite large)"), + nargs='?', + default="0,1,2", + ), + "enter_reason_list": Arg( + "--enter_reason_list", + help=("Comma separated list of entry signals to analyse. Default: all. ", + "e.g. 'entry_tag_a,entry_tag_b'"), + nargs='?', + default='all', + ), + "exit_reason_list": Arg( + "--exit_reason_list", + help=("Comma separated list of exit signals to analyse. Default: all. ", + "e.g. 'exit_tag_a,roi,stop_loss,trailing_stop_loss'"), + nargs='?', + default='all', + ), + "indicator_list": Arg( + "--indicator_list", + help=("Comma separated list of indicators to analyse. ", + "e.g. 'close,rsi,bb_lowerband,profit_abs'"), + nargs='?', + ), } diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 96b585cd1..ea4bcace8 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -95,6 +95,8 @@ class Configuration: self._process_data_options(config) + self._process_analyze_options(config) + # Check if the exchange set by the user is supported check_exchange(config, config.get('experimental', {}).get('block_bad_exchanges', True)) @@ -433,6 +435,19 @@ class Configuration: self._args_to_config(config, argname='candle_types', logstring='Detected --candle-types: {}') + def _process_analyze_options(self, config: Dict[str, Any]) -> None: + self._args_to_config(config, argname='analysis_groups', + logstring='Analysis reason groups: {}') + + self._args_to_config(config, argname='enter_reason_list', + logstring='Analysis enter tag list: {}') + + self._args_to_config(config, argname='exit_reason_list', + logstring='Analysis exit tag list: {}') + + self._args_to_config(config, argname='indicator_list', + logstring='Analysis indicator list: {}') + def _process_runmode(self, config: Dict[str, Any]) -> None: self._args_to_config(config, argname='dry_run', diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py new file mode 100755 index 000000000..62216d5ea --- /dev/null +++ b/freqtrade/data/entryexitanalysis.py @@ -0,0 +1,258 @@ +import joblib +import logging +import os + +from pathlib import Path +from typing import List, Optional + +import pandas as pd +from tabulate import tabulate + +from freqtrade.data.btanalysis import (load_backtest_data, get_latest_backtest_filename) +from freqtrade.exceptions import OperationalException + + +logger = logging.getLogger(__name__) + + +def _load_signal_candles(backtest_dir: Path): + scpf = Path(backtest_dir, + os.path.splitext( + get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl" + ) + try: + scp = open(scpf, "rb") + signal_candles = joblib.load(scp) + logger.info(f"Loaded signal candles: {str(scpf)}") + except Exception as e: + logger.error("Cannot load signal candles from pickled results: ", e) + + return signal_candles + + +def _process_candles_and_indicators(pairlist, strategy_name, trades, signal_candles): + analysed_trades_dict = {} + analysed_trades_dict[strategy_name] = {} + + try: + logger.info(f"Processing {strategy_name} : {len(pairlist)} pairs") + + for pair in pairlist: + if pair in signal_candles[strategy_name]: + analysed_trades_dict[strategy_name][pair] = _analyze_candles_and_indicators( + pair, + trades, + signal_candles[strategy_name][pair]) + except Exception: + pass + + return analysed_trades_dict + + +def _analyze_candles_and_indicators(pair, trades, signal_candles): + buyf = signal_candles + + if len(buyf) > 0: + buyf = buyf.set_index('date', drop=False) + trades_red = trades.loc[trades['pair'] == pair].copy() + + trades_inds = pd.DataFrame() + + if trades_red.shape[0] > 0 and buyf.shape[0] > 0: + for t, v in trades_red.open_date.items(): + allinds = buyf.loc[(buyf['date'] < v)] + if allinds.shape[0] > 0: + tmp_inds = allinds.iloc[[-1]] + + trades_red.loc[t, 'signal_date'] = tmp_inds['date'].values[0] + trades_red.loc[t, 'enter_reason'] = trades_red.loc[t, 'enter_tag'] + tmp_inds.index.rename('signal_date', inplace=True) + trades_inds = pd.concat([trades_inds, tmp_inds]) + + if 'signal_date' in trades_red: + trades_red['signal_date'] = pd.to_datetime(trades_red['signal_date'], utc=True) + trades_red.set_index('signal_date', inplace=True) + + try: + trades_red = pd.merge(trades_red, trades_inds, on='signal_date', how='outer') + except Exception as e: + print(e) + return trades_red + else: + return pd.DataFrame() + + +def _do_group_table_output(bigdf, glist): + if "0" in glist: + wins = bigdf.loc[bigdf['profit_abs'] >= 0] \ + .groupby(['enter_reason']) \ + .agg({'profit_abs': ['sum']}) + + wins.columns = ['profit_abs_wins'] + loss = bigdf.loc[bigdf['profit_abs'] < 0] \ + .groupby(['enter_reason']) \ + .agg({'profit_abs': ['sum']}) + loss.columns = ['profit_abs_loss'] + + new = bigdf.groupby(['enter_reason']).agg({'profit_abs': [ + 'count', + lambda x: sum(x > 0), + lambda x: sum(x <= 0)]}) + + new = pd.merge(new, wins, left_index=True, right_index=True) + new = pd.merge(new, loss, left_index=True, right_index=True) + + new['profit_tot'] = new['profit_abs_wins'] - abs(new['profit_abs_loss']) + + new['wl_ratio_pct'] = (new.iloc[:, 1] / new.iloc[:, 0] * 100) + new['avg_win'] = (new['profit_abs_wins'] / new.iloc[:, 1]) + new['avg_loss'] = (new['profit_abs_loss'] / new.iloc[:, 2]) + + new.columns = ['total_num_buys', 'wins', 'losses', 'profit_abs_wins', 'profit_abs_loss', + 'profit_tot', 'wl_ratio_pct', 'avg_win', 'avg_loss'] + + sortcols = ['total_num_buys'] + + _print_table(new, sortcols, show_index=True) + if "1" in glist: + new = bigdf.groupby(['enter_reason']) \ + .agg({'profit_abs': ['count', 'sum', 'median', 'mean'], + 'profit_ratio': ['sum', 'median', 'mean']} + ).reset_index() + new.columns = ['enter_reason', 'num_buys', 'profit_abs_sum', 'profit_abs_median', + 'profit_abs_mean', 'median_profit_pct', 'mean_profit_pct', + 'total_profit_pct'] + sortcols = ['profit_abs_sum', 'enter_reason'] + + new['median_profit_pct'] = new['median_profit_pct'] * 100 + new['mean_profit_pct'] = new['mean_profit_pct'] * 100 + new['total_profit_pct'] = new['total_profit_pct'] * 100 + + _print_table(new, sortcols) + if "2" in glist: + new = bigdf.groupby(['enter_reason', 'exit_reason']) \ + .agg({'profit_abs': ['count', 'sum', 'median', 'mean'], + 'profit_ratio': ['sum', 'median', 'mean']} + ).reset_index() + new.columns = ['enter_reason', 'exit_reason', 'num_buys', 'profit_abs_sum', + 'profit_abs_median', 'profit_abs_mean', 'median_profit_pct', + 'mean_profit_pct', 'total_profit_pct'] + sortcols = ['profit_abs_sum', 'enter_reason'] + + new['median_profit_pct'] = new['median_profit_pct'] * 100 + new['mean_profit_pct'] = new['mean_profit_pct'] * 100 + new['total_profit_pct'] = new['total_profit_pct'] * 100 + + _print_table(new, sortcols) + if "3" in glist: + new = bigdf.groupby(['pair', 'enter_reason']) \ + .agg({'profit_abs': ['count', 'sum', 'median', 'mean'], + 'profit_ratio': ['sum', 'median', 'mean']} + ).reset_index() + new.columns = ['pair', 'enter_reason', 'num_buys', 'profit_abs_sum', + 'profit_abs_median', 'profit_abs_mean', 'median_profit_pct', + 'mean_profit_pct', 'total_profit_pct'] + sortcols = ['profit_abs_sum', 'enter_reason'] + + new['median_profit_pct'] = new['median_profit_pct'] * 100 + new['mean_profit_pct'] = new['mean_profit_pct'] * 100 + new['total_profit_pct'] = new['total_profit_pct'] * 100 + + _print_table(new, sortcols) + if "4" in glist: + new = bigdf.groupby(['pair', 'enter_reason', 'exit_reason']) \ + .agg({'profit_abs': ['count', 'sum', 'median', 'mean'], + 'profit_ratio': ['sum', 'median', 'mean']} + ).reset_index() + new.columns = ['pair', 'enter_reason', 'exit_reason', 'num_buys', 'profit_abs_sum', + 'profit_abs_median', 'profit_abs_mean', 'median_profit_pct', + 'mean_profit_pct', 'total_profit_pct'] + sortcols = ['profit_abs_sum', 'enter_reason'] + + new['median_profit_pct'] = new['median_profit_pct'] * 100 + new['mean_profit_pct'] = new['mean_profit_pct'] * 100 + new['total_profit_pct'] = new['total_profit_pct'] * 100 + + _print_table(new, sortcols) + + +def _print_results(analysed_trades, stratname, group, + enter_reason_list, exit_reason_list, + indicator_list, columns=None): + + if columns is None: + columns = ['pair', 'open_date', 'close_date', 'profit_abs', 'enter_reason', 'exit_reason'] + + bigdf = pd.DataFrame() + for pair, trades in analysed_trades[stratname].items(): + bigdf = pd.concat([bigdf, trades], ignore_index=True) + + if bigdf.shape[0] > 0 and ('enter_reason' in bigdf.columns): + if group is not None: + glist = group.split(",") + _do_group_table_output(bigdf, glist) + + if enter_reason_list is not None and not enter_reason_list == "all": + enter_reason_list = enter_reason_list.split(",") + bigdf = bigdf.loc[(bigdf['enter_reason'].isin(enter_reason_list))] + + if exit_reason_list is not None and not exit_reason_list == "all": + exit_reason_list = exit_reason_list.split(",") + bigdf = bigdf.loc[(bigdf['exit_reason'].isin(exit_reason_list))] + + if indicator_list is not None: + if indicator_list == "all": + print(bigdf) + else: + available_inds = [] + for ind in indicator_list.split(","): + if ind in bigdf: + available_inds.append(ind) + ilist = ["pair", "enter_reason", "exit_reason"] + available_inds + print(tabulate(bigdf[ilist].sort_values(['exit_reason']), + headers='keys', tablefmt='psql', showindex=False)) + else: + print(tabulate(bigdf[columns].sort_values(['pair']), + headers='keys', tablefmt='psql', showindex=False)) + else: + print("\\_ No trades to show") + + +def _print_table(df, sortcols=None, show_index=False): + if (sortcols is not None): + data = df.sort_values(sortcols) + else: + data = df + + print( + tabulate( + data, + headers='keys', + tablefmt='psql', + showindex=show_index + ) + ) + + +def process_entry_exit_reasons(backtest_dir: Path, + pairlist: List[str], + strategy_name: str, + analysis_groups: Optional[str] = "0,1,2", + enter_reason_list: Optional[str] = "all", + exit_reason_list: Optional[str] = "all", + indicator_list: Optional[str] = None): + + try: + trades = load_backtest_data(backtest_dir, strategy_name) + except ValueError as e: + raise OperationalException(e) from e + if not trades.empty: + signal_candles = _load_signal_candles(backtest_dir) + analysed_trades_dict = _process_candles_and_indicators(pairlist, strategy_name, + trades, signal_candles) + _print_results(analysed_trades_dict, + strategy_name, + analysis_groups, + enter_reason_list, + exit_reason_list, + indicator_list) From a1a09a802b8232b0285dbdad1d9542936cf53232 Mon Sep 17 00:00:00 2001 From: froggleston Date: Sun, 22 May 2022 23:34:31 +0100 Subject: [PATCH 193/449] Add analyze_commands --- freqtrade/commands/analyze_commands.py | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100755 freqtrade/commands/analyze_commands.py diff --git a/freqtrade/commands/analyze_commands.py b/freqtrade/commands/analyze_commands.py new file mode 100755 index 000000000..0bda9935a --- /dev/null +++ b/freqtrade/commands/analyze_commands.py @@ -0,0 +1,62 @@ +import logging +import os + +from pathlib import Path +from typing import Any, Dict + +from freqtrade.configuration import setup_utils_configuration +from freqtrade.enums import RunMode +from freqtrade.exceptions import OperationalException + + +logger = logging.getLogger(__name__) + + +def setup_analyze_configuration(args: Dict[str, Any], method: RunMode) -> Dict[str, Any]: + """ + Prepare the configuration for the entry/exit reason analysis module + :param args: Cli args from Arguments() + :param method: Bot running mode + :return: Configuration + """ + config = setup_utils_configuration(args, method) + + no_unlimited_runmodes = { + RunMode.BACKTEST: 'backtesting', + } + if method in no_unlimited_runmodes.keys(): + from freqtrade.data.btanalysis import get_latest_backtest_filename + + btp = Path(config.get('user_data_dir'), "backtest_results") + btfile = get_latest_backtest_filename(btp) + signals_file = f"{os.path.basename(os.path.splitext(btfile)[0])}_signals.pkl" + + if (not os.path.exists(Path(btp, signals_file))): + raise OperationalException( + "Cannot find latest backtest signals file. Run backtesting with --export signals." + ) + + return config + + +def start_analysis_entries_exits(args: Dict[str, Any]) -> None: + """ + Start analysis script + :param args: Cli args from Arguments() + :return: None + """ + from freqtrade.data.entryexitanalysis import process_entry_exit_reasons + + # Initialize configuration + config = setup_analyze_configuration(args, RunMode.BACKTEST) + + logger.info('Starting freqtrade in analysis mode') + + process_entry_exit_reasons(Path(config['user_data_dir'], 'backtest_results'), + config['exchange']['pair_whitelist'], + config['strategy'], + config['analysis_groups'], + config['enter_reason_list'], + config['exit_reason_list'], + config['indicator_list'] + ) From ae1ede58da1193553d5fcb5c85c3911b6e1c8664 Mon Sep 17 00:00:00 2001 From: froggleston Date: Sun, 22 May 2022 23:41:28 +0100 Subject: [PATCH 194/449] Fix import order --- freqtrade/commands/analyze_commands.py | 1 - freqtrade/data/entryexitanalysis.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/freqtrade/commands/analyze_commands.py b/freqtrade/commands/analyze_commands.py index 0bda9935a..1590dc519 100755 --- a/freqtrade/commands/analyze_commands.py +++ b/freqtrade/commands/analyze_commands.py @@ -1,6 +1,5 @@ import logging import os - from pathlib import Path from typing import Any, Dict diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index 62216d5ea..e22a2475e 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -1,14 +1,13 @@ -import joblib import logging import os - from pathlib import Path from typing import List, Optional +import joblib import pandas as pd from tabulate import tabulate -from freqtrade.data.btanalysis import (load_backtest_data, get_latest_backtest_filename) +from freqtrade.data.btanalysis import get_latest_backtest_filename, load_backtest_data from freqtrade.exceptions import OperationalException From 80c6190c055f606510abef151886f0607f3fd88a Mon Sep 17 00:00:00 2001 From: froggleston Date: Sun, 22 May 2022 23:55:59 +0100 Subject: [PATCH 195/449] Fix analyze_commands setup --- freqtrade/commands/analyze_commands.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/freqtrade/commands/analyze_commands.py b/freqtrade/commands/analyze_commands.py index 1590dc519..a4b3d3f52 100755 --- a/freqtrade/commands/analyze_commands.py +++ b/freqtrade/commands/analyze_commands.py @@ -26,11 +26,10 @@ def setup_analyze_configuration(args: Dict[str, Any], method: RunMode) -> Dict[s if method in no_unlimited_runmodes.keys(): from freqtrade.data.btanalysis import get_latest_backtest_filename - btp = Path(config.get('user_data_dir'), "backtest_results") - btfile = get_latest_backtest_filename(btp) + btfile = get_latest_backtest_filename(config['user_data_dir'] / 'backtest_results') signals_file = f"{os.path.basename(os.path.splitext(btfile)[0])}_signals.pkl" - if (not os.path.exists(Path(btp, signals_file))): + if (not os.path.exists(config['user_data_dir'] / 'backtest_results' / signals_file)): raise OperationalException( "Cannot find latest backtest signals file. Run backtesting with --export signals." ) From 8c03ebb78ff637a4545391c2ac62510ba1a1c4f1 Mon Sep 17 00:00:00 2001 From: froggleston Date: Tue, 24 May 2022 12:48:13 +0100 Subject: [PATCH 196/449] Fix group 0 table, add pathlib.Path use --- freqtrade/commands/analyze_commands.py | 14 ++++++++++---- freqtrade/commands/cli_options.py | 1 + freqtrade/data/entryexitanalysis.py | 12 +++++------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/freqtrade/commands/analyze_commands.py b/freqtrade/commands/analyze_commands.py index a4b3d3f52..73ae19eaf 100755 --- a/freqtrade/commands/analyze_commands.py +++ b/freqtrade/commands/analyze_commands.py @@ -1,5 +1,4 @@ import logging -import os from pathlib import Path from typing import Any, Dict @@ -26,14 +25,19 @@ def setup_analyze_configuration(args: Dict[str, Any], method: RunMode) -> Dict[s if method in no_unlimited_runmodes.keys(): from freqtrade.data.btanalysis import get_latest_backtest_filename - btfile = get_latest_backtest_filename(config['user_data_dir'] / 'backtest_results') - signals_file = f"{os.path.basename(os.path.splitext(btfile)[0])}_signals.pkl" + btfile = Path(get_latest_backtest_filename(config['user_data_dir'] / 'backtest_results')) + signals_file = f"{btfile.stem}_signals.pkl" - if (not os.path.exists(config['user_data_dir'] / 'backtest_results' / signals_file)): + if (not (config['user_data_dir'] / 'backtest_results' / signals_file).exists()): raise OperationalException( "Cannot find latest backtest signals file. Run backtesting with --export signals." ) + if ('strategy' not in config): + raise OperationalException( + "No strategy defined. Use --strategy or supply in config." + ) + return config @@ -48,6 +52,8 @@ def start_analysis_entries_exits(args: Dict[str, Any]) -> None: # Initialize configuration config = setup_analyze_configuration(args, RunMode.BACKTEST) + print(config) + logger.info('Starting freqtrade in analysis mode') process_entry_exit_reasons(Path(config['user_data_dir'], 'backtest_results'), diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index f925bd699..f76f3688c 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -644,5 +644,6 @@ AVAILABLE_CLI_OPTIONS = { help=("Comma separated list of indicators to analyse. ", "e.g. 'close,rsi,bb_lowerband,profit_abs'"), nargs='?', + default='', ), } diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index e22a2475e..8bfc940dc 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -97,15 +97,12 @@ def _do_group_table_output(bigdf, glist): 'count', lambda x: sum(x > 0), lambda x: sum(x <= 0)]}) - - new = pd.merge(new, wins, left_index=True, right_index=True) - new = pd.merge(new, loss, left_index=True, right_index=True) + new = pd.concat([new, wins, loss], axis=1).fillna(0) new['profit_tot'] = new['profit_abs_wins'] - abs(new['profit_abs_loss']) - - new['wl_ratio_pct'] = (new.iloc[:, 1] / new.iloc[:, 0] * 100) - new['avg_win'] = (new['profit_abs_wins'] / new.iloc[:, 1]) - new['avg_loss'] = (new['profit_abs_loss'] / new.iloc[:, 2]) + new['wl_ratio_pct'] = (new.iloc[:, 1] / new.iloc[:, 0] * 100).fillna(0) + new['avg_win'] = (new['profit_abs_wins'] / new.iloc[:, 1]).fillna(0) + new['avg_loss'] = (new['profit_abs_loss'] / new.iloc[:, 2]).fillna(0) new.columns = ['total_num_buys', 'wins', 'losses', 'profit_abs_wins', 'profit_abs_loss', 'profit_tot', 'wl_ratio_pct', 'avg_win', 'avg_loss'] @@ -249,6 +246,7 @@ def process_entry_exit_reasons(backtest_dir: Path, signal_candles = _load_signal_candles(backtest_dir) analysed_trades_dict = _process_candles_and_indicators(pairlist, strategy_name, trades, signal_candles) + _print_results(analysed_trades_dict, strategy_name, analysis_groups, From a8ee77cd5e39b002d629f649147a96264394ad45 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 May 2022 19:13:35 +0200 Subject: [PATCH 197/449] Simplify backtesting typechecking --- freqtrade/optimize/backtesting.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 19922ee57..445de69f0 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -661,7 +661,7 @@ class Backtesting: return self._get_exit_trade_entry_for_candle(trade, row) def get_valid_price_and_stake( - self, pair: str, row: Tuple, propose_rate: float, stake_amount_inp: Optional[float], + self, pair: str, row: Tuple, propose_rate: float, stake_amount: float, direction: LongShort, current_time: datetime, entry_tag: Optional[str], trade: Optional[LocalTrade], order_type: str ) -> Tuple[float, float, float, float]: @@ -699,8 +699,6 @@ class Backtesting: ) if self._can_short else 1.0 # Cap leverage between 1.0 and max_leverage. leverage = min(max(leverage, 1.0), max_leverage) - elif stake_amount_inp is not None: - stake_amount = stake_amount_inp min_stake_amount = self.exchange.get_min_pair_stake_amount( pair, propose_rate, -0.05, leverage=leverage) or 0 @@ -737,8 +735,9 @@ class Backtesting: order_type = self.strategy.order_types['entry'] pos_adjust = trade is not None and requested_rate is None + stake_amount_ = stake_amount or (trade.stake_amount if trade else 0.0) propose_rate, stake_amount, leverage, min_stake_amount = self.get_valid_price_and_stake( - pair, row, row[OPEN_IDX], stake_amount, direction, current_time, entry_tag, trade, + pair, row, row[OPEN_IDX], stake_amount_, direction, current_time, entry_tag, trade, order_type ) From 3adda84b96bdcde1909a6cecb12ef9b3fbd9296c Mon Sep 17 00:00:00 2001 From: froggleston Date: Tue, 24 May 2022 20:27:15 +0100 Subject: [PATCH 198/449] Update docs, add test --- docs/advanced-backtesting.md | 16 ++-- freqtrade/commands/analyze_commands.py | 2 - freqtrade/data/entryexitanalysis.py | 17 ++-- tests/data/test_entryexitanalysis.py | 94 +++++++++++++++++++++++ tests/strategy/strats/strategy_test_v3.py | 9 ++- 5 files changed, 117 insertions(+), 21 deletions(-) create mode 100755 tests/data/test_entryexitanalysis.py diff --git a/docs/advanced-backtesting.md b/docs/advanced-backtesting.md index 2a484da69..4b40bad8e 100644 --- a/docs/advanced-backtesting.md +++ b/docs/advanced-backtesting.md @@ -22,23 +22,19 @@ DataFrame of the candles that resulted in buy signals. Depending on how many buy makes, this file may get quite large, so periodically check your `user_data/backtest_results` folder to delete old exports. -To analyze the buy tags, we need to use the `buy_reasons.py` script from -[froggleston's repo](https://github.com/froggleston/freqtrade-buyreasons). Follow the instructions -in their README to copy the script into your `freqtrade/scripts/` folder. - Before running your next backtest, make sure you either delete your old backtest results or run backtesting with the `--cache none` option to make sure no cached results are used. If all goes well, you should now see a `backtest-result-{timestamp}_signals.pkl` file in the `user_data/backtest_results` folder. -Now run the `buy_reasons.py` script, supplying a few options: +To analyze the entry/exit tags, we now need to use the `freqtrade analysis` command: ``` bash -python3 scripts/buy_reasons.py -c -s -t -g0,1,2,3,4 +freqtrade analysis -c -s --analysis_groups 0,1,2,3,4 ``` -The `-g` option is used to specify the various tabular outputs, ranging from the simplest (0) +The `--analysis_groups` option is used to specify the various tabular outputs, ranging from the simplest (0) to the most detailed per pair, per buy and per sell tag (4). More options are available by running with the `-h` option. @@ -54,18 +50,18 @@ To show only certain buy and sell tags in the displayed output, use the followin For example: ```bash -python3 scripts/buy_reasons.py -c -s -t -g0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss" +freqtrade analysis -c -s --analysis_groups 0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss" ``` ### Outputting signal candle indicators -The real power of the buy_reasons.py script comes from the ability to print out the indicator +The real power of `freqtrade analysis` comes from the ability to print out the indicator values present on signal candles to allow fine-grained investigation and tuning of buy signal indicators. To print out a column for a given set of indicators, use the `--indicator-list` option: ```bash -python3 scripts/buy_reasons.py -c -s -t -g0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss" --indicator_list "rsi,rsi_1h,bb_lowerband,ema_9,macd,macdsignal" +freqtrade analysis -c -s --analysis_groups 0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss" --indicator_list "rsi,rsi_1h,bb_lowerband,ema_9,macd,macdsignal" ``` The indicators have to be present in your strategy's main DataFrame (either for your main diff --git a/freqtrade/commands/analyze_commands.py b/freqtrade/commands/analyze_commands.py index 73ae19eaf..56330bed3 100755 --- a/freqtrade/commands/analyze_commands.py +++ b/freqtrade/commands/analyze_commands.py @@ -52,8 +52,6 @@ def start_analysis_entries_exits(args: Dict[str, Any]) -> None: # Initialize configuration config = setup_analyze_configuration(args, RunMode.BACKTEST) - print(config) - logger.info('Starting freqtrade in analysis mode') process_entry_exit_reasons(Path(config['user_data_dir'], 'backtest_results'), diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index 8bfc940dc..9d6c470da 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -15,10 +15,18 @@ logger = logging.getLogger(__name__) def _load_signal_candles(backtest_dir: Path): - scpf = Path(backtest_dir, - os.path.splitext( - get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl" - ) + + if backtest_dir.is_dir(): + scpf = Path(backtest_dir, + os.path.splitext( + get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl" + ) + else: + scpf = Path(os.path.splitext( + get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl" + ) + + print(scpf) try: scp = open(scpf, "rb") signal_candles = joblib.load(scp) @@ -246,7 +254,6 @@ def process_entry_exit_reasons(backtest_dir: Path, signal_candles = _load_signal_candles(backtest_dir) analysed_trades_dict = _process_candles_and_indicators(pairlist, strategy_name, trades, signal_candles) - _print_results(analysed_trades_dict, strategy_name, analysis_groups, diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py new file mode 100755 index 000000000..548cd88b9 --- /dev/null +++ b/tests/data/test_entryexitanalysis.py @@ -0,0 +1,94 @@ +from pathlib import Path +from unittest.mock import MagicMock, PropertyMock + +import pandas as pd + +from freqtrade.commands.analyze_commands import start_analysis_entries_exits +from freqtrade.commands.optimize_commands import start_backtesting +from freqtrade.enums import ExitType +from tests.conftest import get_args, patch_exchange, patched_configuration_load_config_file + + +def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, capsys): + default_conf.update({ + "use_exit_signal": True, + "exit_profit_only": False, + "exit_profit_offset": 0.0, + "ignore_roi_if_entry_signal": False, + 'analysis_groups': "0", + 'enter_reason_list': "all", + 'exit_reason_list': "all", + 'indicator_list': "bb_upperband,ema_10" + }) + patch_exchange(mocker) + result1 = pd.DataFrame({'pair': ['ETH/BTC', 'LTC/BTC'], + 'profit_ratio': [0.0, 0.0], + 'profit_abs': [0.0, 0.0], + 'open_date': pd.to_datetime(['2018-01-29 18:40:00', + '2018-01-30 03:30:00', ], utc=True + ), + 'close_date': pd.to_datetime(['2018-01-29 20:45:00', + '2018-01-30 05:35:00', ], utc=True), + 'trade_duration': [235, 40], + 'is_open': [False, False], + 'stake_amount': [0.01, 0.01], + 'open_rate': [0.104445, 0.10302485], + 'close_rate': [0.104969, 0.103541], + "is_short": [False, False], + 'enter_tag': ["enter_tag_long", "enter_tag_long"], + 'exit_reason': [ExitType.ROI, ExitType.ROI] + }) + + backtestmock = MagicMock(side_effect=[ + { + 'results': result1, + 'config': default_conf, + 'locks': [], + 'rejected_signals': 20, + 'timedout_entry_orders': 0, + 'timedout_exit_orders': 0, + 'canceled_trade_entries': 0, + 'canceled_entry_orders': 0, + 'replaced_entry_orders': 0, + 'final_balance': 1000, + } + ]) + mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', + PropertyMock(return_value=['ETH/BTC', 'LTC/BTC', 'DASH/BTC'])) + mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock) + + patched_configuration_load_config_file(mocker, default_conf) + + args = [ + 'backtesting', + '--config', 'config.json', + '--datadir', str(testdatadir), + '--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'), + '--timeframe', '5m', + '--timerange', '1515560100-1517287800', + '--export', 'signals', + '--cache', 'none', + '--strategy-list', + 'StrategyTestV3', + ] + args = get_args(args) + start_backtesting(args) + + captured = capsys.readouterr() + assert 'BACKTESTING REPORT' in captured.out + assert 'EXIT REASON STATS' in captured.out + assert 'LEFT OPEN TRADES REPORT' in captured.out + + args = [ + 'analysis', + '--config', 'config.json', + '--datadir', str(testdatadir), + '--analysis_groups', '0', + '--strategy', + 'StrategyTestV3', + ] + args = get_args(args) + start_analysis_entries_exits(args) + + captured = capsys.readouterr() + assert 'enter_tag_long' in captured.out diff --git a/tests/strategy/strats/strategy_test_v3.py b/tests/strategy/strats/strategy_test_v3.py index df83d3663..f1c9d8e99 100644 --- a/tests/strategy/strats/strategy_test_v3.py +++ b/tests/strategy/strats/strategy_test_v3.py @@ -143,12 +143,13 @@ class StrategyTestV3(IStrategy): (dataframe['adx'] > 65) & (dataframe['plus_di'] > self.buy_plusdi.value) ), - 'enter_long'] = 1 + ['enter_long', 'enter_tag']] = 1, 'enter_tag_long' + dataframe.loc[ ( qtpylib.crossed_below(dataframe['rsi'], self.sell_rsi.value) ), - 'enter_short'] = 1 + ['enter_short', 'enter_tag']] = 1, 'enter_tag_short' return dataframe @@ -166,13 +167,13 @@ class StrategyTestV3(IStrategy): (dataframe['adx'] > 70) & (dataframe['minus_di'] > self.sell_minusdi.value) ), - 'exit_long'] = 1 + ['exit_long', 'exit_tag']] = 1, 'exit_tag_long' dataframe.loc[ ( qtpylib.crossed_above(dataframe['rsi'], self.buy_rsi.value) ), - 'exit_short'] = 1 + ['exit_long', 'exit_tag']] = 1, 'exit_tag_short' return dataframe From 22b9805e472f44ce1da2928b6d8177c293012048 Mon Sep 17 00:00:00 2001 From: froggleston Date: Tue, 24 May 2022 21:04:23 +0100 Subject: [PATCH 199/449] Fix all tests --- tests/data/test_entryexitanalysis.py | 4 +- tests/rpc/test_rpc_apiserver.py | 6 +- tests/strategy/strats/strategy_test_v3.py | 8 +- .../strats/strategy_test_v3_analysis.py | 195 ++++++++++++++++++ tests/strategy/test_strategy_loading.py | 6 +- 5 files changed, 209 insertions(+), 10 deletions(-) create mode 100644 tests/strategy/strats/strategy_test_v3_analysis.py diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index 548cd88b9..151fc3ff8 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -69,7 +69,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap '--export', 'signals', '--cache', 'none', '--strategy-list', - 'StrategyTestV3', + 'StrategyTestV3Analysis', ] args = get_args(args) start_backtesting(args) @@ -85,7 +85,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap '--datadir', str(testdatadir), '--analysis_groups', '0', '--strategy', - 'StrategyTestV3', + 'StrategyTestV3Analysis', ] args = get_args(args) start_analysis_entries_exits(args) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 03ba895a1..c887e7776 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1384,12 +1384,16 @@ def test_api_strategies(botclient): rc = client_get(client, f"{BASE_URI}/strategies") assert_response(rc) + + print(rc.json()) + assert rc.json() == {'strategies': [ 'HyperoptableStrategy', 'InformativeDecoratorTest', 'StrategyTestV2', 'StrategyTestV3', - 'StrategyTestV3Futures', + 'StrategyTestV3Analysis', + 'StrategyTestV3Futures' ]} diff --git a/tests/strategy/strats/strategy_test_v3.py b/tests/strategy/strats/strategy_test_v3.py index f1c9d8e99..9ca2471bd 100644 --- a/tests/strategy/strats/strategy_test_v3.py +++ b/tests/strategy/strats/strategy_test_v3.py @@ -143,13 +143,13 @@ class StrategyTestV3(IStrategy): (dataframe['adx'] > 65) & (dataframe['plus_di'] > self.buy_plusdi.value) ), - ['enter_long', 'enter_tag']] = 1, 'enter_tag_long' + 'enter_long'] = 1 dataframe.loc[ ( qtpylib.crossed_below(dataframe['rsi'], self.sell_rsi.value) ), - ['enter_short', 'enter_tag']] = 1, 'enter_tag_short' + 'enter_short'] = 1 return dataframe @@ -167,13 +167,13 @@ class StrategyTestV3(IStrategy): (dataframe['adx'] > 70) & (dataframe['minus_di'] > self.sell_minusdi.value) ), - ['exit_long', 'exit_tag']] = 1, 'exit_tag_long' + 'exit_long'] = 1 dataframe.loc[ ( qtpylib.crossed_above(dataframe['rsi'], self.buy_rsi.value) ), - ['exit_long', 'exit_tag']] = 1, 'exit_tag_short' + 'exit_short'] = 1 return dataframe diff --git a/tests/strategy/strats/strategy_test_v3_analysis.py b/tests/strategy/strats/strategy_test_v3_analysis.py new file mode 100644 index 000000000..b237f548f --- /dev/null +++ b/tests/strategy/strats/strategy_test_v3_analysis.py @@ -0,0 +1,195 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement + +from datetime import datetime + +import talib.abstract as ta +from pandas import DataFrame + +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.persistence import Trade +from freqtrade.strategy import (BooleanParameter, DecimalParameter, IntParameter, IStrategy, + RealParameter) + + +class StrategyTestV3Analysis(IStrategy): + """ + Strategy used by tests freqtrade bot. + Please do not modify this strategy, it's intended for internal use only. + Please look at the SampleStrategy in the user_data/strategy directory + or strategy repository https://github.com/freqtrade/freqtrade-strategies + for samples and inspiration. + """ + INTERFACE_VERSION = 3 + + # Minimal ROI designed for the strategy + minimal_roi = { + "40": 0.0, + "30": 0.01, + "20": 0.02, + "0": 0.04 + } + + # Optimal stoploss designed for the strategy + stoploss = -0.10 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # Optional order type mapping + order_types = { + 'entry': 'limit', + 'exit': 'limit', + 'stoploss': 'limit', + 'stoploss_on_exchange': False + } + + # Number of candles the strategy requires before producing valid signals + startup_candle_count: int = 20 + + # Optional time in force for orders + order_time_in_force = { + 'entry': 'gtc', + 'exit': 'gtc', + } + + buy_params = { + 'buy_rsi': 35, + # Intentionally not specified, so "default" is tested + # 'buy_plusdi': 0.4 + } + + sell_params = { + 'sell_rsi': 74, + 'sell_minusdi': 0.4 + } + + buy_rsi = IntParameter([0, 50], default=30, space='buy') + buy_plusdi = RealParameter(low=0, high=1, default=0.5, space='buy') + sell_rsi = IntParameter(low=50, high=100, default=70, space='sell') + sell_minusdi = DecimalParameter(low=0, high=1, default=0.5001, decimals=3, space='sell', + load=False) + protection_enabled = BooleanParameter(default=True) + protection_cooldown_lookback = IntParameter([0, 50], default=30) + + # TODO: Can this work with protection tests? (replace HyperoptableStrategy implicitly ... ) + # @property + # def protections(self): + # prot = [] + # if self.protection_enabled.value: + # prot.append({ + # "method": "CooldownPeriod", + # "stop_duration_candles": self.protection_cooldown_lookback.value + # }) + # return prot + + bot_started = False + + def bot_start(self): + self.bot_started = True + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Momentum Indicator + # ------------------------------------ + + # ADX + dataframe['adx'] = ta.ADX(dataframe) + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # Minus Directional Indicator / Movement + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # Plus Directional Indicator / Movement + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Stoch fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # Bollinger bands + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) + dataframe['bb_lowerband'] = bollinger['lower'] + dataframe['bb_middleband'] = bollinger['mid'] + dataframe['bb_upperband'] = bollinger['upper'] + + # EMA - Exponential Moving Average + dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + + return dataframe + + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi'] < self.buy_rsi.value) & + (dataframe['fastd'] < 35) & + (dataframe['adx'] > 30) & + (dataframe['plus_di'] > self.buy_plusdi.value) + ) | + ( + (dataframe['adx'] > 65) & + (dataframe['plus_di'] > self.buy_plusdi.value) + ), + ['enter_long', 'enter_tag']] = 1, 'enter_tag_long' + + dataframe.loc[ + ( + qtpylib.crossed_below(dataframe['rsi'], self.sell_rsi.value) + ), + ['enter_short', 'enter_tag']] = 1, 'enter_tag_short' + + return dataframe + + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + ( + (qtpylib.crossed_above(dataframe['rsi'], self.sell_rsi.value)) | + (qtpylib.crossed_above(dataframe['fastd'], 70)) + ) & + (dataframe['adx'] > 10) & + (dataframe['minus_di'] > 0) + ) | + ( + (dataframe['adx'] > 70) & + (dataframe['minus_di'] > self.sell_minusdi.value) + ), + ['exit_long', 'exit_tag']] = 1, 'exit_tag_long' + + dataframe.loc[ + ( + qtpylib.crossed_above(dataframe['rsi'], self.buy_rsi.value) + ), + ['exit_long', 'exit_tag']] = 1, 'exit_tag_short' + + return dataframe + + def leverage(self, pair: str, current_time: datetime, current_rate: float, + proposed_leverage: float, max_leverage: float, side: str, + **kwargs) -> float: + # Return 3.0 in all cases. + # Bot-logic must make sure it's an allowed leverage and eventually adjust accordingly. + + return 3.0 + + def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, + current_profit: float, min_stake: float, max_stake: float, **kwargs): + + if current_profit < -0.0075: + orders = trade.select_filled_orders(trade.entry_side) + return round(orders[0].cost, 0) + + return None diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index 919a4bd00..666ae2b05 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -34,7 +34,7 @@ def test_search_all_strategies_no_failed(): directory = Path(__file__).parent / "strats" strategies = StrategyResolver.search_all_objects(directory, enum_failed=False) assert isinstance(strategies, list) - assert len(strategies) == 5 + assert len(strategies) == 6 assert isinstance(strategies[0], dict) @@ -42,10 +42,10 @@ def test_search_all_strategies_with_failed(): directory = Path(__file__).parent / "strats" strategies = StrategyResolver.search_all_objects(directory, enum_failed=True) assert isinstance(strategies, list) - assert len(strategies) == 6 + assert len(strategies) == 7 # with enum_failed=True search_all_objects() shall find 2 good strategies # and 1 which fails to load - assert len([x for x in strategies if x['class'] is not None]) == 5 + assert len([x for x in strategies if x['class'] is not None]) == 6 assert len([x for x in strategies if x['class'] is None]) == 1 From edd474e663b950ade4b4fe172846a8045b013b3e Mon Sep 17 00:00:00 2001 From: froggleston Date: Tue, 24 May 2022 21:21:20 +0100 Subject: [PATCH 200/449] Another test fix attempt --- .../strats/strategy_test_v3_analysis.py | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/tests/strategy/strats/strategy_test_v3_analysis.py b/tests/strategy/strats/strategy_test_v3_analysis.py index b237f548f..290fef156 100644 --- a/tests/strategy/strats/strategy_test_v3_analysis.py +++ b/tests/strategy/strats/strategy_test_v3_analysis.py @@ -1,12 +1,9 @@ # pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement -from datetime import datetime - import talib.abstract as ta from pandas import DataFrame import freqtrade.vendor.qtpylib.indicators as qtpylib -from freqtrade.persistence import Trade from freqtrade.strategy import (BooleanParameter, DecimalParameter, IntParameter, IStrategy, RealParameter) @@ -176,20 +173,3 @@ class StrategyTestV3Analysis(IStrategy): ['exit_long', 'exit_tag']] = 1, 'exit_tag_short' return dataframe - - def leverage(self, pair: str, current_time: datetime, current_rate: float, - proposed_leverage: float, max_leverage: float, side: str, - **kwargs) -> float: - # Return 3.0 in all cases. - # Bot-logic must make sure it's an allowed leverage and eventually adjust accordingly. - - return 3.0 - - def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, - current_profit: float, min_stake: float, max_stake: float, **kwargs): - - if current_profit < -0.0075: - orders = trade.select_filled_orders(trade.entry_side) - return round(orders[0].cost, 0) - - return None From 43f726ba8f18cfd4bc068727d69136edc5c0a20d Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 25 May 2022 06:14:45 +0000 Subject: [PATCH 201/449] Run CI against different templates --- .github/workflows/ci.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d11285ba4..d2e420e8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,11 +78,13 @@ jobs: # Allow failure for coveralls coveralls || true - - name: Backtesting + - name: Backtesting (multi) run: | cp config_examples/config_bittrex.example.json config.json freqtrade create-userdir --userdir user_data - freqtrade backtesting --datadir tests/testdata --strategy SampleStrategy + freqtrade new-strategy -s AwesomeStrategy + freqtrade new-strategy -s AwesomeStrategyMin --template minimal + freqtrade backtesting --datadir tests/testdata --strategy-list AwesomeStrategy AwesomeStrategyMin -i 5m - name: Hyperopt run: | @@ -164,7 +166,8 @@ jobs: run: | cp config_examples/config_bittrex.example.json config.json freqtrade create-userdir --userdir user_data - freqtrade backtesting --datadir tests/testdata --strategy SampleStrategy + freqtrade new-strategy -s AwesomeStrategyAdv --template advanced + freqtrade backtesting --datadir tests/testdata --strategy AwesomeStrategyAdv - name: Hyperopt run: | From 2873ca6d38329245f6aedb84f93f94f1a992eb77 Mon Sep 17 00:00:00 2001 From: froggleston Date: Wed, 25 May 2022 09:57:12 +0100 Subject: [PATCH 202/449] Add cleanup, adjust _print_table for indicators, add rsi to test output --- freqtrade/data/entryexitanalysis.py | 7 ++----- tests/data/test_entryexitanalysis.py | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index 9d6c470da..192d666ae 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -26,7 +26,6 @@ def _load_signal_candles(backtest_dir: Path): get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl" ) - print(scpf) try: scp = open(scpf, "rb") signal_candles = joblib.load(scp) @@ -213,11 +212,9 @@ def _print_results(analysed_trades, stratname, group, if ind in bigdf: available_inds.append(ind) ilist = ["pair", "enter_reason", "exit_reason"] + available_inds - print(tabulate(bigdf[ilist].sort_values(['exit_reason']), - headers='keys', tablefmt='psql', showindex=False)) + _print_table(bigdf[ilist], sortcols=['exit_reason'], show_index=False) else: - print(tabulate(bigdf[columns].sort_values(['pair']), - headers='keys', tablefmt='psql', showindex=False)) + _print_table(bigdf[columns], sortcols=['pair'], show_index=False) else: print("\\_ No trades to show") diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index 151fc3ff8..70ba5fa21 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -2,13 +2,22 @@ from pathlib import Path from unittest.mock import MagicMock, PropertyMock import pandas as pd +import pytest from freqtrade.commands.analyze_commands import start_analysis_entries_exits from freqtrade.commands.optimize_commands import start_backtesting from freqtrade.enums import ExitType +from freqtrade.optimize.backtesting import Backtesting from tests.conftest import get_args, patch_exchange, patched_configuration_load_config_file +@pytest.fixture(autouse=True) +def backtesting_cleanup() -> None: + yield None + + Backtesting.cleanup() + + def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, capsys): default_conf.update({ "use_exit_signal": True, @@ -18,7 +27,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap 'analysis_groups': "0", 'enter_reason_list': "all", 'exit_reason_list': "all", - 'indicator_list': "bb_upperband,ema_10" + 'indicator_list': "rsi" }) patch_exchange(mocker) result1 = pd.DataFrame({'pair': ['ETH/BTC', 'LTC/BTC'], @@ -84,6 +93,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap '--config', 'config.json', '--datadir', str(testdatadir), '--analysis_groups', '0', + '--indicator_list', 'rsi', '--strategy', 'StrategyTestV3Analysis', ] @@ -92,3 +102,6 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap captured = capsys.readouterr() assert 'enter_tag_long' in captured.out + assert '34.049' in captured.out + + Backtesting.cleanup() From f5c2930889c7d9de7e999817389bff185adb117c Mon Sep 17 00:00:00 2001 From: froggleston Date: Wed, 25 May 2022 09:58:38 +0100 Subject: [PATCH 203/449] Presume that pytest will call the cleanup call --- tests/data/test_entryexitanalysis.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index 70ba5fa21..3ee986600 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -12,7 +12,7 @@ from tests.conftest import get_args, patch_exchange, patched_configuration_load_ @pytest.fixture(autouse=True) -def backtesting_cleanup() -> None: +def entryexitanalysis_cleanup() -> None: yield None Backtesting.cleanup() @@ -103,5 +103,3 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap captured = capsys.readouterr() assert 'enter_tag_long' in captured.out assert '34.049' in captured.out - - Backtesting.cleanup() From 21e6c14e1e80e65eff1d50e7d85e0aa330b7983c Mon Sep 17 00:00:00 2001 From: froggleston Date: Wed, 25 May 2022 10:08:03 +0100 Subject: [PATCH 204/449] Final test changes --- tests/data/test_entryexitanalysis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index 3ee986600..9ae89a2f8 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -102,4 +102,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap captured = capsys.readouterr() assert 'enter_tag_long' in captured.out + assert 'ETH/BTC' in captured.out assert '34.049' in captured.out + assert 'LTC/BTC' in captured.out + assert '54.3204' in captured.out From b2968df5dc3aa0e81ba366cea37fa68d1b7382b3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 25 May 2022 10:13:37 +0000 Subject: [PATCH 205/449] Fix some type problems --- freqtrade/exchange/binance.py | 4 ++-- freqtrade/exchange/exchange.py | 4 ++-- freqtrade/exchange/kraken.py | 2 +- freqtrade/persistence/trade_model.py | 4 ++-- pyproject.toml | 8 ++++++++ 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 69ae5198a..1b6496a64 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -57,7 +57,7 @@ class Binance(Exchange): (side == "buy" and stop_loss < float(order['info']['stopPrice'])) ) - def get_tickers(self, symbols: List[str] = None, cached: bool = False) -> Dict: + def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: tickers = super().get_tickers(symbols=symbols, cached=cached) if self.trading_mode == TradingMode.FUTURES: # Binance's future result has no bid/ask values. @@ -95,7 +95,7 @@ class Binance(Exchange): async def _async_get_historic_ohlcv(self, pair: str, timeframe: str, since_ms: int, candle_type: CandleType, is_new_pair: bool = False, raise_: bool = False, - until_ms: int = None + until_ms: Optional[int] = None ) -> Tuple[str, str, str, List]: """ Overwrite to introduce "fast new pair" functionality by detecting the pair's listing date diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 6ef61f227..c1a9059a7 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1351,7 +1351,7 @@ class Exchange: raise OperationalException(e) from e @retrier - def fetch_bids_asks(self, symbols: List[str] = None, cached: bool = False) -> Dict: + def fetch_bids_asks(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: """ :param cached: Allow cached result :return: fetch_tickers result @@ -1379,7 +1379,7 @@ class Exchange: raise OperationalException(e) from e @retrier - def get_tickers(self, symbols: List[str] = None, cached: bool = False) -> Dict: + def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: """ :param cached: Allow cached result :return: fetch_tickers result diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 900f6c898..0103e2702 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -45,7 +45,7 @@ class Kraken(Exchange): return (parent_check and market.get('darkpool', False) is False) - def get_tickers(self, symbols: List[str] = None, cached: bool = False) -> Dict: + def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: # Only fetch tickers for current stake currency # Otherwise the request for kraken becomes too large. symbols = list(self.get_markets(quote_currencies=[self._config['stake_currency']])) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index d2abb48d6..45a16bfbd 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -868,8 +868,8 @@ class LocalTrade(): return o return None - def select_order( - self, order_side: str = None, is_open: Optional[bool] = None) -> Optional[Order]: + def select_order(self, order_side: Optional[str] = None, + is_open: Optional[bool] = None) -> Optional[Order]: """ Finds latest order for this orderside and status :param order_side: ft_order_side of the order (either 'buy', 'sell' or 'stoploss') diff --git a/pyproject.toml b/pyproject.toml index 935874ab8..0cb81f745 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,3 +42,11 @@ ignore_errors = true [build-system] requires = ["setuptools >= 46.4.0", "wheel"] build-backend = "setuptools.build_meta" + +[tool.pyright] +include = ["freqtrade"] +exclude = [ + "**/__pycache__", + "build_helpers/*.py", +] +ignore = ["freqtrade/vendor/**"] From 023f8171794e9d7415c1c3e7a7e268a1899b3828 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 25 May 2022 19:37:32 +0200 Subject: [PATCH 206/449] Improve wording for supported futures exchanges --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6c3c8fe25..881895c9a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Please read the [exchange specific notes](docs/exchanges.md) to learn about even - [X] [OKX](https://okx.com/) (Former OKEX) - [ ] [potentially many others](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ -### Experimentally, freqtrade also supports futures on the following exchanges +### Supported Futures Exchanges (experimental) - [X] [Binance](https://www.binance.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) diff --git a/docs/index.md b/docs/index.md index 16c4ded94..7c35e92b6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -47,7 +47,7 @@ Please read the [exchange specific notes](exchanges.md) to learn about eventual, - [X] [OKX](https://okx.com/) (Former OKEX) - [ ] [potentially many others through ccxt](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ -### Experimentally, freqtrade also supports futures on the following exchanges: +### Supported Futures Exchanges (experimental) - [X] [Binance](https://www.binance.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) From 3e66275c98d1a9d59bf97d48554141a4e4660bf8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 25 May 2022 20:01:21 +0200 Subject: [PATCH 207/449] Refactor bot_start to separate function to be reused further ... --- freqtrade/freqtradebot.py | 2 +- freqtrade/optimize/backtesting.py | 2 +- freqtrade/optimize/edge_cli.py | 2 +- freqtrade/plot/plotting.py | 2 +- freqtrade/strategy/interface.py | 7 +++++++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index df541e3a9..a2a12a03a 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -123,7 +123,7 @@ class FreqtradeBot(LoggingMixin): self._schedule.every().day.at(t).do(update) self.last_process = datetime(1970, 1, 1, tzinfo=timezone.utc) - self.strategy.bot_start() + self.strategy.ft_bot_start() def notify_status(self, msg: str) -> None: """ diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index ef2b222a0..f1e9b7251 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -187,7 +187,7 @@ class Backtesting: # since a "perfect" stoploss-exit is assumed anyway # And the regular "stoploss" function would not apply to that case self.strategy.order_types['stoploss_on_exchange'] = False - self.strategy.bot_start() + self.strategy.ft_bot_start() def _load_protections(self, strategy: IStrategy): if self.config.get('enable_protections', False): diff --git a/freqtrade/optimize/edge_cli.py b/freqtrade/optimize/edge_cli.py index 30eabecd0..aa3b02529 100644 --- a/freqtrade/optimize/edge_cli.py +++ b/freqtrade/optimize/edge_cli.py @@ -44,7 +44,7 @@ class EdgeCli: self.edge._timerange = TimeRange.parse_timerange(None if self.config.get( 'timerange') is None else str(self.config.get('timerange'))) - self.strategy.bot_start() + self.strategy.ft_bot_start() def start(self) -> None: result = self.edge.calculate(self.config['exchange']['pair_whitelist']) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index ce8f54cbd..a64281156 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -633,7 +633,7 @@ def load_and_plot_trades(config: Dict[str, Any]): exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config) IStrategy.dp = DataProvider(config, exchange) - strategy.bot_start() + strategy.ft_bot_start() strategy.bot_loop_start() plot_elements = init_plotscript(config, list(exchange.markets), strategy.startup_candle_count) timerange = plot_elements['timerange'] diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 60ac9da5a..c521943b1 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -144,6 +144,13 @@ class IStrategy(ABC, HyperStrategyMixin): informative_data.candle_type = config['candle_type_def'] self._ft_informative.append((informative_data, cls_method)) + def ft_bot_start(self, **kwargs) -> None: + """ + Strategy init - runs after dataprovider has been added. + Must call bot_start() + """ + strategy_safe_wrapper(self.bot_start)() + @abstractmethod def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ From 537d10c627bb307875507b69219ad29ce82a31da Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 25 May 2022 20:43:43 +0200 Subject: [PATCH 208/449] Improve some typing --- freqtrade/configuration/configuration.py | 5 +++-- freqtrade/configuration/directory_operations.py | 2 +- freqtrade/strategy/hyper.py | 4 ++-- freqtrade/strategy/parameters.py | 2 ++ pyproject.toml | 3 +++ 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 96b585cd1..3f563b6cd 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -490,7 +490,8 @@ class Configuration: if not pairs_file.exists(): raise OperationalException(f'No pairs file found with path "{pairs_file}".') config['pairs'] = load_file(pairs_file) - config['pairs'].sort() + if isinstance(config['pairs'], list): + config['pairs'].sort() return if 'config' in self.args and self.args['config']: @@ -501,5 +502,5 @@ class Configuration: pairs_file = config['datadir'] / 'pairs.json' if pairs_file.exists(): config['pairs'] = load_file(pairs_file) - if 'pairs' in config: + if 'pairs' in config and isinstance(config['pairs'], list): config['pairs'].sort() diff --git a/freqtrade/configuration/directory_operations.py b/freqtrade/configuration/directory_operations.py index ca305c260..771fd53cc 100644 --- a/freqtrade/configuration/directory_operations.py +++ b/freqtrade/configuration/directory_operations.py @@ -15,7 +15,7 @@ def create_datadir(config: Dict[str, Any], datadir: Optional[str] = None) -> Pat folder = Path(datadir) if datadir else Path(f"{config['user_data_dir']}/data") if not datadir: # set datadir - exchange_name = config.get('exchange', {}).get('name').lower() + exchange_name = config.get('exchange', {}).get('name', '').lower() folder = folder.joinpath(exchange_name) if not folder.is_dir(): diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index 15f5be483..5c09dd862 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -69,7 +69,7 @@ class HyperStrategyMixin: @classmethod def detect_all_parameters(cls) -> Dict: """ Detect all parameters and return them as a list""" - params: Dict = { + params: Dict[str, Any] = { 'buy': list(cls.detect_parameters('buy')), 'sell': list(cls.detect_parameters('sell')), 'protection': list(cls.detect_parameters('protection')), @@ -148,7 +148,7 @@ class HyperStrategyMixin: """ Returns list of Parameters that are not part of the current optimize job """ - params = { + params: Dict[str, Dict] = { 'buy': {}, 'sell': {}, 'protection': {}, diff --git a/freqtrade/strategy/parameters.py b/freqtrade/strategy/parameters.py index 02706690d..83dd41de9 100644 --- a/freqtrade/strategy/parameters.py +++ b/freqtrade/strategy/parameters.py @@ -97,6 +97,8 @@ class NumericParameter(BaseParameter): class IntParameter(NumericParameter): default: int value: int + low: int + high: int def __init__(self, low: Union[int, Sequence[int]], high: Optional[int] = None, *, default: int, space: Optional[str] = None, optimize: bool = True, load: bool = True, **kwargs): diff --git a/pyproject.toml b/pyproject.toml index 0cb81f745..8020b0636 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,3 +50,6 @@ exclude = [ "build_helpers/*.py", ] ignore = ["freqtrade/vendor/**"] + +# Align pyright to mypy config +strictParameterNoneValue = false From e1c6cf5f91d43f795968c191807e38bb8a36b015 Mon Sep 17 00:00:00 2001 From: Stefano Ariestasia Date: Thu, 26 May 2022 10:12:50 +0900 Subject: [PATCH 209/449] fix typo --- freqtrade/configuration/deprecated_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/configuration/deprecated_settings.py b/freqtrade/configuration/deprecated_settings.py index 70d29e2bd..e88383785 100644 --- a/freqtrade/configuration/deprecated_settings.py +++ b/freqtrade/configuration/deprecated_settings.py @@ -113,7 +113,7 @@ def process_temporary_deprecated_settings(config: Dict[str, Any]) -> None: process_removed_setting(config, 'experimental', 'ignore_roi_if_buy_signal', None, 'ignore_roi_if_entry_signal') - process_removed_setting(config, 'ask_strategy', 'use_sell_signal', None, 'exit_sell_signal') + process_removed_setting(config, 'ask_strategy', 'use_sell_signal', None, 'use_exit_signal') process_removed_setting(config, 'ask_strategy', 'sell_profit_only', None, 'exit_profit_only') process_removed_setting(config, 'ask_strategy', 'sell_profit_offset', None, 'exit_profit_offset') From 145faf98178e5b8bc69c7cd1dba3a01eda9d2d7e Mon Sep 17 00:00:00 2001 From: froggleston Date: Thu, 26 May 2022 11:06:38 +0100 Subject: [PATCH 210/449] Use tmpdir for testing --- tests/data/test_entryexitanalysis.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index 9ae89a2f8..ed0bab76b 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -18,7 +18,7 @@ def entryexitanalysis_cleanup() -> None: Backtesting.cleanup() -def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, capsys): +def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmpdir, capsys): default_conf.update({ "use_exit_signal": True, "exit_profit_only": False, @@ -72,6 +72,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap 'backtesting', '--config', 'config.json', '--datadir', str(testdatadir), + '--user-data-dir', str(tmpdir), '--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'), '--timeframe', '5m', '--timerange', '1515560100-1517287800', @@ -92,6 +93,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, cap 'analysis', '--config', 'config.json', '--datadir', str(testdatadir), + '--user-data-dir', str(tmpdir), '--analysis_groups', '0', '--indicator_list', 'rsi', '--strategy', From 682daa4e941abf2235e60d9ecd1ad029eec5d3c4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 26 May 2022 18:05:40 +0200 Subject: [PATCH 211/449] Reset logging mixin to avoid random test failure --- freqtrade/exchange/common.py | 8 ++++++++ tests/exchange/test_exchange.py | 2 ++ 2 files changed, 10 insertions(+) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index a9f03ba1a..841f45cd0 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -12,6 +12,14 @@ logger = logging.getLogger(__name__) __logging_mixin = None +def _reset_logging_mixin(): + """ + Reset global logging mixin - used in tests only. + """ + global __logging_mixin + __logging_mixin = LoggingMixin(logger) + + def _get_logging_mixin(): # Logging-mixin to cache kucoin responses # Only to be used in retrier diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index b19c59e50..9da2dbc11 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2155,6 +2155,8 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_ @pytest.mark.asyncio async def test__async_kucoin_get_candle_history(default_conf, mocker, caplog): + from freqtrade.exchange.common import _reset_logging_mixin + _reset_logging_mixin() caplog.set_level(logging.INFO) api_mock = MagicMock() api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.DDoSProtection( From 43b7955fc2b43a78102f802ed5dee9e348564823 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 26 May 2022 19:37:55 +0200 Subject: [PATCH 212/449] Fully rely on pathlib --- freqtrade/data/entryexitanalysis.py | 10 +++------- tests/rpc/test_rpc_apiserver.py | 2 -- tests/strategy/strats/strategy_test_v3.py | 1 - 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index 192d666ae..3c83d4abf 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -1,5 +1,4 @@ import logging -import os from pathlib import Path from typing import List, Optional @@ -18,14 +17,11 @@ def _load_signal_candles(backtest_dir: Path): if backtest_dir.is_dir(): scpf = Path(backtest_dir, - os.path.splitext( - get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl" + Path(get_latest_backtest_filename(backtest_dir)).stem + "_signals.pkl" ) else: - scpf = Path(os.path.splitext( - get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl" - ) - + scpf = Path(Path(get_latest_backtest_filename(backtest_dir)).stem + "_signals.pkl") + print(scpf) try: scp = open(scpf, "rb") signal_candles = joblib.load(scp) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index c887e7776..8b3ac18ac 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1385,8 +1385,6 @@ def test_api_strategies(botclient): assert_response(rc) - print(rc.json()) - assert rc.json() == {'strategies': [ 'HyperoptableStrategy', 'InformativeDecoratorTest', diff --git a/tests/strategy/strats/strategy_test_v3.py b/tests/strategy/strats/strategy_test_v3.py index 9ca2471bd..df83d3663 100644 --- a/tests/strategy/strats/strategy_test_v3.py +++ b/tests/strategy/strats/strategy_test_v3.py @@ -144,7 +144,6 @@ class StrategyTestV3(IStrategy): (dataframe['plus_di'] > self.buy_plusdi.value) ), 'enter_long'] = 1 - dataframe.loc[ ( qtpylib.crossed_below(dataframe['rsi'], self.sell_rsi.value) From 24cf0446468be71f2979b27affa66bd1f036745b Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 27 May 2022 08:18:04 +0000 Subject: [PATCH 213/449] Fix bybit spot mode --- freqtrade/exchange/bybit.py | 14 ++++++++++++++ tests/exchange/test_exchange.py | 1 + 2 files changed, 15 insertions(+) diff --git a/freqtrade/exchange/bybit.py b/freqtrade/exchange/bybit.py index 484b8b9d3..1c4bb858b 100644 --- a/freqtrade/exchange/bybit.py +++ b/freqtrade/exchange/bybit.py @@ -29,3 +29,17 @@ class Bybit(Exchange): # (TradingMode.FUTURES, MarginMode.CROSS), # (TradingMode.FUTURES, MarginMode.ISOLATED) ] + + @property + def _ccxt_config(self) -> Dict: + # Parameters to add directly to ccxt sync/async initialization. + # ccxt defaults to swap mode. + config = {} + if self.trading_mode == TradingMode.SPOT: + config.update({ + "options": { + "defaultType": "spot" + } + }) + config.update(super()._ccxt_config) + return config diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 9da2dbc11..708a0e889 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3819,6 +3819,7 @@ def test_validate_trading_mode_and_margin_mode( ("bibox", "spot", {"has": {"fetchCurrencies": False}}), ("bibox", "margin", {"has": {"fetchCurrencies": False}, "options": {"defaultType": "margin"}}), ("bibox", "futures", {"has": {"fetchCurrencies": False}, "options": {"defaultType": "swap"}}), + ("bybit", "spot", {"options": {"defaultType": "spot"}}), ("bybit", "futures", {"options": {"defaultType": "linear"}}), ("ftx", "futures", {"options": {"defaultType": "swap"}}), ("gateio", "futures", {"options": {"defaultType": "swap"}}), From b04fe5d4ee7b9a0fb7ef79ec810064148ab3623b Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 27 May 2022 19:30:14 +0200 Subject: [PATCH 214/449] Simplify test v2 strategy --- tests/strategy/strats/strategy_test_v2.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/strategy/strats/strategy_test_v2.py b/tests/strategy/strats/strategy_test_v2.py index 46181ac7e..4e45b1463 100644 --- a/tests/strategy/strats/strategy_test_v2.py +++ b/tests/strategy/strats/strategy_test_v2.py @@ -150,13 +150,3 @@ class StrategyTestV2(IStrategy): ), 'sell'] = 1 return dataframe - - def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, - current_profit: float, - min_stake: Optional[float], max_stake: float, **kwargs): - - if current_profit < -0.0075: - orders = trade.select_filled_orders('buy') - return round(orders[0].cost, 0) - - return None From 3e7bf6a9ef786fa5b283347b9c7ba1c58f35ce93 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 27 May 2022 19:31:34 +0200 Subject: [PATCH 215/449] Remove imports in test_strategy2 --- tests/strategy/strats/strategy_test_v2.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/strategy/strats/strategy_test_v2.py b/tests/strategy/strats/strategy_test_v2.py index 4e45b1463..9e1c47575 100644 --- a/tests/strategy/strats/strategy_test_v2.py +++ b/tests/strategy/strats/strategy_test_v2.py @@ -1,13 +1,9 @@ # pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement -from datetime import datetime -from typing import Optional - import talib.abstract as ta from pandas import DataFrame import freqtrade.vendor.qtpylib.indicators as qtpylib -from freqtrade.persistence import Trade from freqtrade.strategy import IStrategy From f64f2b1ad8f1f5a289e14d305b205961375a5b46 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 May 2022 10:34:22 +0200 Subject: [PATCH 216/449] Fix /stats Formatting issue in multi-message settings --- freqtrade/rpc/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index f26de8b5c..4a274002e 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -785,7 +785,7 @@ class Telegram(RPCHandler): headers=['Exit Reason', 'Exits', 'Wins', 'Losses'] ) if len(exit_reasons_tabulate) > 25: - self._send_msg(exit_reasons_msg, ParseMode.MARKDOWN) + self._send_msg(f"```\n{exit_reasons_msg}```", ParseMode.MARKDOWN) exit_reasons_msg = '' durations = stats['durations'] From a875a7dc40996355cfe32bb9136b44fdea354213 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 May 2022 10:58:01 +0200 Subject: [PATCH 217/449] Use unified stopPrice for binance --- freqtrade/exchange/binance.py | 4 ++-- tests/exchange/test_binance.py | 1 + tests/test_freqtradebot.py | 4 +--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 1b6496a64..03546dcf9 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -53,8 +53,8 @@ class Binance(Exchange): ordertype = 'stop' if self.trading_mode == TradingMode.FUTURES else 'stop_loss_limit' return order['type'] == ordertype and ( - (side == "sell" and stop_loss > float(order['info']['stopPrice'])) or - (side == "buy" and stop_loss < float(order['info']['stopPrice'])) + (side == "sell" and stop_loss > float(order['stopPrice'])) or + (side == "buy" and stop_loss < float(order['stopPrice'])) ) def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index 324be9962..45f8a3817 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -154,6 +154,7 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side): order = { 'type': 'stop_loss_limit', 'price': 1500, + 'stopPrice': 1500, 'info': {'stopPrice': 1500}, } assert exchange.stoploss_adjust(sl1, order, side=side) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 23ef4ffc2..5a5467370 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1775,9 +1775,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, 'type': 'stop_loss_limit', 'price': 3, 'average': 2, - 'info': { - 'stopPrice': '2.178' - } + 'stopPrice': '2.178' }) mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', stoploss_order_hanging) From e7c5818d1645af2e373f346cee98e3a69e47395b Mon Sep 17 00:00:00 2001 From: froggleston Date: Sun, 29 May 2022 11:20:11 +0100 Subject: [PATCH 218/449] First pass changes for cleaning up --- freqtrade/commands/arguments.py | 6 +- freqtrade/commands/cli_options.py | 8 +- freqtrade/data/entryexitanalysis.py | 145 ++++++++++++--------------- tests/data/test_entryexitanalysis.py | 12 +-- 4 files changed, 75 insertions(+), 96 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 4dd0141fa..679193e49 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -101,8 +101,8 @@ ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperop "print_json", "hyperoptexportfilename", "hyperopt_show_no_header", "disableparamexport", "backtest_breakdown"] -ARGS_ANALYZE_ENTRIES_EXITS = ["analysis_groups", "enter_reason_list", - "exit_reason_list", "indicator_list"] +ARGS_ANALYZE_ENTRIES_EXITS = ["analysis-groups", "enter-reason-list", + "exit-reason-list", "indicator-list"] NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes", "list-markets", "list-pairs", "list-strategies", "list-data", @@ -421,7 +421,7 @@ class Arguments: self._build_args(optionlist=ARGS_WEBSERVER, parser=webserver_cmd) # Add backtesting analysis subcommand - analysis_cmd = subparsers.add_parser('analysis', help='Analysis module.', + analysis_cmd = subparsers.add_parser('analysis', help='Backtest Analysis module.', parents=[_common_parser, _strategy_parser]) analysis_cmd.set_defaults(func=start_analysis_entries_exits) self._build_args(optionlist=ARGS_ANALYZE_ENTRIES_EXITS, parser=analysis_cmd) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index f76f3688c..ce7320b95 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -615,7 +615,7 @@ AVAILABLE_CLI_OPTIONS = { action="store_true", ), "analysis_groups": Arg( - "--analysis_groups", + "--analysis-groups", help=("grouping output - ", "0: simple wins/losses by enter tag, ", "1: by enter_tag, ", @@ -626,21 +626,21 @@ AVAILABLE_CLI_OPTIONS = { default="0,1,2", ), "enter_reason_list": Arg( - "--enter_reason_list", + "--enter-reason-list", help=("Comma separated list of entry signals to analyse. Default: all. ", "e.g. 'entry_tag_a,entry_tag_b'"), nargs='?', default='all', ), "exit_reason_list": Arg( - "--exit_reason_list", + "--exit-reason-list", help=("Comma separated list of exit signals to analyse. Default: all. ", "e.g. 'exit_tag_a,roi,stop_loss,trailing_stop_loss'"), nargs='?', default='all', ), "indicator_list": Arg( - "--indicator_list", + "--indicator-list", help=("Comma separated list of indicators to analyse. ", "e.g. 'close,rsi,bb_lowerband,profit_abs'"), nargs='?', diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index 192d666ae..53a256633 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -7,7 +7,8 @@ import joblib import pandas as pd from tabulate import tabulate -from freqtrade.data.btanalysis import get_latest_backtest_filename, load_backtest_data +from freqtrade.data.btanalysis import (get_latest_backtest_filename, load_backtest_data, + load_backtest_stats) from freqtrade.exceptions import OperationalException @@ -49,8 +50,8 @@ def _process_candles_and_indicators(pairlist, strategy_name, trades, signal_cand pair, trades, signal_candles[strategy_name][pair]) - except Exception: - pass + except Exception as e: + print(f"Cannot process entry/exit reasons for {strategy_name}: ", e) return analysed_trades_dict @@ -82,104 +83,79 @@ def _analyze_candles_and_indicators(pair, trades, signal_candles): try: trades_red = pd.merge(trades_red, trades_inds, on='signal_date', how='outer') except Exception as e: - print(e) + raise e return trades_red else: return pd.DataFrame() def _do_group_table_output(bigdf, glist): - if "0" in glist: - wins = bigdf.loc[bigdf['profit_abs'] >= 0] \ - .groupby(['enter_reason']) \ - .agg({'profit_abs': ['sum']}) + for g in glist: + # 0: summary wins/losses grouped by enter tag + if g == "0": + group_mask = ['enter_reason'] + wins = bigdf.loc[bigdf['profit_abs'] >= 0] \ + .groupby(group_mask) \ + .agg({'profit_abs': ['sum']}) - wins.columns = ['profit_abs_wins'] - loss = bigdf.loc[bigdf['profit_abs'] < 0] \ - .groupby(['enter_reason']) \ - .agg({'profit_abs': ['sum']}) - loss.columns = ['profit_abs_loss'] + wins.columns = ['profit_abs_wins'] + loss = bigdf.loc[bigdf['profit_abs'] < 0] \ + .groupby(group_mask) \ + .agg({'profit_abs': ['sum']}) + loss.columns = ['profit_abs_loss'] - new = bigdf.groupby(['enter_reason']).agg({'profit_abs': [ - 'count', - lambda x: sum(x > 0), - lambda x: sum(x <= 0)]}) - new = pd.concat([new, wins, loss], axis=1).fillna(0) + new = bigdf.groupby(group_mask).agg({'profit_abs': [ + 'count', + lambda x: sum(x > 0), + lambda x: sum(x <= 0)]}) + new = pd.concat([new, wins, loss], axis=1).fillna(0) - new['profit_tot'] = new['profit_abs_wins'] - abs(new['profit_abs_loss']) - new['wl_ratio_pct'] = (new.iloc[:, 1] / new.iloc[:, 0] * 100).fillna(0) - new['avg_win'] = (new['profit_abs_wins'] / new.iloc[:, 1]).fillna(0) - new['avg_loss'] = (new['profit_abs_loss'] / new.iloc[:, 2]).fillna(0) + new['profit_tot'] = new['profit_abs_wins'] - abs(new['profit_abs_loss']) + new['wl_ratio_pct'] = (new.iloc[:, 1] / new.iloc[:, 0] * 100).fillna(0) + new['avg_win'] = (new['profit_abs_wins'] / new.iloc[:, 1]).fillna(0) + new['avg_loss'] = (new['profit_abs_loss'] / new.iloc[:, 2]).fillna(0) - new.columns = ['total_num_buys', 'wins', 'losses', 'profit_abs_wins', 'profit_abs_loss', - 'profit_tot', 'wl_ratio_pct', 'avg_win', 'avg_loss'] + new.columns = ['total_num_buys', 'wins', 'losses', 'profit_abs_wins', 'profit_abs_loss', + 'profit_tot', 'wl_ratio_pct', 'avg_win', 'avg_loss'] - sortcols = ['total_num_buys'] + sortcols = ['total_num_buys'] - _print_table(new, sortcols, show_index=True) - if "1" in glist: - new = bigdf.groupby(['enter_reason']) \ - .agg({'profit_abs': ['count', 'sum', 'median', 'mean'], - 'profit_ratio': ['sum', 'median', 'mean']} - ).reset_index() - new.columns = ['enter_reason', 'num_buys', 'profit_abs_sum', 'profit_abs_median', - 'profit_abs_mean', 'median_profit_pct', 'mean_profit_pct', - 'total_profit_pct'] - sortcols = ['profit_abs_sum', 'enter_reason'] + _print_table(new, sortcols, show_index=True) - new['median_profit_pct'] = new['median_profit_pct'] * 100 - new['mean_profit_pct'] = new['mean_profit_pct'] * 100 - new['total_profit_pct'] = new['total_profit_pct'] * 100 - - _print_table(new, sortcols) - if "2" in glist: - new = bigdf.groupby(['enter_reason', 'exit_reason']) \ - .agg({'profit_abs': ['count', 'sum', 'median', 'mean'], - 'profit_ratio': ['sum', 'median', 'mean']} - ).reset_index() - new.columns = ['enter_reason', 'exit_reason', 'num_buys', 'profit_abs_sum', - 'profit_abs_median', 'profit_abs_mean', 'median_profit_pct', - 'mean_profit_pct', 'total_profit_pct'] - sortcols = ['profit_abs_sum', 'enter_reason'] - - new['median_profit_pct'] = new['median_profit_pct'] * 100 - new['mean_profit_pct'] = new['mean_profit_pct'] * 100 - new['total_profit_pct'] = new['total_profit_pct'] * 100 - - _print_table(new, sortcols) - if "3" in glist: - new = bigdf.groupby(['pair', 'enter_reason']) \ - .agg({'profit_abs': ['count', 'sum', 'median', 'mean'], + else: + agg_mask = {'profit_abs': ['count', 'sum', 'median', 'mean'], 'profit_ratio': ['sum', 'median', 'mean']} - ).reset_index() - new.columns = ['pair', 'enter_reason', 'num_buys', 'profit_abs_sum', - 'profit_abs_median', 'profit_abs_mean', 'median_profit_pct', - 'mean_profit_pct', 'total_profit_pct'] - sortcols = ['profit_abs_sum', 'enter_reason'] + agg_cols = ['num_buys', 'profit_abs_sum', 'profit_abs_median', + 'profit_abs_mean', 'median_profit_pct', 'mean_profit_pct', + 'total_profit_pct'] + sortcols = ['profit_abs_sum', 'enter_reason'] - new['median_profit_pct'] = new['median_profit_pct'] * 100 - new['mean_profit_pct'] = new['mean_profit_pct'] * 100 - new['total_profit_pct'] = new['total_profit_pct'] * 100 + # 1: profit summaries grouped by enter_tag + if g == "1": + group_mask = ['enter_reason'] - _print_table(new, sortcols) - if "4" in glist: - new = bigdf.groupby(['pair', 'enter_reason', 'exit_reason']) \ - .agg({'profit_abs': ['count', 'sum', 'median', 'mean'], - 'profit_ratio': ['sum', 'median', 'mean']} - ).reset_index() - new.columns = ['pair', 'enter_reason', 'exit_reason', 'num_buys', 'profit_abs_sum', - 'profit_abs_median', 'profit_abs_mean', 'median_profit_pct', - 'mean_profit_pct', 'total_profit_pct'] - sortcols = ['profit_abs_sum', 'enter_reason'] + # 2: profit summaries grouped by enter_tag and exit_tag + if g == "2": + group_mask = ['enter_reason', 'exit_reason'] - new['median_profit_pct'] = new['median_profit_pct'] * 100 - new['mean_profit_pct'] = new['mean_profit_pct'] * 100 - new['total_profit_pct'] = new['total_profit_pct'] * 100 + # 3: profit summaries grouped by pair and enter_tag + if g == "3": + group_mask = ['pair', 'enter_reason'] - _print_table(new, sortcols) + # 4: profit summaries grouped by pair, enter_ and exit_tag (this can get quite large) + if g == "4": + group_mask = ['pair', 'enter_reason', 'exit_reason'] + + new = bigdf.groupby(group_mask).agg(agg_mask).reset_index() + new.columns = group_mask + agg_cols + new['median_profit_pct'] = new['median_profit_pct'] * 100 + new['mean_profit_pct'] = new['mean_profit_pct'] * 100 + new['total_profit_pct'] = new['total_profit_pct'] * 100 + + _print_table(new, sortcols) -def _print_results(analysed_trades, stratname, group, +def _print_results(analysed_trades, stratname, analysis_groups, enter_reason_list, exit_reason_list, indicator_list, columns=None): @@ -191,8 +167,8 @@ def _print_results(analysed_trades, stratname, group, bigdf = pd.concat([bigdf, trades], ignore_index=True) if bigdf.shape[0] > 0 and ('enter_reason' in bigdf.columns): - if group is not None: - glist = group.split(",") + if analysis_groups is not None: + glist = analysis_groups.split(",") _do_group_table_output(bigdf, glist) if enter_reason_list is not None and not enter_reason_list == "all": @@ -244,6 +220,9 @@ def process_entry_exit_reasons(backtest_dir: Path, indicator_list: Optional[str] = None): try: + bt_stats = load_backtest_stats(backtest_dir) + logger.info(bt_stats) + # strategy_name = bt_stats['something'] trades = load_backtest_data(backtest_dir, strategy_name) except ValueError as e: raise OperationalException(e) from e diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index ed0bab76b..90da80ce9 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -24,10 +24,10 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp "exit_profit_only": False, "exit_profit_offset": 0.0, "ignore_roi_if_entry_signal": False, - 'analysis_groups': "0", - 'enter_reason_list': "all", - 'exit_reason_list': "all", - 'indicator_list': "rsi" + 'analysis-groups': "0", + 'enter-reason-list': "all", + 'exit-reason-list': "all", + 'indicator-list': "rsi" }) patch_exchange(mocker) result1 = pd.DataFrame({'pair': ['ETH/BTC', 'LTC/BTC'], @@ -94,8 +94,8 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp '--config', 'config.json', '--datadir', str(testdatadir), '--user-data-dir', str(tmpdir), - '--analysis_groups', '0', - '--indicator_list', 'rsi', + '--analysis-groups', '0', + '--indicator-list', 'rsi', '--strategy', 'StrategyTestV3Analysis', ] From df1c36e5aa7085a78ee06ab2cdd1558b0ccd7331 Mon Sep 17 00:00:00 2001 From: froggleston Date: Sun, 29 May 2022 11:54:27 +0100 Subject: [PATCH 219/449] Change command name, use load_backtest_stats for strategy resolving --- freqtrade/commands/analyze_commands.py | 1 - freqtrade/commands/arguments.py | 7 +++--- freqtrade/data/entryexitanalysis.py | 35 ++++++++++++-------------- tests/data/test_entryexitanalysis.py | 13 ++++++---- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/freqtrade/commands/analyze_commands.py b/freqtrade/commands/analyze_commands.py index 56330bed3..2fa13f683 100755 --- a/freqtrade/commands/analyze_commands.py +++ b/freqtrade/commands/analyze_commands.py @@ -56,7 +56,6 @@ def start_analysis_entries_exits(args: Dict[str, Any]) -> None: process_entry_exit_reasons(Path(config['user_data_dir'], 'backtest_results'), config['exchange']['pair_whitelist'], - config['strategy'], config['analysis_groups'], config['enter_reason_list'], config['exit_reason_list'], diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 679193e49..d5831a2ac 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -101,8 +101,8 @@ ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperop "print_json", "hyperoptexportfilename", "hyperopt_show_no_header", "disableparamexport", "backtest_breakdown"] -ARGS_ANALYZE_ENTRIES_EXITS = ["analysis-groups", "enter-reason-list", - "exit-reason-list", "indicator-list"] +ARGS_ANALYZE_ENTRIES_EXITS = ["analysis_groups", "enter_reason_list", + "exit_reason_list", "indicator_list"] NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes", "list-markets", "list-pairs", "list-strategies", "list-data", @@ -421,7 +421,8 @@ class Arguments: self._build_args(optionlist=ARGS_WEBSERVER, parser=webserver_cmd) # Add backtesting analysis subcommand - analysis_cmd = subparsers.add_parser('analysis', help='Backtest Analysis module.', + analysis_cmd = subparsers.add_parser('backtesting-analysis', + help='Backtest Analysis module.', parents=[_common_parser, _strategy_parser]) analysis_cmd.set_defaults(func=start_analysis_entries_exits) self._build_args(optionlist=ARGS_ANALYZE_ENTRIES_EXITS, parser=analysis_cmd) diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index 1ee6eea42..15ac6ba09 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -15,14 +15,13 @@ logger = logging.getLogger(__name__) def _load_signal_candles(backtest_dir: Path): - if backtest_dir.is_dir(): scpf = Path(backtest_dir, Path(get_latest_backtest_filename(backtest_dir)).stem + "_signals.pkl" ) else: scpf = Path(Path(get_latest_backtest_filename(backtest_dir)).stem + "_signals.pkl") - print(scpf) + try: scp = open(scpf, "rb") signal_candles = joblib.load(scp) @@ -154,7 +153,6 @@ def _do_group_table_output(bigdf, glist): def _print_results(analysed_trades, stratname, analysis_groups, enter_reason_list, exit_reason_list, indicator_list, columns=None): - if columns is None: columns = ['pair', 'open_date', 'close_date', 'profit_abs', 'enter_reason', 'exit_reason'] @@ -209,26 +207,25 @@ def _print_table(df, sortcols=None, show_index=False): def process_entry_exit_reasons(backtest_dir: Path, pairlist: List[str], - strategy_name: str, analysis_groups: Optional[str] = "0,1,2", enter_reason_list: Optional[str] = "all", exit_reason_list: Optional[str] = "all", indicator_list: Optional[str] = None): - try: - bt_stats = load_backtest_stats(backtest_dir) - logger.info(bt_stats) - # strategy_name = bt_stats['something'] - trades = load_backtest_data(backtest_dir, strategy_name) + backtest_stats = load_backtest_stats(backtest_dir) + for strategy_name, results in backtest_stats['strategy'].items(): + trades = load_backtest_data(backtest_dir, strategy_name) + + if not trades.empty: + signal_candles = _load_signal_candles(backtest_dir) + analysed_trades_dict = _process_candles_and_indicators(pairlist, strategy_name, + trades, signal_candles) + _print_results(analysed_trades_dict, + strategy_name, + analysis_groups, + enter_reason_list, + exit_reason_list, + indicator_list) + except ValueError as e: raise OperationalException(e) from e - if not trades.empty: - signal_candles = _load_signal_candles(backtest_dir) - analysed_trades_dict = _process_candles_and_indicators(pairlist, strategy_name, - trades, signal_candles) - _print_results(analysed_trades_dict, - strategy_name, - analysis_groups, - enter_reason_list, - exit_reason_list, - indicator_list) diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index 90da80ce9..eadf79179 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -24,10 +24,6 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp "exit_profit_only": False, "exit_profit_offset": 0.0, "ignore_roi_if_entry_signal": False, - 'analysis-groups': "0", - 'enter-reason-list': "all", - 'exit-reason-list': "all", - 'indicator-list': "rsi" }) patch_exchange(mocker) result1 = pd.DataFrame({'pair': ['ETH/BTC', 'LTC/BTC'], @@ -89,8 +85,15 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert 'EXIT REASON STATS' in captured.out assert 'LEFT OPEN TRADES REPORT' in captured.out + default_conf.update({ + 'analysis_groups': "0", + 'enter_reason_list': "all", + 'exit_reason_list': "all", + 'indicator_list': "rsi" + }) + args = [ - 'analysis', + 'backtesting-analysis', '--config', 'config.json', '--datadir', str(testdatadir), '--user-data-dir', str(tmpdir), From 1ee08d22d24973d0ec435e619ad168cc0ad7a3b6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 May 2022 15:58:40 +0200 Subject: [PATCH 220/449] Delay parameter init closes #6894 --- freqtrade/optimize/backtesting.py | 3 +++ freqtrade/strategy/hyper.py | 33 ++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index f1e9b7251..43bc97f32 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -187,6 +187,9 @@ class Backtesting: # since a "perfect" stoploss-exit is assumed anyway # And the regular "stoploss" function would not apply to that case self.strategy.order_types['stoploss_on_exchange'] = False + if self.dataprovider.runmode == RunMode.BACKTEST: + # in hyperopt mode - don't re-init params + self.strategy.ft_load_hyper_params(False) self.strategy.ft_bot_start() def _load_protections(self, strategy: IStrategy): diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index 5c09dd862..bbd6ef5fe 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -31,7 +31,12 @@ class HyperStrategyMixin: self.ft_sell_params: List[BaseParameter] = [] self.ft_protection_params: List[BaseParameter] = [] - self._load_hyper_params(config.get('runmode') == RunMode.HYPEROPT) + params = self.load_params_from_file() + params = params.get('params', {}) + self._ft_params_from_file = params + + if config.get('runmode') != RunMode.BACKTEST: + self.ft_load_hyper_params(config.get('runmode') == RunMode.HYPEROPT) def enumerate_parameters(self, category: str = None) -> Iterator[Tuple[str, BaseParameter]]: """ @@ -80,21 +85,25 @@ class HyperStrategyMixin: return params - def _load_hyper_params(self, hyperopt: bool = False) -> None: + def ft_load_hyper_params(self, hyperopt: bool = False) -> None: """ Load Hyperoptable parameters + Prevalence: + * Parameters from parameter file + * Parameters defined in parameters objects (buy_params, sell_params, ...) + * Parameter defaults """ - params = self.load_params_from_file() - params = params.get('params', {}) - self._ft_params_from_file = params - buy_params = deep_merge_dicts(params.get('buy', {}), getattr(self, 'buy_params', {})) - sell_params = deep_merge_dicts(params.get('sell', {}), getattr(self, 'sell_params', {})) - protection_params = deep_merge_dicts(params.get('protection', {}), + + buy_params = deep_merge_dicts(self._ft_params_from_file.get('buy', {}), + getattr(self, 'buy_params', {})) + sell_params = deep_merge_dicts(self._ft_params_from_file.get('sell', {}), + getattr(self, 'sell_params', {})) + protection_params = deep_merge_dicts(self._ft_params_from_file.get('protection', {}), getattr(self, 'protection_params', {})) - self._load_params(buy_params, 'buy', hyperopt) - self._load_params(sell_params, 'sell', hyperopt) - self._load_params(protection_params, 'protection', hyperopt) + self._ft_load_params(buy_params, 'buy', hyperopt) + self._ft_load_params(sell_params, 'sell', hyperopt) + self._ft_load_params(protection_params, 'protection', hyperopt) def load_params_from_file(self) -> Dict: filename_str = getattr(self, '__file__', '') @@ -117,7 +126,7 @@ class HyperStrategyMixin: return {} - def _load_params(self, params: Dict, space: str, hyperopt: bool = False) -> None: + def _ft_load_params(self, params: Dict, space: str, hyperopt: bool = False) -> None: """ Set optimizable parameter values. :param params: Dictionary with new parameter values. From e6affcc23e01ecd8fe4a48ea41d7ca15b20f9727 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 May 2022 16:39:47 +0200 Subject: [PATCH 221/449] Move parameter file loading to hyper-mixin --- freqtrade/resolvers/strategy_resolver.py | 21 +-------------------- freqtrade/strategy/hyper.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 44d590b67..c63c133ce 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -47,26 +47,7 @@ class StrategyResolver(IResolver): strategy: IStrategy = StrategyResolver._load_strategy( strategy_name, config=config, extra_dir=config.get('strategy_path')) - - if strategy._ft_params_from_file: - # Set parameters from Hyperopt results file - params = strategy._ft_params_from_file - strategy.minimal_roi = params.get('roi', getattr(strategy, 'minimal_roi', {})) - - strategy.stoploss = params.get('stoploss', {}).get( - 'stoploss', getattr(strategy, 'stoploss', -0.1)) - trailing = params.get('trailing', {}) - strategy.trailing_stop = trailing.get( - 'trailing_stop', getattr(strategy, 'trailing_stop', False)) - strategy.trailing_stop_positive = trailing.get( - 'trailing_stop_positive', getattr(strategy, 'trailing_stop_positive', None)) - strategy.trailing_stop_positive_offset = trailing.get( - 'trailing_stop_positive_offset', - getattr(strategy, 'trailing_stop_positive_offset', 0)) - strategy.trailing_only_offset_is_reached = trailing.get( - 'trailing_only_offset_is_reached', - getattr(strategy, 'trailing_only_offset_is_reached', 0.0)) - + strategy.ft_load_hyper_params_from_file() # Set attributes # Check if we need to override configuration # (Attribute name, default, subkey) diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index bbd6ef5fe..c4119173b 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -85,6 +85,27 @@ class HyperStrategyMixin: return params + def ft_load_hyper_params_from_file(self) -> None: + """ Load Parameters from parameter file""" + if self._ft_params_from_file: + # Set parameters from Hyperopt results file + params = self._ft_params_from_file + self.minimal_roi = params.get('roi', getattr(self, 'minimal_roi', {})) + + self.stoploss = params.get('stoploss', {}).get( + 'stoploss', getattr(self, 'stoploss', -0.1)) + trailing = params.get('trailing', {}) + self.trailing_stop = trailing.get( + 'trailing_stop', getattr(self, 'trailing_stop', False)) + self.trailing_stop_positive = trailing.get( + 'trailing_stop_positive', getattr(self, 'trailing_stop_positive', None)) + self.trailing_stop_positive_offset = trailing.get( + 'trailing_stop_positive_offset', + getattr(self, 'trailing_stop_positive_offset', 0)) + self.trailing_only_offset_is_reached = trailing.get( + 'trailing_only_offset_is_reached', + getattr(self, 'trailing_only_offset_is_reached', 0.0)) + def ft_load_hyper_params(self, hyperopt: bool = False) -> None: """ Load Hyperoptable parameters From 24b02127ec03e7c7e05b13fb450310980a7663a4 Mon Sep 17 00:00:00 2001 From: froggleston Date: Sun, 29 May 2022 15:42:34 +0100 Subject: [PATCH 222/449] Update docs --- docs/advanced-backtesting.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/advanced-backtesting.md b/docs/advanced-backtesting.md index 4b40bad8e..7f2be1f1a 100644 --- a/docs/advanced-backtesting.md +++ b/docs/advanced-backtesting.md @@ -28,40 +28,47 @@ backtesting with the `--cache none` option to make sure no cached results are us If all goes well, you should now see a `backtest-result-{timestamp}_signals.pkl` file in the `user_data/backtest_results` folder. -To analyze the entry/exit tags, we now need to use the `freqtrade analysis` command: +To analyze the entry/exit tags, we now need to use the `freqtrade backtesting-analysis` command: ``` bash -freqtrade analysis -c -s --analysis_groups 0,1,2,3,4 +freqtrade backtesting-analysis -c --analysis-groups 0,1,2,3,4 ``` -The `--analysis_groups` option is used to specify the various tabular outputs, ranging from the simplest (0) -to the most detailed per pair, per buy and per sell tag (4). More options are available by -running with the `-h` option. +This command will read from the last backtesting results. The `--analysis-groups` option is +used to specify the various tabular outputs showing the profit fo each group or trade, +ranging from the simplest (0) to the most detailed per pair, per buy and per sell tag (4): + +* 1: profit summaries grouped by enter_tag +* 2: profit summaries grouped by enter_tag and exit_tag +* 3: profit summaries grouped by pair and enter_tag +* 4: profit summaries grouped by pair, enter_ and exit_tag (this can get quite large) + +More options are available by running with the `-h` option. ### Tuning the buy tags and sell tags to display To show only certain buy and sell tags in the displayed output, use the following two options: ``` ---enter_reason_list : Comma separated list of enter signals to analyse. Default: "all" ---exit_reason_list : Comma separated list of exit signals to analyse. Default: "stop_loss,trailing_stop_loss" +--enter-reason-list : Comma separated list of enter signals to analyse. Default: "all" +--exit-reason-list : Comma separated list of exit signals to analyse. Default: "stop_loss,trailing_stop_loss" ``` For example: ```bash -freqtrade analysis -c -s --analysis_groups 0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss" +freqtrade backtesting-analysis -c --analysis-groups 0,1,2,3,4 --enter-reason-list "enter_tag_a,enter_tag_b" --exit-reason-list "roi,custom_exit_tag_a,stop_loss" ``` ### Outputting signal candle indicators -The real power of `freqtrade analysis` comes from the ability to print out the indicator +The real power of `freqtrade backtesting-analysis` comes from the ability to print out the indicator values present on signal candles to allow fine-grained investigation and tuning of buy signal indicators. To print out a column for a given set of indicators, use the `--indicator-list` option: ```bash -freqtrade analysis -c -s --analysis_groups 0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss" --indicator_list "rsi,rsi_1h,bb_lowerband,ema_9,macd,macdsignal" +freqtrade backtesting-analysis -c --analysis-groups 0,1,2,3,4 --enter-reason-list "enter_tag_a,enter_tag_b" --exit-reason-list "roi,custom_exit_tag_a,stop_loss" --indicator-list "rsi,rsi_1h,bb_lowerband,ema_9,macd,macdsignal" ``` The indicators have to be present in your strategy's main DataFrame (either for your main From 9a068c0b14ebb80df49d917223469e950ba4a358 Mon Sep 17 00:00:00 2001 From: froggleston Date: Sun, 29 May 2022 16:25:31 +0100 Subject: [PATCH 223/449] Add test for each analysis group, remove default table output if not indicator-list --- freqtrade/data/entryexitanalysis.py | 4 +- tests/data/test_entryexitanalysis.py | 149 +++++++++++++++++++++------ 2 files changed, 119 insertions(+), 34 deletions(-) diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index 15ac6ba09..1c21fcc15 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -173,7 +173,7 @@ def _print_results(analysed_trades, stratname, analysis_groups, exit_reason_list = exit_reason_list.split(",") bigdf = bigdf.loc[(bigdf['exit_reason'].isin(exit_reason_list))] - if indicator_list is not None: + if indicator_list is not None and indicator_list != "": if indicator_list == "all": print(bigdf) else: @@ -183,8 +183,6 @@ def _print_results(analysed_trades, stratname, analysis_groups, available_inds.append(ind) ilist = ["pair", "enter_reason", "exit_reason"] + available_inds _print_table(bigdf[ilist], sortcols=['exit_reason'], show_index=False) - else: - _print_table(bigdf[columns], sortcols=['pair'], show_index=False) else: print("\\_ No trades to show") diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index eadf79179..971cb51aa 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -1,3 +1,4 @@ +import logging from pathlib import Path from unittest.mock import MagicMock, PropertyMock @@ -19,6 +20,8 @@ def entryexitanalysis_cleanup() -> None: def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmpdir, capsys): + caplog.set_level(logging.INFO) + default_conf.update({ "use_exit_signal": True, "exit_profit_only": False, @@ -26,22 +29,32 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp "ignore_roi_if_entry_signal": False, }) patch_exchange(mocker) - result1 = pd.DataFrame({'pair': ['ETH/BTC', 'LTC/BTC'], - 'profit_ratio': [0.0, 0.0], - 'profit_abs': [0.0, 0.0], + result1 = pd.DataFrame({'pair': ['ETH/BTC', 'LTC/BTC', 'ETH/BTC', 'LTC/BTC'], + 'profit_ratio': [0.025, 0.05, -0.1, -0.05], + 'profit_abs': [0.5, 2.0, -4.0, -2.0], 'open_date': pd.to_datetime(['2018-01-29 18:40:00', - '2018-01-30 03:30:00', ], utc=True + '2018-01-30 03:30:00', + '2018-01-30 08:10:00', + '2018-01-31 13:30:00', ], utc=True ), 'close_date': pd.to_datetime(['2018-01-29 20:45:00', - '2018-01-30 05:35:00', ], utc=True), - 'trade_duration': [235, 40], - 'is_open': [False, False], - 'stake_amount': [0.01, 0.01], - 'open_rate': [0.104445, 0.10302485], - 'close_rate': [0.104969, 0.103541], - "is_short": [False, False], - 'enter_tag': ["enter_tag_long", "enter_tag_long"], - 'exit_reason': [ExitType.ROI, ExitType.ROI] + '2018-01-30 05:35:00', + '2018-01-30 09:10:00', + '2018-01-31 15:00:00', ], utc=True), + 'trade_duration': [235, 40, 60, 90], + 'is_open': [False, False, False, False], + 'stake_amount': [0.01, 0.01, 0.01, 0.01], + 'open_rate': [0.104445, 0.10302485, 0.10302485, 0.10302485], + 'close_rate': [0.104969, 0.103541, 0.102041, 0.102541], + "is_short": [False, False, False, False], + 'enter_tag': ["enter_tag_long_a", + "enter_tag_long_b", + "enter_tag_long_a", + "enter_tag_long_b"], + 'exit_reason': [ExitType.ROI, + ExitType.EXIT_SIGNAL, + ExitType.STOP_LOSS, + ExitType.TRAILING_STOP_LOSS] }) backtestmock = MagicMock(side_effect=[ @@ -85,29 +98,103 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert 'EXIT REASON STATS' in captured.out assert 'LEFT OPEN TRADES REPORT' in captured.out - default_conf.update({ - 'analysis_groups': "0", - 'enter_reason_list': "all", - 'exit_reason_list': "all", - 'indicator_list': "rsi" - }) - - args = [ + base_args = [ 'backtesting-analysis', '--config', 'config.json', '--datadir', str(testdatadir), '--user-data-dir', str(tmpdir), - '--analysis-groups', '0', - '--indicator-list', 'rsi', - '--strategy', - 'StrategyTestV3Analysis', ] - args = get_args(args) - start_analysis_entries_exits(args) + strat_args = ['--strategy', 'StrategyTestV3Analysis'] + # test group 0 and indicator list + args = get_args(base_args + + ['--analysis-groups', '0', + '--indicator-list', 'close,rsi,profit_abs'] + + strat_args) + start_analysis_entries_exits(args) captured = capsys.readouterr() - assert 'enter_tag_long' in captured.out - assert 'ETH/BTC' in captured.out - assert '34.049' in captured.out assert 'LTC/BTC' in captured.out - assert '54.3204' in captured.out + assert 'ETH/BTC' in captured.out + assert 'enter_tag_long_a' in captured.out + assert 'enter_tag_long_b' in captured.out + assert 'exit_signal' in captured.out + assert 'roi' in captured.out + assert 'stop_loss' in captured.out + assert 'trailing_stop_loss' in captured.out + assert '0.5' in captured.out + assert '-4' in captured.out + assert '-2' in captured.out + assert '-3.5' in captured.out + assert '50' in captured.out + assert '0' in captured.out + assert '0.01616' in captured.out + assert '34.049' in captured.out + assert '0.104104' in captured.out + assert '47.0996' in captured.out + + # test group 1 + args = get_args(base_args + ['--analysis-groups', '1'] + + strat_args) + start_analysis_entries_exits(args) + captured = capsys.readouterr() + assert 'enter_tag_long_a' in captured.out + assert 'enter_tag_long_b' in captured.out + assert 'total_profit_pct' in captured.out + assert '-3.5' in captured.out + assert '-1.75' in captured.out + assert '-7.5' in captured.out + assert '-3.75' in captured.out + assert '0' in captured.out + + # test group 2 + args = get_args(base_args + ['--analysis-groups', '2'] + + strat_args) + start_analysis_entries_exits(args) + captured = capsys.readouterr() + assert 'enter_tag_long_a' in captured.out + assert 'enter_tag_long_b' in captured.out + assert 'exit_signal' in captured.out + assert 'roi' in captured.out + assert 'stop_loss' in captured.out + assert 'trailing_stop_loss' in captured.out + assert 'total_profit_pct' in captured.out + assert '-10' in captured.out + assert '-5' in captured.out + assert '2.5' in captured.out + + # test group 3 + args = get_args(base_args + ['--analysis-groups', '3'] + + strat_args) + start_analysis_entries_exits(args) + captured = capsys.readouterr() + assert 'LTC/BTC' in captured.out + assert 'ETH/BTC' in captured.out + assert 'enter_tag_long_a' in captured.out + assert 'enter_tag_long_b' in captured.out + assert 'total_profit_pct' in captured.out + assert '-7.5' in captured.out + assert '-3.75' in captured.out + assert '-1.75' in captured.out + assert '0' in captured.out + assert '2' in captured.out + + # test group 4 + args = get_args(base_args + ['--analysis-groups', '4'] + + strat_args) + start_analysis_entries_exits(args) + captured = capsys.readouterr() + assert 'LTC/BTC' in captured.out + assert 'ETH/BTC' in captured.out + assert 'enter_tag_long_a' in captured.out + assert 'enter_tag_long_b' in captured.out + assert 'exit_signal' in captured.out + assert 'roi' in captured.out + assert 'stop_loss' in captured.out + assert 'trailing_stop_loss' in captured.out + assert 'total_profit_pct' in captured.out + assert '-10' in captured.out + assert '-5' in captured.out + assert '-4' in captured.out + assert '0.5' in captured.out + assert '1' in captured.out + assert '2.5' in captured.out From 056047f6352dcbe473890b8ec0df258ea55abdea Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 May 2022 20:07:02 +0200 Subject: [PATCH 224/449] Fix --help --- freqtrade/commands/cli_options.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index ce7320b95..e90d3478d 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -616,32 +616,32 @@ AVAILABLE_CLI_OPTIONS = { ), "analysis_groups": Arg( "--analysis-groups", - help=("grouping output - ", - "0: simple wins/losses by enter tag, ", - "1: by enter_tag, ", - "2: by enter_tag and exit_tag, ", - "3: by pair and enter_tag, ", + help=("grouping output - " + "0: simple wins/losses by enter tag, " + "1: by enter_tag, " + "2: by enter_tag and exit_tag, " + "3: by pair and enter_tag, " "4: by pair, enter_ and exit_tag (this can get quite large)"), nargs='?', default="0,1,2", ), "enter_reason_list": Arg( "--enter-reason-list", - help=("Comma separated list of entry signals to analyse. Default: all. ", + help=("Comma separated list of entry signals to analyse. Default: all. " "e.g. 'entry_tag_a,entry_tag_b'"), nargs='?', default='all', ), "exit_reason_list": Arg( "--exit-reason-list", - help=("Comma separated list of exit signals to analyse. Default: all. ", + help=("Comma separated list of exit signals to analyse. Default: all. " "e.g. 'exit_tag_a,roi,stop_loss,trailing_stop_loss'"), nargs='?', default='all', ), "indicator_list": Arg( "--indicator-list", - help=("Comma separated list of indicators to analyse. ", + help=("Comma separated list of indicators to analyse. " "e.g. 'close,rsi,bb_lowerband,profit_abs'"), nargs='?', default='', From f65df4901e2acb3f400328950b17fa1333ce7078 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 29 May 2022 20:53:09 +0200 Subject: [PATCH 225/449] Update doc clarity --- docs/hyperopt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 030d73f4b..63c7a4413 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -680,7 +680,7 @@ class MyAwesomeStrategy(IStrategy): !!! Note Values in the configuration file will overwrite Parameter-file level parameters - and both will overwrite parameters within the strategy. - The prevalence is therefore: config > parameter file > strategy + The prevalence is therefore: config > parameter file > strategy `*_params` > parameter default ### Understand Hyperopt ROI results From b52fd0b4df21dcd04c2aed91a486e0ccad4cf72f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 03:01:56 +0000 Subject: [PATCH 226/449] Bump python-telegram-bot from 13.11 to 13.12 Bumps [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) from 13.11 to 13.12. - [Release notes](https://github.com/python-telegram-bot/python-telegram-bot/releases) - [Changelog](https://github.com/python-telegram-bot/python-telegram-bot/blob/v13.12/CHANGES.rst) - [Commits](https://github.com/python-telegram-bot/python-telegram-bot/compare/v13.11...v13.12) --- updated-dependencies: - dependency-name: python-telegram-bot dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ae1ff7a89..9c12f7cdf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ ccxt==1.83.62 cryptography==37.0.2 aiohttp==3.8.1 SQLAlchemy==1.4.36 -python-telegram-bot==13.11 +python-telegram-bot==13.12 arrow==1.2.2 cachetools==4.2.2 requests==2.27.1 From e7c78529e97edc5514fc7d3c8177aef491d16a2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 03:01:58 +0000 Subject: [PATCH 227/449] Bump types-python-dateutil from 2.8.16 to 2.8.17 Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.16 to 2.8.17. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-python-dateutil dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index e863238bd..3823e5ebb 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -26,4 +26,4 @@ types-cachetools==5.0.1 types-filelock==3.2.6 types-requests==2.27.27 types-tabulate==0.8.9 -types-python-dateutil==2.8.16 +types-python-dateutil==2.8.17 From 9366c1d36f0bfa88f2d734e81357babf926c4921 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 03:02:03 +0000 Subject: [PATCH 228/449] Bump mkdocs-material from 8.2.15 to 8.2.16 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.2.15 to 8.2.16. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/8.2.15...8.2.16) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 3fa35d80d..e7ca17c34 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 -mkdocs-material==8.2.15 +mkdocs-material==8.2.16 mdx_truly_sane_lists==1.2 pymdown-extensions==9.4 jinja2==3.1.2 From a937f36997b93d2f047f2174020b0c5a0f35e97b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 03:02:13 +0000 Subject: [PATCH 229/449] Bump mypy from 0.950 to 0.960 Bumps [mypy](https://github.com/python/mypy) from 0.950 to 0.960. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.950...v0.960) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index e863238bd..1c96108cc 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ coveralls==3.3.1 flake8==4.0.1 flake8-tidy-imports==4.8.0 -mypy==0.950 +mypy==0.960 pre-commit==2.19.0 pytest==7.1.2 pytest-asyncio==0.18.3 From 23fa00e29aca9d0da473a454201c595184a56525 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 03:02:26 +0000 Subject: [PATCH 230/449] Bump ccxt from 1.83.62 to 1.84.39 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.83.62 to 1.84.39. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.83.62...1.84.39) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ae1ff7a89..08425294d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.4 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.83.62 +ccxt==1.84.39 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From 41052b4e1e2cad4ad23bab66e2e2fd6764744950 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 06:28:03 +0200 Subject: [PATCH 231/449] Bump types dateutil precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d59010154..99bf35f7d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - types-filelock==3.2.6 - types-requests==2.27.27 - types-tabulate==0.8.9 - - types-python-dateutil==2.8.16 + - types-python-dateutil==2.8.17 # stages: [push] - repo: https://github.com/pycqa/isort From ad8ff10a05912d1075579060588e7e9328d24af5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 06:32:35 +0200 Subject: [PATCH 232/449] Minor doc changes --- docs/strategy-callbacks.md | 3 +++ freqtrade/strategy/hyper.py | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 06e7152aa..e1e57a1f3 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -46,6 +46,9 @@ class AwesomeStrategy(IStrategy): self.cust_remote_data = requests.get('https://some_remote_source.example.com') ``` + +During hyperopt, this runs only once at startup. + ## Bot loop start A simple callback which is called once at the start of every bot throttling iteration (roughly every 5 seconds, unless configured differently). diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index c4119173b..622ad7718 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -86,7 +86,10 @@ class HyperStrategyMixin: return params def ft_load_hyper_params_from_file(self) -> None: - """ Load Parameters from parameter file""" + """ + Load Parameters from parameter file + Should/must run before config values are loaded in strategy_resolver. + """ if self._ft_params_from_file: # Set parameters from Hyperopt results file params = self._ft_params_from_file From 386d3e035337cea7cbe9e38a5a8100fa79948fbb Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 06:52:44 +0200 Subject: [PATCH 233/449] Rename stop/roi loading method --- freqtrade/resolvers/strategy_resolver.py | 2 +- freqtrade/strategy/hyper.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index c63c133ce..8b01980ce 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -47,7 +47,7 @@ class StrategyResolver(IResolver): strategy: IStrategy = StrategyResolver._load_strategy( strategy_name, config=config, extra_dir=config.get('strategy_path')) - strategy.ft_load_hyper_params_from_file() + strategy.ft_load_params_from_file() # Set attributes # Check if we need to override configuration # (Attribute name, default, subkey) diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index 622ad7718..ee62b5516 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -85,7 +85,7 @@ class HyperStrategyMixin: return params - def ft_load_hyper_params_from_file(self) -> None: + def ft_load_params_from_file(self) -> None: """ Load Parameters from parameter file Should/must run before config values are loaded in strategy_resolver. From 2b2967f34e0b83b386269d1c025fad3ee1ef95fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 May 2022 04:54:54 +0000 Subject: [PATCH 234/449] Bump types-requests from 2.27.27 to 2.27.29 Bumps [types-requests](https://github.com/python/typeshed) from 2.27.27 to 2.27.29. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 3823e5ebb..1c8cc2352 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -24,6 +24,6 @@ nbconvert==6.5.0 # mypy types types-cachetools==5.0.1 types-filelock==3.2.6 -types-requests==2.27.27 +types-requests==2.27.29 types-tabulate==0.8.9 types-python-dateutil==2.8.17 From eaa656f859a5edfb9837707b14846aa5a44f06cc Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 07:07:47 +0200 Subject: [PATCH 235/449] Hyperoptable parameters can be instance attributes --- freqtrade/optimize/backtesting.py | 4 +--- freqtrade/strategy/hyper.py | 12 ++++-------- freqtrade/strategy/interface.py | 3 +++ 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 43bc97f32..fa32666cc 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -187,9 +187,7 @@ class Backtesting: # since a "perfect" stoploss-exit is assumed anyway # And the regular "stoploss" function would not apply to that case self.strategy.order_types['stoploss_on_exchange'] = False - if self.dataprovider.runmode == RunMode.BACKTEST: - # in hyperopt mode - don't re-init params - self.strategy.ft_load_hyper_params(False) + self.strategy.ft_bot_start() def _load_protections(self, strategy: IStrategy): diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index ee62b5516..7f99c9b8a 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -6,7 +6,6 @@ import logging from pathlib import Path from typing import Any, Dict, Iterator, List, Tuple -from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException from freqtrade.misc import deep_merge_dicts, json_load from freqtrade.optimize.hyperopt_tools import HyperoptTools @@ -34,9 +33,7 @@ class HyperStrategyMixin: params = self.load_params_from_file() params = params.get('params', {}) self._ft_params_from_file = params - - if config.get('runmode') != RunMode.BACKTEST: - self.ft_load_hyper_params(config.get('runmode') == RunMode.HYPEROPT) + # Init/loading of parameters is done as part of ft_bot_start(). def enumerate_parameters(self, category: str = None) -> Iterator[Tuple[str, BaseParameter]]: """ @@ -56,12 +53,11 @@ class HyperStrategyMixin: for par in params: yield par.name, par - @classmethod - def detect_parameters(cls, category: str) -> Iterator[Tuple[str, BaseParameter]]: + def detect_parameters(self, category: str) -> Iterator[Tuple[str, BaseParameter]]: """ Detect all parameters for 'category' """ - for attr_name in dir(cls): + for attr_name in dir(self): if not attr_name.startswith('__'): # Ignore internals, not strictly necessary. - attr = getattr(cls, attr_name) + attr = getattr(self, attr_name) if issubclass(attr.__class__, BaseParameter): if (attr_name.startswith(category + '_') and attr.category is not None and attr.category != category): diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index c521943b1..344c43b15 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -14,6 +14,7 @@ from freqtrade.constants import ListPairsWithTimeframes from freqtrade.data.dataprovider import DataProvider from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, SignalDirection, SignalTagType, SignalType, TradingMode) +from freqtrade.enums.runmode import RunMode from freqtrade.exceptions import OperationalException, StrategyError from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date, timeframe_to_seconds from freqtrade.persistence import Order, PairLocks, Trade @@ -151,6 +152,8 @@ class IStrategy(ABC, HyperStrategyMixin): """ strategy_safe_wrapper(self.bot_start)() + self.ft_load_hyper_params(self.config.get('runmode') == RunMode.HYPEROPT) + @abstractmethod def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ From 5bf021be2e8f1479753e66573575fa7cde00a2b6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 07:08:37 +0200 Subject: [PATCH 236/449] Enhance hyperoptable strategy to test instance parameters --- tests/optimize/test_hyperopt.py | 1 - tests/strategy/strats/hyperoptable_strategy.py | 7 ++++++- tests/strategy/test_interface.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 8522894f7..9f3c5845f 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -509,7 +509,6 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None: hyperopt.min_date = Arrow(2017, 12, 10) hyperopt.max_date = Arrow(2017, 12, 13) hyperopt.init_spaces() - hyperopt.dimensions = hyperopt.dimensions generate_optimizer_value = hyperopt.generate_optimizer(list(optimizer_param.values())) assert generate_optimizer_value == response_expected diff --git a/tests/strategy/strats/hyperoptable_strategy.py b/tests/strategy/strats/hyperoptable_strategy.py index f4dcf1a05..28ecf617a 100644 --- a/tests/strategy/strats/hyperoptable_strategy.py +++ b/tests/strategy/strats/hyperoptable_strategy.py @@ -27,7 +27,6 @@ class HyperoptableStrategy(StrategyTestV2): 'sell_minusdi': 0.4 } - buy_rsi = IntParameter([0, 50], default=30, space='buy') buy_plusdi = RealParameter(low=0, high=1, default=0.5, space='buy') sell_rsi = IntParameter(low=50, high=100, default=70, space='sell') sell_minusdi = DecimalParameter(low=0, high=1, default=0.5001, decimals=3, space='sell', @@ -45,6 +44,12 @@ class HyperoptableStrategy(StrategyTestV2): }) return prot + def bot_start(self, **kwargs) -> None: + """ + Parameters can also be defined here ... + """ + self.buy_rsi = IntParameter([0, 50], default=30, space='buy') + def informative_pairs(self): """ Define additional, informative pair/interval combinations to be cached from the exchange. diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 12cbf5370..2ce27d36b 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -893,7 +893,7 @@ def test_auto_hyperopt_interface(default_conf): default_conf.update({'strategy': 'HyperoptableStrategy'}) PairLocks.timeframe = default_conf['timeframe'] strategy = StrategyResolver.load_strategy(default_conf) - + strategy.ft_bot_start() with pytest.raises(OperationalException): next(strategy.enumerate_parameters('deadBeef')) From f323cbc7694986588f8242646c2a6fb5178ad955 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 07:23:05 +0200 Subject: [PATCH 237/449] Bump types-requests precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 99bf35f7d..95a1d5002 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: additional_dependencies: - types-cachetools==5.0.1 - types-filelock==3.2.6 - - types-requests==2.27.27 + - types-requests==2.27.29 - types-tabulate==0.8.9 - types-python-dateutil==2.8.17 # stages: [push] From 8e2c7e1298faeb173fd50e57be94cb554232a7a5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 07:22:16 +0200 Subject: [PATCH 238/449] extract detect_parameters to separate function --- freqtrade/strategy/hyper.py | 46 +++++++++++++++++++------------- tests/strategy/test_interface.py | 10 ++++--- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index 7f99c9b8a..cdcfc969e 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -4,7 +4,7 @@ This module defines a base class for auto-hyperoptable strategies. """ import logging from pathlib import Path -from typing import Any, Dict, Iterator, List, Tuple +from typing import Any, Dict, Iterator, List, Tuple, Type, Union from freqtrade.exceptions import OperationalException from freqtrade.misc import deep_merge_dicts, json_load @@ -53,27 +53,13 @@ class HyperStrategyMixin: for par in params: yield par.name, par - def detect_parameters(self, category: str) -> Iterator[Tuple[str, BaseParameter]]: - """ Detect all parameters for 'category' """ - for attr_name in dir(self): - if not attr_name.startswith('__'): # Ignore internals, not strictly necessary. - attr = getattr(self, attr_name) - if issubclass(attr.__class__, BaseParameter): - if (attr_name.startswith(category + '_') - and attr.category is not None and attr.category != category): - raise OperationalException( - f'Inconclusive parameter name {attr_name}, category: {attr.category}.') - if (category == attr.category or - (attr_name.startswith(category + '_') and attr.category is None)): - yield attr_name, attr - @classmethod def detect_all_parameters(cls) -> Dict: """ Detect all parameters and return them as a list""" params: Dict[str, Any] = { - 'buy': list(cls.detect_parameters('buy')), - 'sell': list(cls.detect_parameters('sell')), - 'protection': list(cls.detect_parameters('protection')), + 'buy': list(detect_parameters(cls, 'buy')), + 'sell': list(detect_parameters(cls, 'sell')), + 'protection': list(detect_parameters(cls, 'protection')), } params.update({ 'count': len(params['buy'] + params['sell'] + params['protection']) @@ -155,7 +141,7 @@ class HyperStrategyMixin: logger.info(f"No params for {space} found, using default values.") param_container: List[BaseParameter] = getattr(self, f"ft_{space}_params") - for attr_name, attr in self.detect_parameters(space): + for attr_name, attr in detect_parameters(self, space): attr.name = attr_name attr.in_space = hyperopt and HyperoptTools.has_space(self.config, space) if not attr.category: @@ -186,3 +172,25 @@ class HyperStrategyMixin: if not p.optimize or not p.in_space: params[p.category][name] = p.value return params + + +def detect_parameters( + obj: Union[HyperStrategyMixin, Type[HyperStrategyMixin]], + category: str + ) -> Iterator[Tuple[str, BaseParameter]]: + """ + Detect all parameters for 'category' for "obj" + :param obj: Strategy object or class + :param category: category - usually `'buy', 'sell', 'protection',... + """ + for attr_name in dir(obj): + if not attr_name.startswith('__'): # Ignore internals, not strictly necessary. + attr = getattr(obj, attr_name) + if issubclass(attr.__class__, BaseParameter): + if (attr_name.startswith(category + '_') + and attr.category is not None and attr.category != category): + raise OperationalException( + f'Inconclusive parameter name {attr_name}, category: {attr.category}.') + if (category == attr.category or + (attr_name.startswith(category + '_') and attr.category is None)): + yield attr_name, attr diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 2ce27d36b..e3c0bcfcb 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -16,6 +16,7 @@ from freqtrade.exceptions import OperationalException, StrategyError from freqtrade.optimize.space import SKDecimal from freqtrade.persistence import PairLocks, Trade from freqtrade.resolvers import StrategyResolver +from freqtrade.strategy.hyper import detect_parameters from freqtrade.strategy.parameters import (BaseParameter, BooleanParameter, CategoricalParameter, DecimalParameter, IntParameter, RealParameter) from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper @@ -908,15 +909,18 @@ def test_auto_hyperopt_interface(default_conf): assert strategy.sell_minusdi.value == 0.5 all_params = strategy.detect_all_parameters() assert isinstance(all_params, dict) - assert len(all_params['buy']) == 2 + # Only one buy param at class level + assert len(all_params['buy']) == 1 + # Running detect params at instance level reveals both parameters. + assert len(list(detect_parameters(strategy, 'buy'))) == 2 assert len(all_params['sell']) == 2 # Number of Hyperoptable parameters - assert all_params['count'] == 6 + assert all_params['count'] == 5 strategy.__class__.sell_rsi = IntParameter([0, 10], default=5, space='buy') with pytest.raises(OperationalException, match=r"Inconclusive parameter.*"): - [x for x in strategy.detect_parameters('sell')] + [x for x in detect_parameters(strategy, 'sell')] def test_auto_hyperopt_interface_loadparams(default_conf, mocker, caplog): From d950b0acbe1ab6c9442430654273ddb4215077c0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 18:17:07 +0200 Subject: [PATCH 239/449] Update documentation about dynamic parameters --- docs/advanced-hyperopt.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index 7f1bd0fed..8a1ebaff3 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -98,6 +98,23 @@ class MyAwesomeStrategy(IStrategy): !!! Note All overrides are optional and can be mixed/matched as necessary. +### Dynamic parameters + +Parameters can also be defined dynamically, but must be available to the instance once the * [`bot_start()` callback](strategy-callbacks.md#bot-start) has been called. + +``` python + +class MyAwesomeStrategy(IStrategy): + + def bot_start(self, **kwargs) -> None: + self.buy_adx = IntParameter(20, 30, default=30, optimize=True) + + # ... +``` + +!!! Warning + Parameters created this way will not show up in the `list-strategies` parameter count. + ### Overriding Base estimator You can define your own estimator for Hyperopt by implementing `generate_estimator()` in the Hyperopt subclass. From c285ad0e2bbd39d2c5e59a38034392b23fb05491 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 May 2022 20:26:24 +0200 Subject: [PATCH 240/449] Remove --strategy parameters, update docs --- docs/utils.md | 50 +++++++++++++++++++++++++++++++++ freqtrade/commands/arguments.py | 15 +++++----- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/docs/utils.md b/docs/utils.md index 9b799e5fc..f87aa2ffc 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -651,6 +651,56 @@ Common arguments: ``` +## Detailed backtest analysis + +Advanced backtest result analysis. + +More details in the [Backtesting analysis](advanced-backtesting.md#analyze-the-buyentry-and-sellexit-tags) Section. + +``` +usage: freqtrade backtesting-analysis [-h] [-v] [--logfile FILE] [-V] + [-c PATH] [-d PATH] [--userdir PATH] + [--analysis-groups [ANALYSIS_GROUPS]] + [--enter-reason-list [ENTER_REASON_LIST]] + [--exit-reason-list [EXIT_REASON_LIST]] + [--indicator-list [INDICATOR_LIST]] + +optional arguments: + -h, --help show this help message and exit + --analysis-groups [ANALYSIS_GROUPS] + grouping output - 0: simple wins/losses by enter tag, + 1: by enter_tag, 2: by enter_tag and exit_tag, 3: by + pair and enter_tag, 4: by pair, enter_ and exit_tag + (this can get quite large) + --enter-reason-list [ENTER_REASON_LIST] + Comma separated list of entry signals to analyse. + Default: all. e.g. 'entry_tag_a,entry_tag_b' + --exit-reason-list [EXIT_REASON_LIST] + Comma separated list of exit signals to analyse. + Default: all. e.g. + 'exit_tag_a,roi,stop_loss,trailing_stop_loss' + --indicator-list [INDICATOR_LIST] + Comma separated list of indicators to analyse. e.g. + 'close,rsi,bb_lowerband,profit_abs' + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. + -V, --version show program's version number and exit + -c PATH, --config PATH + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. + -d PATH, --datadir PATH + Path to directory with historical backtesting data. + --userdir PATH, --user-data-dir PATH + Path to userdata directory. + +``` + ## List Hyperopt results You can list the hyperoptimization epochs the Hyperopt module evaluated previously with the `hyperopt-list` sub-command. diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index d5831a2ac..aed96d042 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -287,6 +287,14 @@ class Arguments: backtesting_show_cmd.set_defaults(func=start_backtesting_show) self._build_args(optionlist=ARGS_BACKTEST_SHOW, parser=backtesting_show_cmd) + # Add backtesting analysis subcommand + analysis_cmd = subparsers.add_parser('backtesting-analysis', + help='Backtest Analysis module.', + parents=[_common_parser]) + analysis_cmd.set_defaults(func=start_analysis_entries_exits) + self._build_args(optionlist=ARGS_ANALYZE_ENTRIES_EXITS, parser=analysis_cmd) + + # Add edge subcommand edge_cmd = subparsers.add_parser('edge', help='Edge module.', parents=[_common_parser, _strategy_parser]) @@ -419,10 +427,3 @@ class Arguments: parents=[_common_parser]) webserver_cmd.set_defaults(func=start_webserver) self._build_args(optionlist=ARGS_WEBSERVER, parser=webserver_cmd) - - # Add backtesting analysis subcommand - analysis_cmd = subparsers.add_parser('backtesting-analysis', - help='Backtest Analysis module.', - parents=[_common_parser, _strategy_parser]) - analysis_cmd.set_defaults(func=start_analysis_entries_exits) - self._build_args(optionlist=ARGS_ANALYZE_ENTRIES_EXITS, parser=analysis_cmd) From be6e0813db1e3bc45f33381c67b8129cd3404de4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 May 2022 06:34:08 +0200 Subject: [PATCH 241/449] Remove --strategy from analysis test --- freqtrade/commands/arguments.py | 1 - tests/data/test_entryexitanalysis.py | 21 ++++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index aed96d042..6092c630b 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -294,7 +294,6 @@ class Arguments: analysis_cmd.set_defaults(func=start_analysis_entries_exits) self._build_args(optionlist=ARGS_ANALYZE_ENTRIES_EXITS, parser=analysis_cmd) - # Add edge subcommand edge_cmd = subparsers.add_parser('edge', help='Edge module.', parents=[_common_parser, _strategy_parser]) diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index 971cb51aa..6209110fe 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -1,5 +1,4 @@ import logging -from pathlib import Path from unittest.mock import MagicMock, PropertyMock import pandas as pd @@ -82,13 +81,10 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp '--config', 'config.json', '--datadir', str(testdatadir), '--user-data-dir', str(tmpdir), - '--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'), '--timeframe', '5m', '--timerange', '1515560100-1517287800', '--export', 'signals', '--cache', 'none', - '--strategy-list', - 'StrategyTestV3Analysis', ] args = get_args(args) start_backtesting(args) @@ -104,13 +100,12 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp '--datadir', str(testdatadir), '--user-data-dir', str(tmpdir), ] - strat_args = ['--strategy', 'StrategyTestV3Analysis'] # test group 0 and indicator list args = get_args(base_args + ['--analysis-groups', '0', - '--indicator-list', 'close,rsi,profit_abs'] + - strat_args) + '--indicator-list', 'close,rsi,profit_abs'] + ) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'LTC/BTC' in captured.out @@ -133,8 +128,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '47.0996' in captured.out # test group 1 - args = get_args(base_args + ['--analysis-groups', '1'] + - strat_args) + args = get_args(base_args + ['--analysis-groups', '1']) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'enter_tag_long_a' in captured.out @@ -147,8 +141,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '0' in captured.out # test group 2 - args = get_args(base_args + ['--analysis-groups', '2'] + - strat_args) + args = get_args(base_args + ['--analysis-groups', '2']) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'enter_tag_long_a' in captured.out @@ -163,8 +156,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '2.5' in captured.out # test group 3 - args = get_args(base_args + ['--analysis-groups', '3'] + - strat_args) + args = get_args(base_args + ['--analysis-groups', '3']) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'LTC/BTC' in captured.out @@ -179,8 +171,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '2' in captured.out # test group 4 - args = get_args(base_args + ['--analysis-groups', '4'] + - strat_args) + args = get_args(base_args + ['--analysis-groups', '4']) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'LTC/BTC' in captured.out From cce8d1aa4d4f424d35a97c6f7cbb79a698dbd38b Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 May 2022 08:48:34 +0000 Subject: [PATCH 242/449] Update get_market_leverage_tiers to be async --- freqtrade/exchange/exchange.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index c1a9059a7..c292d7dcb 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -2131,10 +2131,11 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - @retrier - def get_market_leverage_tiers(self, symbol) -> List[Dict]: + @retrier_async + async def get_market_leverage_tiers(self, symbol: str) -> Tuple[str, List[Dict]]: try: - return self._api.fetch_market_leverage_tiers(symbol) + tier = await self._api_async.fetch_market_leverage_tiers(symbol) + return symbol, tier except ccxt.DDoSProtection as e: raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: @@ -2168,8 +2169,14 @@ class Exchange: f"Initializing leverage_tiers for {len(symbols)} markets. " "This will take about a minute.") - for symbol in sorted(symbols): - tiers[symbol] = self.get_market_leverage_tiers(symbol) + coros = [self.get_market_leverage_tiers(symbol) for symbol in sorted(symbols)] + + for input_coro in chunks(coros, 100): + + results = self.loop.run_until_complete( + asyncio.gather(*input_coro, return_exceptions=True)) + for symbol, res in results: + tiers[symbol] = res logger.info(f"Done initializing {len(symbols)} markets.") From ea537b32c73f6ce0a0cd17c1630292a3f0bcb9c6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 May 2022 11:40:14 +0000 Subject: [PATCH 243/449] Update tests for leverage_tier_loading --- tests/conftest.py | 16 ++++++++++++++-- tests/exchange/test_okx.py | 4 ++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 02738b0e9..c5c253891 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -78,9 +78,21 @@ def get_args(args): # Source: https://stackoverflow.com/questions/29881236/how-to-mock-asyncio-coroutines -def get_mock_coro(return_value): +# TODO: This should be replaced with AsyncMock once support for python 3.7 is dropped. +def get_mock_coro(return_value=None, side_effect=None): async def mock_coro(*args, **kwargs): - return return_value + if side_effect: + if isinstance(side_effect, list): + effect = side_effect.pop(0) + else: + effect = side_effect + if isinstance(effect, Exception): + raise effect + if callable(effect): + return effect(*args, **kwargs) + return effect + else: + return return_value return Mock(wraps=mock_coro) diff --git a/tests/exchange/test_okx.py b/tests/exchange/test_okx.py index 19c09ad9e..91c4a3368 100644 --- a/tests/exchange/test_okx.py +++ b/tests/exchange/test_okx.py @@ -6,7 +6,7 @@ import pytest from freqtrade.enums import MarginMode, TradingMode from freqtrade.enums.candletype import CandleType from freqtrade.exchange.exchange import timeframe_to_minutes -from tests.conftest import get_patched_exchange +from tests.conftest import get_mock_coro, get_patched_exchange from tests.exchange.test_exchange import ccxt_exceptionhandlers @@ -273,7 +273,7 @@ def test_load_leverage_tiers_okx(default_conf, mocker, markets): 'fetchLeverageTiers': False, 'fetchMarketLeverageTiers': True, }) - api_mock.fetch_market_leverage_tiers = MagicMock(side_effect=[ + api_mock.fetch_market_leverage_tiers = get_mock_coro(side_effect=[ [ { 'tier': 1, From 88845f6d88c7e02c3ffa98923e992f13dee11a9f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 May 2022 17:49:51 +0200 Subject: [PATCH 244/449] Fix cancel order deleting trade if one order was successfully filled, the trade cannot be deleted. closes #6907 --- freqtrade/freqtradebot.py | 13 +++++++------ tests/test_freqtradebot.py | 8 +++++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index a2a12a03a..fba63459b 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1203,15 +1203,15 @@ class FreqtradeBot(LoggingMixin): current_order_rate=order_obj.price, entry_tag=trade.enter_tag, side=trade.entry_side) - full_cancel = False + replacing = True cancel_reason = constants.CANCEL_REASON['REPLACE'] if not adjusted_entry_price: - full_cancel = True if trade.nr_of_successful_entries == 0 else False + replacing = False cancel_reason = constants.CANCEL_REASON['USER_CANCEL'] if order_obj.price != adjusted_entry_price: # cancel existing order if new price is supplied or None self.handle_cancel_enter(trade, order, cancel_reason, - allow_full_cancel=full_cancel) + replacing=replacing) if adjusted_entry_price: # place new order only if new price is supplied self.execute_entry( @@ -1245,10 +1245,11 @@ class FreqtradeBot(LoggingMixin): def handle_cancel_enter( self, trade: Trade, order: Dict, reason: str, - allow_full_cancel: Optional[bool] = True + replacing: Optional[bool] = False ) -> bool: """ Buy cancel - cancel order + :param replacing: Replacing order - prevent trade deletion. :return: True if order was fully cancelled """ was_trade_fully_canceled = False @@ -1286,7 +1287,7 @@ class FreqtradeBot(LoggingMixin): if isclose(filled_amount, 0.0, abs_tol=constants.MATH_CLOSE_PREC): # if trade is not partially completed and it's the only order, just delete the trade open_order_count = len([order for order in trade.orders if order.status == 'open']) - if open_order_count <= 1 and allow_full_cancel: + if open_order_count <= 1 and trade.nr_of_successful_entries == 0 and not replacing: logger.info(f'{side} order fully cancelled. Removing {trade} from database.') trade.delete() was_trade_fully_canceled = True @@ -1295,7 +1296,7 @@ class FreqtradeBot(LoggingMixin): # FIXME TODO: This could possibly reworked to not duplicate the code 15 lines below. self.update_trade_state(trade, trade.open_order_id, corder) trade.open_order_id = None - logger.info(f'Partial {side} order timeout for {trade}.') + logger.info(f'{side} Order timeout for {trade}.') else: # if trade is partially complete, edit the stake details for the trade # and close the order diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 5a5467370..0e4f9db99 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2572,6 +2572,7 @@ def test_check_handle_cancelled_buy( get_fee=fee ) freqtrade = FreqtradeBot(default_conf_usdt) + open_trade.orders = [] open_trade.is_short = is_short Trade.query.session.add(open_trade) @@ -2954,6 +2955,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_ freqtrade = FreqtradeBot(default_conf_usdt) freqtrade._notify_enter_cancel = MagicMock() + # TODO: Convert to real trade trade = MagicMock() trade.pair = 'LTC/USDT' trade.open_rate = 200 @@ -2961,6 +2963,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_ trade.entry_side = "buy" l_order['filled'] = 0.0 l_order['status'] = 'open' + trade.nr_of_successful_entries = 0 reason = CANCEL_REASON['TIMEOUT'] assert freqtrade.handle_cancel_enter(trade, l_order, reason) assert cancel_order_mock.call_count == 1 @@ -3003,7 +3006,9 @@ def test_handle_cancel_enter_exchanges(mocker, caplog, default_conf_usdt, is_sho freqtrade = FreqtradeBot(default_conf_usdt) reason = CANCEL_REASON['TIMEOUT'] + # TODO: Convert to real trade trade = MagicMock() + trade.nr_of_successful_entries = 0 trade.pair = 'LTC/ETH' trade.entry_side = "sell" if is_short else "buy" assert freqtrade.handle_cancel_enter(trade, limit_buy_order_canceled_empty, reason) @@ -3036,13 +3041,14 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order freqtrade = FreqtradeBot(default_conf_usdt) freqtrade._notify_enter_cancel = MagicMock() - + # TODO: Convert to real trade trade = MagicMock() trade.pair = 'LTC/USDT' trade.entry_side = "buy" trade.open_rate = 200 trade.entry_side = "buy" trade.open_order_id = "open_order_noop" + trade.nr_of_successful_entries = 0 l_order['filled'] = 0.0 l_order['status'] = 'open' reason = CANCEL_REASON['TIMEOUT'] From 3549176370369242f9fec333d5b6e1644dced186 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 May 2022 17:52:45 +0200 Subject: [PATCH 245/449] Update missleading docstring closes #6913 --- docs/strategy-callbacks.md | 12 +++++++----- freqtrade/strategy/interface.py | 4 ++-- .../subtemplates/strategy_methods_advanced.j2 | 10 +++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index e1e57a1f3..f0f7d8f69 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -549,10 +549,11 @@ class AwesomeStrategy(IStrategy): :param pair: Pair that's about to be bought/shorted. :param order_type: Order type (as configured in order_types). usually limit or market. - :param amount: Amount in target (quote) currency that's going to be traded. + :param amount: Amount in target (base) currency that's going to be traded. :param rate: Rate that's going to be used when using limit orders :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param current_time: datetime object, containing the current datetime + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param side: 'long' or 'short' - indicating the direction of the proposed trade :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. :return bool: When True is returned, then the buy-order is placed on the exchange. @@ -586,7 +587,7 @@ class AwesomeStrategy(IStrategy): rate: float, time_in_force: str, exit_reason: str, current_time: datetime, **kwargs) -> bool: """ - Called right before placing a regular sell order. + Called right before placing a regular exit order. Timing for this function is critical, so avoid doing heavy computations or network requests in this method. @@ -594,9 +595,10 @@ class AwesomeStrategy(IStrategy): When not implemented by a strategy, returns True (always confirming). - :param pair: Pair that's about to be sold. + :param pair: Pair for trade that's about to be exited. + :param trade: trade object. :param order_type: Order type (as configured in order_types). usually limit or market. - :param amount: Amount in quote currency. + :param amount: Amount in base currency. :param rate: Rate that's going to be used when using limit orders :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param exit_reason: Exit reason. @@ -604,7 +606,7 @@ class AwesomeStrategy(IStrategy): 'exit_signal', 'force_exit', 'emergency_exit'] :param current_time: datetime object, containing the current datetime :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. - :return bool: When True is returned, then the exit-order is placed on the exchange. + :return bool: When True, then the exit-order is placed on the exchange. False aborts the process """ if exit_reason == 'force_exit' and trade.calc_profit_ratio(rate) < 0: diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 344c43b15..99dd1bfd7 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -287,7 +287,7 @@ class IStrategy(ABC, HyperStrategyMixin): :param pair: Pair that's about to be bought/shorted. :param order_type: Order type (as configured in order_types). usually limit or market. - :param amount: Amount in target (quote) currency that's going to be traded. + :param amount: Amount in target (base) currency that's going to be traded. :param rate: Rate that's going to be used when using limit orders :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param current_time: datetime object, containing the current datetime @@ -314,7 +314,7 @@ class IStrategy(ABC, HyperStrategyMixin): :param pair: Pair for trade that's about to be exited. :param trade: trade object. :param order_type: Order type (as configured in order_types). usually limit or market. - :param amount: Amount in quote currency. + :param amount: Amount in base currency. :param rate: Rate that's going to be used when using limit orders :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param exit_reason: Exit reason. diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 3854efd85..103541efe 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -159,7 +159,7 @@ def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: f :param pair: Pair that's about to be bought/shorted. :param order_type: Order type (as configured in order_types). usually limit or market. - :param amount: Amount in target (quote) currency that's going to be traded. + :param amount: Amount in target (base) currency that's going to be traded. :param rate: Rate that's going to be used when using limit orders :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param current_time: datetime object, containing the current datetime @@ -175,7 +175,7 @@ def confirm_trade_exit(self, pair: str, trade: 'Trade', order_type: str, amount: rate: float, time_in_force: str, exit_reason: str, current_time: 'datetime', **kwargs) -> bool: """ - Called right before placing a regular sell order. + Called right before placing a regular exit order. Timing for this function is critical, so avoid doing heavy computations or network requests in this method. @@ -183,10 +183,10 @@ def confirm_trade_exit(self, pair: str, trade: 'Trade', order_type: str, amount: When not implemented by a strategy, returns True (always confirming). - :param pair: Pair that's currently analyzed + :param pair: Pair for trade that's about to be exited. :param trade: trade object. :param order_type: Order type (as configured in order_types). usually limit or market. - :param amount: Amount in quote currency. + :param amount: Amount in base currency. :param rate: Rate that's going to be used when using limit orders :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param exit_reason: Exit reason. @@ -194,7 +194,7 @@ def confirm_trade_exit(self, pair: str, trade: 'Trade', order_type: str, amount: 'exit_signal', 'force_exit', 'emergency_exit'] :param current_time: datetime object, containing the current datetime :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. - :return bool: When True is returned, then the exit-order is placed on the exchange. + :return bool: When True, then the exit-order is placed on the exchange. False aborts the process """ return True From 66edbcd3d5facf31788319b874ba195ab92b27ab Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 May 2022 20:08:34 +0200 Subject: [PATCH 246/449] Fix slight backtesting bug in edge-case scenarios --- freqtrade/optimize/backtesting.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index fa32666cc..bfb4031cc 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -895,26 +895,30 @@ class Backtesting: self.protections.stop_per_pair(pair, current_time, side) self.protections.global_stop(current_time, side) - def manage_open_orders(self, trade: LocalTrade, current_time, row: Tuple) -> bool: + def manage_open_orders(self, trade: LocalTrade, current_time: datetime, row: Tuple) -> bool: """ Check if any open order needs to be cancelled or replaced. Returns True if the trade should be deleted. """ for order in [o for o in trade.orders if o.ft_is_open]: - if self.check_order_cancel(trade, order, current_time): + oc = self.check_order_cancel(trade, order, current_time) + if oc: # delete trade due to order timeout return True - elif self.check_order_replace(trade, order, current_time, row): + elif oc is None and self.check_order_replace(trade, order, current_time, row): # delete trade due to user request self.canceled_trade_entries += 1 return True # default maintain trade return False - def check_order_cancel(self, trade: LocalTrade, order: Order, current_time) -> bool: + def check_order_cancel( + self, trade: LocalTrade, order: Order, current_time: datetime) -> Optional[bool]: """ Check if current analyzed order has to be canceled. - Returns True if the trade should be Deleted (initial order was canceled). + Returns True if the trade should be Deleted (initial order was canceled), + False if it's Canceled + None if the order is still active. """ timedout = self.strategy.ft_check_timed_out( trade, # type: ignore[arg-type] @@ -928,12 +932,13 @@ class Backtesting: else: # Close additional entry order del trade.orders[trade.orders.index(order)] + return False if order.side == trade.exit_side: self.timedout_exit_orders += 1 # Close exit order and retry exiting on next signal. del trade.orders[trade.orders.index(order)] - - return False + return False + return None def check_order_replace(self, trade: LocalTrade, order: Order, current_time, row: Tuple) -> bool: From 34a44b9dd23212a2f8de07ac13ae5d081658d736 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 May 2022 20:32:29 +0200 Subject: [PATCH 247/449] Fix backtesting bug when canceling orders closes #6911 --- freqtrade/optimize/backtesting.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index bfb4031cc..fa5065370 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -932,11 +932,13 @@ class Backtesting: else: # Close additional entry order del trade.orders[trade.orders.index(order)] + trade.open_order_id = None return False if order.side == trade.exit_side: self.timedout_exit_orders += 1 # Close exit order and retry exiting on next signal. del trade.orders[trade.orders.index(order)] + trade.open_order_id = None return False return None From 7fe8b7661d7cfe64129c78082622f8e4e9744599 Mon Sep 17 00:00:00 2001 From: Surfer Admin Date: Tue, 31 May 2022 15:46:43 -0400 Subject: [PATCH 248/449] Display the signal candle analyzed in telegram. --- freqtrade/freqtradebot.py | 20 ++++++++++++++++++++ freqtrade/rpc/telegram.py | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index fba63459b..a9e15d972 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -852,6 +852,16 @@ class FreqtradeBot(LoggingMixin): 'current_rate': current_rate, } + # display the candle analyzed in telegram + analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair, + self.strategy.timeframe) + analyzed_candle = analyzed_df.iloc[-1] if len(analyzed_df) > 0 else None + if analyzed_candle is not None: + candle_columns = analyzed_candle[['date', 'open', 'high', 'low', 'close']] + msg.update({ + 'analyzed_candle': candle_columns.to_json(date_unit='s', date_format='iso') + }) + # Send the message self.rpc.send_msg(msg) @@ -1540,6 +1550,16 @@ class FreqtradeBot(LoggingMixin): 'fiat_currency': self.config['fiat_display_currency'], }) + # display the candle analyzed in telegram + analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair, + self.strategy.timeframe) + analyzed_candle = analyzed_df.iloc[-1] if len(analyzed_df) > 0 else None + if analyzed_candle is not None: + candle_columns = analyzed_candle[['date', 'open', 'high', 'low', 'close']] + msg.update({ + 'analyzed_candle': candle_columns.to_json(date_unit='s', date_format='iso') + }) + # Send the message self.rpc.send_msg(msg) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 4a274002e..8364578a4 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -241,6 +241,8 @@ class Telegram(RPCHandler): f" {entry_side['entered'] if is_fill else entry_side['enter']} {msg['pair']}" f" (#{msg['trade_id']})\n" ) + if msg.get('analyzed_candle'): + message += f"*Analyzed Candle:* `{msg['analyzed_candle']}`\n" message += f"*Enter Tag:* `{msg['enter_tag']}`\n" if msg.get('enter_tag', None) else "" message += f"*Amount:* `{msg['amount']:.8f}`\n" if msg.get('leverage') and msg.get('leverage', 1.0) != 1.0: @@ -288,6 +290,12 @@ class Telegram(RPCHandler): message = ( f"{msg['emoji']} *{msg['exchange']}:* " f"{'Exited' if is_fill else 'Exiting'} {msg['pair']} (#{msg['trade_id']})\n" + ) + if not is_fill and msg.get('analyzed_candle'): + message += ( + f"*Analyzed Candle:* `{msg['analyzed_candle']}`\n" + ) + message += ( f"*{'Profit' if is_fill else 'Unrealized Profit'}:* " f"`{msg['profit_ratio']:.2%}{msg['profit_extra']}`\n" f"*Enter Tag:* `{msg['enter_tag']}`\n" From afd8e85835c27a051b188296fc078a22bb0af5ef Mon Sep 17 00:00:00 2001 From: Anuj Shah Date: Wed, 1 Jun 2022 15:54:32 +0530 Subject: [PATCH 249/449] feat: add support for discord notification --- freqtrade/freqtradebot.py | 131 +++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 37 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index fba63459b..f7e022987 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -2,6 +2,7 @@ Freqtrade is the main module of this bot. It contains the class Freqtrade() """ import copy +import json import logging import traceback from datetime import datetime, time, timezone @@ -9,6 +10,7 @@ from math import isclose from threading import Lock from typing import Any, Dict, List, Optional, Tuple +import requests from schedule import Scheduler from freqtrade import __version__, constants @@ -34,7 +36,6 @@ from freqtrade.strategy.interface import IStrategy from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.wallets import Wallets - logger = logging.getLogger(__name__) @@ -379,9 +380,9 @@ class FreqtradeBot(LoggingMixin): except ExchangeError: logger.warning(f"Error updating {order.order_id}.") -# -# BUY / enter positions / open trades logic and methods -# + # + # BUY / enter positions / open trades logic and methods + # def enter_positions(self) -> int: """ @@ -489,9 +490,9 @@ class FreqtradeBot(LoggingMixin): else: return False -# -# BUY / increase positions / DCA logic and methods -# + # + # BUY / increase positions / DCA logic and methods + # def process_open_trade_positions(self): """ Tries to execute additional buy or sell orders for open trades (positions) @@ -579,16 +580,16 @@ class FreqtradeBot(LoggingMixin): return False def execute_entry( - self, - pair: str, - stake_amount: float, - price: Optional[float] = None, - *, - is_short: bool = False, - ordertype: Optional[str] = None, - enter_tag: Optional[str] = None, - trade: Optional[Trade] = None, - order_adjust: bool = False + self, + pair: str, + stake_amount: float, + price: Optional[float] = None, + *, + is_short: bool = False, + ordertype: Optional[str] = None, + enter_tag: Optional[str] = None, + trade: Optional[Trade] = None, + order_adjust: bool = False ) -> bool: """ Executes a limit buy for the given pair @@ -622,9 +623,9 @@ class FreqtradeBot(LoggingMixin): if not pos_adjust and not strategy_safe_wrapper( self.strategy.confirm_trade_entry, default_retval=True)( - pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested, - time_in_force=time_in_force, current_time=datetime.now(timezone.utc), - entry_tag=enter_tag, side=trade_side): + pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested, + time_in_force=time_in_force, current_time=datetime.now(timezone.utc), + entry_tag=enter_tag, side=trade_side): logger.info(f"User requested abortion of buying {pair}") return False order = self.exchange.create_order( @@ -746,11 +747,11 @@ class FreqtradeBot(LoggingMixin): return trade def get_valid_enter_price_and_stake( - self, pair: str, price: Optional[float], stake_amount: float, - trade_side: LongShort, - entry_tag: Optional[str], - trade: Optional[Trade], - order_adjust: bool, + self, pair: str, price: Optional[float], stake_amount: float, + trade_side: LongShort, + entry_tag: Optional[str], + trade: Optional[Trade], + order_adjust: bool, ) -> Tuple[float, float, float]: if price: @@ -885,9 +886,9 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) -# -# SELL / exit positions / close trades logic and methods -# + # + # SELL / exit positions / close trades logic and methods + # def exit_positions(self, trades: List[Any]) -> int: """ @@ -1059,10 +1060,10 @@ class FreqtradeBot(LoggingMixin): # Finally we check if stoploss on exchange should be moved up because of trailing. # Triggered Orders are now real orders - so don't replace stoploss anymore if ( - trade.is_open and stoploss_order - and stoploss_order.get('status_stop') != 'triggered' - and (self.config.get('trailing_stop', False) - or self.config.get('use_custom_stoploss', False)) + trade.is_open and stoploss_order + and stoploss_order.get('status_stop') != 'triggered' + and (self.config.get('trailing_stop', False) + or self.config.get('use_custom_stoploss', False)) ): # if trailing stoploss is enabled we check if stoploss value has changed # in which case we cancel stoploss order and put another one with new @@ -1145,7 +1146,7 @@ class FreqtradeBot(LoggingMixin): if not_closed: if fully_cancelled or (order_obj and self.strategy.ft_check_timed_out( - trade, order_obj, datetime.now(timezone.utc))): + trade, order_obj, datetime.now(timezone.utc))): self.handle_timedout_order(order, trade) else: self.replace_order(order, order_obj, trade) @@ -1424,7 +1425,7 @@ class FreqtradeBot(LoggingMixin): # if stoploss is on exchange and we are on dry_run mode, # we consider the sell price stop price if (self.config['dry_run'] and exit_type == 'stoploss' - and self.strategy.order_types['stoploss_on_exchange']): + and self.strategy.order_types['stoploss_on_exchange']): limit = trade.stop_loss # set custom_exit_price if available @@ -1543,6 +1544,43 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) + open_date = trade.open_date.strftime('%Y-%m-%d %H:%M:%S') + close_date = trade.close_date.strftime('%Y-%m-%d %H:%M:%S') if trade.close_date else None + + # Send the message to the discord bot + embeds = [{ + 'title': '{} Trade: {}'.format( + 'Profit' if profit_ratio > 0 else 'Loss', + trade.pair), + 'color': (0x00FF00 if profit_ratio > 0 else 0xFF0000), + 'fields': [ + {'name': 'Trade ID', 'value': trade.id, 'inline': True}, + {'name': 'Exchange', 'value': trade.exchange.capitalize(), 'inline': True}, + {'name': 'Pair', 'value': trade.pair, 'inline': True}, + {'name': 'Direction', 'value': 'Short' if trade.is_short else 'Long', 'inline': True}, + {'name': 'Open rate', 'value': trade.open_rate, 'inline': True}, + {'name': 'Close rate', 'value': trade.close_rate, 'inline': True}, + {'name': 'Amount', 'value': trade.amount, 'inline': True}, + {'name': 'Open order', 'value': trade.open_order_id, 'inline': True}, + {'name': 'Open date', 'value': open_date, 'inline': True}, + {'name': 'Close date', 'value': close_date, 'inline': True}, + {'name': 'Profit', 'value': profit_trade, 'inline': True}, + {'name': 'Profitability', 'value': '{:.2f}%'.format(profit_ratio * 100), 'inline': True}, + {'name': 'Stake currency', 'value': self.config['stake_currency'], 'inline': True}, + {'name': 'Fiat currency', 'value': self.config.get('fiat_display_currency', None), 'inline': True}, + {'name': 'Buy Tag', 'value': trade.enter_tag, 'inline': True}, + {'name': 'Sell Reason', 'value': trade.exit_reason, 'inline': True}, + {'name': 'Strategy', 'value': trade.strategy, 'inline': True}, + {'name': 'Timeframe', 'value': trade.timeframe, 'inline': True}, + ], + }] + # convert all value in fields to string + for embed in embeds: + for field in embed['fields']: + field['value'] = str(field['value']) + if fill: + self.discord_send(embeds) + def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str) -> None: """ Sends rpc notification when a sell cancel occurred. @@ -1593,9 +1631,9 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) -# -# Common update trade state methods -# + # + # Common update trade state methods + # def update_trade_state(self, trade: Trade, order_id: str, action_order: Dict[str, Any] = None, stoploss_order: bool = False, send_msg: bool = True) -> bool: @@ -1818,3 +1856,22 @@ class FreqtradeBot(LoggingMixin): return max( min(valid_custom_price, max_custom_price_allowed), min_custom_price_allowed) + + def discord_send(self, embeds): + if not 'discord' in self.config or self.config['discord']['enabled'] == False: + return + if self.config['runmode'].value in ('dry_run', 'live'): + webhook_url = self.config['discord']['webhook_url'] + + payload = { + "embeds": embeds + } + + headers = { + "Content-Type": "application/json" + } + + try: + requests.post(webhook_url, data=json.dumps(payload), headers=headers) + except Exception as e: + logger.error(f"Error sending discord message: {e}") From 45c47bda6000b2b57026fdedffaaa69f8fc1797e Mon Sep 17 00:00:00 2001 From: Anuj Shah Date: Wed, 1 Jun 2022 21:14:48 +0530 Subject: [PATCH 250/449] refactor into discord rpc module --- freqtrade/freqtradebot.py | 131 ++++++++++------------------------- freqtrade/rpc/discord.py | 101 +++++++++++++++++++++++++++ freqtrade/rpc/rpc_manager.py | 6 ++ 3 files changed, 144 insertions(+), 94 deletions(-) create mode 100644 freqtrade/rpc/discord.py diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index f7e022987..fba63459b 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -2,7 +2,6 @@ Freqtrade is the main module of this bot. It contains the class Freqtrade() """ import copy -import json import logging import traceback from datetime import datetime, time, timezone @@ -10,7 +9,6 @@ from math import isclose from threading import Lock from typing import Any, Dict, List, Optional, Tuple -import requests from schedule import Scheduler from freqtrade import __version__, constants @@ -36,6 +34,7 @@ from freqtrade.strategy.interface import IStrategy from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.wallets import Wallets + logger = logging.getLogger(__name__) @@ -380,9 +379,9 @@ class FreqtradeBot(LoggingMixin): except ExchangeError: logger.warning(f"Error updating {order.order_id}.") - # - # BUY / enter positions / open trades logic and methods - # +# +# BUY / enter positions / open trades logic and methods +# def enter_positions(self) -> int: """ @@ -490,9 +489,9 @@ class FreqtradeBot(LoggingMixin): else: return False - # - # BUY / increase positions / DCA logic and methods - # +# +# BUY / increase positions / DCA logic and methods +# def process_open_trade_positions(self): """ Tries to execute additional buy or sell orders for open trades (positions) @@ -580,16 +579,16 @@ class FreqtradeBot(LoggingMixin): return False def execute_entry( - self, - pair: str, - stake_amount: float, - price: Optional[float] = None, - *, - is_short: bool = False, - ordertype: Optional[str] = None, - enter_tag: Optional[str] = None, - trade: Optional[Trade] = None, - order_adjust: bool = False + self, + pair: str, + stake_amount: float, + price: Optional[float] = None, + *, + is_short: bool = False, + ordertype: Optional[str] = None, + enter_tag: Optional[str] = None, + trade: Optional[Trade] = None, + order_adjust: bool = False ) -> bool: """ Executes a limit buy for the given pair @@ -623,9 +622,9 @@ class FreqtradeBot(LoggingMixin): if not pos_adjust and not strategy_safe_wrapper( self.strategy.confirm_trade_entry, default_retval=True)( - pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested, - time_in_force=time_in_force, current_time=datetime.now(timezone.utc), - entry_tag=enter_tag, side=trade_side): + pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested, + time_in_force=time_in_force, current_time=datetime.now(timezone.utc), + entry_tag=enter_tag, side=trade_side): logger.info(f"User requested abortion of buying {pair}") return False order = self.exchange.create_order( @@ -747,11 +746,11 @@ class FreqtradeBot(LoggingMixin): return trade def get_valid_enter_price_and_stake( - self, pair: str, price: Optional[float], stake_amount: float, - trade_side: LongShort, - entry_tag: Optional[str], - trade: Optional[Trade], - order_adjust: bool, + self, pair: str, price: Optional[float], stake_amount: float, + trade_side: LongShort, + entry_tag: Optional[str], + trade: Optional[Trade], + order_adjust: bool, ) -> Tuple[float, float, float]: if price: @@ -886,9 +885,9 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) - # - # SELL / exit positions / close trades logic and methods - # +# +# SELL / exit positions / close trades logic and methods +# def exit_positions(self, trades: List[Any]) -> int: """ @@ -1060,10 +1059,10 @@ class FreqtradeBot(LoggingMixin): # Finally we check if stoploss on exchange should be moved up because of trailing. # Triggered Orders are now real orders - so don't replace stoploss anymore if ( - trade.is_open and stoploss_order - and stoploss_order.get('status_stop') != 'triggered' - and (self.config.get('trailing_stop', False) - or self.config.get('use_custom_stoploss', False)) + trade.is_open and stoploss_order + and stoploss_order.get('status_stop') != 'triggered' + and (self.config.get('trailing_stop', False) + or self.config.get('use_custom_stoploss', False)) ): # if trailing stoploss is enabled we check if stoploss value has changed # in which case we cancel stoploss order and put another one with new @@ -1146,7 +1145,7 @@ class FreqtradeBot(LoggingMixin): if not_closed: if fully_cancelled or (order_obj and self.strategy.ft_check_timed_out( - trade, order_obj, datetime.now(timezone.utc))): + trade, order_obj, datetime.now(timezone.utc))): self.handle_timedout_order(order, trade) else: self.replace_order(order, order_obj, trade) @@ -1425,7 +1424,7 @@ class FreqtradeBot(LoggingMixin): # if stoploss is on exchange and we are on dry_run mode, # we consider the sell price stop price if (self.config['dry_run'] and exit_type == 'stoploss' - and self.strategy.order_types['stoploss_on_exchange']): + and self.strategy.order_types['stoploss_on_exchange']): limit = trade.stop_loss # set custom_exit_price if available @@ -1544,43 +1543,6 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) - open_date = trade.open_date.strftime('%Y-%m-%d %H:%M:%S') - close_date = trade.close_date.strftime('%Y-%m-%d %H:%M:%S') if trade.close_date else None - - # Send the message to the discord bot - embeds = [{ - 'title': '{} Trade: {}'.format( - 'Profit' if profit_ratio > 0 else 'Loss', - trade.pair), - 'color': (0x00FF00 if profit_ratio > 0 else 0xFF0000), - 'fields': [ - {'name': 'Trade ID', 'value': trade.id, 'inline': True}, - {'name': 'Exchange', 'value': trade.exchange.capitalize(), 'inline': True}, - {'name': 'Pair', 'value': trade.pair, 'inline': True}, - {'name': 'Direction', 'value': 'Short' if trade.is_short else 'Long', 'inline': True}, - {'name': 'Open rate', 'value': trade.open_rate, 'inline': True}, - {'name': 'Close rate', 'value': trade.close_rate, 'inline': True}, - {'name': 'Amount', 'value': trade.amount, 'inline': True}, - {'name': 'Open order', 'value': trade.open_order_id, 'inline': True}, - {'name': 'Open date', 'value': open_date, 'inline': True}, - {'name': 'Close date', 'value': close_date, 'inline': True}, - {'name': 'Profit', 'value': profit_trade, 'inline': True}, - {'name': 'Profitability', 'value': '{:.2f}%'.format(profit_ratio * 100), 'inline': True}, - {'name': 'Stake currency', 'value': self.config['stake_currency'], 'inline': True}, - {'name': 'Fiat currency', 'value': self.config.get('fiat_display_currency', None), 'inline': True}, - {'name': 'Buy Tag', 'value': trade.enter_tag, 'inline': True}, - {'name': 'Sell Reason', 'value': trade.exit_reason, 'inline': True}, - {'name': 'Strategy', 'value': trade.strategy, 'inline': True}, - {'name': 'Timeframe', 'value': trade.timeframe, 'inline': True}, - ], - }] - # convert all value in fields to string - for embed in embeds: - for field in embed['fields']: - field['value'] = str(field['value']) - if fill: - self.discord_send(embeds) - def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str) -> None: """ Sends rpc notification when a sell cancel occurred. @@ -1631,9 +1593,9 @@ class FreqtradeBot(LoggingMixin): # Send the message self.rpc.send_msg(msg) - # - # Common update trade state methods - # +# +# Common update trade state methods +# def update_trade_state(self, trade: Trade, order_id: str, action_order: Dict[str, Any] = None, stoploss_order: bool = False, send_msg: bool = True) -> bool: @@ -1856,22 +1818,3 @@ class FreqtradeBot(LoggingMixin): return max( min(valid_custom_price, max_custom_price_allowed), min_custom_price_allowed) - - def discord_send(self, embeds): - if not 'discord' in self.config or self.config['discord']['enabled'] == False: - return - if self.config['runmode'].value in ('dry_run', 'live'): - webhook_url = self.config['discord']['webhook_url'] - - payload = { - "embeds": embeds - } - - headers = { - "Content-Type": "application/json" - } - - try: - requests.post(webhook_url, data=json.dumps(payload), headers=headers) - except Exception as e: - logger.error(f"Error sending discord message: {e}") diff --git a/freqtrade/rpc/discord.py b/freqtrade/rpc/discord.py new file mode 100644 index 000000000..ee9970dc5 --- /dev/null +++ b/freqtrade/rpc/discord.py @@ -0,0 +1,101 @@ +import json +import logging +from typing import Dict, Any + +import requests + +from freqtrade.enums import RPCMessageType +from freqtrade.rpc import RPCHandler, RPC + + +class Discord(RPCHandler): + def __init__(self, rpc: 'RPC', config: Dict[str, Any]): + super().__init__(rpc, config) + self.logger = logging.getLogger(__name__) + self.strategy = config.get('strategy', '') + self.timeframe = config.get('timeframe', '') + self.config = config + + def send_msg(self, msg: Dict[str, str]) -> None: + self._send_msg(msg) + + def _send_msg(self, msg): + """ + msg = { + 'type': (RPCMessageType.EXIT_FILL if fill + else RPCMessageType.EXIT), + 'trade_id': trade.id, + 'exchange': trade.exchange.capitalize(), + 'pair': trade.pair, + 'leverage': trade.leverage, + 'direction': 'Short' if trade.is_short else 'Long', + 'gain': gain, + 'limit': profit_rate, + 'order_type': order_type, + 'amount': trade.amount, + 'open_rate': trade.open_rate, + 'close_rate': trade.close_rate, + 'current_rate': current_rate, + 'profit_amount': profit_trade, + 'profit_ratio': profit_ratio, + 'buy_tag': trade.enter_tag, + 'enter_tag': trade.enter_tag, + 'sell_reason': trade.exit_reason, # Deprecated + 'exit_reason': trade.exit_reason, + 'open_date': trade.open_date, + 'close_date': trade.close_date or datetime.utcnow(), + 'stake_currency': self.config['stake_currency'], + 'fiat_currency': self.config.get('fiat_display_currency', None), + } + """ + self.logger.info(f"Sending discord message: {msg}") + + # TODO: handle other message types + if msg['type'] == RPCMessageType.EXIT_FILL: + profit_ratio = msg.get('profit_ratio') + open_date = msg.get('open_date').strftime('%Y-%m-%d %H:%M:%S') + close_date = msg.get('close_date').strftime('%Y-%m-%d %H:%M:%S') if msg.get('close_date') else '' + + embeds = [{ + 'title': '{} Trade: {}'.format( + 'Profit' if profit_ratio > 0 else 'Loss', + msg.get('pair')), + 'color': (0x00FF00 if profit_ratio > 0 else 0xFF0000), + 'fields': [ + {'name': 'Trade ID', 'value': msg.get('id'), 'inline': True}, + {'name': 'Exchange', 'value': msg.get('exchange').capitalize(), 'inline': True}, + {'name': 'Pair', 'value': msg.get('pair'), 'inline': True}, + {'name': 'Direction', 'value': 'Short' if msg.get('is_short') else 'Long', 'inline': True}, + {'name': 'Open rate', 'value': msg.get('open_rate'), 'inline': True}, + {'name': 'Close rate', 'value': msg.get('close_rate'), 'inline': True}, + {'name': 'Amount', 'value': msg.get('amount'), 'inline': True}, + {'name': 'Open order', 'value': msg.get('open_order_id'), 'inline': True}, + {'name': 'Open date', 'value': open_date, 'inline': True}, + {'name': 'Close date', 'value': close_date, 'inline': True}, + {'name': 'Profit', 'value': msg.get('profit_amount'), 'inline': True}, + {'name': 'Profitability', 'value': '{:.2f}%'.format(profit_ratio * 100), 'inline': True}, + {'name': 'Stake currency', 'value': msg.get('stake_currency'), 'inline': True}, + {'name': 'Fiat currency', 'value': msg.get('fiat_display_currency'), 'inline': True}, + {'name': 'Buy Tag', 'value': msg.get('enter_tag'), 'inline': True}, + {'name': 'Sell Reason', 'value': msg.get('exit_reason'), 'inline': True}, + {'name': 'Strategy', 'value': self.strategy, 'inline': True}, + {'name': 'Timeframe', 'value': self.timeframe, 'inline': True}, + ], + }] + + # convert all value in fields to string for discord + for embed in embeds: + for field in embed['fields']: + field['value'] = str(field['value']) + + # Send the message to discord channel + payload = { + 'embeds': embeds, + } + headers = { + 'Content-Type': 'application/json', + } + try: + requests.post(self.config['discord']['webhook_url'], data=json.dumps(payload), headers=headers) + except Exception as e: + self.logger.error(f"Failed to send discord message: {e}") diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index d97d1df5f..66e84029f 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -27,6 +27,12 @@ class RPCManager: from freqtrade.rpc.telegram import Telegram self.registered_modules.append(Telegram(self._rpc, config)) + # Enable discord + if config.get('discord', {}).get('enabled', False): + logger.info('Enabling rpc.discord ...') + from freqtrade.rpc.discord import Discord + self.registered_modules.append(Discord(self._rpc, config)) + # Enable Webhook if config.get('webhook', {}).get('enabled', False): logger.info('Enabling rpc.webhook ...') From eb4adeab4d7511fe084924e72c14065c6c106ebf Mon Sep 17 00:00:00 2001 From: Anuj Shah Date: Thu, 2 Jun 2022 11:19:29 +0530 Subject: [PATCH 251/449] fix flake8 issues --- freqtrade/rpc/discord.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/freqtrade/rpc/discord.py b/freqtrade/rpc/discord.py index ee9970dc5..43a8e9a05 100644 --- a/freqtrade/rpc/discord.py +++ b/freqtrade/rpc/discord.py @@ -54,7 +54,8 @@ class Discord(RPCHandler): if msg['type'] == RPCMessageType.EXIT_FILL: profit_ratio = msg.get('profit_ratio') open_date = msg.get('open_date').strftime('%Y-%m-%d %H:%M:%S') - close_date = msg.get('close_date').strftime('%Y-%m-%d %H:%M:%S') if msg.get('close_date') else '' + close_date = msg.get('close_date').strftime( + '%Y-%m-%d %H:%M:%S') if msg.get('close_date') else '' embeds = [{ 'title': '{} Trade: {}'.format( @@ -65,7 +66,8 @@ class Discord(RPCHandler): {'name': 'Trade ID', 'value': msg.get('id'), 'inline': True}, {'name': 'Exchange', 'value': msg.get('exchange').capitalize(), 'inline': True}, {'name': 'Pair', 'value': msg.get('pair'), 'inline': True}, - {'name': 'Direction', 'value': 'Short' if msg.get('is_short') else 'Long', 'inline': True}, + {'name': 'Direction', 'value': 'Short' if msg.get( + 'is_short') else 'Long', 'inline': True}, {'name': 'Open rate', 'value': msg.get('open_rate'), 'inline': True}, {'name': 'Close rate', 'value': msg.get('close_rate'), 'inline': True}, {'name': 'Amount', 'value': msg.get('amount'), 'inline': True}, @@ -73,9 +75,11 @@ class Discord(RPCHandler): {'name': 'Open date', 'value': open_date, 'inline': True}, {'name': 'Close date', 'value': close_date, 'inline': True}, {'name': 'Profit', 'value': msg.get('profit_amount'), 'inline': True}, - {'name': 'Profitability', 'value': '{:.2f}%'.format(profit_ratio * 100), 'inline': True}, + {'name': 'Profitability', 'value': '{:.2f}%'.format( + profit_ratio * 100), 'inline': True}, {'name': 'Stake currency', 'value': msg.get('stake_currency'), 'inline': True}, - {'name': 'Fiat currency', 'value': msg.get('fiat_display_currency'), 'inline': True}, + {'name': 'Fiat currency', 'value': msg.get( + 'fiat_display_currency'), 'inline': True}, {'name': 'Buy Tag', 'value': msg.get('enter_tag'), 'inline': True}, {'name': 'Sell Reason', 'value': msg.get('exit_reason'), 'inline': True}, {'name': 'Strategy', 'value': self.strategy, 'inline': True}, @@ -96,6 +100,9 @@ class Discord(RPCHandler): 'Content-Type': 'application/json', } try: - requests.post(self.config['discord']['webhook_url'], data=json.dumps(payload), headers=headers) + requests.post( + self.config['discord']['webhook_url'], + data=json.dumps(payload), + headers=headers) except Exception as e: self.logger.error(f"Failed to send discord message: {e}") From 27bea580d492afa73f2b79e7ad3f63f8995fa4ba Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 5 Jun 2022 09:40:04 +0200 Subject: [PATCH 252/449] Fix rest-client script's force_enter closes #6927 --- scripts/rest_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/rest_client.py b/scripts/rest_client.py index ecbb65253..e5d358c98 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -261,7 +261,7 @@ class FtRestClient(): } return self._post("forcebuy", data=data) - def force_enter(self, pair, side, price=None): + def forceenter(self, pair, side, price=None): """Force entering a trade :param pair: Pair to buy (ETH/BTC) @@ -273,7 +273,7 @@ class FtRestClient(): "side": side, "price": price, } - return self._post("force_enter", data=data) + return self._post("forceenter", data=data) def forceexit(self, tradeid): """Force-exit a trade. From a790bad1e4dd8248d95c9ed8d2d9d50a76a196b6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 5 Jun 2022 10:21:06 +0200 Subject: [PATCH 253/449] Add entry_tag to leverage callback closes #6929 --- docs/strategy-callbacks.md | 7 ++++--- freqtrade/freqtradebot.py | 2 +- freqtrade/optimize/backtesting.py | 2 +- freqtrade/strategy/interface.py | 5 +++-- .../templates/subtemplates/strategy_methods_advanced.j2 | 5 +++-- tests/strategy/strats/strategy_test_v3.py | 4 ++-- tests/strategy/test_interface.py | 2 ++ 7 files changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index f0f7d8f69..656f206a4 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -804,17 +804,18 @@ For markets / exchanges that don't support leverage, this method is ignored. ``` python class AwesomeStrategy(IStrategy): - def leverage(self, pair: str, current_time: 'datetime', current_rate: float, - proposed_leverage: float, max_leverage: float, side: str, + def leverage(self, pair: str, current_time: datetime, current_rate: float, + proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], side: str, **kwargs) -> float: """ - Customize leverage for each new trade. + Customize leverage for each new trade. This method is only called in futures mode. :param pair: Pair that's currently analyzed :param current_time: datetime object, containing the current datetime :param current_rate: Rate, calculated based on pricing settings in exit_pricing. :param proposed_leverage: A leverage proposed by the bot. :param max_leverage: Max leverage allowed on this pair + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param side: 'long' or 'short' - indicating the direction of the proposed trade :return: A leverage amount, which is between 1.0 and max_leverage. """ diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index fba63459b..95eb911cf 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -781,7 +781,7 @@ class FreqtradeBot(LoggingMixin): current_rate=enter_limit_requested, proposed_leverage=1.0, max_leverage=max_leverage, - side=trade_side, + side=trade_side, entry_tag=entry_tag, ) if self.trading_mode != TradingMode.SPOT else 1.0 # Cap leverage between 1.0 and max_leverage. leverage = min(max(leverage, 1.0), max_leverage) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index fa5065370..aebaecaca 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -704,7 +704,7 @@ class Backtesting: current_rate=row[OPEN_IDX], proposed_leverage=1.0, max_leverage=max_leverage, - side=direction, + side=direction, entry_tag=entry_tag, ) if self._can_short else 1.0 # Cap leverage between 1.0 and max_leverage. leverage = min(max(leverage, 1.0), max_leverage) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 99dd1bfd7..3b3d326ff 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -509,8 +509,8 @@ class IStrategy(ABC, HyperStrategyMixin): return current_order_rate def leverage(self, pair: str, current_time: datetime, current_rate: float, - proposed_leverage: float, max_leverage: float, side: str, - **kwargs) -> float: + proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], + side: str, **kwargs) -> float: """ Customize leverage for each new trade. This method is only called in futures mode. @@ -519,6 +519,7 @@ class IStrategy(ABC, HyperStrategyMixin): :param current_rate: Rate, calculated based on pricing settings in exit_pricing. :param proposed_leverage: A leverage proposed by the bot. :param max_leverage: Max leverage allowed on this pair + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param side: 'long' or 'short' - indicating the direction of the proposed trade :return: A leverage amount, which is between 1.0 and max_leverage. """ diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 103541efe..acefd0363 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -267,8 +267,8 @@ def adjust_trade_position(self, trade: 'Trade', current_time: 'datetime', return None def leverage(self, pair: str, current_time: datetime, current_rate: float, - proposed_leverage: float, max_leverage: float, side: str, - **kwargs) -> float: + proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], + side: str, **kwargs) -> float: """ Customize leverage for each new trade. This method is only called in futures mode. @@ -277,6 +277,7 @@ def leverage(self, pair: str, current_time: datetime, current_rate: float, :param current_rate: Rate, calculated based on pricing settings in exit_pricing. :param proposed_leverage: A leverage proposed by the bot. :param max_leverage: Max leverage allowed on this pair + :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param side: 'long' or 'short' - indicating the direction of the proposed trade :return: A leverage amount, which is between 1.0 and max_leverage. """ diff --git a/tests/strategy/strats/strategy_test_v3.py b/tests/strategy/strats/strategy_test_v3.py index 340001ef2..2c7ccbdf2 100644 --- a/tests/strategy/strats/strategy_test_v3.py +++ b/tests/strategy/strats/strategy_test_v3.py @@ -178,8 +178,8 @@ class StrategyTestV3(IStrategy): return dataframe def leverage(self, pair: str, current_time: datetime, current_rate: float, - proposed_leverage: float, max_leverage: float, side: str, - **kwargs) -> float: + proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], + side: str, **kwargs) -> float: # Return 3.0 in all cases. # Bot-logic must make sure it's an allowed leverage and eventually adjust accordingly. diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index e3c0bcfcb..b7b73bdcf 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -615,6 +615,7 @@ def test_leverage_callback(default_conf, side) -> None: proposed_leverage=1.0, max_leverage=5.0, side=side, + entry_tag=None, ) == 1 default_conf['strategy'] = CURRENT_TEST_STRATEGY @@ -626,6 +627,7 @@ def test_leverage_callback(default_conf, side) -> None: proposed_leverage=1.0, max_leverage=5.0, side=side, + entry_tag='entry_tag_test', ) == 3 From c499bb051f4753f20c9daef9660932c2b610ecd7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 5 Jun 2022 19:41:17 +0200 Subject: [PATCH 254/449] Allow empty unfilledtimeout for webserver mode --- freqtrade/rpc/api_server/api_schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index f21334bc6..a31c74c2e 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -166,7 +166,7 @@ class ShowConfig(BaseModel): trailing_stop_positive: Optional[float] trailing_stop_positive_offset: Optional[float] trailing_only_offset_is_reached: Optional[bool] - unfilledtimeout: UnfilledTimeout + unfilledtimeout: Optional[UnfilledTimeout] # Empty in webserver mode order_types: Optional[OrderTypes] use_custom_stoploss: Optional[bool] timeframe: Optional[str] From f709222943fcc2807561ae4a8fc7bcb9a8d6c66c Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 29 Apr 2022 06:53:30 +0200 Subject: [PATCH 255/449] Properly close out orders in backtesting --- freqtrade/optimize/backtesting.py | 1 + freqtrade/persistence/trade_model.py | 1 + 2 files changed, 2 insertions(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index aebaecaca..8fe5f509e 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -1094,6 +1094,7 @@ class Backtesting: # 5. Process exit orders. order = trade.select_order(trade.exit_side, is_open=True) if order and self._get_order_filled(order.price, row): + order.close_bt_order(current_time, trade) trade.open_order_id = None trade.close_date = current_time trade.close(order.price, show_msg=False) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 45a16bfbd..7b475d618 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -166,6 +166,7 @@ class Order(_DECL_BASE): def close_bt_order(self, close_date: datetime, trade: 'LocalTrade'): self.order_filled_date = close_date self.filled = self.amount + self.remaining = 0 self.status = 'closed' self.ft_is_open = False if (self.ft_order_side == trade.entry_side From c0ff554d5be871098cd10424fdd579322b5370df Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 May 2022 20:12:05 +0200 Subject: [PATCH 256/449] Cleanup old, left open dry-run orders --- freqtrade/persistence/migrations.py | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index 53e35d9da..b0fdf0412 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -247,6 +247,35 @@ def set_sqlite_to_wal(engine): connection.execute(text("PRAGMA journal_mode=wal")) +def fix_old_dry_orders(engine): + with engine.begin() as connection: + connection.execute( + text( + """ + update orders + set ft_is_open = 0 + where ft_is_open = 1 and (ft_trade_id, order_id) not in ( + select id, stoploss_order_id from trades where stoploss_order_id is not null + ) and ft_order_side = 'stoploss' + and order_id like 'dry_%' + """ + ) + ) + connection.execute( + text( + """ + update orders + set ft_is_open = 0 + where ft_is_open = 1 + and (ft_trade_id, order_id) not in ( + select id, open_order_id from trades where open_order_id is not null + ) and ft_order_side != 'stoploss' + and order_id like 'dry_%' + """ + ) + ) + + def check_migrate(engine, decl_base, previous_tables) -> None: """ Checks if migration is necessary and migrates if necessary @@ -288,3 +317,4 @@ def check_migrate(engine, decl_base, previous_tables) -> None: "start with a fresh database.") set_sqlite_to_wal(engine) + fix_old_dry_orders(engine) From 8369d5bedd25f7679b060fd075be2eb061623ebe Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 24 May 2022 20:31:45 +0200 Subject: [PATCH 257/449] Include open orders in json responses --- freqtrade/persistence/trade_model.py | 17 ++++++++++++++++- freqtrade/rpc/telegram.py | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 7b475d618..ded616f8a 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -395,7 +395,7 @@ class LocalTrade(): ) def to_json(self) -> Dict[str, Any]: - filled_orders = self.select_filled_orders() + filled_orders = self.select_filled_or_open_orders() orders = [order.to_json(self.entry_side) for order in filled_orders] return { @@ -898,6 +898,21 @@ class LocalTrade(): (o.filled or 0) > 0 and o.status in NON_OPEN_EXCHANGE_STATES] + def select_filled_or_open_orders(self) -> List['Order']: + """ + Finds filled or open orders + :param order_side: Side of the order (either 'buy', 'sell', or None) + :return: array of Order objects + """ + return [o for o in self.orders if + ( + o.ft_is_open is False + and (o.filled or 0) > 0 + and o.status in NON_OPEN_EXCHANGE_STATES + ) + or (o.ft_is_open is True and o.status is not None) + ] + @property def nr_of_successful_entries(self) -> int: """ diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 4a274002e..e456b1eef 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -396,7 +396,7 @@ class Telegram(RPCHandler): first_avg = filled_orders[0]["safe_price"] for x, order in enumerate(filled_orders): - if not order['ft_is_entry']: + if not order['ft_is_entry'] or order['is_open'] is True: continue cur_entry_datetime = arrow.get(order["order_filled_date"]) cur_entry_amount = order["amount"] From 79107fd062e9e60f78c467367b7c34cc68f5b6c6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 26 May 2022 07:11:43 +0200 Subject: [PATCH 258/449] Add minimal order object serialization --- freqtrade/data/btanalysis.py | 2 +- freqtrade/persistence/trade_model.py | 44 +++++++++++++++------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index fef432576..0b466241f 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -337,7 +337,7 @@ def trade_list_to_dataframe(trades: List[LocalTrade]) -> pd.DataFrame: :param trades: List of trade objects :return: Dataframe with BT_DATA_COLUMNS """ - df = pd.DataFrame.from_records([t.to_json() for t in trades], columns=BT_DATA_COLUMNS) + df = pd.DataFrame.from_records([t.to_json(True) for t in trades], columns=BT_DATA_COLUMNS) if len(df) > 0: df.loc[:, 'close_date'] = pd.to_datetime(df['close_date'], utc=True) df.loc[:, 'open_date'] = pd.to_datetime(df['open_date'], utc=True) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index ded616f8a..0be9d22c1 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -137,31 +137,35 @@ class Order(_DECL_BASE): 'info': {}, } - def to_json(self, entry_side: str) -> Dict[str, Any]: - return { - 'pair': self.ft_pair, - 'order_id': self.order_id, - 'status': self.status, + def to_json(self, entry_side: str, minified: bool = False) -> Dict[str, Any]: + resp = { 'amount': self.amount, - 'average': round(self.average, 8) if self.average else 0, 'safe_price': self.safe_price, - 'cost': self.cost if self.cost else 0, - 'filled': self.filled, 'ft_order_side': self.ft_order_side, - 'is_open': self.ft_is_open, - 'order_date': self.order_date.strftime(DATETIME_PRINT_FORMAT) - if self.order_date else None, - 'order_timestamp': int(self.order_date.replace( - tzinfo=timezone.utc).timestamp() * 1000) if self.order_date else None, - 'order_filled_date': self.order_filled_date.strftime(DATETIME_PRINT_FORMAT) - if self.order_filled_date else None, 'order_filled_timestamp': int(self.order_filled_date.replace( tzinfo=timezone.utc).timestamp() * 1000) if self.order_filled_date else None, - 'order_type': self.order_type, - 'price': self.price, 'ft_is_entry': self.ft_order_side == entry_side, - 'remaining': self.remaining, } + if not minified: + resp.update({ + 'pair': self.ft_pair, + 'order_id': self.order_id, + 'status': self.status, + 'average': round(self.average, 8) if self.average else 0, + 'cost': self.cost if self.cost else 0, + 'filled': self.filled, + 'is_open': self.ft_is_open, + 'order_date': self.order_date.strftime(DATETIME_PRINT_FORMAT) + if self.order_date else None, + 'order_timestamp': int(self.order_date.replace( + tzinfo=timezone.utc).timestamp() * 1000) if self.order_date else None, + 'order_filled_date': self.order_filled_date.strftime(DATETIME_PRINT_FORMAT) + if self.order_filled_date else None, + 'order_type': self.order_type, + 'price': self.price, + 'remaining': self.remaining, + }) + return resp def close_bt_order(self, close_date: datetime, trade: 'LocalTrade'): self.order_filled_date = close_date @@ -394,9 +398,9 @@ class LocalTrade(): f'open_rate={self.open_rate:.8f}, open_since={open_since})' ) - def to_json(self) -> Dict[str, Any]: + def to_json(self, minified: bool = False) -> Dict[str, Any]: filled_orders = self.select_filled_or_open_orders() - orders = [order.to_json(self.entry_side) for order in filled_orders] + orders = [order.to_json(self.entry_side, minified) for order in filled_orders] return { 'trade_id': self.id, From 786bc3616352a650d4107a539aad84f7c32d1714 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 03:01:44 +0000 Subject: [PATCH 259/449] Bump orjson from 3.6.8 to 3.7.1 Bumps [orjson](https://github.com/ijl/orjson) from 3.6.8 to 3.7.1. - [Release notes](https://github.com/ijl/orjson/releases) - [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md) - [Commits](https://github.com/ijl/orjson/compare/3.6.8...3.7.1) --- updated-dependencies: - dependency-name: orjson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a7dbaf57c..21d80571f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,7 +28,7 @@ py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.6 # Properly format api responses -orjson==3.6.8 +orjson==3.7.1 # Notify systemd sdnotify==0.3.2 From 04cb49b7e404fb0ab29245e769296f7c5ec17d41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 03:01:48 +0000 Subject: [PATCH 260/449] Bump filelock from 3.7.0 to 3.7.1 Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.7.0 to 3.7.1. - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.7.0...3.7.1) --- updated-dependencies: - dependency-name: filelock dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index b8762214a..94e59ec15 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -5,5 +5,5 @@ scipy==1.8.1 scikit-learn==1.1.1 scikit-optimize==0.9.0 -filelock==3.7.0 +filelock==3.7.1 progressbar2==4.0.0 From 6547f3aadb96f60e9d5a42b0008a55de1c47e75c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 03:01:52 +0000 Subject: [PATCH 261/449] Bump mkdocs-material from 8.2.16 to 8.3.2 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.2.16 to 8.3.2. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/8.2.16...8.3.2) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index e7ca17c34..f351151ab 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 -mkdocs-material==8.2.16 +mkdocs-material==8.3.2 mdx_truly_sane_lists==1.2 pymdown-extensions==9.4 jinja2==3.1.2 From 35316ec06841b9b2638ab6068c6d58aa3c15991a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 03:01:55 +0000 Subject: [PATCH 262/449] Bump jsonschema from 4.5.1 to 4.6.0 Bumps [jsonschema](https://github.com/python-jsonschema/jsonschema) from 4.5.1 to 4.6.0. - [Release notes](https://github.com/python-jsonschema/jsonschema/releases) - [Changelog](https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst) - [Commits](https://github.com/python-jsonschema/jsonschema/compare/v4.5.1...v4.6.0) --- updated-dependencies: - dependency-name: jsonschema dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a7dbaf57c..d0b662d2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ arrow==1.2.2 cachetools==4.2.2 requests==2.27.1 urllib3==1.26.9 -jsonschema==4.5.1 +jsonschema==4.6.0 TA-Lib==0.4.24 technical==1.3.0 tabulate==0.8.9 From 963dc0221caa59b8cf4cb2309cab6735f8be6161 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 03:01:59 +0000 Subject: [PATCH 263/449] Bump types-requests from 2.27.29 to 2.27.30 Bumps [types-requests](https://github.com/python/typeshed) from 2.27.29 to 2.27.30. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 6a7e15870..4eb157aae 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -24,6 +24,6 @@ nbconvert==6.5.0 # mypy types types-cachetools==5.0.1 types-filelock==3.2.6 -types-requests==2.27.29 +types-requests==2.27.30 types-tabulate==0.8.9 types-python-dateutil==2.8.17 From 4affa75ff5103e95fdbc6c59fa457423326fdc74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 03:02:07 +0000 Subject: [PATCH 264/449] Bump sqlalchemy from 1.4.36 to 1.4.37 Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.36 to 1.4.37. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: sqlalchemy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a7dbaf57c..717577480 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ ccxt==1.84.39 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 -SQLAlchemy==1.4.36 +SQLAlchemy==1.4.37 python-telegram-bot==13.12 arrow==1.2.2 cachetools==4.2.2 From 05922e9ebc0c7911f0bc75e50b5a57dc6a0cc29d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jun 2022 03:02:15 +0000 Subject: [PATCH 265/449] Bump ccxt from 1.84.39 to 1.84.97 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.84.39 to 1.84.97. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.84.39...1.84.97) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a7dbaf57c..432ff976d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.4 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.84.39 +ccxt==1.84.97 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From 99f6c75c40dc95073ec81a03c82e775d87753667 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Jun 2022 10:22:19 +0200 Subject: [PATCH 266/449] Bump types-requests precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 95a1d5002..685d789ec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: additional_dependencies: - types-cachetools==5.0.1 - types-filelock==3.2.6 - - types-requests==2.27.29 + - types-requests==2.27.30 - types-tabulate==0.8.9 - types-python-dateutil==2.8.17 # stages: [push] From ea9b68baddeb76f2581660d13ff11b797f4a6b00 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Jun 2022 10:50:48 +0200 Subject: [PATCH 267/449] Add updating freqtrade to updating desc --- docs/updating.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/updating.md b/docs/updating.md index 1839edc4c..8dc7279a4 100644 --- a/docs/updating.md +++ b/docs/updating.md @@ -32,4 +32,8 @@ Please ensure that you're also updating dependencies - otherwise things might br ``` bash git pull pip install -U -r requirements.txt +pip install -e . + +# Ensure freqUI is at the latest version +freqtrade install-ui ``` From 82c5a6b29dc1c45e0e542d2caace0fb2d87dad68 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Jun 2022 10:57:33 +0200 Subject: [PATCH 268/449] Update CI to use concurrency --- .github/workflows/ci.yml | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2e420e8e..c3ed6d80d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,10 @@ on: schedule: - cron: '0 5 * * 4' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build_linux: @@ -296,17 +300,17 @@ jobs: details: Freqtrade doc test failed! webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} - cleanup-prior-runs: - permissions: - actions: write # for rokroskar/workflow-run-cleanup-action to obtain workflow name & cancel it - contents: read # for rokroskar/workflow-run-cleanup-action to obtain branch - runs-on: ubuntu-20.04 - steps: - - name: Cleanup previous runs on this branch - uses: rokroskar/workflow-run-cleanup-action@v0.3.3 - if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/stable' && github.repository == 'freqtrade/freqtrade'" - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + # cleanup-prior-runs: + # permissions: + # actions: write # for rokroskar/workflow-run-cleanup-action to obtain workflow name & cancel it + # contents: read # for rokroskar/workflow-run-cleanup-action to obtain branch + # runs-on: ubuntu-20.04 + # steps: + # - name: Cleanup previous runs on this branch + # uses: rokroskar/workflow-run-cleanup-action@v0.3.3 + # if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/stable' && github.repository == 'freqtrade/freqtrade'" + # env: + # GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # Notify only once - when CI completes (and after deploy) in case it's successfull notify-complete: From 0b806af48756bcb5190fadc1cd50cd9b2ff32b3d Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 26 May 2022 07:17:22 +0200 Subject: [PATCH 269/449] Add orders column to btresult --- freqtrade/data/btanalysis.py | 4 +++- freqtrade/optimize/optimize_reports.py | 4 ---- tests/data/test_btanalysis.py | 4 ++-- tests/optimize/test_backtesting.py | 17 +++++++++++++++++ .../test_backtesting_adjust_position.py | 7 ++++++- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 0b466241f..9e38f6833 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -26,7 +26,7 @@ BT_DATA_COLUMNS = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date', 'profit_ratio', 'profit_abs', 'exit_reason', 'initial_stop_loss_abs', 'initial_stop_loss_ratio', 'stop_loss_abs', 'stop_loss_ratio', 'min_rate', 'max_rate', 'is_open', 'enter_tag', - 'is_short' + 'is_short', 'open_timestamp', 'close_timestamp', 'orders' ] @@ -283,6 +283,8 @@ def load_backtest_data(filename: Union[Path, str], strategy: Optional[str] = Non if 'enter_tag' not in df.columns: df['enter_tag'] = df['buy_tag'] df = df.drop(['buy_tag'], axis=1) + if 'orders' not in df.columns: + df.loc[:, 'orders'] = None else: # old format - only with lists. diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 93336fa3f..e3dd17411 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -4,7 +4,6 @@ from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Any, Dict, List, Union -from numpy import int64 from pandas import DataFrame, to_datetime from tabulate import tabulate @@ -417,9 +416,6 @@ def generate_strategy_stats(pairlist: List[str], key=lambda x: x['profit_sum']) if len(pair_results) > 1 else None worst_pair = min([pair for pair in pair_results if pair['key'] != 'TOTAL'], key=lambda x: x['profit_sum']) if len(pair_results) > 1 else None - if not results.empty: - results['open_timestamp'] = results['open_date'].view(int64) // 1e6 - results['close_timestamp'] = results['close_date'].view(int64) // 1e6 backtest_days = (max_date - min_date).days or 1 strat_stats = { diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 4157bd899..977140ebb 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -85,7 +85,7 @@ def test_load_backtest_data_new_format(testdatadir): filename = testdatadir / "backtest_results/backtest-result_new.json" bt_data = load_backtest_data(filename) assert isinstance(bt_data, DataFrame) - assert set(bt_data.columns) == set(BT_DATA_COLUMNS + ['close_timestamp', 'open_timestamp']) + assert set(bt_data.columns) == set(BT_DATA_COLUMNS) assert len(bt_data) == 179 # Test loading from string (must yield same result) @@ -110,7 +110,7 @@ def test_load_backtest_data_multi(testdatadir): bt_data = load_backtest_data(filename, strategy=strategy) assert isinstance(bt_data, DataFrame) assert set(bt_data.columns) == set( - BT_DATA_COLUMNS + ['close_timestamp', 'open_timestamp']) + BT_DATA_COLUMNS) assert len(bt_data) == 179 # Test loading from string (must yield same result) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index f169e0a35..6912184aa 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -795,10 +795,27 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None: 'is_open': [False, False], 'enter_tag': [None, None], "is_short": [False, False], + 'open_timestamp': [1517251200000, 1517283000000], + 'close_timestamp': [1517265300000, 1517285400000], + 'orders': [ + [ + {'amount': 0.00957442, 'safe_price': 0.104445, 'ft_order_side': 'buy', + 'order_filled_timestamp': 1517251200000, 'ft_is_entry': True}, + {'amount': 0.00957442, 'safe_price': 0.10496853383458644, 'ft_order_side': 'sell', + 'order_filled_timestamp': 1517265300000, 'ft_is_entry': False} + ], [ + {'amount': 0.0097064, 'safe_price': 0.10302485, 'ft_order_side': 'buy', + 'order_filled_timestamp': 1517283000000, 'ft_is_entry': True}, + {'amount': 0.0097064, 'safe_price': 0.10354126528822055, 'ft_order_side': 'sell', + 'order_filled_timestamp': 1517285400000, 'ft_is_entry': False} + ] + ] }) pd.testing.assert_frame_equal(results, expected) + assert 'orders' in results.columns data_pair = processed[pair] for _, t in results.iterrows(): + assert len(t['orders']) == 2 ln = data_pair.loc[data_pair["date"] == t["open_date"]] # Check open trade rate alignes to open rate assert ln is not None diff --git a/tests/optimize/test_backtesting_adjust_position.py b/tests/optimize/test_backtesting_adjust_position.py index 94505e3ce..fca9c01b2 100644 --- a/tests/optimize/test_backtesting_adjust_position.py +++ b/tests/optimize/test_backtesting_adjust_position.py @@ -70,9 +70,14 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) -> 'is_open': [False, False], 'enter_tag': [None, None], 'is_short': [False, False], + 'open_timestamp': [1517251200000, 1517283000000], + 'close_timestamp': [1517265300000, 1517285400000], }) - pd.testing.assert_frame_equal(results, expected) + pd.testing.assert_frame_equal(results.drop(columns=['orders']), expected) data_pair = processed[pair] + assert len(results.iloc[0]['orders']) == 6 + assert len(results.iloc[1]['orders']) == 2 + for _, t in results.iterrows(): ln = data_pair.loc[data_pair["date"] == t["open_date"]] # Check open trade rate alignes to open rate From 057be50941c25fb493b90086dabc7997987b7f05 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Jun 2022 11:11:47 +0200 Subject: [PATCH 270/449] Remove old concurrency method --- .github/workflows/ci.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3ed6d80d..bbe0bcf6e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -300,18 +300,6 @@ jobs: details: Freqtrade doc test failed! webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} - # cleanup-prior-runs: - # permissions: - # actions: write # for rokroskar/workflow-run-cleanup-action to obtain workflow name & cancel it - # contents: read # for rokroskar/workflow-run-cleanup-action to obtain branch - # runs-on: ubuntu-20.04 - # steps: - # - name: Cleanup previous runs on this branch - # uses: rokroskar/workflow-run-cleanup-action@v0.3.3 - # if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/stable' && github.repository == 'freqtrade/freqtrade'" - # env: - # GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - # Notify only once - when CI completes (and after deploy) in case it's successfull notify-complete: needs: [ build_linux, build_macos, build_windows, docs_check, mypy_version_check ] From 9534d6cca177de8aee7edd330fc8103e8d07e4bb Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 7 Jun 2022 07:03:40 +0200 Subject: [PATCH 271/449] Cancel orders which can no longer be found after several days --- freqtrade/freqtradebot.py | 11 ++++++++++- tests/test_freqtradebot.py | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 95eb911cf..d96c63bcc 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -4,7 +4,7 @@ Freqtrade is the main module of this bot. It contains the class Freqtrade() import copy import logging import traceback -from datetime import datetime, time, timezone +from datetime import datetime, time, timedelta, timezone from math import isclose from threading import Lock from typing import Any, Dict, List, Optional, Tuple @@ -302,6 +302,15 @@ class FreqtradeBot(LoggingMixin): self.update_trade_state(order.trade, order.order_id, fo, stoploss_order=(order.ft_order_side == 'stoploss')) + except InvalidOrderException as e: + logger.warning(f"Error updating Order {order.order_id} due to {e}.") + if order.order_date_utc - timedelta(days=5) < datetime.now(timezone.utc): + logger.warning( + "Order is older than 5 days. Assuming order was fully cancelled.") + fo = order.to_ccxt_object() + fo['status'] = 'canceled' + self.handle_timedout_order(fo, order.trade) + except ExchangeError as e: logger.warning(f"Error updating Order {order.order_id} due to {e}") diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 0e4f9db99..cd7459cbe 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -4802,10 +4802,19 @@ def test_startup_update_open_orders(mocker, default_conf_usdt, fee, caplog, is_s assert len(Order.get_open_orders()) == 2 caplog.clear() - mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=InvalidOrderException) + mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=ExchangeError) freqtrade.startup_update_open_orders() assert log_has_re(r"Error updating Order .*", caplog) + mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=InvalidOrderException) + hto_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_timedout_order') + # Orders which are no longer found after X days should be assumed as canceled. + freqtrade.startup_update_open_orders() + assert log_has_re(r"Order is older than \d days.*", caplog) + assert hto_mock.call_count == 2 + assert hto_mock.call_args_list[0][0][0]['status'] == 'canceled' + assert hto_mock.call_args_list[1][0][0]['status'] == 'canceled' + @pytest.mark.usefixtures("init_persistence") @pytest.mark.parametrize("is_short", [False, True]) From 381d64833d30ee10684e0633826a473d4f873197 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 7 Jun 2022 21:05:31 +0200 Subject: [PATCH 272/449] version-bump ccxt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index acaecd872..05d5a10db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.4 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.84.97 +ccxt==1.85.57 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From ac40ae89b9d50fba5bb088ba902e1ac6bce0f6a1 Mon Sep 17 00:00:00 2001 From: gautier pialat Date: Wed, 8 Jun 2022 00:20:33 +0200 Subject: [PATCH 273/449] give extra info on rate origin for confirm_trade_* Documentation : Take into consideration the market buy/sell rates use case for the confirm_trade_entry and confirm_trade_exit callback function --- docs/strategy-callbacks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 656f206a4..b897453e7 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -550,7 +550,7 @@ class AwesomeStrategy(IStrategy): :param pair: Pair that's about to be bought/shorted. :param order_type: Order type (as configured in order_types). usually limit or market. :param amount: Amount in target (base) currency that's going to be traded. - :param rate: Rate that's going to be used when using limit orders + :param rate: Rate that's going to be used when using limit orders or current rate for market orders. :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param current_time: datetime object, containing the current datetime :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. @@ -599,7 +599,7 @@ class AwesomeStrategy(IStrategy): :param trade: trade object. :param order_type: Order type (as configured in order_types). usually limit or market. :param amount: Amount in base currency. - :param rate: Rate that's going to be used when using limit orders + :param rate: Rate that's going to be used when using limit orders or current rate for market orders. :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param exit_reason: Exit reason. Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss', From 7eacb847b05c53f7db80016885303be654cfb64b Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 8 Jun 2022 20:21:45 +0200 Subject: [PATCH 274/449] Fix backtesting bug when order is not replaced --- freqtrade/optimize/backtesting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 8fe5f509e..1aad8520a 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -966,6 +966,7 @@ class Backtesting: return False else: del trade.orders[trade.orders.index(order)] + trade.open_order_id = None self.canceled_entry_orders += 1 # place new order if result was not None From d265b8adb621f93cee91d9fdea85a52f9d425171 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jun 2022 03:01:48 +0000 Subject: [PATCH 275/449] Bump python from 3.10.4-slim-bullseye to 3.10.5-slim-bullseye Bumps python from 3.10.4-slim-bullseye to 3.10.5-slim-bullseye. --- updated-dependencies: - dependency-name: python dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5f7b52265..5138ecec9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.10.4-slim-bullseye as base +FROM python:3.10.5-slim-bullseye as base # Setup env ENV LANG C.UTF-8 From c550cd8b0d2b8559f22a91c87e01c7afd1b00dd2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Jun 2022 07:04:46 +0200 Subject: [PATCH 276/449] Simplify query in freqtradebot --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d96c63bcc..fdccc2f8a 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -227,7 +227,7 @@ class FreqtradeBot(LoggingMixin): Notify the user when the bot is stopped (not reloaded) and there are still open trades active. """ - open_trades = Trade.get_trades([Trade.is_open.is_(True)]).all() + open_trades = Trade.get_open_trades() if len(open_trades) != 0 and self.state != State.RELOAD_CONFIG: msg = { From 3cb15a2a5470e8a915aa5f39123808882b4b93eb Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 8 Jun 2022 07:08:01 +0200 Subject: [PATCH 277/449] Combine weekly and daily profit methods --- freqtrade/rpc/rpc.py | 67 ++++++++++----------------------------- freqtrade/rpc/telegram.py | 5 +-- 2 files changed, 20 insertions(+), 52 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index a98e3f96d..571438059 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -285,23 +285,33 @@ class RPC: def _rpc_daily_profit( self, timescale: int, - stake_currency: str, fiat_display_currency: str) -> Dict[str, Any]: - today = datetime.now(timezone.utc).date() - profit_days: Dict[date, Dict] = {} + stake_currency: str, fiat_display_currency: str, + timeunit: str = 'days') -> Dict[str, Any]: + """ + :param timeunit: Valid entries are 'days', 'weeks', 'months' + """ + start_date = datetime.now(timezone.utc).date() + if timeunit == 'weeks': + # weekly + start_date = start_date - timedelta(days=start_date.weekday()) # Monday + if timeunit == 'months': + start_date = start_date.replace(day=1) + + profit_units: Dict[date, Dict] = {} if not (isinstance(timescale, int) and timescale > 0): raise RPCException('timescale must be an integer greater than 0') for day in range(0, timescale): - profitday = today - timedelta(days=day) + profitday = start_date - timedelta(**{timeunit: day}) trades = Trade.get_trades(trade_filter=[ Trade.is_open.is_(False), Trade.close_date >= profitday, - Trade.close_date < (profitday + timedelta(days=1)) + Trade.close_date < (profitday + timedelta(**{timeunit: 1})) ]).order_by(Trade.close_date).all() curdayprofit = sum( trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) - profit_days[profitday] = { + profit_units[profitday] = { 'amount': curdayprofit, 'trades': len(trades) } @@ -317,50 +327,7 @@ class RPC: ) if self._fiat_converter else 0, 'trade_count': value["trades"], } - for key, value in profit_days.items() - ] - return { - 'stake_currency': stake_currency, - 'fiat_display_currency': fiat_display_currency, - 'data': data - } - - def _rpc_weekly_profit( - self, timescale: int, - stake_currency: str, fiat_display_currency: str) -> Dict[str, Any]: - today = datetime.now(timezone.utc).date() - first_iso_day_of_week = today - timedelta(days=today.weekday()) # Monday - profit_weeks: Dict[date, Dict] = {} - - if not (isinstance(timescale, int) and timescale > 0): - raise RPCException('timescale must be an integer greater than 0') - - for week in range(0, timescale): - profitweek = first_iso_day_of_week - timedelta(weeks=week) - trades = Trade.get_trades(trade_filter=[ - Trade.is_open.is_(False), - Trade.close_date >= profitweek, - Trade.close_date < (profitweek + timedelta(weeks=1)) - ]).order_by(Trade.close_date).all() - curweekprofit = sum( - trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) - profit_weeks[profitweek] = { - 'amount': curweekprofit, - 'trades': len(trades) - } - - data = [ - { - 'date': key, - 'abs_profit': value["amount"], - 'fiat_value': self._fiat_converter.convert_amount( - value['amount'], - stake_currency, - fiat_display_currency - ) if self._fiat_converter else 0, - 'trade_count': value["trades"], - } - for key, value in profit_weeks.items() + for key, value in profit_units.items() ] return { 'stake_currency': stake_currency, diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index e456b1eef..cfbd3949f 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -618,10 +618,11 @@ class Telegram(RPCHandler): except (TypeError, ValueError, IndexError): timescale = 8 try: - stats = self._rpc._rpc_weekly_profit( + stats = self._rpc._rpc_daily_profit( timescale, stake_cur, - fiat_disp_cur + fiat_disp_cur, + 'weeks' ) stats_tab = tabulate( [[week['date'], From d4dd026310b411ee78d7857dde4bec974226bb60 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 8 Jun 2022 19:52:05 +0200 Subject: [PATCH 278/449] Consolidate monthly stats to common method --- freqtrade/rpc/api_server/api_v1.py | 4 +-- freqtrade/rpc/rpc.py | 55 +++++------------------------- freqtrade/rpc/telegram.py | 12 ++++--- 3 files changed, 18 insertions(+), 53 deletions(-) diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index a8b9873d7..271e3de1b 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -86,8 +86,8 @@ def stats(rpc: RPC = Depends(get_rpc)): @router.get('/daily', response_model=Daily, tags=['info']) def daily(timescale: int = 7, rpc: RPC = Depends(get_rpc), config=Depends(get_config)): - return rpc._rpc_daily_profit(timescale, config['stake_currency'], - config.get('fiat_display_currency', '')) + return rpc._rpc_timeunit_profit(timescale, config['stake_currency'], + config.get('fiat_display_currency', '')) @router.get('/status', response_model=List[OpenTradeSchema], tags=['info']) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 571438059..a6290bd5a 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -283,7 +283,7 @@ class RPC: columns.append('# Entries') return trades_list, columns, fiat_profit_sum - def _rpc_daily_profit( + def _rpc_timeunit_profit( self, timescale: int, stake_currency: str, fiat_display_currency: str, timeunit: str = 'days') -> Dict[str, Any]: @@ -297,17 +297,22 @@ class RPC: if timeunit == 'months': start_date = start_date.replace(day=1) + def time_offset(step: int): + if timeunit == 'months': + return relativedelta(months=step) + return timedelta(**{timeunit: step}) + profit_units: Dict[date, Dict] = {} if not (isinstance(timescale, int) and timescale > 0): raise RPCException('timescale must be an integer greater than 0') for day in range(0, timescale): - profitday = start_date - timedelta(**{timeunit: day}) + profitday = start_date - time_offset(day) trades = Trade.get_trades(trade_filter=[ Trade.is_open.is_(False), Trade.close_date >= profitday, - Trade.close_date < (profitday + timedelta(**{timeunit: 1})) + Trade.close_date < (profitday + time_offset(1)) ]).order_by(Trade.close_date).all() curdayprofit = sum( trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) @@ -318,7 +323,7 @@ class RPC: data = [ { - 'date': key, + 'date': f"{key.year}-{key.month:02d}" if timeunit == 'months' else key, 'abs_profit': value["amount"], 'fiat_value': self._fiat_converter.convert_amount( value['amount'], @@ -335,48 +340,6 @@ class RPC: 'data': data } - def _rpc_monthly_profit( - self, timescale: int, - stake_currency: str, fiat_display_currency: str) -> Dict[str, Any]: - first_day_of_month = datetime.now(timezone.utc).date().replace(day=1) - profit_months: Dict[date, Dict] = {} - - if not (isinstance(timescale, int) and timescale > 0): - raise RPCException('timescale must be an integer greater than 0') - - for month in range(0, timescale): - profitmonth = first_day_of_month - relativedelta(months=month) - trades = Trade.get_trades(trade_filter=[ - Trade.is_open.is_(False), - Trade.close_date >= profitmonth, - Trade.close_date < (profitmonth + relativedelta(months=1)) - ]).order_by(Trade.close_date).all() - curmonthprofit = sum( - trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) - profit_months[profitmonth] = { - 'amount': curmonthprofit, - 'trades': len(trades) - } - - data = [ - { - 'date': f"{key.year}-{key.month:02d}", - 'abs_profit': value["amount"], - 'fiat_value': self._fiat_converter.convert_amount( - value['amount'], - stake_currency, - fiat_display_currency - ) if self._fiat_converter else 0, - 'trade_count': value["trades"], - } - for key, value in profit_months.items() - ] - return { - 'stake_currency': stake_currency, - 'fiat_display_currency': fiat_display_currency, - 'data': data - } - def _rpc_trade_history(self, limit: int, offset: int = 0, order_by_id: bool = False) -> Dict: """ Returns the X last trades """ order_by = Trade.id if order_by_id else Trade.close_date.desc() diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index cfbd3949f..5efdcdbed 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -579,10 +579,11 @@ class Telegram(RPCHandler): except (TypeError, ValueError, IndexError): timescale = 7 try: - stats = self._rpc._rpc_daily_profit( + stats = self._rpc._rpc_timeunit_profit( timescale, stake_cur, - fiat_disp_cur + fiat_disp_cur, + 'days' ) stats_tab = tabulate( [[day['date'], @@ -618,7 +619,7 @@ class Telegram(RPCHandler): except (TypeError, ValueError, IndexError): timescale = 8 try: - stats = self._rpc._rpc_daily_profit( + stats = self._rpc._rpc_timeunit_profit( timescale, stake_cur, fiat_disp_cur, @@ -659,10 +660,11 @@ class Telegram(RPCHandler): except (TypeError, ValueError, IndexError): timescale = 6 try: - stats = self._rpc._rpc_monthly_profit( + stats = self._rpc._rpc_timeunit_profit( timescale, stake_cur, - fiat_disp_cur + fiat_disp_cur, + 'months' ) stats_tab = tabulate( [[month['date'], From a547001601f785f5c6d2171edc8a52159241e07d Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 8 Jun 2022 20:09:51 +0200 Subject: [PATCH 279/449] Reduce Telegram "unit" stats --- freqtrade/rpc/telegram.py | 158 ++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 93 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 5efdcdbed..e64ab7b8a 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -6,6 +6,7 @@ This module manage Telegram communication import json import logging import re +from dataclasses import dataclass from datetime import date, datetime, timedelta from functools import partial from html import escape @@ -37,6 +38,15 @@ logger.debug('Included module rpc.telegram ...') MAX_TELEGRAM_MESSAGE_LENGTH = 4096 +@dataclass +class TimeunitMappings: + header: str + message: str + message2: str + callback: str + default: int + + def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]: """ Decorator to check if the message comes from the correct chat_id @@ -563,6 +573,58 @@ class Telegram(RPCHandler): except RPCException as e: self._send_msg(str(e)) + @authorized_only + def _timeunit_stats(self, update: Update, context: CallbackContext, unit: str) -> None: + """ + Handler for /daily + Returns a daily profit (in BTC) over the last n days. + :param bot: telegram bot + :param update: message update + :return: None + """ + + vals = { + 'days': TimeunitMappings('Day', 'Daily', 'days', 'update_daily', 7), + 'weeks': TimeunitMappings('Monday', 'Weekly', 'weeks (starting from Monday)', + 'update_weekly', 8), + 'months': TimeunitMappings('Month', 'Monthly', 'months', 'update_monthly', 6), + } + val = vals[unit] + + stake_cur = self._config['stake_currency'] + fiat_disp_cur = self._config.get('fiat_display_currency', '') + try: + timescale = int(context.args[0]) if context.args else val.default + except (TypeError, ValueError, IndexError): + timescale = val.default + try: + stats = self._rpc._rpc_timeunit_profit( + timescale, + stake_cur, + fiat_disp_cur, + unit + ) + stats_tab = tabulate( + [[day['date'], + f"{round_coin_value(day['abs_profit'], stats['stake_currency'])}", + f"{day['fiat_value']:.3f} {stats['fiat_display_currency']}", + f"{day['trade_count']} trades"] for day in stats['data']], + headers=[ + val.header, + f'Profit {stake_cur}', + f'Profit {fiat_disp_cur}', + 'Trades', + ], + tablefmt='simple') + message = ( + f'{val.message} Profit over the last {timescale} {val.message2}:\n' + f'
{stats_tab}
' + ) + self._send_msg(message, parse_mode=ParseMode.HTML, reload_able=True, + callback_path=val.callback, query=update.callback_query) + except RPCException as e: + self._send_msg(str(e)) + @authorized_only def _daily(self, update: Update, context: CallbackContext) -> None: """ @@ -572,36 +634,7 @@ class Telegram(RPCHandler): :param update: message update :return: None """ - stake_cur = self._config['stake_currency'] - fiat_disp_cur = self._config.get('fiat_display_currency', '') - try: - timescale = int(context.args[0]) if context.args else 7 - except (TypeError, ValueError, IndexError): - timescale = 7 - try: - stats = self._rpc._rpc_timeunit_profit( - timescale, - stake_cur, - fiat_disp_cur, - 'days' - ) - stats_tab = tabulate( - [[day['date'], - f"{round_coin_value(day['abs_profit'], stats['stake_currency'])}", - f"{day['fiat_value']:.3f} {stats['fiat_display_currency']}", - f"{day['trade_count']} trades"] for day in stats['data']], - headers=[ - 'Day', - f'Profit {stake_cur}', - f'Profit {fiat_disp_cur}', - 'Trades', - ], - tablefmt='simple') - message = f'Daily Profit over the last {timescale} days:\n
{stats_tab}
' - self._send_msg(message, parse_mode=ParseMode.HTML, reload_able=True, - callback_path="update_daily", query=update.callback_query) - except RPCException as e: - self._send_msg(str(e)) + self._timeunit_stats(update, context, 'days') @authorized_only def _weekly(self, update: Update, context: CallbackContext) -> None: @@ -612,37 +645,7 @@ class Telegram(RPCHandler): :param update: message update :return: None """ - stake_cur = self._config['stake_currency'] - fiat_disp_cur = self._config.get('fiat_display_currency', '') - try: - timescale = int(context.args[0]) if context.args else 8 - except (TypeError, ValueError, IndexError): - timescale = 8 - try: - stats = self._rpc._rpc_timeunit_profit( - timescale, - stake_cur, - fiat_disp_cur, - 'weeks' - ) - stats_tab = tabulate( - [[week['date'], - f"{round_coin_value(week['abs_profit'], stats['stake_currency'])}", - f"{week['fiat_value']:.3f} {stats['fiat_display_currency']}", - f"{week['trade_count']} trades"] for week in stats['data']], - headers=[ - 'Monday', - f'Profit {stake_cur}', - f'Profit {fiat_disp_cur}', - 'Trades', - ], - tablefmt='simple') - message = f'Weekly Profit over the last {timescale} weeks ' \ - f'(starting from Monday):\n
{stats_tab}
' - self._send_msg(message, parse_mode=ParseMode.HTML, reload_able=True, - callback_path="update_weekly", query=update.callback_query) - except RPCException as e: - self._send_msg(str(e)) + self._timeunit_stats(update, context, 'weeks') @authorized_only def _monthly(self, update: Update, context: CallbackContext) -> None: @@ -653,38 +656,7 @@ class Telegram(RPCHandler): :param update: message update :return: None """ - stake_cur = self._config['stake_currency'] - fiat_disp_cur = self._config.get('fiat_display_currency', '') - try: - timescale = int(context.args[0]) if context.args else 6 - except (TypeError, ValueError, IndexError): - timescale = 6 - try: - stats = self._rpc._rpc_timeunit_profit( - timescale, - stake_cur, - fiat_disp_cur, - 'months' - ) - stats_tab = tabulate( - [[month['date'], - f"{round_coin_value(month['abs_profit'], stats['stake_currency'])}", - f"{month['fiat_value']:.3f} {stats['fiat_display_currency']}", - f"{month['trade_count']} trades"] for month in stats['data']], - headers=[ - 'Month', - f'Profit {stake_cur}', - f'Profit {fiat_disp_cur}', - 'Trades', - ], - tablefmt='simple') - message = f'Monthly Profit over the last {timescale} months' \ - f':\n
{stats_tab}
' - self._send_msg(message, parse_mode=ParseMode.HTML, reload_able=True, - callback_path="update_monthly", query=update.callback_query) - except RPCException as e: - self._send_msg(str(e)) - + self._timeunit_stats(update, context, 'months') @authorized_only def _profit(self, update: Update, context: CallbackContext) -> None: """ From b211a5156f5b7e92a652369ed1f6be19d3535b69 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Jun 2022 19:36:15 +0200 Subject: [PATCH 280/449] Add test for strategy_wrapper lazy loading --- tests/strategy/test_interface.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index b7b73bdcf..dca87e724 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -20,7 +20,8 @@ from freqtrade.strategy.hyper import detect_parameters from freqtrade.strategy.parameters import (BaseParameter, BooleanParameter, CategoricalParameter, DecimalParameter, IntParameter, RealParameter) from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper -from tests.conftest import CURRENT_TEST_STRATEGY, TRADE_SIDES, log_has, log_has_re +from tests.conftest import (CURRENT_TEST_STRATEGY, TRADE_SIDES, create_mock_trades, log_has, + log_has_re) from .strats.strategy_test_v3 import StrategyTestV3 @@ -812,6 +813,28 @@ def test_strategy_safe_wrapper(value): assert ret == value +@pytest.mark.usefixtures("init_persistence") +def test_strategy_safe_wrapper_trade_copy(fee): + create_mock_trades(fee) + + def working_method(trade): + assert len(trade.orders) > 0 + assert trade.orders + trade.orders = [] + assert len(trade.orders) == 0 + return trade + + trade = Trade.get_open_trades()[0] + # Don't assert anything before strategy_wrapper. + # This ensures that relationship loading works correctly. + ret = strategy_safe_wrapper(working_method, message='DeadBeef')(trade=trade) + assert isinstance(ret, Trade) + assert id(trade) != id(ret) + # Did not modify the original order + assert len(trade.orders) > 0 + assert len(ret.orders) == 0 + + def test_hyperopt_parameters(): from skopt.space import Categorical, Integer, Real with pytest.raises(OperationalException, match=r"Name is determined.*"): From 88f8cbe17278f21d459a323d66d85cbe6c03db48 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Jun 2022 06:45:22 +0200 Subject: [PATCH 281/449] Update tests to reflect new naming --- freqtrade/rpc/telegram.py | 1 + tests/rpc/test_rpc.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index e64ab7b8a..27eb04b89 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -657,6 +657,7 @@ class Telegram(RPCHandler): :return: None """ self._timeunit_stats(update, context, 'months') + @authorized_only def _profit(self, update: Update, context: CallbackContext) -> None: """ diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 95645c8ba..e1f40bcd2 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -284,8 +284,8 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: assert isnan(fiat_profit_sum) -def test_rpc_daily_profit(default_conf, update, ticker, fee, - limit_buy_order, limit_sell_order, markets, mocker) -> None: +def test__rpc_timeunit_profit(default_conf, update, ticker, fee, + limit_buy_order, limit_sell_order, markets, mocker) -> None: mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -316,7 +316,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee, # Try valid data update.message.text = '/daily 2' - days = rpc._rpc_daily_profit(7, stake_currency, fiat_display_currency) + days = rpc._rpc_timeunit_profit(7, stake_currency, fiat_display_currency) assert len(days['data']) == 7 assert days['stake_currency'] == default_conf['stake_currency'] assert days['fiat_display_currency'] == default_conf['fiat_display_currency'] @@ -332,7 +332,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee, # Try invalid data with pytest.raises(RPCException, match=r'.*must be an integer greater than 0*'): - rpc._rpc_daily_profit(0, stake_currency, fiat_display_currency) + rpc._rpc_timeunit_profit(0, stake_currency, fiat_display_currency) @pytest.mark.parametrize('is_short', [True, False]) From 1ddd5f1901d08073dd7d8c9cc3b819c728a20350 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Jun 2022 19:41:08 +0200 Subject: [PATCH 282/449] Update docstring throughout the bot. --- docs/strategy-callbacks.md | 6 ++++-- freqtrade/strategy/interface.py | 2 ++ .../templates/subtemplates/strategy_methods_advanced.j2 | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index b897453e7..410641f44 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -550,7 +550,8 @@ class AwesomeStrategy(IStrategy): :param pair: Pair that's about to be bought/shorted. :param order_type: Order type (as configured in order_types). usually limit or market. :param amount: Amount in target (base) currency that's going to be traded. - :param rate: Rate that's going to be used when using limit orders or current rate for market orders. + :param rate: Rate that's going to be used when using limit orders + or current rate for market orders. :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param current_time: datetime object, containing the current datetime :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. @@ -599,7 +600,8 @@ class AwesomeStrategy(IStrategy): :param trade: trade object. :param order_type: Order type (as configured in order_types). usually limit or market. :param amount: Amount in base currency. - :param rate: Rate that's going to be used when using limit orders or current rate for market orders. + :param rate: Rate that's going to be used when using limit orders + or current rate for market orders. :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param exit_reason: Exit reason. Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss', diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 3b3d326ff..d4ccfc5db 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -289,6 +289,7 @@ class IStrategy(ABC, HyperStrategyMixin): :param order_type: Order type (as configured in order_types). usually limit or market. :param amount: Amount in target (base) currency that's going to be traded. :param rate: Rate that's going to be used when using limit orders + or current rate for market orders. :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param current_time: datetime object, containing the current datetime :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. @@ -316,6 +317,7 @@ class IStrategy(ABC, HyperStrategyMixin): :param order_type: Order type (as configured in order_types). usually limit or market. :param amount: Amount in base currency. :param rate: Rate that's going to be used when using limit orders + or current rate for market orders. :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param exit_reason: Exit reason. Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss', diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index acefd0363..815ca7cd3 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -161,6 +161,7 @@ def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: f :param order_type: Order type (as configured in order_types). usually limit or market. :param amount: Amount in target (base) currency that's going to be traded. :param rate: Rate that's going to be used when using limit orders + or current rate for market orders. :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param current_time: datetime object, containing the current datetime :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. @@ -188,6 +189,7 @@ def confirm_trade_exit(self, pair: str, trade: 'Trade', order_type: str, amount: :param order_type: Order type (as configured in order_types). usually limit or market. :param amount: Amount in base currency. :param rate: Rate that's going to be used when using limit orders + or current rate for market orders. :param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled). :param exit_reason: Exit reason. Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss', From a9c7ad8a0fcbf00063beba6a2b59809b99a97218 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Jun 2022 19:51:21 +0200 Subject: [PATCH 283/449] Add warning about sqlite disabled foreign keys --- docs/sql_cheatsheet.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index 49372b002..c9fcba557 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -100,6 +100,9 @@ DELETE FROM trades WHERE id = 31; !!! Warning This will remove this trade from the database. Please make sure you got the correct id and **NEVER** run this query without the `where` clause. +!!! Danger + Some systems (Ubuntu) disable foreign keys in their sqlite3 implementation. When using sqlite3 - please ensure that foreign keys are on by running `PRAGMA foreign_keys = ON` before the above query. + ## Use a different database system !!! Warning From 3c2ba99fc480d028f8c6c86db68cfa5813b2b0e5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Jun 2022 19:57:56 +0200 Subject: [PATCH 284/449] Improve sql cheatsheet docs --- docs/sql_cheatsheet.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index c9fcba557..c42cb5575 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -89,29 +89,34 @@ WHERE id=31; If you'd still like to remove a trade from the database directly, you can use the below query. -```sql -DELETE FROM trades WHERE id = ; -``` +!!! Danger + Some systems (Ubuntu) disable foreign keys in their sqlite3 packaging. When using sqlite - please ensure that foreign keys are on by running `PRAGMA foreign_keys = ON` before the above query. ```sql +DELETE FROM trades WHERE id = ; + DELETE FROM trades WHERE id = 31; ``` !!! Warning This will remove this trade from the database. Please make sure you got the correct id and **NEVER** run this query without the `where` clause. -!!! Danger - Some systems (Ubuntu) disable foreign keys in their sqlite3 implementation. When using sqlite3 - please ensure that foreign keys are on by running `PRAGMA foreign_keys = ON` before the above query. - ## Use a different database system +Freqtrade is using SQLAlchemy, which supports multiple different database systems. As such, a multitude of database systems should be supported. +Freqtrade does not depend or install any additional database driver. Please refer to the [SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/engines.html#database-urls) on installation instructions for the respective database systems. + +The following systems have been tested and are known to work with freqtrade: + +* sqlite (default) +* PostgreSQL) +* MariaDB + !!! Warning - By using one of the below database systems, you acknowledge that you know how to manage such a system. Freqtrade will not provide any support with setup or maintenance (or backups) of the below database systems. + By using one of the below database systems, you acknowledge that you know how to manage such a system. The freqtrade team will not provide any support with setup or maintenance (or backups) of the below database systems. ### PostgreSQL -Freqtrade supports PostgreSQL by using SQLAlchemy, which supports multiple different database systems. - Installation: `pip install psycopg2-binary` From 8fb743b91d33d7187c32765a6c6f3c2c5d7fd2eb Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Jun 2022 20:13:26 +0200 Subject: [PATCH 285/449] improve variable wording --- freqtrade/rpc/telegram.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 27eb04b89..106a5f011 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -605,10 +605,10 @@ class Telegram(RPCHandler): unit ) stats_tab = tabulate( - [[day['date'], - f"{round_coin_value(day['abs_profit'], stats['stake_currency'])}", - f"{day['fiat_value']:.3f} {stats['fiat_display_currency']}", - f"{day['trade_count']} trades"] for day in stats['data']], + [[period['date'], + f"{round_coin_value(period['abs_profit'], stats['stake_currency'])}", + f"{period['fiat_value']:.3f} {stats['fiat_display_currency']}", + f"{period['trade_count']} trades"] for period in stats['data']], headers=[ val.header, f'Profit {stake_cur}', From dce9fdd0e4717559862b85df0850d5a1608e62fd Mon Sep 17 00:00:00 2001 From: Italo <45588475+italodamato@users.noreply.github.com> Date: Thu, 9 Jun 2022 20:06:23 +0100 Subject: [PATCH 286/449] don't overwrite is_random this should fix issue #6746 --- freqtrade/optimize/hyperopt.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index d1697709b..ac1b7b8ba 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -429,18 +429,19 @@ class Hyperopt: return new_list i = 0 asked_non_tried: List[List[Any]] = [] - is_random: List[bool] = [] + is_random_non_tried: List[bool] = [] while i < 5 and len(asked_non_tried) < n_points: if i < 3: self.opt.cache_ = {} asked = unique_list(self.opt.ask(n_points=n_points * 5)) is_random = [False for _ in range(len(asked))] else: - asked = unique_list(self.opt.space.rvs(n_samples=n_points * 5)) + asked = unique_list(self.opt.space.rvs( + n_samples=n_points * 5, random_state=self.random_state + i)) is_random = [True for _ in range(len(asked))] - is_random += [rand for x, rand in zip(asked, is_random) - if x not in self.opt.Xi - and x not in asked_non_tried] + is_random_non_tried += [rand for x, rand in zip(asked, is_random) + if x not in self.opt.Xi + and x not in asked_non_tried] asked_non_tried += [x for x in asked if x not in self.opt.Xi and x not in asked_non_tried] @@ -449,7 +450,7 @@ class Hyperopt: if asked_non_tried: return ( asked_non_tried[:min(len(asked_non_tried), n_points)], - is_random[:min(len(asked_non_tried), n_points)] + is_random_non_tried[:min(len(asked_non_tried), n_points)] ) else: return self.opt.ask(n_points=n_points), [False for _ in range(n_points)] From ad3c01736e74f4986cba86f685c2999fd202883f Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 10 Jun 2022 07:26:53 +0200 Subject: [PATCH 287/449] time aggregate to only query for data necessary improves the query by not creating a full trade object. --- freqtrade/rpc/rpc.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index a6290bd5a..64584382a 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -309,16 +309,18 @@ class RPC: for day in range(0, timescale): profitday = start_date - time_offset(day) - trades = Trade.get_trades(trade_filter=[ + # Only query for necessary columns for performance reasons. + trades = Trade.query.session.query(Trade.close_profit_abs).filter( Trade.is_open.is_(False), Trade.close_date >= profitday, Trade.close_date < (profitday + time_offset(1)) - ]).order_by(Trade.close_date).all() + ).order_by(Trade.close_date).all() + curdayprofit = sum( trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) profit_units[profitday] = { 'amount': curdayprofit, - 'trades': len(trades) + 'trades': len(trades), } data = [ From 7142394121abc4d511f110d805dd848989eb9126 Mon Sep 17 00:00:00 2001 From: Italo <45588475+italodamato@users.noreply.github.com> Date: Fri, 10 Jun 2022 09:46:45 +0100 Subject: [PATCH 288/449] remove random_state condition otherwise the random sample always draws the same set of points --- freqtrade/optimize/hyperopt.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index ac1b7b8ba..cb0d788da 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -436,8 +436,7 @@ class Hyperopt: asked = unique_list(self.opt.ask(n_points=n_points * 5)) is_random = [False for _ in range(len(asked))] else: - asked = unique_list(self.opt.space.rvs( - n_samples=n_points * 5, random_state=self.random_state + i)) + asked = unique_list(self.opt.space.rvs(n_samples=n_points * 5)) is_random = [True for _ in range(len(asked))] is_random_non_tried += [rand for x, rand in zip(asked, is_random) if x not in self.opt.Xi From 76f87377ba542a106476828cd04846e29c0cfb88 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 10 Jun 2022 20:18:33 +0200 Subject: [PATCH 289/449] Reduce decimals on FIAT daily column --- freqtrade/rpc/telegram.py | 2 +- tests/rpc/test_rpc_telegram.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 106a5f011..61b73553f 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -607,7 +607,7 @@ class Telegram(RPCHandler): stats_tab = tabulate( [[period['date'], f"{round_coin_value(period['abs_profit'], stats['stake_currency'])}", - f"{period['fiat_value']:.3f} {stats['fiat_display_currency']}", + f"{period['fiat_value']:.2f} {stats['fiat_display_currency']}", f"{period['trade_count']} trades"] for period in stats['data']], headers=[ val.header, diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 2bc4fc5c3..5271c5a30 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -447,7 +447,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, assert 'Day ' in msg_mock.call_args_list[0][0][0] assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0] assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] @@ -459,7 +459,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, assert "Daily Profit over the last 7 days:" in msg_mock.call_args_list[0][0][0] assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0] assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] @@ -482,7 +482,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, context.args = ["1"] telegram._daily(update=update, context=context) assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 2.798 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 2.80 USD') in msg_mock.call_args_list[0][0][0] assert str(' 3 trades') in msg_mock.call_args_list[0][0][0] @@ -561,7 +561,7 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee, first_iso_day_of_current_week = today - timedelta(days=today.weekday()) assert str(first_iso_day_of_current_week) in msg_mock.call_args_list[0][0][0] assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] @@ -574,7 +574,7 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee, in msg_mock.call_args_list[0][0][0] assert 'Weekly' in msg_mock.call_args_list[0][0][0] assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] @@ -599,7 +599,7 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee, context.args = ["1"] telegram._weekly(update=update, context=context) assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 2.798 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 2.80 USD') in msg_mock.call_args_list[0][0][0] assert str(' 3 trades') in msg_mock.call_args_list[0][0][0] @@ -678,7 +678,7 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee, current_month = f"{today.year}-{today.month:02} " assert current_month in msg_mock.call_args_list[0][0][0] assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] @@ -692,7 +692,7 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee, assert 'Month ' in msg_mock.call_args_list[0][0][0] assert current_month in msg_mock.call_args_list[0][0][0] assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.933 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] @@ -717,7 +717,7 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee, assert msg_mock.call_count == 1 assert 'Monthly Profit over the last 12 months:' in msg_mock.call_args_list[0][0][0] assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 2.798 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 2.80 USD') in msg_mock.call_args_list[0][0][0] assert str(' 3 trades') in msg_mock.call_args_list[0][0][0] # The one-digit months should contain a zero, Eg: September 2021 = "2021-09" From 2c7c5f9a6e0815760d1bafed9a96e8804c15b7b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 10 Jun 2022 20:34:17 +0200 Subject: [PATCH 290/449] Update mock_usdt trade method --- tests/conftest.py | 19 +++-- tests/conftest_trades_usdt.py | 151 +++++++++++++++++++-------------- tests/plugins/test_pairlist.py | 4 +- 3 files changed, 100 insertions(+), 74 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 02738b0e9..b4b98cbeb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -325,7 +325,7 @@ def create_mock_trades_with_leverage(fee, use_db: bool = True): Trade.query.session.flush() -def create_mock_trades_usdt(fee, use_db: bool = True): +def create_mock_trades_usdt(fee, is_short: Optional[bool] = False, use_db: bool = True): """ Create some fake trades ... """ @@ -335,26 +335,29 @@ def create_mock_trades_usdt(fee, use_db: bool = True): else: LocalTrade.add_bt_trade(trade) + is_short1 = is_short if is_short is not None else True + is_short2 = is_short if is_short is not None else False + # Simulate dry_run entries - trade = mock_trade_usdt_1(fee) + trade = mock_trade_usdt_1(fee, is_short1) add_trade(trade) - trade = mock_trade_usdt_2(fee) + trade = mock_trade_usdt_2(fee, is_short1) add_trade(trade) - trade = mock_trade_usdt_3(fee) + trade = mock_trade_usdt_3(fee, is_short1) add_trade(trade) - trade = mock_trade_usdt_4(fee) + trade = mock_trade_usdt_4(fee, is_short2) add_trade(trade) - trade = mock_trade_usdt_5(fee) + trade = mock_trade_usdt_5(fee, is_short2) add_trade(trade) - trade = mock_trade_usdt_6(fee) + trade = mock_trade_usdt_6(fee, is_short1) add_trade(trade) - trade = mock_trade_usdt_7(fee) + trade = mock_trade_usdt_7(fee, is_short1) add_trade(trade) if use_db: Trade.commit() diff --git a/tests/conftest_trades_usdt.py b/tests/conftest_trades_usdt.py index 59e7f0457..6f83bb8be 100644 --- a/tests/conftest_trades_usdt.py +++ b/tests/conftest_trades_usdt.py @@ -6,12 +6,24 @@ from freqtrade.persistence.models import Order, Trade MOCK_TRADE_COUNT = 6 -def mock_order_usdt_1(): +def entry_side(is_short: bool): + return "sell" if is_short else "buy" + + +def exit_side(is_short: bool): + return "buy" if is_short else "sell" + + +def direc(is_short: bool): + return "short" if is_short else "long" + + +def mock_order_usdt_1(is_short: bool): return { - 'id': '1234', + 'id': f'1234_{direc(is_short)}', 'symbol': 'ADA/USDT', 'status': 'closed', - 'side': 'buy', + 'side': entry_side(is_short), 'type': 'limit', 'price': 2.0, 'amount': 10.0, @@ -20,7 +32,7 @@ def mock_order_usdt_1(): } -def mock_trade_usdt_1(fee): +def mock_trade_usdt_1(fee, is_short: bool): trade = Trade( pair='ADA/USDT', stake_amount=20.0, @@ -32,21 +44,22 @@ def mock_trade_usdt_1(fee): open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17), open_rate=2.0, exchange='binance', - open_order_id='dry_run_buy_12345', + open_order_id=f'1234_{direc(is_short)}', strategy='StrategyTestV2', timeframe=5, + is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_1(), 'ADA/USDT', 'buy') + o = Order.parse_from_ccxt_object(mock_order_usdt_1(is_short), 'ADA/USDT', entry_side(is_short)) trade.orders.append(o) return trade -def mock_order_usdt_2(): +def mock_order_usdt_2(is_short: bool): return { - 'id': '1235', + 'id': f'1235_{direc(is_short)}', 'symbol': 'ETC/USDT', 'status': 'closed', - 'side': 'buy', + 'side': entry_side(is_short), 'type': 'limit', 'price': 2.0, 'amount': 100.0, @@ -55,12 +68,12 @@ def mock_order_usdt_2(): } -def mock_order_usdt_2_sell(): +def mock_order_usdt_2_exit(is_short: bool): return { - 'id': '12366', + 'id': f'12366_{direc(is_short)}', 'symbol': 'ETC/USDT', 'status': 'closed', - 'side': 'sell', + 'side': exit_side(is_short), 'type': 'limit', 'price': 2.05, 'amount': 100.0, @@ -69,7 +82,7 @@ def mock_order_usdt_2_sell(): } -def mock_trade_usdt_2(fee): +def mock_trade_usdt_2(fee, is_short: bool): """ Closed trade... """ @@ -86,26 +99,28 @@ def mock_trade_usdt_2(fee): close_profit_abs=3.9875, exchange='binance', is_open=False, - open_order_id='dry_run_sell_12345', + open_order_id=f'12366_{direc(is_short)}', strategy='StrategyTestV2', timeframe=5, - exit_reason='sell_signal', + exit_reason='exit_signal', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), + is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_2(), 'ETC/USDT', 'buy') + o = Order.parse_from_ccxt_object(mock_order_usdt_2(is_short), 'ETC/USDT', entry_side(is_short)) trade.orders.append(o) - o = Order.parse_from_ccxt_object(mock_order_usdt_2_sell(), 'ETC/USDT', 'sell') + o = Order.parse_from_ccxt_object( + mock_order_usdt_2_exit(is_short), 'ETC/USDT', exit_side(is_short)) trade.orders.append(o) return trade -def mock_order_usdt_3(): +def mock_order_usdt_3(is_short: bool): return { - 'id': '41231a12a', + 'id': f'41231a12a_{direc(is_short)}', 'symbol': 'XRP/USDT', 'status': 'closed', - 'side': 'buy', + 'side': entry_side(is_short), 'type': 'limit', 'price': 1.0, 'amount': 30.0, @@ -114,12 +129,12 @@ def mock_order_usdt_3(): } -def mock_order_usdt_3_sell(): +def mock_order_usdt_3_exit(is_short: bool): return { - 'id': '41231a666a', + 'id': f'41231a666a_{direc(is_short)}', 'symbol': 'XRP/USDT', 'status': 'closed', - 'side': 'sell', + 'side': exit_side(is_short), 'type': 'stop_loss_limit', 'price': 1.1, 'average': 1.1, @@ -129,7 +144,7 @@ def mock_order_usdt_3_sell(): } -def mock_trade_usdt_3(fee): +def mock_trade_usdt_3(fee, is_short: bool): """ Closed trade """ @@ -151,20 +166,22 @@ def mock_trade_usdt_3(fee): exit_reason='roi', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc), + is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_3(), 'XRP/USDT', 'buy') + o = Order.parse_from_ccxt_object(mock_order_usdt_3(is_short), 'XRP/USDT', entry_side(is_short)) trade.orders.append(o) - o = Order.parse_from_ccxt_object(mock_order_usdt_3_sell(), 'XRP/USDT', 'sell') + o = Order.parse_from_ccxt_object(mock_order_usdt_3_exit(is_short), + 'XRP/USDT', exit_side(is_short)) trade.orders.append(o) return trade -def mock_order_usdt_4(): +def mock_order_usdt_4(is_short: bool): return { - 'id': 'prod_buy_12345', + 'id': f'prod_buy_12345_{direc(is_short)}', 'symbol': 'ETC/USDT', 'status': 'open', - 'side': 'buy', + 'side': entry_side(is_short), 'type': 'limit', 'price': 2.0, 'amount': 10.0, @@ -173,7 +190,7 @@ def mock_order_usdt_4(): } -def mock_trade_usdt_4(fee): +def mock_trade_usdt_4(fee, is_short: bool): """ Simulate prod entry """ @@ -188,21 +205,22 @@ def mock_trade_usdt_4(fee): is_open=True, open_rate=2.0, exchange='binance', - open_order_id='prod_buy_12345', + open_order_id=f'prod_buy_12345_{direc(is_short)}', strategy='StrategyTestV2', timeframe=5, + is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_4(), 'ETC/USDT', 'buy') + o = Order.parse_from_ccxt_object(mock_order_usdt_4(is_short), 'ETC/USDT', entry_side(is_short)) trade.orders.append(o) return trade -def mock_order_usdt_5(): +def mock_order_usdt_5(is_short: bool): return { - 'id': 'prod_buy_3455', + 'id': f'prod_buy_3455_{direc(is_short)}', 'symbol': 'XRP/USDT', 'status': 'closed', - 'side': 'buy', + 'side': entry_side(is_short), 'type': 'limit', 'price': 2.0, 'amount': 10.0, @@ -211,12 +229,12 @@ def mock_order_usdt_5(): } -def mock_order_usdt_5_stoploss(): +def mock_order_usdt_5_stoploss(is_short: bool): return { - 'id': 'prod_stoploss_3455', + 'id': f'prod_stoploss_3455_{direc(is_short)}', 'symbol': 'XRP/USDT', 'status': 'open', - 'side': 'sell', + 'side': exit_side(is_short), 'type': 'stop_loss_limit', 'price': 2.0, 'amount': 10.0, @@ -225,7 +243,7 @@ def mock_order_usdt_5_stoploss(): } -def mock_trade_usdt_5(fee): +def mock_trade_usdt_5(fee, is_short: bool): """ Simulate prod entry with stoploss """ @@ -241,22 +259,23 @@ def mock_trade_usdt_5(fee): open_rate=2.0, exchange='binance', strategy='SampleStrategy', - stoploss_order_id='prod_stoploss_3455', + stoploss_order_id=f'prod_stoploss_3455_{direc(is_short)}', timeframe=5, + is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_5(), 'XRP/USDT', 'buy') + o = Order.parse_from_ccxt_object(mock_order_usdt_5(is_short), 'XRP/USDT', entry_side(is_short)) trade.orders.append(o) - o = Order.parse_from_ccxt_object(mock_order_usdt_5_stoploss(), 'XRP/USDT', 'stoploss') + o = Order.parse_from_ccxt_object(mock_order_usdt_5_stoploss(is_short), 'XRP/USDT', 'stoploss') trade.orders.append(o) return trade -def mock_order_usdt_6(): +def mock_order_usdt_6(is_short: bool): return { - 'id': 'prod_buy_6', + 'id': f'prod_entry_6_{direc(is_short)}', 'symbol': 'LTC/USDT', 'status': 'closed', - 'side': 'buy', + 'side': entry_side(is_short), 'type': 'limit', 'price': 10.0, 'amount': 2.0, @@ -265,12 +284,12 @@ def mock_order_usdt_6(): } -def mock_order_usdt_6_sell(): +def mock_order_usdt_6_exit(is_short: bool): return { - 'id': 'prod_sell_6', + 'id': f'prod_exit_6_{direc(is_short)}', 'symbol': 'LTC/USDT', 'status': 'open', - 'side': 'sell', + 'side': exit_side(is_short), 'type': 'limit', 'price': 12.0, 'amount': 2.0, @@ -279,7 +298,7 @@ def mock_order_usdt_6_sell(): } -def mock_trade_usdt_6(fee): +def mock_trade_usdt_6(fee, is_short: bool): """ Simulate prod entry with open sell order """ @@ -295,22 +314,24 @@ def mock_trade_usdt_6(fee): open_rate=10.0, exchange='binance', strategy='SampleStrategy', - open_order_id="prod_sell_6", + open_order_id=f'prod_exit_6_{direc(is_short)}', timeframe=5, + is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_6(), 'LTC/USDT', 'buy') + o = Order.parse_from_ccxt_object(mock_order_usdt_6(is_short), 'LTC/USDT', entry_side(is_short)) trade.orders.append(o) - o = Order.parse_from_ccxt_object(mock_order_usdt_6_sell(), 'LTC/USDT', 'sell') + o = Order.parse_from_ccxt_object(mock_order_usdt_6_exit(is_short), + 'LTC/USDT', exit_side(is_short)) trade.orders.append(o) return trade -def mock_order_usdt_7(): +def mock_order_usdt_7(is_short: bool): return { - 'id': 'prod_buy_7', + 'id': f'prod_entry_7_{direc(is_short)}', 'symbol': 'LTC/USDT', 'status': 'closed', - 'side': 'buy', + 'side': entry_side(is_short), 'type': 'limit', 'price': 10.0, 'amount': 2.0, @@ -319,12 +340,12 @@ def mock_order_usdt_7(): } -def mock_order_usdt_7_sell(): +def mock_order_usdt_7_exit(is_short: bool): return { - 'id': 'prod_sell_7', + 'id': f'prod_exit_7_{direc(is_short)}', 'symbol': 'LTC/USDT', 'status': 'closed', - 'side': 'sell', + 'side': exit_side(is_short), 'type': 'limit', 'price': 8.0, 'amount': 2.0, @@ -333,7 +354,7 @@ def mock_order_usdt_7_sell(): } -def mock_trade_usdt_7(fee): +def mock_trade_usdt_7(fee, is_short: bool): """ Simulate prod entry with open sell order """ @@ -342,8 +363,8 @@ def mock_trade_usdt_7(fee): stake_amount=20.0, amount=2.0, amount_requested=2.0, - open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), - close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=5), + open_date=datetime.now(tz=timezone.utc) - timedelta(days=2, minutes=20), + close_date=datetime.now(tz=timezone.utc) - timedelta(days=2, minutes=5), fee_open=fee.return_value, fee_close=fee.return_value, is_open=False, @@ -353,11 +374,13 @@ def mock_trade_usdt_7(fee): close_profit_abs=-4.0, exchange='binance', strategy='SampleStrategy', - open_order_id="prod_sell_6", + open_order_id=f'prod_exit_7_{direc(is_short)}', timeframe=5, + is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_7(), 'LTC/USDT', 'buy') + o = Order.parse_from_ccxt_object(mock_order_usdt_7(is_short), 'LTC/USDT', entry_side(is_short)) trade.orders.append(o) - o = Order.parse_from_ccxt_object(mock_order_usdt_7_sell(), 'LTC/USDT', 'sell') + o = Order.parse_from_ccxt_object(mock_order_usdt_7_exit(is_short), + 'LTC/USDT', exit_side(is_short)) trade.orders.append(o) return trade diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index c29e619b1..c56f405e2 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -762,8 +762,8 @@ def test_PerformanceFilter_keep_mid_order(mocker, default_conf_usdt, fee, caplog with time_machine.travel("2021-09-01 05:00:00 +00:00") as t: create_mock_trades_usdt(fee) pm.refresh_pairlist() - assert pm.whitelist == ['XRP/USDT', 'ETC/USDT', 'ETH/USDT', - 'NEO/USDT', 'TKN/USDT', 'ADA/USDT', 'LTC/USDT'] + assert pm.whitelist == ['XRP/USDT', 'ETC/USDT', 'ETH/USDT', 'LTC/USDT', + 'NEO/USDT', 'TKN/USDT', 'ADA/USDT', ] # assert log_has_re(r'Removing pair .* since .* is below .*', caplog) # Move to "outside" of lookback window, so original sorting is restored. From ab6a306e074da244c3798670cf00760a3c3c44aa Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 10 Jun 2022 20:52:05 +0200 Subject: [PATCH 291/449] Update daily test to USDT --- tests/rpc/test_rpc_telegram.py | 59 ++++++++++------------------------ 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 5271c5a30..3cafb2d7d 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -27,8 +27,9 @@ from freqtrade.persistence.models import Order from freqtrade.rpc import RPC from freqtrade.rpc.rpc import RPCException from freqtrade.rpc.telegram import Telegram, authorized_only -from tests.conftest import (CURRENT_TEST_STRATEGY, create_mock_trades, get_patched_freqtradebot, - log_has, log_has_re, patch_exchange, patch_get_signal, patch_whitelist) +from tests.conftest import (CURRENT_TEST_STRATEGY, create_mock_trades, create_mock_trades_usdt, + get_patched_freqtradebot, log_has, log_has_re, patch_exchange, + patch_get_signal, patch_whitelist) class DummyCls(Telegram): @@ -404,12 +405,10 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None: assert msg_mock.call_count == 1 -def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, - limit_sell_order, mocker) -> None: - default_conf['max_open_trades'] = 1 +def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: mocker.patch( 'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', - return_value=15000.0 + return_value=1.1 ) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -417,25 +416,10 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, get_fee=fee, ) - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) - - patch_get_signal(freqtradebot) + telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade - - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobjs = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobjs) - - trade.close_date = datetime.utcnow() - trade.is_open = False + create_mock_trades_usdt(fee) # Try valid data # /daily 2 @@ -446,9 +430,9 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, assert "Daily Profit over the last 2 days:" in msg_mock.call_args_list[0][0][0] assert 'Day ' in msg_mock.call_args_list[0][0][0] assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0] - assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] + assert str(' 13.83 USDT') in msg_mock.call_args_list[0][0][0] + assert str(' 15.21 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 2 trade') in msg_mock.call_args_list[0][0][0] assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] # Reset msg_mock @@ -458,32 +442,23 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, assert msg_mock.call_count == 1 assert "Daily Profit over the last 7 days:" in msg_mock.call_args_list[0][0][0] assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0] - assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] + assert str((datetime.utcnow() - timedelta(days=5)).date()) in msg_mock.call_args_list[0][0][0] + assert str(' 13.83 USDT') in msg_mock.call_args_list[0][0][0] + assert str(' 15.21 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 2 trade') in msg_mock.call_args_list[0][0][0] assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() - freqtradebot.config['max_open_trades'] = 2 - # Add two other trades - n = freqtradebot.enter_positions() - assert n == 2 - - trades = Trade.query.all() - for trade in trades: - trade.update_trade(oobj) - trade.update_trade(oobjs) - trade.close_date = datetime.utcnow() - trade.is_open = False # /daily 1 context = MagicMock() context.args = ["1"] telegram._daily(update=update, context=context) - assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 2.80 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 3 trades') in msg_mock.call_args_list[0][0][0] + assert str(' 13.83 USDT') in msg_mock.call_args_list[0][0][0] + assert str(' 15.21 USD') in msg_mock.call_args_list[0][0][0] + assert str(' 2 trade') in msg_mock.call_args_list[0][0][0] def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None: From 1a5c3c587d4936b9e6978197b2e257a7040ba5bc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 08:38:30 +0200 Subject: [PATCH 292/449] Simplify weekly/monthly tests, convert to usdt --- tests/rpc/test_rpc.py | 3 +- tests/rpc/test_rpc_telegram.py | 178 +++++++++------------------------ 2 files changed, 47 insertions(+), 134 deletions(-) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index e1f40bcd2..da477edf4 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -284,7 +284,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: assert isnan(fiat_profit_sum) -def test__rpc_timeunit_profit(default_conf, update, ticker, fee, +def test__rpc_timeunit_profit(default_conf, ticker, fee, limit_buy_order, limit_sell_order, markets, mocker) -> None: mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( @@ -315,7 +315,6 @@ def test__rpc_timeunit_profit(default_conf, update, ticker, fee, trade.is_open = False # Try valid data - update.message.text = '/daily 2' days = rpc._rpc_timeunit_profit(7, stake_currency, fiat_display_currency) assert len(days['data']) == 7 assert days['stake_currency'] == default_conf['stake_currency'] diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 3cafb2d7d..404fdd2b0 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -430,10 +430,11 @@ def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert "Daily Profit over the last 2 days:" in msg_mock.call_args_list[0][0][0] assert 'Day ' in msg_mock.call_args_list[0][0][0] assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0] - assert str(' 13.83 USDT') in msg_mock.call_args_list[0][0][0] - assert str(' 15.21 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 2 trade') in msg_mock.call_args_list[0][0][0] - assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] + assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0] + assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0] + assert ' 2 trade' in msg_mock.call_args_list[0][0][0] + assert '13.83 USDT 15.21 USD 2 trades' in msg_mock.call_args_list[0][0][0] + assert ' 0 trade' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -443,11 +444,11 @@ def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert "Daily Profit over the last 7 days:" in msg_mock.call_args_list[0][0][0] assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0] assert str((datetime.utcnow() - timedelta(days=5)).date()) in msg_mock.call_args_list[0][0][0] - assert str(' 13.83 USDT') in msg_mock.call_args_list[0][0][0] - assert str(' 15.21 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 2 trade') in msg_mock.call_args_list[0][0][0] - assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] - assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] + assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0] + assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0] + assert ' 2 trade' in msg_mock.call_args_list[0][0][0] + assert ' 1 trade' in msg_mock.call_args_list[0][0][0] + assert ' 0 trade' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -456,9 +457,9 @@ def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: context = MagicMock() context.args = ["1"] telegram._daily(update=update, context=context) - assert str(' 13.83 USDT') in msg_mock.call_args_list[0][0][0] - assert str(' 15.21 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 2 trade') in msg_mock.call_args_list[0][0][0] + assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0] + assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0] + assert ' 2 trade' in msg_mock.call_args_list[0][0][0] def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None: @@ -487,15 +488,14 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None: context = MagicMock() context.args = ["today"] telegram._daily(update=update, context=context) - assert str('Daily Profit over the last 7 days:') in msg_mock.call_args_list[0][0][0] + assert 'Daily Profit over the last 7 days:' in msg_mock.call_args_list[0][0][0] -def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee, - limit_sell_order, mocker) -> None: - default_conf['max_open_trades'] = 1 +def test_weekly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: + default_conf_usdt['max_open_trades'] = 1 mocker.patch( 'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', - return_value=15000.0 + return_value=1.1 ) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -503,25 +503,9 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee, get_fee=fee, ) - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) + telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) - patch_get_signal(freqtradebot) - - # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade - - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobjs = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobjs) - - trade.close_date = datetime.utcnow() - trade.is_open = False + create_mock_trades_usdt(fee) # Try valid data # /weekly 2 @@ -535,10 +519,10 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee, today = datetime.utcnow().date() first_iso_day_of_current_week = today - timedelta(days=today.weekday()) assert str(first_iso_day_of_current_week) in msg_mock.call_args_list[0][0][0] - assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] - assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] + assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] + assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] + assert ' 3 trade' in msg_mock.call_args_list[0][0][0] + assert ' 0 trade' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -548,44 +532,10 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee, assert "Weekly Profit over the last 8 weeks (starting from Monday):" \ in msg_mock.call_args_list[0][0][0] assert 'Weekly' in msg_mock.call_args_list[0][0][0] - assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] - assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] - - # Reset msg_mock - msg_mock.reset_mock() - freqtradebot.config['max_open_trades'] = 2 - # Add two other trades - n = freqtradebot.enter_positions() - assert n == 2 - - trades = Trade.query.all() - for trade in trades: - trade.update_trade(oobj) - trade.update_trade(oobjs) - trade.close_date = datetime.utcnow() - trade.is_open = False - - # /weekly 1 - # By default, the 8 previous weeks are shown - # So the previous modified trade should be excluded from the stats - context = MagicMock() - context.args = ["1"] - telegram._weekly(update=update, context=context) - assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 2.80 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 3 trades') in msg_mock.call_args_list[0][0][0] - - -def test_weekly_wrong_input(default_conf, update, ticker, mocker) -> None: - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=ticker - ) - - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) - patch_get_signal(freqtradebot) + assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] + assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] + assert ' 3 trade' in msg_mock.call_args_list[0][0][0] + assert ' 0 trade' in msg_mock.call_args_list[0][0][0] # Try invalid data msg_mock.reset_mock() @@ -604,16 +554,17 @@ def test_weekly_wrong_input(default_conf, update, ticker, mocker) -> None: context = MagicMock() context.args = ["this week"] telegram._weekly(update=update, context=context) - assert str('Weekly Profit over the last 8 weeks (starting from Monday):') \ + assert ( + 'Weekly Profit over the last 8 weeks (starting from Monday):' in msg_mock.call_args_list[0][0][0] + ) -def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee, - limit_sell_order, mocker) -> None: - default_conf['max_open_trades'] = 1 +def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: + default_conf_usdt['max_open_trades'] = 1 mocker.patch( 'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', - return_value=15000.0 + return_value=1.1 ) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -621,25 +572,9 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee, get_fee=fee, ) - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) + telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) - patch_get_signal(freqtradebot) - - # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade - - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobjs = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobjs) - - trade.close_date = datetime.utcnow() - trade.is_open = False + create_mock_trades_usdt(fee) # Try valid data # /monthly 2 @@ -652,10 +587,10 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee, today = datetime.utcnow().date() current_month = f"{today.year}-{today.month:02} " assert current_month in msg_mock.call_args_list[0][0][0] - assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] - assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] + assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] + assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] + assert ' 3 trade' in msg_mock.call_args_list[0][0][0] + assert ' 0 trade' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -666,24 +601,13 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee, assert 'Monthly Profit over the last 6 months:' in msg_mock.call_args_list[0][0][0] assert 'Month ' in msg_mock.call_args_list[0][0][0] assert current_month in msg_mock.call_args_list[0][0][0] - assert str(' 0.00006217 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 0.93 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 1 trade') in msg_mock.call_args_list[0][0][0] - assert str(' 0 trade') in msg_mock.call_args_list[0][0][0] + assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] + assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] + assert ' 3 trade' in msg_mock.call_args_list[0][0][0] + assert ' 0 trade' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() - freqtradebot.config['max_open_trades'] = 2 - # Add two other trades - n = freqtradebot.enter_positions() - assert n == 2 - - trades = Trade.query.all() - for trade in trades: - trade.update_trade(oobj) - trade.update_trade(oobjs) - trade.close_date = datetime.utcnow() - trade.is_open = False # /monthly 12 context = MagicMock() @@ -691,24 +615,14 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee, telegram._monthly(update=update, context=context) assert msg_mock.call_count == 1 assert 'Monthly Profit over the last 12 months:' in msg_mock.call_args_list[0][0][0] - assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0] - assert str(' 2.80 USD') in msg_mock.call_args_list[0][0][0] - assert str(' 3 trades') in msg_mock.call_args_list[0][0][0] + assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] + assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] + assert ' 3 trade' in msg_mock.call_args_list[0][0][0] # The one-digit months should contain a zero, Eg: September 2021 = "2021-09" # Since we loaded the last 12 months, any month should appear assert str('-09') in msg_mock.call_args_list[0][0][0] - -def test_monthly_wrong_input(default_conf, update, ticker, mocker) -> None: - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=ticker - ) - - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) - patch_get_signal(freqtradebot) - # Try invalid data msg_mock.reset_mock() freqtradebot.state = State.RUNNING From 0a801c022316eb5a944f7690cc191d90a3364939 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 08:58:36 +0200 Subject: [PATCH 293/449] Simplify daily RPC test --- tests/rpc/test_rpc.py | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index da477edf4..982ac65d7 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -15,7 +15,8 @@ from freqtrade.persistence.models import Order from freqtrade.persistence.pairlock_middleware import PairLocks from freqtrade.rpc import RPC, RPCException from freqtrade.rpc.fiat_convert import CryptoToFiatConverter -from tests.conftest import create_mock_trades, get_patched_freqtradebot, patch_get_signal +from tests.conftest import (create_mock_trades, create_mock_trades_usdt, get_patched_freqtradebot, + patch_get_signal) # Functions for recurrent object patching @@ -284,7 +285,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: assert isnan(fiat_profit_sum) -def test__rpc_timeunit_profit(default_conf, ticker, fee, +def test__rpc_timeunit_profit(default_conf_usdt, ticker, fee, limit_buy_order, limit_sell_order, markets, mocker) -> None: mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( @@ -294,38 +295,27 @@ def test__rpc_timeunit_profit(default_conf, ticker, fee, markets=PropertyMock(return_value=markets) ) - freqtradebot = get_patched_freqtradebot(mocker, default_conf) - patch_get_signal(freqtradebot) - stake_currency = default_conf['stake_currency'] - fiat_display_currency = default_conf['fiat_display_currency'] + freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt) + create_mock_trades_usdt(fee) + + stake_currency = default_conf_usdt['stake_currency'] + fiat_display_currency = default_conf_usdt['fiat_display_currency'] rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() - # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade - - # Simulate buy & sell - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - trade.close_date = datetime.utcnow() - trade.is_open = False # Try valid data days = rpc._rpc_timeunit_profit(7, stake_currency, fiat_display_currency) assert len(days['data']) == 7 - assert days['stake_currency'] == default_conf['stake_currency'] - assert days['fiat_display_currency'] == default_conf['fiat_display_currency'] + assert days['stake_currency'] == default_conf_usdt['stake_currency'] + assert days['fiat_display_currency'] == default_conf_usdt['fiat_display_currency'] for day in days['data']: - # [datetime.date(2018, 1, 11), '0.00000000 BTC', '0.000 USD'] - assert (day['abs_profit'] == 0.0 or - day['abs_profit'] == 0.00006217) + # {'date': datetime.date(2022, 6, 11), 'abs_profit': 13.8299999, + # 'fiat_value': 0.0, 'trade_count': 2} + assert day['abs_profit'] in (0.0, pytest.approx(13.8299999), pytest.approx(-4.0)) + assert day['trade_count'] in (0, 1, 2) - assert (day['fiat_value'] == 0.0 or - day['fiat_value'] == 0.76748865) + assert day['fiat_value'] in (0.0, ) # ensure first day is current date assert str(days['data'][0]['date']) == str(datetime.utcnow().date()) From 76827b31a9c59d0d7344ff379f5ef7f0fc1a56f4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 11:18:21 +0200 Subject: [PATCH 294/449] Add relative profit to daily/weekly commands --- freqtrade/rpc/rpc.py | 11 +++++++++-- freqtrade/rpc/telegram.py | 12 +++++++----- tests/rpc/test_rpc.py | 4 +++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 64584382a..da5144dab 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -302,11 +302,12 @@ class RPC: return relativedelta(months=step) return timedelta(**{timeunit: step}) - profit_units: Dict[date, Dict] = {} - if not (isinstance(timescale, int) and timescale > 0): raise RPCException('timescale must be an integer greater than 0') + profit_units: Dict[date, Dict] = {} + daily_stake = self._freqtrade.wallets.get_total_stake_amount() + for day in range(0, timescale): profitday = start_date - time_offset(day) # Only query for necessary columns for performance reasons. @@ -318,8 +319,12 @@ class RPC: curdayprofit = sum( trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) + # Calculate this periods starting balance + daily_stake = daily_stake - curdayprofit profit_units[profitday] = { 'amount': curdayprofit, + 'daily_stake': daily_stake, + 'rel_profit': round(curdayprofit / daily_stake, 8) if daily_stake > 0 else 0, 'trades': len(trades), } @@ -327,6 +332,8 @@ class RPC: { 'date': f"{key.year}-{key.month:02d}" if timeunit == 'months' else key, 'abs_profit': value["amount"], + 'starting_balance': value["daily_stake"], + 'rel_profit': value["rel_profit"], 'fiat_value': self._fiat_converter.convert_amount( value['amount'], stake_currency, diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 61b73553f..c3e4c1152 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -605,14 +605,16 @@ class Telegram(RPCHandler): unit ) stats_tab = tabulate( - [[period['date'], + [[f"{period['date']} ({period['trade_count']})", f"{round_coin_value(period['abs_profit'], stats['stake_currency'])}", f"{period['fiat_value']:.2f} {stats['fiat_display_currency']}", - f"{period['trade_count']} trades"] for period in stats['data']], + f"{period['rel_profit']:.2%}", + ] for period in stats['data']], headers=[ - val.header, - f'Profit {stake_cur}', - f'Profit {fiat_disp_cur}', + f"{val.header} (trades)", + f'Prof {stake_cur}', + f'Prof {fiat_disp_cur}', + 'Profit %', 'Trades', ], tablefmt='simple') diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 982ac65d7..0273b8237 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -311,10 +311,12 @@ def test__rpc_timeunit_profit(default_conf_usdt, ticker, fee, assert days['fiat_display_currency'] == default_conf_usdt['fiat_display_currency'] for day in days['data']: # {'date': datetime.date(2022, 6, 11), 'abs_profit': 13.8299999, + # 'starting_balance': 1055.37, 'rel_profit': 0.0131044, # 'fiat_value': 0.0, 'trade_count': 2} assert day['abs_profit'] in (0.0, pytest.approx(13.8299999), pytest.approx(-4.0)) + assert day['rel_profit'] in (0.0, pytest.approx(0.01310441), pytest.approx(-0.00377583)) assert day['trade_count'] in (0, 1, 2) - + assert day['starting_balance'] in (pytest.approx(1059.37), pytest.approx(1055.37)) assert day['fiat_value'] in (0.0, ) # ensure first day is current date assert str(days['data'][0]['date']) == str(datetime.utcnow().date()) From 9ba11f7bcc0481bbc6db6c3faf3a9e25b8a0edd3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 11:26:49 +0200 Subject: [PATCH 295/449] Update docs and tests for new daily command --- docs/telegram-usage.md | 30 +++++++++++++++--------------- freqtrade/rpc/telegram.py | 6 +++--- tests/rpc/test_rpc_telegram.py | 32 ++++++++++++++++---------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 27f5f91b6..6e21d3689 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -328,11 +328,11 @@ Per default `/daily` will return the 7 last days. The example below if for `/dai > **Daily Profit over the last 3 days:** ``` -Day Profit BTC Profit USD ----------- -------------- ------------ -2018-01-03 0.00224175 BTC 29,142 USD -2018-01-02 0.00033131 BTC 4,307 USD -2018-01-01 0.00269130 BTC 34.986 USD +Day (count) USDT USD Profit % +-------------- ------------ ---------- ---------- +2022-06-11 (1) -0.746 USDT -0.75 USD -0.08% +2022-06-10 (0) 0 USDT 0.00 USD 0.00% +2022-06-09 (5) 20 USDT 20.10 USD 5.00% ``` ### /weekly @@ -342,11 +342,11 @@ from Monday. The example below if for `/weekly 3`: > **Weekly Profit over the last 3 weeks (starting from Monday):** ``` -Monday Profit BTC Profit USD ----------- -------------- ------------ -2018-01-03 0.00224175 BTC 29,142 USD -2017-12-27 0.00033131 BTC 4,307 USD -2017-12-20 0.00269130 BTC 34.986 USD +Monday (count) Profit BTC Profit USD Profit % +------------- -------------- ------------ ---------- +2018-01-03 (5) 0.00224175 BTC 29,142 USD 4.98% +2017-12-27 (1) 0.00033131 BTC 4,307 USD 0.00% +2017-12-20 (4) 0.00269130 BTC 34.986 USD 5.12% ``` ### /monthly @@ -356,11 +356,11 @@ if for `/monthly 3`: > **Monthly Profit over the last 3 months:** ``` -Month Profit BTC Profit USD ----------- -------------- ------------ -2018-01 0.00224175 BTC 29,142 USD -2017-12 0.00033131 BTC 4,307 USD -2017-11 0.00269130 BTC 34.986 USD +Month (count) Profit BTC Profit USD Profit % +------------- -------------- ------------ ---------- +2018-01 (20) 0.00224175 BTC 29,142 USD 4.98% +2017-12 (5) 0.00033131 BTC 4,307 USD 0.00% +2017-11 (10) 0.00269130 BTC 34.986 USD 5.10% ``` ### /whitelist diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index c3e4c1152..2e1d23621 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -611,9 +611,9 @@ class Telegram(RPCHandler): f"{period['rel_profit']:.2%}", ] for period in stats['data']], headers=[ - f"{val.header} (trades)", - f'Prof {stake_cur}', - f'Prof {fiat_disp_cur}', + f"{val.header} (count)", + f'{stake_cur}', + f'{fiat_disp_cur}', 'Profit %', 'Trades', ], diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 404fdd2b0..11a783f3a 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -432,9 +432,9 @@ def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0] assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0] assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0] - assert ' 2 trade' in msg_mock.call_args_list[0][0][0] - assert '13.83 USDT 15.21 USD 2 trades' in msg_mock.call_args_list[0][0][0] - assert ' 0 trade' in msg_mock.call_args_list[0][0][0] + assert '(2)' in msg_mock.call_args_list[0][0][0] + assert '(2) 13.83 USDT 15.21 USD 1.31%' in msg_mock.call_args_list[0][0][0] + assert '(0)' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -446,9 +446,9 @@ def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert str((datetime.utcnow() - timedelta(days=5)).date()) in msg_mock.call_args_list[0][0][0] assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0] assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0] - assert ' 2 trade' in msg_mock.call_args_list[0][0][0] - assert ' 1 trade' in msg_mock.call_args_list[0][0][0] - assert ' 0 trade' in msg_mock.call_args_list[0][0][0] + assert '(2)' in msg_mock.call_args_list[0][0][0] + assert '(1)' in msg_mock.call_args_list[0][0][0] + assert '(0)' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -459,7 +459,7 @@ def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: telegram._daily(update=update, context=context) assert ' 13.83 USDT' in msg_mock.call_args_list[0][0][0] assert ' 15.21 USD' in msg_mock.call_args_list[0][0][0] - assert ' 2 trade' in msg_mock.call_args_list[0][0][0] + assert '(2)' in msg_mock.call_args_list[0][0][0] def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None: @@ -521,8 +521,8 @@ def test_weekly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert str(first_iso_day_of_current_week) in msg_mock.call_args_list[0][0][0] assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] - assert ' 3 trade' in msg_mock.call_args_list[0][0][0] - assert ' 0 trade' in msg_mock.call_args_list[0][0][0] + assert '(3)' in msg_mock.call_args_list[0][0][0] + assert '(0)' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -534,8 +534,8 @@ def test_weekly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert 'Weekly' in msg_mock.call_args_list[0][0][0] assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] - assert ' 3 trade' in msg_mock.call_args_list[0][0][0] - assert ' 0 trade' in msg_mock.call_args_list[0][0][0] + assert '(3)' in msg_mock.call_args_list[0][0][0] + assert '(0)' in msg_mock.call_args_list[0][0][0] # Try invalid data msg_mock.reset_mock() @@ -589,8 +589,8 @@ def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert current_month in msg_mock.call_args_list[0][0][0] assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] - assert ' 3 trade' in msg_mock.call_args_list[0][0][0] - assert ' 0 trade' in msg_mock.call_args_list[0][0][0] + assert '(3)' in msg_mock.call_args_list[0][0][0] + assert '(0)' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -603,8 +603,8 @@ def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert current_month in msg_mock.call_args_list[0][0][0] assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] - assert ' 3 trade' in msg_mock.call_args_list[0][0][0] - assert ' 0 trade' in msg_mock.call_args_list[0][0][0] + assert '(3)' in msg_mock.call_args_list[0][0][0] + assert '(0)' in msg_mock.call_args_list[0][0][0] # Reset msg_mock msg_mock.reset_mock() @@ -617,7 +617,7 @@ def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert 'Monthly Profit over the last 12 months:' in msg_mock.call_args_list[0][0][0] assert ' 9.83 USDT' in msg_mock.call_args_list[0][0][0] assert ' 10.81 USD' in msg_mock.call_args_list[0][0][0] - assert ' 3 trade' in msg_mock.call_args_list[0][0][0] + assert '(3)' in msg_mock.call_args_list[0][0][0] # The one-digit months should contain a zero, Eg: September 2021 = "2021-09" # Since we loaded the last 12 months, any month should appear From 3a06337601b1ff4ca0609010635fb95b7eee7aa7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 11:28:45 +0200 Subject: [PATCH 296/449] Update API to provide new values. --- freqtrade/rpc/api_server/api_schemas.py | 2 ++ freqtrade/rpc/api_server/api_v1.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index a31c74c2e..11fdc0121 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -120,6 +120,8 @@ class Stats(BaseModel): class DailyRecord(BaseModel): date: date abs_profit: float + rel_profit: float + starting_balance: float fiat_value: float trade_count: int diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index 271e3de1b..225fe66b9 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -36,7 +36,8 @@ logger = logging.getLogger(__name__) # versions 2.xx -> futures/short branch # 2.14: Add entry/exit orders to trade response # 2.15: Add backtest history endpoints -API_VERSION = 2.15 +# 2.16: Additional daily metrics +API_VERSION = 2.16 # Public API, requires no auth. router_public = APIRouter() From f816c15e1eb1452b332aa39bbd5d59b105a5324e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 12:02:41 +0200 Subject: [PATCH 297/449] Update discord message format --- freqtrade/rpc/discord.py | 91 ++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 60 deletions(-) diff --git a/freqtrade/rpc/discord.py b/freqtrade/rpc/discord.py index 43a8e9a05..41185a090 100644 --- a/freqtrade/rpc/discord.py +++ b/freqtrade/rpc/discord.py @@ -1,61 +1,44 @@ -import json import logging -from typing import Dict, Any - -import requests +from typing import Any, Dict +from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.enums import RPCMessageType -from freqtrade.rpc import RPCHandler, RPC +from freqtrade.rpc import RPC +from freqtrade.rpc.webhook import Webhook -class Discord(RPCHandler): +logger = logging.getLogger(__name__) + + +class Discord(Webhook): def __init__(self, rpc: 'RPC', config: Dict[str, Any]): - super().__init__(rpc, config) - self.logger = logging.getLogger(__name__) + # super().__init__(rpc, config) + self.rpc = rpc + self.config = config self.strategy = config.get('strategy', '') self.timeframe = config.get('timeframe', '') - self.config = config - def send_msg(self, msg: Dict[str, str]) -> None: - self._send_msg(msg) + self._url = self.config['discord']['webhook_url'] + self._format = 'json' + self._retries = 1 + self._retry_delay = 0.1 - def _send_msg(self, msg): + def cleanup(self) -> None: """ - msg = { - 'type': (RPCMessageType.EXIT_FILL if fill - else RPCMessageType.EXIT), - 'trade_id': trade.id, - 'exchange': trade.exchange.capitalize(), - 'pair': trade.pair, - 'leverage': trade.leverage, - 'direction': 'Short' if trade.is_short else 'Long', - 'gain': gain, - 'limit': profit_rate, - 'order_type': order_type, - 'amount': trade.amount, - 'open_rate': trade.open_rate, - 'close_rate': trade.close_rate, - 'current_rate': current_rate, - 'profit_amount': profit_trade, - 'profit_ratio': profit_ratio, - 'buy_tag': trade.enter_tag, - 'enter_tag': trade.enter_tag, - 'sell_reason': trade.exit_reason, # Deprecated - 'exit_reason': trade.exit_reason, - 'open_date': trade.open_date, - 'close_date': trade.close_date or datetime.utcnow(), - 'stake_currency': self.config['stake_currency'], - 'fiat_currency': self.config.get('fiat_display_currency', None), - } + Cleanup pending module resources. + This will do nothing for webhooks, they will simply not be called anymore """ - self.logger.info(f"Sending discord message: {msg}") + pass + + def send_msg(self, msg) -> None: + logger.info(f"Sending discord message: {msg}") # TODO: handle other message types if msg['type'] == RPCMessageType.EXIT_FILL: profit_ratio = msg.get('profit_ratio') - open_date = msg.get('open_date').strftime('%Y-%m-%d %H:%M:%S') + open_date = msg.get('open_date').strftime(DATETIME_PRINT_FORMAT) close_date = msg.get('close_date').strftime( - '%Y-%m-%d %H:%M:%S') if msg.get('close_date') else '' + DATETIME_PRINT_FORMAT) if msg.get('close_date') else '' embeds = [{ 'title': '{} Trade: {}'.format( @@ -63,7 +46,7 @@ class Discord(RPCHandler): msg.get('pair')), 'color': (0x00FF00 if profit_ratio > 0 else 0xFF0000), 'fields': [ - {'name': 'Trade ID', 'value': msg.get('id'), 'inline': True}, + {'name': 'Trade ID', 'value': msg.get('trade_id'), 'inline': True}, {'name': 'Exchange', 'value': msg.get('exchange').capitalize(), 'inline': True}, {'name': 'Pair', 'value': msg.get('pair'), 'inline': True}, {'name': 'Direction', 'value': 'Short' if msg.get( @@ -75,11 +58,10 @@ class Discord(RPCHandler): {'name': 'Open date', 'value': open_date, 'inline': True}, {'name': 'Close date', 'value': close_date, 'inline': True}, {'name': 'Profit', 'value': msg.get('profit_amount'), 'inline': True}, - {'name': 'Profitability', 'value': '{:.2f}%'.format( - profit_ratio * 100), 'inline': True}, + {'name': 'Profitability', 'value': f'{profit_ratio:.2%}', 'inline': True}, {'name': 'Stake currency', 'value': msg.get('stake_currency'), 'inline': True}, - {'name': 'Fiat currency', 'value': msg.get( - 'fiat_display_currency'), 'inline': True}, + {'name': 'Fiat currency', 'value': msg.get('fiat_display_currency'), + 'inline': True}, {'name': 'Buy Tag', 'value': msg.get('enter_tag'), 'inline': True}, {'name': 'Sell Reason', 'value': msg.get('exit_reason'), 'inline': True}, {'name': 'Strategy', 'value': self.strategy, 'inline': True}, @@ -89,20 +71,9 @@ class Discord(RPCHandler): # convert all value in fields to string for discord for embed in embeds: - for field in embed['fields']: + for field in embed['fields']: # type: ignore field['value'] = str(field['value']) # Send the message to discord channel - payload = { - 'embeds': embeds, - } - headers = { - 'Content-Type': 'application/json', - } - try: - requests.post( - self.config['discord']['webhook_url'], - data=json.dumps(payload), - headers=headers) - except Exception as e: - self.logger.error(f"Failed to send discord message: {e}") + payload = {'embeds': embeds} + self._send_msg(payload) From fdfa94bcc31b5fc751873ccfa943dc962a24a030 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 17:30:56 +0200 Subject: [PATCH 298/449] make discord notifications fully configurable. --- docs/assets/discord_notification.png | Bin 0 -> 48861 bytes docs/webhook-config.md | 49 +++++++++++++++++++++++ freqtrade/constants.py | 41 +++++++++++++++++++ freqtrade/rpc/discord.py | 57 +++++++++------------------ 4 files changed, 108 insertions(+), 39 deletions(-) create mode 100644 docs/assets/discord_notification.png diff --git a/docs/assets/discord_notification.png b/docs/assets/discord_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..05a7705d7f599de625de31782344f98d93ccb17b GIT binary patch literal 48861 zcmbrl1#I2i+vV#pGcz>}Q^QORLmOslnDK-;4MUrxX_(V6r(tGhW@cti=DhDWpGNo2 zXzpLSlC5J|hO_Ox?PvYga`;z8DHKFPL;wI#WTZbU0{}!Wc)o;(1h4s0_1OUYgWw>o zBrSs7;mC;PjW^(gDLL5BSp04<8%d>3a68Au+sDjJI_ zivE1>5Ibh#1nK|2(rlg@Kt6zUF8p4l;NjY0lgirQbzhk|W3;qP2_)?Z&2kZm{=_2< z7V`)f^EjlAuD09uQr4J;R zHh6y=_dCbn4I5CysQc>`qTGJ&`bOgjquQ-o1;z!K9C&halFROeoK^!1bnz_ zBnduf(G#)=7x=&hVeCV6=qf+jDGK;+?_cx8(R<#qr9;WXUd8`yL?|VAk2|#gWCyQu zN|JG5*ZckcIV8(Ef^lTT{?X-x@k#|rn+=sfW30OVNFD%C)ZaYj{?h~RxU39+wII-g z=S+&ZN08~pXp%LLt%IE$**%S2H|Q6})n}~ek5^Jh2*tW+wnnyBzn%K4aYV?nSY=Zw zC8-*e0p+t2)X)H$qxqIevYt0$dW0yH(Oi@79FDDT;;KJ#{56s1xVz@_dboeH;cB)! z%WBa;Fq{^GsZ0Q}g8pZVZ&-`Tr%lDI3{m!&{q42cf1&(03EMvM4a`T6cgVv=S1YCY z?1&tKvciSh(>7*tMrGpl3oMF?1_To{O4v|D%kHu+AdM;aVy1C?owBOCxvs}Mphb1& zB%Tl(P@7s3vV$vpGU}q%Jxx4D=x~lvlp3V7X3`;nCH(V=U`o4qdW?=bF^nBHf+lG= zHx$oXTS62-zfVgZnejt5l{{dWy{U*#+cfr0Gnl1B*z~((E*@8`V)B?308*&1`a3=! zgrfogR&*}`E#w;78BSvl(tM71lK%lFkajK^#UCaKF83pzcUZBSoZ$n&D618 z$$YlP+DtMnPh_{_HHz!?ZDvBPk%aa&`W$`mF7NVsf05`_C6N&PQdH$aWBJ2q%82po z`my2npWRM|SN)Y1S=CGtzJRt)_Eqv_(>>pZyz_QPWE9Z005kYRgbCZ#cdnWI!?8lbl^E?!& zk|1sYUj?>U22J23+}l@gj#ly_v}JnDDRhrt41O?|CUT}n?V+j8G7meMAn0=db1NUT zd=#SqXB}4_ZU!1#gz-AsK;+f}jKflVQnu&1(57mOiVa3Yp*0PjxttcyqL!-&)P0X& z`|vwwAnT&bjiz@5cj7Nff*OhyrstUi&*Qn`GWLx|&Q>H8!M8wRH?^ZZ;TXtLe}zVa zT^!#84R?;EYqV57J5W8^X1_LT@S5B zx_aWTAV{)PoLc#wCp{Gn_1qHx@Nw39d^``sNT>F4ovwUJQOBD2=<&z{0bH27U(!u@ z7RmEY;GMgaasE;81Xx#XXqjS5Y_BnP!U>z!j>*1NOFLS9c2bNd1wIK~$kp71v;KIf z2^HgQxg`FHiWjWdDVji5&(l~AWzm)@dlz218O4HlZ5%iH%k<8kfWX-eAMBYm{iAQgWevZ!p@~Oq)i(7-)DS;rmAeDJ>)W2AyuzU+-ff*$P*tJR zTsdo*J|5@zER$i8j>tkN-gNz`z^uSR(hJEJ9-re*#l=YnW}S@Q`GVPxOeE^jHrmU8r@GXV%XH znXUA<+zMX<-8Xpl!hV2<$X4RIturi__C_ES>t{=4B{xE$l+XZFphN6$ofQE1QYirU zBAx~m=4uJl>?H>1V_m3q}9@8?C%8M2$={DQttbVfI1s%J91E6AkJqx$;`FJ6@ zm{zDt+V)KLMNPazT&Q-=iyHzxarh6cQC9PO8ldYRtHID)s1qT8m$Am9$FhXI72xvQA+dfPNLAYj z+pPOz^Ai9#mVAz43d;-Upw38Y7oz7Tb+rQ8++qaCGW1i+@!|(fAU6J?;B91vao=QT0FgR|lI{Xp&OQA2_ z?0a-1;bGlg*om_6i@&TS_{z(9X-h8wZQ(N^w6)z$+&tUu;tkfkt<%6z={9Iu-6IA` zkpUM27OSrV+&je;me|-JM4WL$SdjL78?*{059IL^$2$XTn6c`$o6ee|aQ|f7R11CS zcLFNWNBdp>=#$#uSCEONY2;jK9W+r=IZsgs$Mjv^+pb_0*^TgVgy8Soh$ zSgO>piO(pOvYBn^V4c?z5@^tJIhjGi+GCx+U@{VdMEinTIKHQ$)lE$Gpt;!Oi$;T) zK(ybJAhzy;7Xp|lFb^X_TLi(tH7W;;j;c3G1QA-+iOU62`+Fsnm-*ZpQvmhMT2FjRw#&(68 z`MKC0TT{Kk%NeSzfO{4e9wuYX_bD1Aw>g0x$Iyku>_``ffSWk5bb zSKL746*KCENlZg3O7Lxp5l_EqgvNwb#UUx&w=Kn5p0qD30Q+O6w;rHBbp50ueUv_dmmAou}sPSQ8M8z-beiA+2&(KcG zNGb`PG~zYaX!JmWvAo)Q!#Fkbl{aj&rMwFC*xGhUny*t%Hu+L%Fp?b?DI>}=O|y5s zvW2MCS}Nn&#!6j!9bcaNx{bE4CT&_RN0al>`YZY&AE`m5s1IE3J5U z_TNvOhIZ`1EO+i?dyQ?ChstZP_Qb>jTSz9=?2~r*{_z?+8EJ9!GAgzbgOh4PdfmF(!?ww9^y)(^cQLd4~r#Yx=CQK0{Ektz=YH;K}cub$cA ztSN1(%eL)@<>A2fMz|FCb>7jcajs8E{$AF2EV9LuU(PfnEjMln+s4Xg#*9VVGLW7s zUa-L(F@=_nz5Y;UO}|+@?;LqyD^nRPWg`N(c89i;C9Ui&+IH`x(0jA84FX(a?Sk?ByCEk?2Ulq zda0)4w#N^j&PvT*0$GKnOiT7+?>4fCc{1caXYioU=#Ml@f^SHROTm9gGuR z2!J&cpctn7vg%i?40SXQ<%EZ19xZ3@W7IZsyMM5=dn*j-FQc#lK(8>%4&IIHwQ@KT z7s?4Kme7czvzmXB)Lp}=&6kD)z$Hy301Pzw#FFh^MpQJ_;OSCrMDiRzTmI1s1e7vPiDd z9a(>sHFre3ZQtQ9^T<3offxLzrs97}=^hg$5jVZb$K<1oCpHXN5}@N;523;OA?B2! z#W7uXEy4(BwOad(i3^Z#x&g@kGljJuE>^wMB92y9`;-TW<`eRzmV=;_=ka8gZ`{Ct zjj==t^Iosp4p(B30DDiL=L_8wD7zH{7jF|nf^1x-kfNZB;bITM{}3;*5*XW@5Hae~ zq>|DcK05mwFT!QcC|CYh$nF~j!mCKAlV8KJSL~ZE`LXOUoG<#O#8x$HPk#V8Uy`#> z)If=X{p=wEQe_{4<^;|OY$uu)$#JB{$M1bOhkCzvA6nNQ@yA6tJTm`0=atDa-ohbe zGs-Cn6u@=7y^s=r-X{rXMym-Kh}@-<;=>Qv1}=*G(}L~nNAC9_X(2X3L-Lo6L~G_v zzqXt?w7xkNoNe(g%b##{pdkE?~nP- zX=(22#ySIQ(dqScldFUZ@(Sj0*T^{w)a6ZEKejnB2-u9OC``%rBIK}**xE`y-64D+ z9O(_B*1Nv+NNxOwTJ=L%P|?7PYXvqUK?8ym`NH05$L_i+$*$zh#iH4i@_^qrG@;T^ zZSkGpE0;5A7xvjb^Dwo)G89#jg1)>OGml{+Qlr^D+f%7Yh9M56XExe0=I)ftAN%uv z9ruNO+v4tJ#&A04s9$@RCOyUYD}v1-?te&#cweE3nfRUq(u45drAJ1-K>KGx_jG#a zXZ_eUtsI}MHtp@?mw|Y#OS~D%@M*h#PxV-9IuH|oh~6tuEWc>I44AUld0=Quiu`ZNPW?S@#oPqHr{3#p8$E?nCsfz0(+%+K^B+`sIihTpR9p$E2E z*|s7T)(knIfFfJEC(70vIQFlriRT730_cgWRyr@d?BETU#Gdr3uPFpUmvtX(FW%ti z69FK1y2vay7TVwI$a%TW_ceaM$+&9??Ou9hby}sMLhimSat%~Og8%>v0Yu*x4eSTG zMwVMMGFs2_a-QwCX6rg-h z$7^rYTxOv5u;c`QS?5s2&~YVNd$%iiEF^vYgdCT$OgEXf#MeKvR^k<%$`r`f#4 zzn?Z<{t-rXg6S57`e@0p?PZVG?sJF>pOO`iA{bBTBOse^)wt`uYO6Of0QQEfc0s})yhau@tK7O zqKYClzBl|Jl!UobJYCFPT(=51dl|ceU)SjL9;Y1_Oj^AV@QH~!B|CcZ(QjGeY9-6P z@-y?+rR*R`&TdBL31M4 zqLGd?Rv%(Y1Z^#hS>}5aw?9j z;YSs&U$HTRuEc%h**wPPzwek61UbK{=-!+z1ZkA&(IB!oeAIKwa-0Z)_HdbxGQ+EV}J+zb%Y5HjPU`hN(&qf2!}e6i}@-Z_@}zIptvAtCYG)(??@?_Szp*iJv%lfSFtwP)!UE<2#cLvaCG zhFo1jA&EJO1zP!{C37byH2*#xBnaz|u?MsHOsa}^qDq|4+G(ukJn_84?5uXXB9ms8 zGuK2f_syNpCcy>qece^28M`J@O7y7pL%qsF*=^NuHZJ-_ihqmihYtY8R)yoH~sXw)^48^q!%ZTdT?pHPKXj{v?aa5Mm9}F74hKW^qQRF zEJ9)>m$6mxmCd-V9wZ%a*8^3LQ)3fACXv%pJCkbqbNp2!7Sw#YCVPkQZ)v%hEB+EA z&rP(v%skJzMry2+724#m9^N}VPn!0QDU)*k!f;;*9aU>!;;2z7fG$GKWcXIZ{60*v z(!XGxok@ar^m3`Qx;ZOl{oXT0tE&WmE^GGNRtH5SInjmo!?($pAZu3E_>j5cT>k5_ z+&Gbaq(sIDhaNz>8|CoQXE!|^>!fyK{L_9iM8~(5RdtP&zY?Dog5UjszVe{5DwO0A}MSn*k-6!`UYR@xuZ6)8Yx-9%X;eUY=chf+ncL}_AyY?@bd z^i?J@0+B_XAz-`4K~M7Tu48fz8S7_$`MB&0U6lXAuhS|@-+79+0rtP_*!l-+-E>M~ z5E9f(42gA+2Kc|-Pp%z0r{P`e_>b8L@L1)*dhH73qN?reC7d9KNi3vqqCInLBCWIXu zn}B*x1ikRk`}R1uFxm>_cV=vbnzX&WBhG%j3Pz8PANZ6kY1#JEpqc}Qdvh5S|1UU- z=77RY<4MGcCOoP?Oulr=SQ%1UGjqXThg23=Vxy5x0huy+^@K#+-ARuk*Q4Ihu<#_klcx(op|M(??Q?lh{HC;<8r!nbOoA}@fqW* zBqv({z$&t9tiLR48s{^aoysnk_eo1_t*$XGW7i*~&db)d(Zjy)tkK+c+!-!)O`iw$ zLBjKR*oFL|Q0w@SSoIBGvg739^4B7LHIw>RlELUG-c`O7cE!1_(mB+%%)wpEELfGY zWN5K&LfFYoFS-dtNY$@zO&&2>`zN3I2%oM~7?? zz2CPA>Gg|$v=Flj0-hg4kXk7622<`H-?{7**PG15z5MyE^ zhE%kQw7zk6b8>tfxfbT)M{?GwqoMd-F}6yOIOjjEpNP4AN%Q3YckoRpS5!~WwN{^T z7C75HpSKR(YBS2Npl|10&gzB{J?3UHp>N~W$ptS*O6Yd12(84U@4?;{OexNxGk1o2 zX?U#(FD()CMs=bI?<8~Fw9dDArn~z5x5&i`JkZsU*N6iZ7WRGU^WL+&N4Us&9mr%S zpkh9c&{oNV0ucRSvP4LqvK_uR?e)-AA!O~Vf=873r+ofI;zVWRz#RS)`>o&{t*E1B zz%Z6f`_3^2_SzBgA}uo75Lh|OIDz>rd+$eVkOdc#q0=&G9syU6m^s~k#R9e-i)*SF z&^UB-tCG7M;P&8;nGXUm=JOu*{yPg0J;;{1Q|}7+3)oTjVYAY2mz0*At<^_=wLv`gtyE}`>3YHFemYF)FUn zDVV?A)?5ywaj3K;LFkLN|4Rx8{#~xvcwn$|hI0RV+`rA8U$31t)x{8n39GQ`cPnI& zRmbb(pr*LqjporOxG23(jz12;YWa&B;=!keF(Qr~oDuj(%KPI~7Km9uW*MQ1IB&g- zm&oJ7xXj};jdl4HoDTEBjVdI7`}^0mnNIAF@i1VAB)+JI!Tg+&{!a=tsd)iJ<0H2GSFO)mX`?&^Op*N}o1Yk&sfCT)!;O_wHIl@Y)CCW&^ z#9!2*E9O81b#f&OzwkrHa9S)QAS*4I01vRj0UHjM_l?M?(Dxa~!_fX0j56*TDH}|F zzGseqZbO4V0DyEQ@S+%p3m`6f?6iz*R(GhDC~1QaDvJUE`7sjqKHP<6EY`Rn!z9nx zlUau^9-%4H6em5ipVr=AbF$j0# z!h>TX3D|emG*mu(Rxmq<4{r##xJ!BT{hrF$dL7fV6{e*qq8iC?>oZ*aP_b!fHCyN# z2tmKTwN!uey6OB)9nJ~6C^B)s@M0oYjJtoW5g&|6n)pwFkQ&EJ3AfTgT(Rq)_m~a_ zeq^u*DMJkJw&|E;!qe-gpv@J>{%O8>ABT49vjhLWO|Z>q1ueph8>l_*mq)0n0GlHb)h5n0>{Ii=EB<)Lpvg;qbL|1)}+0>WIoDtx2|~8f6q# zn6(-UQ#seL{|zBH#)wL#0GXJ-(L?ckWBqE)QB85ygL|P%*8;9AA>Aw z3;$slGx70aIaE+QDb+g*Jy*{p)ptWVLyd56KcPrb9_NY*iT&8Tn6gi7yTDK<^JR9T{t$f!LDUG9U}oaSG{yJ_6&zt9{ub!hX3!-4$7g*$Ec3)AKn@hLWxG}cn2nOuUqy* z8R3)i#xzst*`QeWsPkZ=xm?eXuKKrZnM4W!l=18LivHbM5 zX5R(gLpY`=zM!pMuU3YiDi?jzojhZ0ANfPSo!t}h2KD$9}Ro1h@$x@D9Nko%x$A8fgdH{HcyuYf=&Mn8wl))U%luydN zSPRz~O3W{pRZcz}JMZZ$O>L*y)ICq^V>f$Ut=aC%ut=VhH~nHz>oF=ed&GiLm%4Jw zV$YNuuxceGIwq98R+9c{&h(7$2^8J5-vi2;IwyR7llfkEvym~f)wH~7YZt;!W*y53 z4z4jSX(ta^A}21Xv~d@gw9|MLX&OP`b5S^*LY}0i6HT)W)P5;^RRq01m##;krE7po z`-MAD2!5*IcR-d{G=f*|My&30A3tN!4C2=BV~T>8T&v&; zOZ7Whred!M!!W-~)0iQ|-3!yOK~da~8%NWLQ2vzN#iB)xXrRNF{oCWZ$AX~0>nsY= z{H~pcw`ck(MT7wUkpth#Ywq=eLs@hb3c8aH!;BfC*Kf4?+vU0d2I709lb1T5 zx8*vmFdz4>*ciUYpakEi+-1}{f})j<+sxAB0$H8{n5?D;#e`D@g|Ep)qzq_bEnw1b zXb7K+J2lK@Uq)S+8(42cs7Cq@gXsLj5Px;j_R{=0@tZ2^o2J{@u)yH>Yw>grUn{r0 z$IIP~e;pAn*9`HBm*vKNd6oGHu~(Tp83Yhz8Bb7O&MRe$KyoZykW#Dh=6Lm2b=7|E z2i|O~jD7psF-hld{`zHtaz^?>SnW@<9&f~F?PFXhzu^46+TOWpIjWWbfn~-XeSyU_ zhS^oOz^9c)E-D~t_K*27ached1kiD6k0h%$=NmG|v*O4D<3DP8jO_#ojMSGGNvGM7 zKJZA8hCN!XmA87$mFw5qc)Vo8-sL>pKi%Dy;>Sao#aIn5yX8F$-D}^Se2u*Zg8jRY z(qs~Uai&1{cbUF(uUh6QIl1>QEi}}^9W5Xk;E*Y(6OY^BSIS6b z64&|rUN)S1C1E^YnNX3WcQ%-_uADv<&DKqmkl3!JS{(A}&f3cUZe~eD6mh$C;(Bkk z?bycl`1)P@G6;k{T39+z(!g(2Jz5|D6q07kHB`5TG7tD!(7ig1_aO(J!y!rDdR0-+ zzMfAnm5h~?wvX&J9}O3<4BVOltR=mVoMswm`W0K^ohxg0E++S$j{K&1@wuI>9kdjy zx34IjzXDqqqoGKJXJoP?C1u&^Gc4wbJgzcq&Sx!Hl~)P6fl@e<)Kd!^d$JSLn!Y9$ zByVLQg%sc6i8t}iwHo?m$bn2r2*O^Qv$h=<#~r85{;RXM;!Dre-)yn3m@7v$Kk(b$ z{M1xUK)5x9_Afn2Tp6fSXVPN9UawSR#;&;%yAN|jQGrP5C2UhZTa|U}!naJ&s&9b{ z1Cvubd28cCH z1L3q5H>s)PoJAD?5W7JE?}g{4i0r_!;MW8BdR#&(WD~B0yBp}}TD%m=;Lq~!NH{>D zuF-|+c0K2-*=s{G(HjMUkbSUlA|l|DK`Sf$J7M^_oZf40h%O?UY(sGU~ zV?{&YflkyhFKBX7(B&1mE>~iio?%RgLjBGto*Ua$hJ>uu^S+^u8qBDRTOIzje+)4nu;)@sWYv`hdA&{Mn|u`vS-ra#?89KhW0?sI+qq8FQ%H_ zoX#bZ8Ho|6l3Znttg}XWe}F2A4JvrYO3}0Ts!cq{GW* z3t~}Tk-D;ygT*o?+Hc#~{t;70<+I7tZ06O>l==Y2b#z!*jcP}EOrc1&LZyt=K<{F z?_YxdD_7vV!9oZLa9Lj7{d#N~aqFF{&=!u8O1>L+4wqhP{Vd{3!(0k;##1k2M~wV7 zGiD0ilV3_`P`l|}J7kg?y6_`A$|cEKRTn=qpKcYCz#tzEFhs03rG^Ptmq<{fnG@QG z4HJkX>TTW{$E+(F7tG&Jg-nsiz-Xtq{sc zJzWBA41BIt$0{kFj(ZwTSPtIb?KnoPb&BMj+|}e|GxF3adEIE$7kK~nrPOikj(BLb za>had7oILgtsl%m;5#4&rYla&bgC2e&PU|%vIC4oaU8SidBH9|tK*$iPG8Jq67mis z{sl1Gy*Un)HBOZM5DtMqW@V>7;{#{7)pP}_Q>qMfgKO9WM5W`_G@3@q3b!7YMw6BX zY6C~qI8uq8e1>+8G*h^&0hD1cvg)xL5=7p3#5!9z8F3np98t@>?Y`4@72wGGh-qhj z+CTY-ye$)D@0EPx#p4&^CXJ&nPkwI5JC+ zE$rc4NUvWl;&%P0xU2F%e@7H`epJ=Rg2;+BBN=GSV?${}`Y3T4o*rT8OIbOlO=(+j zYOoLKKTn0ZEin?ZQy8}6sf$mzCCR}ME>^@4W@@{9tbALsH5P47w~sE%*V&JY0Y z%e`x9>fl5Xib(DTeo>)7LP83)I=im8ahJgRw642+X`TOJbIxBMiL#I2hGu+6Z{u?_ z*VTp+^3s!yf+4HPqg6$ zt2bRE2;y@-dkDZe^>`RcLFwB|K-$SoiopH_U+%XS|7EVm0^Z3=)Gd1zwAgjJ6T zkQ5KG7s$4=KSIN6;d-pSsU+b2C`c%>fZQx~6lAZ1;`8vZlmSm#43m1sc^uTAn5hMC zi5d}DiTgpfrg20cG{feqRd~P6`nW$ z8P&qlHZ`$aACs2J*~Vo)v3?K`l3S5=5)hv=HL<@kM)z?m2SMOZCbjIOUo_Y>%J>S{ z?T$s!_mZS5m%$l2HoX5SX8c(KAq^T0SCIgH*O{;(J@wQ&s=69lxe?%X2!2yx9T`;+ zp-LIYpCt#~-OI`vSkn9c+bLcnBIxx8M0Oj&D zuJfc1x~zBpc|L&z*(%MBKC6$3fE3qe4mxaG;4hio<^h{=tgAqX(EX0HWz@Utn zIl9GD1&#eNBi`|FoHQdhpisS#3HYoa!L-TUy=&)-i1&J_6(Oq~0wcZR^9 zH&p)o{w5({$X}lf31m$Rt}q`6p8A9AiWR>wIxUkVP(=dqZ?@qY#QXOdKw3e zz<05!!tnIIepqCE!3$ot5-8q?nciV%Rrdp>>{R1(U1VUxZ8hB$=w57i$l;$eLCU7+ zaQVb*zO)ZcMTkL!onK*1^*{pv1r9fQO{-7h<2A_*4xZBdZ8F#QSX5~bN!hoXUmG1H zyv)u-+6aVx5s66gs(T*`X5F|BI|dnE#KlfGFt9r~^n~@VNQ$O^&-yitnGafV>X&hB zzR-!;z4kkfa@Cwg+BB@lLnBIr!(HyJLkqPL1A@SW1F=7sQy}Xv>ZE27Lj`E0%i#*Z z+h|7;>;CvA;!~C4LAwJ8UX>OeZjFfjLD>7wanFql$vx(OMpZQaiK;NzR`bWUqeFjv z2w*$T+ObJ_$aWRYv}AxSb&g_x1EG2+z8}U?%H)cfw-yQ@f-P2KMQj~MwQOa#4f_Yg ztXxrTxrGy5nM_NEw3yD}2X}j=hj*M1#Ut4_h5tpSl>U#rNI9g#lp~)}M)A2g|BN4H za#ob0xEBPQomm05!d(2BsmXkKB4!$6c2H?@F!{6LuDi3xlJb~}j>;w` zE@SPtD@9^36iMxTRv*i9vb?fWu4%4PK@A18A1pqFHY5?JDwh*cMTDzonBc2 zIMfuy!|_gjhFN1zt-ZW(W@qDu63TnG;E?ZB6)r(A#E75-(o|5aJ2+M^QvY^zs6ypDI7yX= zP4)IC!b(dbiZV8wD#4zGQzsqKSpMy$zABWO(iQ3B2Dhy7aWyEq*Aas>{VY5aQhiYQfL?3LJA2y|1p!$N*4?tnohKX7qUffCE}<0fu+ z*;54dP8zlX^M2{T!P#)Uu%qol6Jtr420dtI#-r2kKA;-qId6^{ErgB9sv8pxt~dO_ zXKD>}sTzHW?5(CoPh{amHq;YF<+zgb#r5Vy0nvUi<9-Rt4f}O-{km%Zbd4-;6|eP+ z>pNmz^OILxVoyXf0GxQ}VA9BL$MvAyqk1&e(9%;*BnKFYyfKbS3wZRxvqo|I!0PF* zU1imHE?l8~s|;FEL@~|FZHhEAN<`~9f0~3xz8@%K$h9k9p<#y#zE@mPZsP!{#SO{3 z`OocvUlJe1L9b)6DiJZo?#bj^>q_q0aSc@wBtQc`=5 zUmp2wo`t)QM#GJi!0%GOjmu@`c8gu++apkb&wtTMUam~9ayRWj>Q)i+QJ}@d77hVNNmchZeylys#~`8c zS17Uj90;#rzzZH$A3f_q(5`?DH*GERylG#ZpN@L3KdVBHnrQpZ&n_PlqG6E|1Sbi= z&wUImDD!E1wZHhJ7qQ!+Oz-_qWFxM2v|bf^O(P^)ab(c|5YjgU3-!*)418UE7do!r z65m$?vy(cXbc#N+apym%>T6#;9mXw_=a2!jvb-D^qJ4pmwoaeV8AmUrR%HYo-+pEa zX+0mU?_U6b;llTUTBJ&QS3CK3@_AHzlD~i8?oDv#SIAlZy>kK`3*jwyzgsfI z_Y}8ln2RNu>eVTVTN;1KxS@kdj6oildSc) z_m8pa^?O9kG}10~hjkz0dulUf_H{?@ji^C1T;MUf}9~(N%m!b>(w)S{>*5= zYV;t;?omR&Jpr>zP6L~8KNo@a`k1u%QgWsHq%=4VsNV1L3nt)2W3BH@8yF$a^4ZL}Zzf6?IbX3o#)2keiDO?t(W1$({cV}^;iE+qKfPj0H5x=b1SD(B&o3Zs$bmk!Uv^T`0l#73p7*&6S$Ude`gapMlN3zyucuov5 z)BD{8iM%N_++TnC^x^h*GQDPlslwm6rCPU}Fil7r)P9ZiPbxGOVYkg*-pfalLBV60 zY!Hlqao`-I$uGOe_=BQA34ZnOf6D~Rs`b!;ujzPYSMRqybFEal6{ktU?g`|#BN0-8BfqpU-v_uhCp_CxbV(X15H2 zuV$52_s(xRU6PPG)U7l+TE{CZrj^w-mK`t^Gg(47CKl2es7*hDAjn$`FIpDTs2>DAh#U`ER!P0PC8Ixo+$o zSu}~is5i%YKAIfpK0Qmwt$Y+7FasSf@=39rE6p*kfODF)pTB`kIybdbxeQ;w(~KV1 zYdH2J1u}VcLt7bwiangyoiqM$MAm`3HMNAZNSy@Da*%#X!+!2q%3+BcwZBA3Low&J zO+e_rCUMA*gKIMre^IN{|EB@N1!eI^V~IxoodM`5v^+Brzb$KXt_G=Sn~(^*oy!UMQvb?JO*b}BcI>^HVeMlEhaT6{;DMa_A0uqlnLs|N$F&<9PhDw2G>gvhH@ z7InL22j%DX@cGy$Lv|csBw&5-Q(39OHEYubBb4<0-T?nxj(aCc46;O_1Ocb6c+HMqM&aCZ;x1ZdpdUFPI}&&)gTGjl&R zH8WMz{?MF;(_OuL@4c?IewU9L?P$fB&RVBmUHow34U@a^X@M%r@4C@AmO89-vs1P8 z(dT>7MJuL_k+=h6d?u&uPi`4JC>b4R#lPt-kzszptlUg&A4lCZhYP5OvHzA)dC_gC=ZmnUW(LhnjRj|13zdqzS_@9*QT<{(vrrbl5U) zIxLVmPNZXww@lHF5!ab%Pf@yZBn}PeI)t?h1Gl|(^Y0dFA#=%yE<16<{8=CI)zBv2^`UhV*B~Pv*apJTFk2ZVD4DLN;aOp^_HWl_KQ7CDc zbsDlb<{xLXu`F5qNs~pdqFLOh*_t}?QeG9|q*Ko9vA=~<)>mY;*^YL}Kd=4n3*jE6 zMLR3?%eB@*-FkZYUO0B#hK4l*5}iYOHYtPx?Hl*SROS{`;UipSbWYx&_{@S}6SHw| zErG-m#Z>RxZ-qG=GET>)+}1$oU7t*t*~Z@ZMIs#5F{)Rq7c6eT*JR5T1(A#z7yDPN z{Clf$ZBS;@lJ6hBYFoa%uV-9VXhe(9)8Ipf0e~OT(iNwC7>^H2%YH~(X>uEBMG5Mq z-()-yJ3jM`$E%_oy|lw*NWp!pc={+>=O;ITHttTj@?XneZe{Y#oi+#h`yDbJm-=kD z3s~WcF+HAj#y;>%Buuljh2ME0e;S%MW_WtvJ-7jGXIT{x3{rn~?e9*z^|TgsIhCyt zXux7+Z)sr}J>k)4`B=vDnXR7h}?AV(x#WLhAjV@YN`* zib}TgktO=AE|j2pSMi{Xlscnpluo}av)R%L$r?UgHWvLE56L5xiL{l8v9|qa5`#el zkN*$f$~zO(?ZHfFl&V<~&)3IuPKK81v3NdI$*(z<>ps7fp(?FlzM5(iOL7_-cPi7} z5wESCmd!GSkYR?IJrJnX4jEHjz%iHRs02DIN@hOq)@`)H>u)D}4{E1XcV&Em1GrQO zKYft+3V!Tnozu_u_6KPn6l9#o_O6YhaAs`3cYCH40hmqi9I|fcU%1?1fUr3J=}08R zjB9+b))xC;IUO)doWk7)$Vk3f7_D3$TYYxcK!Qu+->dA z@g@@6oe7lZ8rC^6te#X^fAXSqoNh$ocWQd4gS%DNld-jxs25XvXF7X@J1pr_Xmofu zpfCr_^6uG`RH5aMBw3^p*{n*YY;7$Sgn~<|A`4gOc9UAl_tA_q?fx(Kjw@jkcrd-0 zjnY}`!PqTQ6=kxEbOb*IlRcMq*G96yFRBzn6%PBI#z`oj{X_P-Ayqj?WS}o7pSk$= zH}{(R3cEjLh+fuH4^N=q?2Zp&Cgki`qJf39G41MAAqVBd$4Gg4)f75AIP1j#`7X7eK)oh@T`jE-ew zc;#mx?->-8_9 zi(~wU3oB`FyEc9#2rTeJb(f) zhF_)KTf64rW6*0+>f(z~9HQ1K*Vk-XOVZE6ge9#`$}b$K|5QA_jJnaNaFCw43T>#N z4sX*po19w{ShjBWdR{HBLWtBXLoq^NPUBar{32BAbBA;H?CIJ5Y+gDN9~Ocn!+ncr z_CB1J-%uM~7Uz&3qwO)2H?$K4+pmhIVz%xNXen6wSzTe?JDCfECh)!S$j&T&sqQPz z1=d~r3i?=7i$lo^@nN!3yP)BaO#h z6DA|Dq>ykpSlG(0OAl6eUaA#rkNe;d^kjP-sm5M?!|q5++s{9C%=zI_fpQ5?p@{$3 z^*bZNnCCDQxL1mBu7FfZ8{vA-n4$z$TF$l?es`v*drCa_H#o-gk3n;NRhGB+O~MkH zgkWy`sHAlu6rsL#-hKytOw;}Gmxjw_0^fEsIe>(VA7S`4T;M8bzEWu1&25gIa(8?e zOE60Bv@~4%f&0nt-79?^*?+N@{x8PBWQTlri^UJ12=?4^IVn*mEVC#Z8xgW+hNiwK z4?fDL?d4k7dESF^h1&X9HTdVQ#_|&gkFut3y__8S>1EAv&VtIi2Xt&*d6*=8_~$9o zm`Gb#R99OG8I8H_LDaS%UVY~&AkLQg@$S`m>SytP5K;eTbZ^LYA8|kjp50&Cj-bJR zU$EBx@>F3d=dE2yi;L^@@~l5H;#yw|oW}o1IMN3%pg74((Du4B`aM+9B8gYJ!Zy!D zK=N!igl`Y#{l-FGo^RTE&wuoKtT4^1+82t8HhX(p9njb1{r#=a%W}JQPT5%Lja6L@fAF>saWAKPWMe@%*XCV7%wI;=kN>CRjpj$9 zIey~@l^?Ugrgg~ac$js~6+ZpHXuZ~C8@z_rW9sS8y4+qO-pLGpSz_FIucv+H`s4F_ zT`!<3XH2U}Cbxji|JpKarxYMj-uj5rVc2YAleiLpGG)x{9#<4e8!|1D(BmrShNbal zhi&9ml4|MPbHO6NTzBNK42!5jY)xcyQ#kTR@g|;x%-dEH*i={BhjmYf{tw$HMjzvI zVVP=N*Rlq$4Eyyve|H@+q>JOfEZ?s?0fD*``-Pc%$2{=HOr}bXlc_N7Ar;V4k2AeO z8KW!|Qf_HgMcIcvl`UV(%y89f{dC2Tk8PZ^_SYSS@mJwRevA&k7lH{F{6#SNI!F%87n|QfS4UBKxjK&K@QCQr@pdI5~CNHw! z11;aH6LD3=K8q%T1ek6u23fxFvgJ%AJT4uT912>0?UFe?&{Ir79^o52j&TG4E4J!;$>ETm1r98%%b*6P%{pFb+p zsb*34aH)H<_sm>1R}sa6qEIra%EJa@5WdX>#ex|>C+VFf5pHpcooU0bS|`L2VM;l` zF_j6QI%MBxyJ~m(gYWhG0ULt0Tv7rwpkA@raJr{H2Z50`u)hlFw+Tm^5dqdp+lr2TJP@bPt8 z?sT(C<+B=O6PrH{6M=M{5ox(;s{MA2J+^7c6{B8g&d!C|{)fSO^F?7l7dVo=u)jns zRN*`&_{A;I)U;qXcwh6D7r21D^Nv4S_mxZRGWtX@I=EkAWVGUm#T<(YG*~YsNmNyR zSv$rBzWmfIE#yylI{>@zQ;Acw8fmIqHR9Q9=LW74iZcBS2Q#E~J>7B{^+JX_qc#Xx z;Ehm*{D9N#6k+cmMU@@spO+neKbBq)?VyY@wyPzc1&w_~&k_2)ol}ctHoM6qtENTy zhrK7ZW!SkrY^Dv4rA%=8U_tHd&y0$RsBurau3qnEviG|cLVxDmnet$*!HwA%Nh*lJ z^2b;KF<1#IE)3?o7@MV>+`s954wmxoL<*f-QUj}9ryoCS>UdE$n+HLt%W6vFfiRNj zJI~|mLIJ@OP9cpRS2I+QU1OiYGF>0uNdG`ZJBee>l|;w+=Ww^$RN`w5KuQ(4HT#yu z%jS}&e6C;4m(KsOBVFG!vi~WojH*bs7RIM7EBEqHrYDFPxmm47X@^P?7T8T0i;LI# z7{Zlu@-bg+Jaz^gQpW`^2g zBGW01(ZjbI8(|b^An*#cdCogJ2kvWl_w7=UbC1{XWJ}XyPY)8p=c39>k1{kC_~wnC zLgCeISfzT)cyyrK#$uc(i3FSXhh_0tRO&$zo?lg={TxWV3JFamwLw>1Cw^UbsoA$( z){k!?W9QKHJ8ke?U+UB;G(BRo%_$Z z$%;O%Dyb{?N$IOL4bDG_^%sdL_2`lLT(K>mtTS&6%!VaKw18B!1OD6Zp4{ujEBo^TZRvC zzkBt_U||*%#BOhNf3lD%WcI?j?GKWzoYw0*kCzv_P1^|2I$ld`LZJL3xAkQW2pboDKM9~w{e|ma04(VtVbu=aPUn9H0W|zW4xFbGLW+8rqgU<`qhs2`7Pih;{G{2 z=w0{m-qoHPLy{yp5J73qn@_a&{;gBGGpkbkPslYoK2F_DMw>cv?9Qa;=j^*_@w*m| zERIhJpUNho4=U0>L)mV23sbeZc(w#NUCnRVhmUy5`(Z@cbTwBiT#EV`uGO8tcZ!DZ zNG7Uv;mPMrvfV5md0WNvU=w%qwZgVDW=g+Hw+oje99p+9iZJFaz@jpdZPb~XmvK;| zo`$$_I?oY>`f<`&Vn;1uV*N6QZ}w!Wk`RhUs5{GY4+kNc?Z7W;J53IG2U*$BSgI*= zdSYI?jjwe7iWy%i>s!}Srd*Y$lu}3ZQg8OIjOS)BR%>!+c5@DeFKrOdPwEyI4yOW# zfr^lKV}&N!G6meR(XMh54KAQ8hK8dMJLY_>CM0~H&%4FHCr-h(tWBzxpf!V~&3>_A zAdh^2IE!h!+u|dRa`XoVFMypZ0nNX2+qRL2pJz6RKj|WZFIvLW#*c-%xxKNyq@Pc# z>61$F^lKkx+jljnJ81oZ-th&X@bqN&>BLajFTO*o!HNgllpxf(B6#rlj2gaKsYiV#H;u#?-{-T|n$0n`>z^#t1v1>rYg9bmG~}PYr^6V1)OFW>gf)9~ zKVYr9`Ftq#tBQd;OeKYDBi19kKTR(yZG6e1l!`OSu_k*ZrGu}Zus7xcv5UAqn^l}$ zDw39H(rAMrV+35P4LJyF7+@f;&L$cveh+C4!vR1{Ls>DGJ;#$z&5LCi0nMOhZ}aJ& z$1*JR$|KUqvD1%4OJ>EC&OK&8DI%Yhq`ZPw&OK2_cGC|So}^mO>il2o2R_x1{9D+v z^Q7%Y3a)F_3mE#Uhb1!=6)i<|>mttzM9Ac+_>>~fp!KB7@`v`*+{&L@7tZY0_PLe7 zquz%HRKd+)+`oIW2+I&&c)(@%xymJ9+H19Xv;0Ao|4sgO_Rq3B&?oBBC)TFENl?4i zEfH!rU3Zo49GG0%GhMtaC1KwaXtU+8$v7^?93!)<=b(B#7)c z?}{Ek)I#rre0ggZYIGG>#mtH5yF}bw*NJC-E&i3or?H*7>gA3PiT}P((w6Jf0Gv1R7@kN|UF_CQ|QR%SiPf0NC)0Mcg?&_GMz(p3IhTN)g-WE0Z08 z4@F2w`Uor%yZ*sWmcr?QFy2GN*NT_rJIaaQmoALe?@65u>VB)GHn1*P4pbVMn<_>F z7Hrl7=&n}3{Lq!C_P=3W6|65Y0-;Ph2X9foV7}QSX`&e}D`R;QfLmM7NNi$?LZ8dK zGod%L#Zm5eTB*xwyl zruKvvNi)w~Hi*7*6=ocDy1DcSE&JF4N2;aTagoGGOgdW7cl`5h2a7AbyA(+M!+oc( zhCk&@LOu80*rOvjARBLkDLG?<+n$&F$h=We9Pkl0qJ5W(rzStK-6(#B`8mCzc?l@J z(|;dpG2g0h7J&`;Knt8f0S!riH+sLxf;f|E2ckK@Lyx;~Tq}h2-lVRh;qx{${^G3Y za0CGPbnG`8LgPJ;=*#DwwuF5R?R(J0%oIc3@>8SJLee)An!}VW`)#fi2~Jn4_gUbY zMY_ZLf*bwvQ;XH^fk@oFj9a4}H0@cbkdaWn7i02tg$t)mT<CPNBU461Bmx4}hXFREEH}^K+nAD0z5z@y9rU$mWj6t%M!lFC3Za85u zjPS4Z#VRo%ED$DOHLO#BGuJbS&3CLDs8Q$U88a;$gy=KN6!5!Ov3$lHevdyyzYiji zy0W2ckBZ9;8sRz?>Mbdb69FH8egMQLUU3;OeyJ$WZwV{x)bra zSZxjEm6dqi_b;2+TS?Y(!@P1bpZ2&WmXShHZ~U`atKU+Koisq}&;f~Fq_2=yEx^za zc^Ipme{K1(Gy$UFm+h))yMs9?ko$aM&Ag9{b%w@&u0W3hXq^O+;n}wM!cHRER#z8-VDFPs`{b45fai;>wm+9l$ zfad|xaxMLw;gjJ-7{t_S{VKy9derM%6?bIt9$h|p2B8PPHyD$=vrS0GH%-(*2 z6)HOoIH#rFJUL$Eu{JWa^%qi?Z&iF3w&WZ{VfpO0!>XRt(3Evkt@<~#s&dNi*&F(- zg2^@LWNVFU!jmC9ZFt1vk>4a}#JeBG+AD84?qNI3AJhfUJ0kop_4B64QRT)&2`YXB z%(#g3>wv1;>YX#FrZ2BuL()g_g6Z;qKS~xQvwb2n&f2jq2;q_*t5-Rc;G<~|K3jPc zK9lw{buWlwUDI4ry~rwzgNyIIab=KwL6+-jnQ4v5IFIc(w}+&PLW6tn`n(4>VH30u z=^S+j|M>mJP(L0Yb@tO)Muhk%CGy99{O8plbXfK^cflD(KUZ?4l8LanVjoh}XU3e{ z0HDSslJJ|ULHmQ5Vw8lz+Fd6)3QIC+c;9K*d|Sn7s-*3xTY5Bj0C>q32oLSr*x2}B zaxqB06*>`lJnpftniaD;riFD!S5^vm%G|1*#mp_9%*Ue&oNWY@udJM(?pMOPI-#!M z9H_4U#5kBYVb70`rWrMTzHIFD-KbGR#t|Rq{IK~ci}SI!u5e1>c|GC(f&U@`_Sy^xt>@noOhJPyd&{-l8?dodX+Q8$~zj_30UvB@LU4^WDPk{Od;&qVRSixEAI>qmO z7Q#(dtl9KswpG4xYMm)xMcA@gw>mu)X0D&(#oi!7Z}i&nGPNP+ceytxrQjR}eTO-S z)Pc!t4k7J^(Za)p->f(v-pr{L@d;kjp$ICxDSh#?Xt=UhvK90_48-eDOHCvkh5vL+)apV@3n>d+?aNW>?mc;6_3>XwOwE%X54CVVkV>-_APz8eBLP!-TV@Q^?o z{qF3CO<{qTQu(ovU-g{wZk2q@TTJY{^mCClEZ~+a7STT2hjAEXg26 zP+C0^*5-hC4tyrYo3N|wT)n&(0|5JP2H{N^*COejigT;3VWAXsyrx$Zt}igZNe)mz z>sP(DS<{R&Mbq4Z%k}CuO59C9GTfI@HFwrhPp-bp*K&)&x9bEjguFHtKH_CtXS|U? z1Ekqp?!mm7XTRV9A5IEJ-!sc4xve4Mp?bHXQ9O#ak(`%+v*PE=a;-@XY#VI4u*Z&X zG!am^6&bt@7mA^Hgi$?a7+x$^z(X)fo>&PaA!Yj? z2`=Yx8{UAX+`Z5Hqgon2VNYM8u{mQETt9ce7N*ZAU9NqvWd_?+QUR|2j#|GaUyh@t zO7_DXB4z4CN94$_@!MKuf3bg$sRk1OQBo^CM{%gj7&+2mJW*$n>2MB`YBL+wOW!(Q zSU0^V^qa9C^sIPd(n+rNaNg>HC7d(wnOd~lM7B8i=RVu-$v955P$<@ujA?0vxMZoL zOUV$o$bBAGp7(6~PQ%OU2ma6j1h;frbp=)(SpF#D8e5(7PYF;qBAiW>dSBl^j?d7A>>6&{Td0`)mUqR*3=J7ti~e7!Yf473#|u2&Lpyb#HS5;ct1c&I=v;D>lLg3iC|$}psU_`bh5wcT6yze}K_ay|G;#zKhbiIf^E(bX`Hgoqga7 z#=SCXSadxH9Wwh8{R;a8IWY-ij%CAEd)nh8W|#=-SeA9Y^oeVdT&?%mY@!{2QY0kv zf^9o&4~(A1rJyrJX!@ ziau?mWcxjwUZllUbT?Y(`go)Epkq~^lb7L~7c5Eti{(X?boIT)K*)FaejUH2nuiZ9 z)eKqaawue5@ZMBe5k75l*%%g}lG)@>;v6vJ?2fbxe`lBufLe0<+QAdNkNm_gP4a;V z$iU(9?sJdDYbEyMf!@z`wXeMB$7;QKWv_Jxmsm?vV?eZ4zFx>#p?y2oJ_2;Se%0zS zyV$W&uK#9dJC3i~T@hXf^SReK^28AcePHbuwsgI-aKm8 zde3x<-qo=MkfN>48XGNM&j5<9pB_GU;aL1>#)n}xGv)KP`PQ~@kK~YUdiLFh0>y_# zGl67TX@OCoYx&g^)3*pbfTnMeR;l+Bff0=7-J02jf}U=JC0Osj;+8URn8<^@YAnyk#6kKqn4-(9><}iHGhALmdOpo@}R@aBa4> zSKX=Z=Uo>R5&A)z!6D6U@#-?(7Mt>d4AspDIw(j6cnc*?wJn8(r%NBPeg#}?FxkgI zi)!E``mi`IE3Zd0KeiqK1w?wvD|3DFp@{*up0xu}V~!I~Qcp z=|t5;bbN2P?Z#3QW>n(SI2+_|n^fhiCPSfbhcSg6XFoWNQNY@q1uw^`{7Yvb2L=A| zGpd5v4_&d+sj)LE=_BD+uFL3NHD@3A={jVDe~daVdr8rc+?P+lT4W8R89xp5equbh zPHTLpka}Px8GjQ~V?9PyY*eN2pf6+rBD&-PW~!EyI?o=EjpC606#X36_LE(7>`5VV z-d(J&`YP;MTY6|J|C%HxIOca}seWzPyM3Bz8TpLV$!W&Wg?Oq)7HhY1(4{ zO!1#<-Yl!y>-D`UN~egB(4p8@9kF;BXuRF}9;;+2c@uT2M#oEh#e?5%0JW?5)iRQ? zxm>siMmK!h2{ta2ayo&A-%VcnSAYaYb}OUJ8w#t)xAJs(6^rVHJM>>AUm0nX=pQ3@ zQ|#rr?);oLl`|B}Fv~A@G|Y;Q;8=>`W(F;rHYCQc_C>bg zsZ`Yc^V&HFuIe;DJE{|fxrdvkdP`zK0x_qK397SvSAik!1%I zR&VaGcJ;adX=fxC7_T#_y1`OP%uTd$iec#Z;pE5u4Pank9|8cI4-v9gtQ!3sO4wnyRwn=sHpU;v4YHluHLwTa^&JHD~8eTUL@ zhppqrHrg&`RWr}jGD;J_xJmwPV*6CUAm+M|&htr-l-J}4^%R5gVjln;OzP;QOBpJ= zTcB?}TE-$KY9j!Ejh42R*vF_Hk& zMAC81`Iif>SYarLQeJtE-AVtou_yeIRPA398023hF#NwHuvX`zodwh~G@tH`>Q7k3 zqilMO=V|~~ZPP{O=htB5C{|ij73emz(47D<`fz^FLdlwP=#ryFDuXF|CR7(P=v{45 zpaU^TA_D6|P)SSTlAC(w#LZA4^T3nuhQ>TR5SGq4h8u0cx5=?In$-54;vA?L<-ZiN zV7tT)ei$>#b@}xHx@+CDdmZ(6SK5KX!jExH$k7<42t_Zw1Bq=;7Pyy#638eLe6W7` zaY+^%u~%y`*ep4oM*Zoafz^m#vi`~+PV!?)cDtOK#K6iGzA>&I)GP-dGFNwb$`KbE zWcGljW82m&lND;zpt>V>_Qo}l2%K~BCY%d;(y~ zM4J~zg6zzsYAPZbc)qG8P_?510tW8Vb{2*ER&J0qZrHG$a3fz$zyZ6bV*UG9E4HTGVNpY%zZv9veUK7O|3|HATFWq?0xdsjN z3sJAdIyo_TS{oYnjLjB~<+FEmr}~uk@QhS1!wO9y;*Hpe9xHe?F})hOCO`Eirc{iN z*N18nQz#_b+@#9?D<%v#6vr#gyYT_<>u)clP_!Tk(vakr^#@;el|OOMb3!{V&iy)vd-qMozJjn*$r+zXORZ^zWA|DQ`@@4;UxP zMP!<$nwd>r>9_cOT)AUmDe|`0Z4TerkDyETE-pd(L?69x96}n4Au@odotgNBsyc)~ z?fs{iJ^z*}xeIPoFqa#<2X@zEnR`Wu;4{Z-GUDw0t(+f00AyW1i@X+CgA?iROp1-M zzg~GpH@XF94>hKJ=jXTTagRb1Srr!qTr!GRW7)$YD=Z)Qs7&=zNdl&e@PEq`awE+N z!?_~RLw{CE^M*i=Ye&162I6evaqw?SyUICFs!bD(y?*=g@ym*A%>CA=e74No7~ksz zdD0w3>i9s(i`Q_IVrj+srw82+($kl?Qfme#f$od~&ei134|STXz$S&2Zg0igA0iLq zl5R>4!Kh{a_K+_j0_@yqKjxTS& zr>b05^*ddfopgXyP~2n;ABl;0UlQi~JT;4(@ZY|H|LPw2Z${LEdP!X0;7=_I8OIgO zi*$m-$i>wi{JSS7$Z2#InvR;N!1qF4Td+yRedH4MM&zG^YV%=-@{^?~SEyK)B#B8Q zV?g)S_7Csfy|7lvyk&)i9b+6;g651#=Eoti3YAY<-cx)0Cf+|k9H|DN%ypoDe{9(I z)Hv6kFVT0Xv{da&6%rpeH4s&ZW|y{Jc4~@S+rJT%{S`EqNL>5EB&&0QgqXrU66Y)D zGhL5K!Z%-i){Htm3KK_)&QvP?1BHJ10U1U_GkWF}nj5Lm0pX%oi@Lh}vQX&ep20#t zMYEi6&NhvvFH9!BeWHez?(Ry6s5h^$@-`@Vt+gNP>J=A7W%bz+M#pahFI^Z zYQynHaM=#BQ=T&9bF*4TV89!P!=0A6MX%jATBE)saJGteNg)QUk*L>P8^-~cab{(I zGgmS(DuKnyM(o$eh$#Qu-xuGQW6pdkF&Q|UbP5!QU)Z`12=)(<<+v~Y zqasHr-t!uqgnq2SK7l|9T%}-|OK}-M(1p{6P--22i$ycTkLL&@nD6-hj(+d9F22)& z8isPSF;RqDLv?;lRKcX$0U9>9yg64mbsU-4w{v$i*`R$c7T1PWcJyzc7N+ND z3G3bS&hV5>dC|k9of(!r$6vf4k7`HjBxHpg3u0jWra6{Y>cOkF%%JzedrmxB&K(^L zEPWBOq*$M@Vtch;;?QuDIeP-CSdY%$%Sv}=+J1As3$B@VhK1=ilX4W^k3|{JtJ|%# zB2*MM5R;OfLJXN&Xjw?UjMAZ`jABYrddBgahxDdLKi~HusWS9;9ts}?iLhE2^%Tt> z=P0+~g>5|?VNDjAY6L{7mYQ>TG7?;y@=nO2*19^iNDXGiua~SC$3;!sAePWMF$wwBwk`fGQI4z00v%~dork0o60?u|iw_C>_ak0YKi={ndDIRLu z$+O*rJn(ooShfKqB_iAzy$F4^Hbv`t5@`^$~%cky}HpN72CAI(r)c*lsFSA~BiZ zT(;*|BPOY_wAZ`IT@*Otk>xahdGB7e!j#2~dxIKSJ~OqjAmVJd&oyFVw3oU&UQ?(_ zJjJO9G;vdS<3^C(1fiR{Npo4LR; z9372@)g!*z4o=NS^ zvhFfWNy)o3oL1a68Y1-fvc9AwEKEb75)C{YBu|^r&5ba0kj#ML;O53#T(~FVg7T@{ zPl2{S#rd>|VE{c0$1PKAN&U_*N4|4uN54yPbT`_vemad8RiZ@R(#gqbUkL%wTuG6R zPIz2Wld5P7ID?%Pzmnb*phklNkj5#EFIGM2B$|U^&BwHCGM$JE3Gu2ZQXIC)|6q+S zxt2QsnOqMeS4_%^kgBrj0Ipd`tyFqKBR}tzm=d*m1^VXU8hf0S^Jc$FLD7yLG#dF#C@7u&=;dDSeWQade`9x*B@2@soy<< zeoSxmUpKs#UXb(9YwV)oocKV?N$vd8|FJ z`ZHW!UK~ENY@EQ8ukcgwwHUa230vF8?Y z$cs@VVuQ4^H_Y>6cxS~#=jY{Cxwv*_88i4yyQl33_GcGyN9&G%UP`vf4d2@qxKGrC z5f-CXOwi*xDX(AO?X4uUSyJwDJ4U>F1%2wVEc$)F$D!rnfaqIB&uxi_0Ygpg)lt^p zC34;-Qkx{H@%mP;{&bh#bJ$r5z+_+{9Q>ILE{2ds4bn4tMMi?=#Q z1#~_4!+-n-vHpKLo}b#(En>>lN0dl^c*@2h zuhU{V#P!hgnU9S86TkT8v267pbAp;@UTLZB%64x$%_3D~(qh+7420Ov5O{N?u#0#~ z2Hp9UK4vHbisPfWOQ=>h<@G6nBka~VWV`G#f3-&^B2)m*cdc#=RkC1 zfT6P#C_n1b6S>fespEY=?U~5dSb+ZT^pM{$VQ_tuIw-pOLuSc%?r1)8j`w*9m;Tw!hSZ*3OS&)iH>M0JRHz`CZDdP6OH1l$oQe0gJSz5)_guB-0%mtN6z+!l73s~s1E?{q-b*MLLC zuay5$->7bctY1X3X>az!-4^YRb9#zKYbRf6ogfw#ZIF_;z&0EG`x}R(Y<2R7;}X+@ z{{9B=ZyVVOdm5>!2`aY)Ap-xOz|=gaSTAbry~IoQzFt*X=M#5q?CSwfK?9eD*a+Tl zffQw}`HwACnhUzwHc!y*lG?Hjf)bvRIOk(jQiLZT2P@n1CGJe($Rn)hf3)E?+*0IM zpcodnjqyD`ImYWaeAORVY6`Dyh*lR`~Laei~oqn|Se{AkPUjzb^TOfEQ z<&*GUjXQ(^LmRrfaxY6P^YH;PkrJUe7nhTyKcuzuT}3R!gI8hrn5jgD=dkma?W2y8OG&};%=I8b@%BI@G za@E2~jpkBr+v%w8d0a?~->5P^o@aEu+v0RT&&_*ii{H0#=Kq$FZ4Kkpxnv@<^SzFe z(@VxmT4ed7r6{Lbbeo6N@A`!D0|$ImC`|0B-f7JbmgK;~%+?Aq^>Z-p=9V^)Xj2yi zx^=@=$Oo4&nrp>21~Pa>!3F5Aax%rbX{8qH5#etORSlaco!nX>rcTL8Zf$}D_PUCzlQ%8W1I76yP z)^VF-C~gdTyl5uPQt&?)O&G*r+PVxGp^|InEaNx63v0wE->x_H^%McS}f&77jb^LWu37Tu=!XT!3y$z^D2&D^0O>>bPmI zAjZz|^n0{}UO-{lSmS8^I-fq)$L}oyJ(yITELe z%9u+#9T#6C*I6U}fW0k4p^Zz+n|`i&^dgutVOHqj{#AF5zhe+Mb-G$_U=l6in3$_D9zWzc(s9W&l;!-&wG;;`}b56W>rPWNa*Q=*XnI76l?110~z zt*o?0vEmQ}2}Eu{u@W+DLpKhH{8fbM&*X5317%c*fKNO9z*sDIv zlT9JI8s%&|YjRjYfl*ChNivi2R}LvA?+^OSkNIayh{pC4 zD-%`iFZD?GAZQb}ss(c-=knkswFv{3fXFmF;%dcVa&tR&t05&A(+doC!uXWitO?tc zoGV{@>=|6jg=DvX&BGGZ)VpqSM}J7~P`Q>Q z2;Z_KJ&DoZq`sSJ{6@NNpF09Onz7Ejg{r9n$}d^=Z^8KDtG)EZv^*+ffu70N^q|SC zLHisd(Ta+dbctUTzn+tCc;wwb3Jg{CI{Oxz&sb0!bH?5cB0k-;qv1s zWUR%~8$XQcHlqk0qK~Z6*9oTuR>-gem|z-?$F`eO<_C{a?)GG5sk%{|BNe`&wl3w~ zq1qS0zEuJ)-}#$s_#A1uJ++@^8i!8}A|i-zjg1?|gqCV;w)s$7Q$* zOY2FZ-BaGaNZZ%~4CZviD=9f3KSES04TEQFWzmBR#LTz0Ez8`frr#%J8c$Un#;5nv zQx#t)gS^frn&%z@WJN5L08!?WJ1b-3Qc+8Ihy8-ow-JCAVU2g{Df#h>$- ztbszJj5KtDym&PKCbL^ow@I4BH1{Di^#5^5@rZgMk~Z_{A?Hh#hxF0nsFq z4%xCr^aODx)yzZFyo=F{W~2O{g}z5SWOhJGCR2x7)OkB#=B_fBTRwujdG$$91;2Rp9y1!LB8y6^3a>>}QU;z6Y@Yb87gJhD%(4yMky>4`1r?HVDSPGKk--ru z&7@~PjWh3ClI(BWF)jF}4H*;Dr=dyj=iP{QmbFW z&2TF+;LoyyR_O~mYkJJlpkup%aHYZUBdr&1GGYCg7|VdToY14-+6pUoBOg*`P7)1+ zMy27V$rAMhua(C0+x*B#=h;l@pj)Pzvi$bM17~};4urkD6_s|@Q{xryCogB;Hnp9{ z<$Y81II`yrV^YU3Q%8&8?{(q*8l@*uqZv5W>SDiO<-+II{MX%7%axj4(uXqHWF88tqx6j#JgPy(u_$eS0^u+#xaZtt_c#D-Z?!-P=O* zDN=)aiVlyYru-#WkEoRkVR(y;m{Yz40kA)a{KKh25hUDNe>5aofAk;-wqeB8_)2YU zd&}c9?yNcByk?lABT&>^d$ZLr$f2?Z4QKQMdo zx1N+Ppa6aG-o{@mlk8!qp$*bL9285CVc z7Gi$&yZeXghFK$&6D&rr`@`B`(V-O7r`|8$&X$SP3QDY;X{zt4Q;Og5UZs%WH`7!5 zPY?|sIlC+GZTX(0^3A+hw~GxuEE?V~rV`%@y5X&Y9qSJtDppSD#u2>Z+hchiT&mvy z!|b_9FXkz1bD`kEIr=gLrCK4P> z=d7fTJ5%fn=y8Pqm)71gD6VLY7Cb<33k27Mgy0t3A-KDHaM#8)Sn%M%rEv`ojeBr+ zcX#*K_s);0H}mSvOx1MtzdpPA*xvQ+wbr*5GqGQ0t2)$GJOTqdh9A^hU&dk8T z#C;kJ&?moL&pzYkhI%@!*VO;P0a6MpH1^mU>EJ|x-uG1BtNPkgl?pk1ZOqTF@0|cq zK$Uc$(a=hb6W&Q~2jBF47sM^Sr8hG$B2=%$HB`Vmf5z)}o7QPdA5RQGVbDj1!Jiex zZa2-`FDaOlH-{q7o8r+BcnmxGK`*DOo;LxVU9Q37L%%XK3;O3;fA}3fEpOkSm=77z zgkb_v8+g8kZ&a{LbZ{Vh`Q1{6hP87{@4)|*a+l7nQ|?e}81PROr!8-G$ zN>IlHLx0fAJlfuV;=!?KZT*dAvRTH)>6@by?7ka)=ljtsyJWj&GaWm2E4%ycB=7}; znfr<>7A(+lfv+&0ko8~Jp6mKj+m#4?!a3@@sW9qa|)v5V`z2@TTlucAA-Tt!cvL%!(1^H5|UV*!;8)vWv;;Ht#5}ZcRgFgVJ+H{bpS8r$&l;fwRGi5pfE4DP+(VveEQk zG>7RU3}(QR@n=||QKE+^cH=(jGJuJH*1G7M(2G({?&p5hlf~s92-#15uIuC2 zI_rbg0H$}6Afs>kAXmr>=<&i@JlnaKh2?0s-j1vH*LZ_T+Gd>zP6MM%fE;l=P|!S{h?mT+*cqu z(yC#w^L|aseq>F?6>6#RYW1$9=B_`hJc6xaMaPtlEm6j6u4W;9zrwdh*B)Q;^6l;R zl)WO%`V9ZxKFu7P!V%&hGcSzKXIldW#+Bi6V^GpLemQ_5{Bi+Jg_?6GwN%Xh1|TH!_Jna zn9OQlW!251u}Uw+p0x{lE+(Xogwle>*Jv4R40hB<&7Ga8+pHzGTgJ=}K47S`u1tfT zh}u=`#UW;LtZskw+Uw0X;1b{}{c0x5Y9_>)?H*ubh!4_Go9$Ge*JGa9`)6rAbNuYk zZPEobS4QsJkT%Nn-QZa!(kk)G6Q%jp<546lWAIvG7{+V(+6raEK{YCY-~ zSkGz7lWfNdFDy*<_B*WG!0?95hxYiS^i8JPB85q~!q} z4%RW7i@@D157*mrOk4yYb&S=buD#Qcnax1ZYrC2Vh}7=A$W3)2=ah!>Q9ffK4;tmw zH=J?{8@V0j0u&`JleyQt>{LqoEp7?LSv#dLMOK4M3I@&IsYlO|hZxo{0D;_11EKi} zM+}HpU2lL-Nl&n5HN9|ZX4c|um&QuaTG@_l)XlG?{`v5Bl|`n1Rq&5hs_jXap&)rc zxrO-VYpa_Je^-(VHQ1k2kjs4R>ajZoV!sln1-rjUYzhUeQGi@-!6NrA^fwOX6p(8rPgr2xhLo_uuW4YxF=_eB1SC z;#q|_E+Os8XXx)!uw}8c=I)(6M`~tABJ?@^sB(7BML@QY(|bY=DQ?dZ15<9dO}(UKh}vk`4u@@-b_ zM@b==>V6UINv`QMkh$Dy4S(rSg!Gpzm3%%oouTHSiq;06Cxe9K0NO5Z+`%?Y)a zZ;B)jj1b!`RBPLNCy3QhxO-j8J2_J5Hh0`S@b)DX$mY|#mJ!-UWMl)RKSq15$v^ru zk##Ug4ZK}MAUWs2_`9Nd`HiEeY+@pV=mXB0$;v;4V@JMH7rmKEMPaQsA+#M?EjCr8 zegNM~F`%Ger^<)d%1EBCovN#`0wByBS+t6JRL_t}qjM*`2`@K;|Nhu{2D|iHzP}aJz^1+M;=&-ooSfA8O ze(NBuHA|Q)Bd7x8t|qk&j!iAvTFe(-tq6{yZMbo;NR#oTYoZ>P_U>$Wi%$jK0)H!* zK^CkHbn1*tXcjcRC|K&oFGahkZwoW;sh!jw%U+q;-dtRlD(ce?T=JKc_u;e39=>9S ztdXq>w43WVDj=SyFn6&S8fgbHbo5mol3%K@ZhQK>dT}oAA!=!nHZR!=%+FNS?+00a zvG~r77}Q$Xq+|uj0$VFIe11L^XiYO)1HCSt2`+p(udEqp-v6V(;oEJxrE$~yx!86? zOr_B_#@1zfmcO3)+lU~p?a)3Ak07ozmz~Ex36bH}hOO3UQo1%m2c3Y52u)O;_SuA~ zbII)X*}Rw-<9xa}9J5v8-c)=98*se5_NI969)3x1v&2J16BxNto6CXMlw?%bHOGLsaf?Z#k zx@pnWLVWwdZ0y|C=AO|~>=75v(1L}?@LdO)fU}(RW;%d4g!@=wPH%)nHHPH2_3C0_ z+V#ma0*jddt>cVt1CKx(EvXXSM&X%X$Jdda_DisNILa6fZf5NB^vUONzp=KrOi-A5 z>yrxz7^ihsjvGQhj>|in6nTdAnfHKKIHy3v3$^YJk*DEzJAlC4d!9BMq~W<-*hRIS zE=UvDR4^d+6{MnKFT?WWf3BOs<4-;i^^m@&C?IWQgKPL-izg+oIv;3jVyYjn8Rqy?PHD9Q-cY4v{@XpR z`tduikXNY*b;7#iEl>yP%Fu3G0(So-~$ zAzs?KJ^ZEyu><)*TAyZ(c-H9MN|MEz;}FbNy!;RoiS9a-*v@o54o_4q>W&;P)o{W# z6D@oLYx;_5x0pvaFf3K8!XU13(?}@%=hPo~w|eA(b9I+h+=JC$N;N7@;djH#tx72S zEfuYP#~S_e&@22`IViuEKkTpv3%K<}CWsW~n<^g+3`fb}+b-9z+KCpb$dKQrQ;=%l z;Jjuc^+8gJNP)jWHM4y&JM1NO4oJTgq>!*Uq%cnTeWSM6-A)Rca{Dg*j^o(@Ok9tp zyA*w>f{2+-moME}4Uz3%^<*^@Tg&lEfZ(`F5;GAa$!Oc;JGMk}`5{JIo1=H%k|>|; zZ-I)6=jn~IsP$H>*y1+-(6YwE!AIFXicwVOw!Gv)9+0f zivsU_eZQ;6UwiisY38gV_x^WY_)o|k9VEj{J&tox0uV>yPn-pE2XH~!HgrWcnfkf8VvR@1C1<29*U_G*_z`yg=P}Qt1V$K=$r=is~jh-e0ZROi9fv5QL;M}5f zRi%w$R(8nkXqj-*H#f_{)9EuD21Dm2U8o2Ad&H=9LKDPEr!Qi>?Xhf5D{#H#_Ds8M zQrH4$SsAM1uRm;thyp4cwtnU>DI}~}TD2@?!+B+c;SicJK|zO`7jfitPV#E|z)kOp zhhSU6&Vr1mU*>5}bzb)Oa_h%~%akjPG;Js#KCZ{Brg-(`rJn)Fa>m(K4cUe3*H)I517$Y+jg2(`%9fpW^1n{p<#8Kro ztLhe@l5FAMn@uUYxq?NVc6Ruf?XzT0*%am`C%3M_fnYd9o3|jo11JC9jh`zN@105j zAw6}6SGzHIqciemDCP6y&pS7C=DYxOh=ZkH-mltwAkWLeVq(pWXDi>d#0nJNea=u% zsbMH@S^8n`eJ&K*5LC%4Gz*Nb1;OGGr4e~qd@a{GboUdriw-_#Xnq*M-hc=b(6GU0ghd^(8h^jF8AVr>lgo2rx6%|+Ls6~t_Bn!mzH>k7ff(yj= zBAc<})TQi3xx8XnBZ7?Y+yt0smvSu&v$3eYyK1WsoU8rE&4XCk-rjGkgp;8Rv$7_K zknOy3AWgZW?P%zae~O>blE=@pej`=N;rXY{duRqcK#3Qj16p<)NTJK>d6J-4ca~9O z(A_|)S|2Qwsnn^MD(Hp~Vm9dlm7a2cc3*F|Kf+|g0`=<*v4Is7&O>b~8Wp9f`m{z^otRbK!wdN5Lv|Rs%ukH z2&{v{2gDdm6f$xgKK`t1b@SXLIvAmQ>~7toEzZghP0<k2pZhfnKq9^m-=EIxz1-6n zKK(NP@@tq6_b8#^{LCQf)}`nJzcbQ;i%rwiLC^M&z`%8OrH<|5PJ0fM(e#Yf{=UB? zY3mH^gDn$(_QBrwl`9Dshb7JnbrfcXK5FCFxJ;mrl=w^}|ln%Z$+Y(y)Z5SG& zbH{LXV+t*1{4hp=JDOM(#O2lmh^yPu`$%^V1TA%^f|d03a&G4)8$KIly=0rnCB6BR z_JSKRlWXbsL5cfD*N=M!|1FSg|MwNq*~5y01n-j^1}dqbZUzgL+F)(I(@T;~=FaWD z0kb91j?V5`k0_6xhr0w<_ypab=yRuh)8hU&w8j3kaz{Is&=}!b$!x~GJ$W=q2L-jap zRcTeZeiN&npw_S-hHKmZR$qxU}7D0ZOOM*l!&EYKNyI- zWWqE&wQiFx5tD-}HnZ)@<2*(;Ik8GUN-#?wPqT*ODmj;E7eQnD7J;A8I3ZSH!CQ6^ zTT{TpSLElSL$kwS-K)yu_OhuwV$aub;5cM_jXaRAJuB2EcQV25m7v|x2Tl8=GyYi; zFK3;WzlXbEAplBPfSoEaWdXC%Q{c<#S#X>Zr`W^hYX>=80ICx-9{O^0Z(Ct zfKn-6wbLyYupU~W)yrGURXS^`z1#D-Zr3rcUhJV_ zp44>L(mPjASA!&iGM;=Dt*I}3Dy1g3RsC{r9mhs>mzBSCEbKktd zs2zn724E2*gbC`~Bu#ABW_(~pC%}6q(=*U5r@S*x^Uw!t_;~C-@~`PD-??lWBY$n_ zr=znvYIoqL5ctdQtT?-z8E{0tSuPN(R$>Hz)g8AL7fR0*91tQwlip#IIKIB+@%nS~ ztzC%O^rLjm#*ad+xn;Nb0&5jMDgdxZwV&Y?ht1xB-SV1+>DQTVd$80Gd^g{Ox{e7TQNt&8Q!mfO*?XFDd$6~$*(9v}L{KnseIGn3Fm9LQsMApB zlaX2Pv(h321DwBnj#pOs4O=%fCAh-E(`v!uu;eS$xF%XF6^;itu-0$m~ga|5wG__@S6-d ziM8|jddpuqakMqjwxxSCM*3}pR;k-e3~76*nr#=;&1C5cO^)cQ``8yeI~t8>0dr1O zK2N|AX+EW!RCOvOx8!jfb&if4FUmKKf2Nu7MEwrvAclJE=JS@ya;FTorjaI>NiMNV zDJfi$XUfX6GVC+H46tRa)TgzZtQMTOnZWm7N!x*lDeOwwTwh^PNc&P0qS(jn{MC&G zqKf7$7AjhNg}ht}EC*M;q^dcW5D;uL_&ARwgNqBLV)Wy%ce=qhGl(2^v{NvKID!XM zPtD48AUlDsN9#}$sveZVy9{4eK7oJ1uWF#(^_=QxXMdlFHt#trGQX8<@P(H2XZKAH z77^>YO389_>WSJO%8AsVZDj_-JzTXqkQ*3PN99l zwedRZ5I#8KAekh3Ah)^qepZy)jj9<)nC+8WC7or_sSA<#WAWuM)9z4%K0-y$Aya^5sw*nJf^%)LSDjzO&!@*^}#}AY0B+}Z?V!P-(4j$5zCVQE)KB*bDH>#92 zxrwCne;}T{xeqK60!x)nVY&~UhEuSuE;`r8DdbGNMHu&NjK48~#a#Y}cKCAXNOYUg z1;44Y?wlD3rWXdCt~{>e2hB}LUSz%XGgQx)Y!A{7D>9Ktwe zC^wh&co%N(4DGoepG!(w>C9FVsO8gGeCMx(H-wfc(8b8Bm2k9gbQt%njUc4r5jMCm z7Y_><+rDnlmSYLkK*DVMPjY>#F0$S4K24dj`2;`TrU{(Q1M5-O>uQ6Uz7+TQGig2$ zUXLNOU9GRKB5eA@ZRu7Jyid=D1^eQ&hddGV%ocSvUII~vw-vEqxXOp&(ecl*+k}IFMgGKZ?f2-h zXX<4PY%cMyMQbL8k;ktbCw{Qm)ZyrTWzKyTI8=Akv|lO9Q8BsNoAOE*j)VgrM&6VK zL7}77LF8<2!!x;eP>=q@EgD$Yz$}*KjgBpfO)o5 zd#z#ayX*%gP6NL>S=>Y3bXpZpuh*E84-LaLT1~5wE()W4yz??T)!OI){T#rQsn@pzrkz-G>c+5;aHZdjuFs9*olz;MhYx9R+6_syhh8Ddq!`rdCva=a9%B|JuvbGuUU{TPIY$) zl2jxO);SPzzUbkn!UMHedByrrsN2jrwN^s(ciXx<0~|B$4wJp-FY0w%jR~f@!HQ8D zpSasg)4HYYk2&ao^!@9X3DO1Ah`V56FRcPsR8)4ovh20>n|ENU zKNUWpF5Sdc7i46s4DJndVtlT=rwuhO#FxanJ1e5=#Hfa&O`o+BtAg>dQtof)QT$)^AHo>8 zQ4kCvQk>noL)xu^e6&2KC8Px4jn}%GC1v?~eT^J7f++M;&CdIxYYp%Zd>?WYknjsMY z-yL|!YI#5@2ju7TQ8a{H%=-&#(2YpH%+jZ#2KMJrx8B6L#cy{6?-wzBKu7Rd=p>Cf z3cvoexXDlW?19P=LG$^KSG68*bK`+B-9pWf(aMy1xuc8A~WM zkST|tw_cO;@{9b>eVzOG56N%r)(b3GDy@n88&c_h+F8*be=#=7YTbk>^besw4i48z z$XHSw{l7-ZTOY_@>pvarX*@ItPLNo{dSm^qE!t7~PP|uq zKo}8>uP&?OCe{Dp;VGP}gq3m-L*d2MAU&RR!{)IyzxZ_Vp}Tkq)ru_D{2-#yPDN0M zquXG+Cs^L6hQj;_e?bFnzW~ka60P*wanw1QG=^;Q0IRbE?n;G=PPvcs^w~uCR&FR? zA^e1o(s2Z~YFyaa`?j|BC{NzE0lKb!#XK5hqLssxf2)IZ{xG8Ze13)(hy`%@IxEkH zSK21Hc>F6KLNRgU{)q*C?pDuVIxP4iO;2vLQh45zmEVW>R+savEBrxY|8#>r0gyCLjppG9sBss{`1>vgdV7O{hNnnk`n?`{wLl%p%AdZ9cyoMiHI+@ulqh-4ln{ zpKIT|DRq;tl*wu20`wfArWPy;O`Qo>8_ zl-@4k9%B50n#Y^AQ@eb`1>d(KGd5MK8Ul+IPxED0G zCr5r%xXWE=vmlER)L=0nD?z!UuBWZ4wq#yT&%^zkrEwyok(M-{z@t3&v;m9O`C z&;4;%%M48AeZMd0*aZ3q&n3q$`h#e0c6(|7mE&^n z$N4HBZnveNW1r<}sO0rB5~*4#l6UP=H*E&(7W}zkO6Bw4Il|oadT3yZp@xd>>BXK# z5wP=87P^n21(eS%kE9fi%2cWk?(8{F8cT4m4+s>M@|^H`3Qls%t>}Dh*QRMtB|jTQ zIK|7`o834etjhTW&BIYlP4pZ*-YMoB%fqME0cM(3iu>t!Vq|UI<-0gne&UO_9U-mU zgj*xjKRu5~8GXO00?AC#HJW9JHkbLVt+*mZt|Z{h5=}S4u;%Kk;F86&E%GRYAsuk+zBc*t zrDqz<{WxRiq%6GOFVL)FMYK4mM$7mfhb@v`3zF+=cWAN!X$gxzo*o~)4+k4lE$UQs zIc2umjp(}Rt%f9~jn+l}Y2U56Ycz}r*J=HiMJW~j%(hjaavu5KC|()#0+%kqdE0jVObc^WD}`bhtr`i=IRP)JT#PiHMcQ%B711a3nJ)pv<6>}qBe{{f zVyM|k$1)@3%uu6iem*Pbbj;?B%;=Z5dALT%rAnwu!&&@6`t#@9!m!NsKuFnCTi%^S zCFYR{c0Pts1PWl-m|6F7?PVaR)rJB!{68Vpp9pSFZfnNI#;5R9bfkE4-xET-dsy(e zf*~NPB#~d#9RGK#eV)m>x4SXjD#k7zY^bZ4&SlY4kFs#VBrvdp0u4&#;9w(K4uT^k zQS3+P0AX|0;^3W*7Ei%AybryQn{s%Di!J zjqM5IUw?c@NM5nYN|~b6{PKbdRpk3IxeKSYw)J>8Jkx)!h#gi+WtGC_gP-3k z;+vD_mgLcS3>pHWF_L;2!!y_W?D!JvYSxt_f=&b-qu%b7ND>{2KC2c+CqHZUbE{$D zGE4h7x@C4TZ~s_XmaGH}ZavDg8UlqqWGDAl708FXv<;iUY2fPhQLg+L2;?y?ee>T{ukwUTp|Cl@S(=+tdRm!|hDEHM3ffm2kCDmx zWV_s^`mq^vo(J6p&@>|469N9(!f+vTy^oAqYh)9BHcT{Hp{>BSx_-NOcFwd^? z1O0HaEC}}rEgFNwIQ}sj10bVSyMxIL^e=zsj~6(K)Zy=!*82WQ%tSGn?6vyZy?{%= zN9Nbv_QyN0biOHBM-d-LH3tsxdYflQW?eyCZqoP78baVXBkP}74S)~5NQ>xY077k1 zqrveiHUC$dfDo8YkDnGDCfwMgvbx45NaWrdXo<^Ds^>ny^Iw`I($NMO{onQ>Fb0-- zH&`I8&WC0MU>!1|-)t5@-k_9IWK=A@dj7TZ7a}p3EAfyuvR*HKLd#goU}IZ?Z5q1){Fbqq3Kr z1Pfwwj;0>mG|(F(I)^`Z{q1#xS&qv)&xe;2*)>OO+c8W5(}ge|T~k^?Ll4d*crxdf z^Vn5n+c_nbCuI!YOq7^4VtL;FIt&%iR8160&kYSB8F)b*kn`iub`-A=Z0au)qNVMnb|1`by9yrCUz|NsDUIC7L6s+};j}H=J zBN^gow^w_@K5f@fOK>zgo-$VdA^7u>xgg6^dj$+^pd5Y8J5eM~WstDyOuV0iESbGS zfBTMcPgXQe^gQXGutsc?=~^+}oSK}i9y0iHT5M;zNa-~?+ue7Q)b^NX^|f zmt`xnu23r)G9-D*U`@@s@E7Jb_*s2HU7MC<$JTR407idO_lC#F%3s#AbXDJqlM?c5 z9=GB?B!YzAxa5*+eWVaZB8R=2=9JX`nE>LyeH$idE}IhA{=btk9%k)Z>hv6G#?03l ztdm)zpG>BzcH|2`#7CfG{G1boi7!NGU--@K>KLrHx|W@L$u>_<4Q-g8C-cfwsqHy1uF;WQEgC^ z?-wHI1|??RU4$MOT`xXq{713!YV*HmW-8r2liu{@sV%wrWw43OkGz5S?V(s_MZ&L7 z|Jj&!3V28CFcIrJOm?2cRwQU)vzztKq4Eu5Lqt3n=Y4Fh5`>cuGUmBrFr0Q$d^wpq z3Wd?}`paY zC;wc)Tb0+4&g{GqO8&s5s0Tgled?JHmNNSHH=@%78^LrGDxF z%ZKUyxkhYe&ZCinyRKr0+=VBbBg4TI9`@?Kicg3?4F%~CqDc05?+4l+rl0{kwRh0q z*}8zTLnVYeQINgGub!5CIZR`^?R!fy1x0c#`<@r= zok2NaEa2ngmRTE8SEnHkshSQZ+C!fSAbe!<^>-R*{bwo+EM$7)@JE_T;b~sqSE~cg0=^;EkC{@`W zzB51;{#@5=0w)KrnGIu;9tfs@3ufyL5znl-l5Cnqdfo2%)1Ik;cI~z`@p3}Y8!!zw zcYR+jpPz!uwUB=)YU`!zkd{cW(_0v7yZBmRGq=c>e>I$UQ754$fMrZ`piwM{WG?=) z@&sZe9$yn^HJ9-{c^~oIH_DDN-xx&y=fE2A+W63#-BrYc-AkT_5ksw9U#AEj@Ei^= zCyNtX8e~8@#O%yUClDF3dRT>KOth2YaEID8%c8gxEV#N{9gq(6GC6*(fo&x?P;Ihy zTPO@JYST0*LmZ;qoKhswX>ReWtZz=+n|a4E^q;grc|ke*fLx`574o%}05=f#eevR zXXOpjVw`HGcLrcDESgItDp{Eaw-2QP^j-3Y*|J?y?3CbB|0gheMqss&Pf(v=zSjIE zTAQB|Nx$vKKprH|8(jz;`8?KMO0LA1x-!`Elkdaas8!VAmL=k6yx#nW*(C2|XWarb zptrM*uqC0RBypg6_RQx0gyhFL)Ffs}l`UbsE=tfGe z6h?oiQqPEqEmfVs^p8Y7Yq}X)p@ckoy;5-hIE-aaB;&R}zi?w=Q1XS&C}L0G{ln8M z{Q}bz0Du|e)sAT9Cc397AL`Kj3ofw}Ybwp>K9>uFy)8T{YLNjjeG(y`PY}J3M%!DX z?{jV1(H5`q>LVrqa`mu4iMeA$vV^Nu< zeF$r3tQyWs=7twKZ=u03a2Pp1=JedMf?ExEkFw-_k2u2erwJ zH`jfvM%`RM`u6n;Jf7%9VvS!DVl%&}ZPUCEHpx9NVsz?6Esvv(W@` z2oc~fwscc^iV2JlM&L|oU~p&UANTIQd^fam`c^XACkyo;J*)%i?AD z#-}l`OjxEZm4pd?`}TDhzJwSBx7%d~_pqezW>5z+Py#Z^S%O}9|8V){anTOr|DaUx zE1fOQtzL7RwMhLou&&`Fdj7iX-4c$VgxP0hOz3h5QU|H1;&D?B zb;Cw=lO?C4<|;VNMS+0l4rwqm(G9~RyxTI`nwm;~n}ijYHW@o?fZS&yD2dO0X~FGC z(V?;fLzF*ktTm=}=h$CQP6wmt8ti75-?a1|KWi3Wqu%Rye zp5;uXUHej*1uTD}46onW3!u82E-z1{etyC<-Ddq1yEzM^-MmJ?F>>VT%tTXg`){>G z__d<^rKn;k-PgRV{{=O!o*B`@8vc^n%`k#obU~o{2|%C`Pl+}H{>|5_1rYW|(ufsvz##kq-O)BG#& zXU;qoX6DoqktKOoKigP2&aJdbbCrv~HJYAlN zlr{!sCktz=`1!)FJZ=tNnXmWvdj{-XWuMM+LA+mLQnV?ID$JR@pq1p+$$54g$WC6T za+1y3^2Hti+6=NqW+t*EiT9fyWwWCH`X(?_fBO*$ARvhQDl64 zUK}FMp<{cMz@+dM>8HE?P_viu1ve{!?Om13iMcg!0%u#W~Q=m4@J;256q0kke3!(+~O!~LMvQ%sT&-4=)f|#|Cf4eDD-^x2FKZ* V+b%kpPX|ChQeyI=72gei{tsZlJYoO< literal 0 HcmV?d00001 diff --git a/docs/webhook-config.md b/docs/webhook-config.md index 5f5933b47..3677ebe89 100644 --- a/docs/webhook-config.md +++ b/docs/webhook-config.md @@ -239,3 +239,52 @@ Possible parameters are: The fields in `webhook.webhookstatus` are used for regular status messages (Started / Stopped / ...). Parameters are filled using string.format. The only possible value here is `{status}`. + +## Discord + +A special form of webhooks is available for discord. +You can configure this as follows: + +```json +"discord": { + "enabled": true, + "webhook_url": "https://discord.com/api/webhooks/", + "exit_fill": [ + {"Trade ID": "{trade_id}"}, + {"Exchange": "{exchange}"}, + {"Pair": "{pair}"}, + {"Direction": "{direction}"}, + {"Open rate": "{open_rate}"}, + {"Close rate": "{close_rate}"}, + {"Amount": "{amount}"}, + {"Open date": "{open_date:%Y-%m-%d %H:%M:%S}"}, + {"Close date": "{close_date:%Y-%m-%d %H:%M:%S}"}, + {"Profit": "{profit_amount} {stake_currency}"}, + {"Profitability": "{profit_ratio:.2%}"}, + {"Enter tag": "{enter_tag}"}, + {"Exit Reason": "{exit_reason}"}, + {"Strategy": "{strategy}"}, + {"Timeframe": "{timeframe}"}, + ], + "entry_fill": [ + {"Trade ID": "{trade_id}"}, + {"Exchange": "{exchange}"}, + {"Pair": "{pair}"}, + {"Direction": "{direction}"}, + {"Open rate": "{open_rate}"}, + {"Amount": "{amount}"}, + {"Open date": "{open_date:%Y-%m-%d %H:%M:%S}"}, + {"Enter tag": "{enter_tag}"}, + {"Strategy": "{strategy} {timeframe}"}, + ] +} +``` + + +The above represents the default (`exit_fill` and `entry_fill` are optional and will default to the above configuration) - modifications are obviously possible. + +Available fields correspond to the fields for webhooks and are documented in the corresponding webhook sections. + +The notifications will look as follows by default. + +![discord-notification](assets/discord_notification.png) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 9fbd70e42..18dbea259 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -336,6 +336,47 @@ CONF_SCHEMA = { 'webhookstatus': {'type': 'object'}, }, }, + 'discord': { + 'type': 'object', + 'properties': { + 'enabled': {'type': 'boolean'}, + 'webhook_url': {'type': 'string'}, + "exit_fill": { + 'type': 'array', 'items': {'type': 'object'}, + 'default': [ + {"Trade ID": "{trade_id}"}, + {"Exchange": "{exchange}"}, + {"Pair": "{pair}"}, + {"Direction": "{direction}"}, + {"Open rate": "{open_rate}"}, + {"Close rate": "{close_rate}"}, + {"Amount": "{amount}"}, + {"Open date": "{open_date:%Y-%m-%d %H:%M:%S}"}, + {"Close date": "{close_date:%Y-%m-%d %H:%M:%S}"}, + {"Profit": "{profit_amount} {stake_currency}"}, + {"Profitability": "{profit_ratio:.2%}"}, + {"Enter tag": "{enter_tag}"}, + {"Exit Reason": "{exit_reason}"}, + {"Strategy": "{strategy}"}, + {"Timeframe": "{timeframe}"}, + ] + }, + "entry_fill": { + 'type': 'array', 'items': {'type': 'object'}, + 'default': [ + {"Trade ID": "{trade_id}"}, + {"Exchange": "{exchange}"}, + {"Pair": "{pair}"}, + {"Direction": "{direction}"}, + {"Open rate": "{open_rate}"}, + {"Amount": "{amount}"}, + {"Open date": "{open_date:%Y-%m-%d %H:%M:%S}"}, + {"Enter tag": "{enter_tag}"}, + {"Strategy": "{strategy} {timeframe}"}, + ] + }, + } + }, 'api_server': { 'type': 'object', 'properties': { diff --git a/freqtrade/rpc/discord.py b/freqtrade/rpc/discord.py index 41185a090..9509b4f23 100644 --- a/freqtrade/rpc/discord.py +++ b/freqtrade/rpc/discord.py @@ -1,8 +1,7 @@ import logging from typing import Any, Dict -from freqtrade.constants import DATETIME_PRINT_FORMAT -from freqtrade.enums import RPCMessageType +from freqtrade.enums.rpcmessagetype import RPCMessageType from freqtrade.rpc import RPC from freqtrade.rpc.webhook import Webhook @@ -33,46 +32,26 @@ class Discord(Webhook): def send_msg(self, msg) -> None: logger.info(f"Sending discord message: {msg}") - # TODO: handle other message types - if msg['type'] == RPCMessageType.EXIT_FILL: - profit_ratio = msg.get('profit_ratio') - open_date = msg.get('open_date').strftime(DATETIME_PRINT_FORMAT) - close_date = msg.get('close_date').strftime( - DATETIME_PRINT_FORMAT) if msg.get('close_date') else '' + if msg['type'].value in self.config['discord']: + + msg['strategy'] = self.strategy + msg['timeframe'] = self.timeframe + fields = self.config['discord'].get(msg['type'].value) + color = 0x0000FF + if msg['type'] in (RPCMessageType.EXIT, RPCMessageType.EXIT_FILL): + profit_ratio = msg.get('profit_ratio') + color = (0x00FF00 if profit_ratio > 0 else 0xFF0000) embeds = [{ - 'title': '{} Trade: {}'.format( - 'Profit' if profit_ratio > 0 else 'Loss', - msg.get('pair')), - 'color': (0x00FF00 if profit_ratio > 0 else 0xFF0000), - 'fields': [ - {'name': 'Trade ID', 'value': msg.get('trade_id'), 'inline': True}, - {'name': 'Exchange', 'value': msg.get('exchange').capitalize(), 'inline': True}, - {'name': 'Pair', 'value': msg.get('pair'), 'inline': True}, - {'name': 'Direction', 'value': 'Short' if msg.get( - 'is_short') else 'Long', 'inline': True}, - {'name': 'Open rate', 'value': msg.get('open_rate'), 'inline': True}, - {'name': 'Close rate', 'value': msg.get('close_rate'), 'inline': True}, - {'name': 'Amount', 'value': msg.get('amount'), 'inline': True}, - {'name': 'Open order', 'value': msg.get('open_order_id'), 'inline': True}, - {'name': 'Open date', 'value': open_date, 'inline': True}, - {'name': 'Close date', 'value': close_date, 'inline': True}, - {'name': 'Profit', 'value': msg.get('profit_amount'), 'inline': True}, - {'name': 'Profitability', 'value': f'{profit_ratio:.2%}', 'inline': True}, - {'name': 'Stake currency', 'value': msg.get('stake_currency'), 'inline': True}, - {'name': 'Fiat currency', 'value': msg.get('fiat_display_currency'), - 'inline': True}, - {'name': 'Buy Tag', 'value': msg.get('enter_tag'), 'inline': True}, - {'name': 'Sell Reason', 'value': msg.get('exit_reason'), 'inline': True}, - {'name': 'Strategy', 'value': self.strategy, 'inline': True}, - {'name': 'Timeframe', 'value': self.timeframe, 'inline': True}, - ], - }] + 'title': f"Trade: {msg['pair']} {msg['type'].value}", + 'color': color, + 'fields': [], - # convert all value in fields to string for discord - for embed in embeds: - for field in embed['fields']: # type: ignore - field['value'] = str(field['value']) + }] + for f in fields: + for k, v in f.items(): + v = v.format(**msg) + embeds[0]['fields'].append({'name': k, 'value': v, 'inline': True}) # Send the message to discord channel payload = {'embeds': embeds} From 4b70e03daadc8cc3213656c6d8eaa32815096dd1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 17:45:37 +0200 Subject: [PATCH 299/449] Add some rudimentary tsts for discord webhook integration --- freqtrade/rpc/discord.py | 3 ++- tests/rpc/test_rpc_webhook.py | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/discord.py b/freqtrade/rpc/discord.py index 9509b4f23..5991f7126 100644 --- a/freqtrade/rpc/discord.py +++ b/freqtrade/rpc/discord.py @@ -51,7 +51,8 @@ class Discord(Webhook): for f in fields: for k, v in f.items(): v = v.format(**msg) - embeds[0]['fields'].append({'name': k, 'value': v, 'inline': True}) + embeds[0]['fields'].append( # type: ignore + {'name': k, 'value': v, 'inline': True}) # Send the message to discord channel payload = {'embeds': embeds} diff --git a/tests/rpc/test_rpc_webhook.py b/tests/rpc/test_rpc_webhook.py index db357f80f..4d65b4966 100644 --- a/tests/rpc/test_rpc_webhook.py +++ b/tests/rpc/test_rpc_webhook.py @@ -1,5 +1,6 @@ # pragma pylint: disable=missing-docstring, C0103, protected-access +from datetime import datetime, timedelta from unittest.mock import MagicMock import pytest @@ -7,6 +8,7 @@ from requests import RequestException from freqtrade.enums import ExitType, RPCMessageType from freqtrade.rpc import RPC +from freqtrade.rpc.discord import Discord from freqtrade.rpc.webhook import Webhook from tests.conftest import get_patched_freqtradebot, log_has @@ -406,3 +408,42 @@ def test__send_msg_with_raw_format(default_conf, mocker, caplog): webhook._send_msg(msg) assert post.call_args[1] == {'data': msg['data'], 'headers': {'Content-Type': 'text/plain'}} + + +def test_send_msg_discord(default_conf, mocker): + + default_conf["discord"] = { + 'enabled': True, + 'webhook_url': "https://webhookurl..." + } + msg_mock = MagicMock() + mocker.patch("freqtrade.rpc.webhook.Webhook._send_msg", msg_mock) + discord = Discord(RPC(get_patched_freqtradebot(mocker, default_conf)), default_conf) + + msg = { + 'type': RPCMessageType.EXIT_FILL, + 'trade_id': 1, + 'exchange': 'Binance', + 'pair': 'ETH/BTC', + 'direction': 'Long', + 'gain': "profit", + 'close_rate': 0.005, + 'amount': 0.8, + 'order_type': 'limit', + 'open_date': datetime.now() - timedelta(days=1), + 'close_date': datetime.now(), + 'open_rate': 0.004, + 'current_rate': 0.005, + 'profit_amount': 0.001, + 'profit_ratio': 0.20, + 'stake_currency': 'BTC', + 'enter_tag': 'enter_tagggg', + 'exit_reason': ExitType.STOP_LOSS.value, + } + discord.send_msg(msg=msg) + + assert msg_mock.call_count == 1 + assert 'embeds' in msg_mock.call_args_list[0][0][0] + assert 'title' in msg_mock.call_args_list[0][0][0]['embeds'][0] + assert 'color' in msg_mock.call_args_list[0][0][0]['embeds'][0] + assert 'fields' in msg_mock.call_args_list[0][0][0]['embeds'][0] From c9761f47361203eafbb08f9a5413e88e0e80159b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Jun 2022 18:02:03 +0200 Subject: [PATCH 300/449] FreqUI should be installed by default when running setup.sh --- setup.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup.sh b/setup.sh index bb51c3a2f..202cb70c7 100755 --- a/setup.sh +++ b/setup.sh @@ -87,6 +87,10 @@ function updateenv() { echo "Failed installing Freqtrade" exit 1 fi + + echo "Installing freqUI" + freqtrade install-ui + echo "pip install completed" echo if [[ $dev =~ ^[Yy]$ ]]; then From 56652c2b391fa1714bf706ed156df72910b7dad5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Jun 2022 17:09:47 +0200 Subject: [PATCH 301/449] Improve test resiliance --- tests/test_freqtradebot.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index cd7459cbe..7f9bc6a46 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -210,13 +210,14 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker, # # mocking the ticker: price is falling ... enter_price = limit_order['buy']['price'] + ticker_val = { + 'bid': enter_price, + 'ask': enter_price, + 'last': enter_price, + } mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=MagicMock(return_value={ - 'bid': enter_price * buy_price_mult, - 'ask': enter_price * buy_price_mult, - 'last': enter_price * buy_price_mult, - }), + fetch_ticker=MagicMock(return_value=ticker_val), get_fee=fee, ) ############################################# @@ -229,9 +230,12 @@ def test_edge_overrides_stoploss(limit_order, fee, caplog, mocker, freqtrade.enter_positions() trade = Trade.query.first() caplog.clear() - oobj = Order.parse_from_ccxt_object(limit_order['buy'], 'ADA/USDT', 'buy') - trade.update_trade(oobj) ############################################# + ticker_val.update({ + 'bid': enter_price * buy_price_mult, + 'ask': enter_price * buy_price_mult, + 'last': enter_price * buy_price_mult, + }) # stoploss shoud be hit assert freqtrade.handle_trade(trade) is not ignore_strat_sl From dff83ef62045c2b006702d5bc855cc9051a3bc80 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Jun 2022 17:30:01 +0200 Subject: [PATCH 302/449] Update telegram profit test to USDT --- tests/rpc/test_rpc_telegram.py | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 11a783f3a..355a8b078 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -643,16 +643,16 @@ def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: assert str('Monthly Profit over the last 6 months:') in msg_mock.call_args_list[0][0][0] -def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, - limit_buy_order, limit_sell_order, mocker) -> None: - mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) +def test_profit_handle(default_conf_usdt, update, ticker_usdt, ticker_sell_up, fee, + limit_sell_order_usdt, mocker) -> None: + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=1.1) mocker.patch.multiple( 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, + fetch_ticker=ticker_usdt, get_fee=fee, ) - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) + telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) patch_get_signal(freqtradebot) telegram._profit(update=update, context=MagicMock()) @@ -664,10 +664,6 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, freqtradebot.enter_positions() trade = Trade.query.first() - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - context = MagicMock() # Test with invalid 2nd argument (should silently pass) context.args = ["aaa"] @@ -675,15 +671,15 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, assert msg_mock.call_count == 1 assert 'No closed trade' in msg_mock.call_args_list[-1][0][0] assert '*ROI:* All trades' in msg_mock.call_args_list[-1][0][0] - mocker.patch('freqtrade.wallets.Wallets.get_starting_balance', return_value=0.01) - assert ('∙ `-0.000005 BTC (-0.50%) (-0.0 \N{GREEK CAPITAL LETTER SIGMA}%)`' + mocker.patch('freqtrade.wallets.Wallets.get_starting_balance', return_value=1000) + assert ('∙ `0.298 USDT (0.50%) (0.03 \N{GREEK CAPITAL LETTER SIGMA}%)`' in msg_mock.call_args_list[-1][0][0]) msg_mock.reset_mock() # Update the ticker with a market going up mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', ticker_sell_up) # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') + oobj = Order.parse_from_ccxt_object(limit_sell_order_usdt, limit_sell_order_usdt['symbol'], 'sell') trade.update_trade(oobj) trade.close_date = datetime.now(timezone.utc) @@ -694,15 +690,15 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, telegram._profit(update=update, context=context) assert msg_mock.call_count == 1 assert '*ROI:* Closed trades' in msg_mock.call_args_list[-1][0][0] - assert ('∙ `0.00006217 BTC (6.20%) (0.62 \N{GREEK CAPITAL LETTER SIGMA}%)`' + assert ('∙ `5.685 USDT (9.45%) (0.57 \N{GREEK CAPITAL LETTER SIGMA}%)`' in msg_mock.call_args_list[-1][0][0]) - assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0] + assert '∙ `6.253 USD`' in msg_mock.call_args_list[-1][0][0] assert '*ROI:* All trades' in msg_mock.call_args_list[-1][0][0] - assert ('∙ `0.00006217 BTC (6.20%) (0.62 \N{GREEK CAPITAL LETTER SIGMA}%)`' + assert ('∙ `5.685 USDT (9.45%) (0.57 \N{GREEK CAPITAL LETTER SIGMA}%)`' in msg_mock.call_args_list[-1][0][0]) - assert '∙ `0.933 USD`' in msg_mock.call_args_list[-1][0][0] + assert '∙ `6.253 USD`' in msg_mock.call_args_list[-1][0][0] - assert '*Best Performing:* `ETH/BTC: 6.20%`' in msg_mock.call_args_list[-1][0][0] + assert '*Best Performing:* `ETH/USDT: 9.45%`' in msg_mock.call_args_list[-1][0][0] @pytest.mark.parametrize('is_short', [True, False]) From 7619fd08d65e4cafee6e5a9f227987392dfe8fe2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Jun 2022 19:31:32 +0200 Subject: [PATCH 303/449] Update telegram tests to use mock_trades --- tests/conftest_trades_usdt.py | 6 +- tests/rpc/test_rpc_telegram.py | 102 ++++++++------------------------- 2 files changed, 27 insertions(+), 81 deletions(-) diff --git a/tests/conftest_trades_usdt.py b/tests/conftest_trades_usdt.py index 6f83bb8be..cc1b1a206 100644 --- a/tests/conftest_trades_usdt.py +++ b/tests/conftest_trades_usdt.py @@ -95,13 +95,14 @@ def mock_trade_usdt_2(fee, is_short: bool): fee_close=fee.return_value, open_rate=2.0, close_rate=2.05, - close_profit=5.0, + close_profit=0.05, close_profit_abs=3.9875, exchange='binance', is_open=False, open_order_id=f'12366_{direc(is_short)}', strategy='StrategyTestV2', timeframe=5, + enter_tag='TEST1', exit_reason='exit_signal', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), @@ -157,12 +158,13 @@ def mock_trade_usdt_3(fee, is_short: bool): fee_close=fee.return_value, open_rate=1.0, close_rate=1.1, - close_profit=10.0, + close_profit=0.1, close_profit_abs=9.8425, exchange='binance', is_open=False, strategy='StrategyTestV2', timeframe=5, + enter_tag='TEST3', exit_reason='roi', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), close_date=datetime.now(tz=timezone.utc), diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 355a8b078..48acda47e 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -679,7 +679,8 @@ def test_profit_handle(default_conf_usdt, update, ticker_usdt, ticker_sell_up, f # Update the ticker with a market going up mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', ticker_sell_up) # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order_usdt, limit_sell_order_usdt['symbol'], 'sell') + oobj = Order.parse_from_ccxt_object( + limit_sell_order_usdt, limit_sell_order_usdt['symbol'], 'sell') trade.update_trade(oobj) trade.close_date = datetime.now(timezone.utc) @@ -1235,71 +1236,43 @@ def test_force_enter_no_pair(default_conf, update, mocker) -> None: assert fbuy_mock.call_count == 1 -def test_telegram_performance_handle(default_conf, update, ticker, fee, - limit_buy_order, limit_sell_order, mocker) -> None: +def test_telegram_performance_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, get_fee=fee, ) - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) - patch_get_signal(freqtradebot) + telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade + create_mock_trades_usdt(fee) - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - - trade.close_date = datetime.utcnow() - trade.is_open = False telegram._performance(update=update, context=MagicMock()) assert msg_mock.call_count == 1 assert 'Performance' in msg_mock.call_args_list[0][0][0] - assert 'ETH/BTC\t0.00006217 BTC (6.20%) (1)' in msg_mock.call_args_list[0][0][0] + assert 'XRP/USDT\t9.842 USDT (10.00%) (1)' in msg_mock.call_args_list[0][0][0] def test_telegram_entry_tag_performance_handle( - default_conf, update, ticker, fee, limit_buy_order, limit_sell_order, mocker) -> None: + default_conf_usdt, update, ticker, fee, mocker) -> None: mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, get_fee=fee, ) - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) + telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) patch_get_signal(freqtradebot) - # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade + create_mock_trades_usdt(fee) - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - trade.enter_tag = "TESTBUY" - # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - - trade.close_date = datetime.utcnow() - trade.is_open = False context = MagicMock() telegram._enter_tag_performance(update=update, context=context) assert msg_mock.call_count == 1 assert 'Entry Tag Performance' in msg_mock.call_args_list[0][0][0] - assert 'TESTBUY\t0.00006217 BTC (6.20%) (1)' in msg_mock.call_args_list[0][0][0] + assert 'TEST1\t3.987 USDT (5.00%) (1)' in msg_mock.call_args_list[0][0][0] - context.args = [trade.pair] + context.args = ['XRP/USDT'] telegram._enter_tag_performance(update=update, context=context) assert msg_mock.call_count == 2 @@ -1312,37 +1285,24 @@ def test_telegram_entry_tag_performance_handle( assert "Error" in msg_mock.call_args_list[0][0][0] -def test_telegram_exit_reason_performance_handle(default_conf, update, ticker, fee, - limit_buy_order, limit_sell_order, mocker) -> None: +def test_telegram_exit_reason_performance_handle(default_conf_usdt, update, ticker, fee, + mocker) -> None: mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, get_fee=fee, ) - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) + telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) patch_get_signal(freqtradebot) - # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade - trade.exit_reason = 'TESTSELL' - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) + create_mock_trades_usdt(fee) - # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - - trade.close_date = datetime.utcnow() - trade.is_open = False context = MagicMock() telegram._exit_reason_performance(update=update, context=context) assert msg_mock.call_count == 1 assert 'Exit Reason Performance' in msg_mock.call_args_list[0][0][0] - assert 'TESTSELL\t0.00006217 BTC (6.20%) (1)' in msg_mock.call_args_list[0][0][0] - context.args = [trade.pair] + assert 'roi\t9.842 USDT (10.00%) (1)' in msg_mock.call_args_list[0][0][0] + context.args = ['XRP/USDT'] telegram._exit_reason_performance(update=update, context=context) assert msg_mock.call_count == 2 @@ -1356,43 +1316,27 @@ def test_telegram_exit_reason_performance_handle(default_conf, update, ticker, f assert "Error" in msg_mock.call_args_list[0][0][0] -def test_telegram_mix_tag_performance_handle(default_conf, update, ticker, fee, - limit_buy_order, limit_sell_order, mocker) -> None: +def test_telegram_mix_tag_performance_handle(default_conf_usdt, update, ticker, fee, + mocker) -> None: mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=ticker, get_fee=fee, ) - telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) + telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) patch_get_signal(freqtradebot) # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade - - trade.enter_tag = "TESTBUY" - trade.exit_reason = "TESTSELL" - - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - - trade.close_date = datetime.utcnow() - trade.is_open = False + create_mock_trades_usdt(fee) context = MagicMock() telegram._mix_tag_performance(update=update, context=context) assert msg_mock.call_count == 1 assert 'Mix Tag Performance' in msg_mock.call_args_list[0][0][0] - assert ('TESTBUY TESTSELL\t0.00006217 BTC (6.20%) (1)' + assert ('TEST3 roi\t9.842 USDT (10.00%) (1)' in msg_mock.call_args_list[0][0][0]) - context.args = [trade.pair] + context.args = ['XRP/USDT'] telegram._mix_tag_performance(update=update, context=context) assert msg_mock.call_count == 2 From 40c7caac16279c9d1e34ef50fe2fc8178b01d886 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 03:01:53 +0000 Subject: [PATCH 304/449] Bump types-filelock from 3.2.6 to 3.2.7 Bumps [types-filelock](https://github.com/python/typeshed) from 3.2.6 to 3.2.7. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-filelock dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 4eb157aae..e7d64a2b6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -23,7 +23,7 @@ nbconvert==6.5.0 # mypy types types-cachetools==5.0.1 -types-filelock==3.2.6 +types-filelock==3.2.7 types-requests==2.27.30 types-tabulate==0.8.9 types-python-dateutil==2.8.17 From 390e600f55cfe868bee74d9d74fc03e323575359 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Jun 2022 06:46:34 +0200 Subject: [PATCH 305/449] Update statistics output --- tests/conftest_trades_usdt.py | 104 +++++++++++++++++----------------- tests/rpc/test_rpc.py | 87 +++++++++------------------- 2 files changed, 78 insertions(+), 113 deletions(-) diff --git a/tests/conftest_trades_usdt.py b/tests/conftest_trades_usdt.py index cc1b1a206..41d705c01 100644 --- a/tests/conftest_trades_usdt.py +++ b/tests/conftest_trades_usdt.py @@ -20,36 +20,60 @@ def direc(is_short: bool): def mock_order_usdt_1(is_short: bool): return { - 'id': f'1234_{direc(is_short)}', - 'symbol': 'ADA/USDT', + 'id': f'prod_entry_1_{direc(is_short)}', + 'symbol': 'LTC/USDT', 'status': 'closed', 'side': entry_side(is_short), 'type': 'limit', - 'price': 2.0, - 'amount': 10.0, - 'filled': 10.0, + 'price': 10.0, + 'amount': 2.0, + 'filled': 2.0, + 'remaining': 0.0, + } + + +def mock_order_usdt_1_exit(is_short: bool): + return { + 'id': f'prod_exit_1_{direc(is_short)}', + 'symbol': 'LTC/USDT', + 'status': 'closed', + 'side': exit_side(is_short), + 'type': 'limit', + 'price': 8.0, + 'amount': 2.0, + 'filled': 2.0, 'remaining': 0.0, } def mock_trade_usdt_1(fee, is_short: bool): + """ + Simulate prod entry with open sell order + """ trade = Trade( - pair='ADA/USDT', + pair='LTC/USDT', stake_amount=20.0, - amount=10.0, - amount_requested=10.0, + amount=2.0, + amount_requested=2.0, + open_date=datetime.now(tz=timezone.utc) - timedelta(days=2, minutes=20), + close_date=datetime.now(tz=timezone.utc) - timedelta(days=2, minutes=5), fee_open=fee.return_value, fee_close=fee.return_value, - is_open=True, - open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17), - open_rate=2.0, + is_open=False, + open_rate=10.0, + close_rate=8.0, + close_profit=-0.2, + close_profit_abs=-4.0, exchange='binance', - open_order_id=f'1234_{direc(is_short)}', - strategy='StrategyTestV2', + strategy='SampleStrategy', + open_order_id=f'prod_exit_1_{direc(is_short)}', timeframe=5, is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_1(is_short), 'ADA/USDT', entry_side(is_short)) + o = Order.parse_from_ccxt_object(mock_order_usdt_1(is_short), 'LTC/USDT', entry_side(is_short)) + trade.orders.append(o) + o = Order.parse_from_ccxt_object(mock_order_usdt_1_exit(is_short), + 'LTC/USDT', exit_side(is_short)) trade.orders.append(o) return trade @@ -330,59 +354,35 @@ def mock_trade_usdt_6(fee, is_short: bool): def mock_order_usdt_7(is_short: bool): return { - 'id': f'prod_entry_7_{direc(is_short)}', - 'symbol': 'LTC/USDT', + 'id': f'1234_{direc(is_short)}', + 'symbol': 'ADA/USDT', 'status': 'closed', 'side': entry_side(is_short), 'type': 'limit', - 'price': 10.0, - 'amount': 2.0, - 'filled': 2.0, - 'remaining': 0.0, - } - - -def mock_order_usdt_7_exit(is_short: bool): - return { - 'id': f'prod_exit_7_{direc(is_short)}', - 'symbol': 'LTC/USDT', - 'status': 'closed', - 'side': exit_side(is_short), - 'type': 'limit', - 'price': 8.0, - 'amount': 2.0, - 'filled': 2.0, + 'price': 2.0, + 'amount': 10.0, + 'filled': 10.0, 'remaining': 0.0, } def mock_trade_usdt_7(fee, is_short: bool): - """ - Simulate prod entry with open sell order - """ trade = Trade( - pair='LTC/USDT', + pair='ADA/USDT', stake_amount=20.0, - amount=2.0, - amount_requested=2.0, - open_date=datetime.now(tz=timezone.utc) - timedelta(days=2, minutes=20), - close_date=datetime.now(tz=timezone.utc) - timedelta(days=2, minutes=5), + amount=10.0, + amount_requested=10.0, fee_open=fee.return_value, fee_close=fee.return_value, - is_open=False, - open_rate=10.0, - close_rate=8.0, - close_profit=-0.2, - close_profit_abs=-4.0, + is_open=True, + open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17), + open_rate=2.0, exchange='binance', - strategy='SampleStrategy', - open_order_id=f'prod_exit_7_{direc(is_short)}', + open_order_id=f'1234_{direc(is_short)}', + strategy='StrategyTestV2', timeframe=5, is_short=is_short, ) - o = Order.parse_from_ccxt_object(mock_order_usdt_7(is_short), 'LTC/USDT', entry_side(is_short)) - trade.orders.append(o) - o = Order.parse_from_ccxt_object(mock_order_usdt_7_exit(is_short), - 'LTC/USDT', exit_side(is_short)) + o = Order.parse_from_ccxt_object(mock_order_usdt_7(is_short), 'ADA/USDT', entry_side(is_short)) trade.orders.append(o) return trade diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 0273b8237..339a6382f 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -407,13 +407,9 @@ def test_rpc_delete_trade(mocker, default_conf, fee, markets, caplog, is_short): assert stoploss_mock.call_count == 0 -def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, - limit_buy_order, limit_sell_order, mocker) -> None: - mocker.patch.multiple( - 'freqtrade.rpc.fiat_convert.CoinGeckoAPI', - get_price=MagicMock(return_value={'bitcoin': {'usd': 15000.0}}), - ) - mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) +def test_rpc_trade_statistics11(default_conf_usdt, ticker, fee, + mocker) -> None: + mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=1.1) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -421,10 +417,9 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, get_fee=fee, ) - freqtradebot = get_patched_freqtradebot(mocker, default_conf) - patch_get_signal(freqtradebot) - stake_currency = default_conf['stake_currency'] - fiat_display_currency = default_conf['fiat_display_currency'] + freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt) + stake_currency = default_conf_usdt['stake_currency'] + fiat_display_currency = default_conf_usdt['fiat_display_currency'] rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() @@ -437,62 +432,32 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, assert res['latest_trade_timestamp'] == 0 # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'sell') - trade.update_trade(oobj) - - # Update the ticker with a market going up - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_up - ) - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - trade.close_date = datetime.utcnow() - trade.is_open = False - - freqtradebot.enter_positions() - trade = Trade.query.first() - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Update the ticker with a market going up - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_up - ) - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - trade.close_date = datetime.utcnow() - trade.is_open = False + create_mock_trades_usdt(fee) stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) - assert prec_satoshi(stats['profit_closed_coin'], 6.217e-05) - assert prec_satoshi(stats['profit_closed_percent_mean'], 6.2) - assert prec_satoshi(stats['profit_closed_fiat'], 0.93255) - assert prec_satoshi(stats['profit_all_coin'], 5.802e-05) - assert prec_satoshi(stats['profit_all_percent_mean'], 2.89) - assert prec_satoshi(stats['profit_all_fiat'], 0.8703) - assert stats['trade_count'] == 2 - assert stats['first_trade_date'] == 'just now' - assert stats['latest_trade_date'] == 'just now' - assert stats['avg_duration'] in ('0:00:00', '0:00:01', '0:00:02') - assert stats['best_pair'] == 'ETH/BTC' - assert prec_satoshi(stats['best_rate'], 6.2) + assert pytest.approx(stats['profit_closed_coin']) == 9.83 + assert pytest.approx(stats['profit_closed_percent_mean']) == -1.67 + assert pytest.approx(stats['profit_closed_fiat']) == 10.813 + assert pytest.approx(stats['profit_all_coin']) == -77.45964918 + assert pytest.approx(stats['profit_all_percent_mean']) == -57.86 + assert pytest.approx(stats['profit_all_fiat']) == -85.205614098 + assert stats['trade_count'] == 7 + assert stats['first_trade_date'] == '2 days ago' + assert stats['latest_trade_date'] == '17 minutes ago' + assert stats['avg_duration'] in ('0:17:40') + assert stats['best_pair'] == 'XRP/USDT' + assert stats['best_rate'] == 10.0 # Test non-available pair mocker.patch('freqtrade.exchange.Exchange.get_rate', - MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available"))) + MagicMock(side_effect=ExchangeError("Pair 'XRP/USDT' not available"))) stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) - assert stats['trade_count'] == 2 - assert stats['first_trade_date'] == 'just now' - assert stats['latest_trade_date'] == 'just now' - assert stats['avg_duration'] in ('0:00:00', '0:00:01', '0:00:02') - assert stats['best_pair'] == 'ETH/BTC' - assert prec_satoshi(stats['best_rate'], 6.2) + assert stats['trade_count'] == 7 + assert stats['first_trade_date'] == '2 days ago' + assert stats['latest_trade_date'] == '17 minutes ago' + assert stats['avg_duration'] in ('0:17:40') + assert stats['best_pair'] == 'XRP/USDT' + assert stats['best_rate'] == 10.0 assert isnan(stats['profit_all_coin']) From 43c871f2f4e4b7022befea6e4dd8c3b8871231a8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Jun 2022 06:49:31 +0200 Subject: [PATCH 306/449] Use time-machine to stabilize time-sensitive tests --- tests/rpc/test_rpc_telegram.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 48acda47e..3bd817ac7 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -405,7 +405,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None: assert msg_mock.call_count == 1 -def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: +def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker, time_machine) -> None: mocker.patch( 'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=1.1 @@ -418,6 +418,8 @@ def test_daily_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) + # Move date to within day + time_machine.move_to('2022-06-11 08:00:00+00:00') # Create some test data create_mock_trades_usdt(fee) @@ -491,7 +493,7 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None: assert 'Daily Profit over the last 7 days:' in msg_mock.call_args_list[0][0][0] -def test_weekly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: +def test_weekly_handle(default_conf_usdt, update, ticker, fee, mocker, time_machine) -> None: default_conf_usdt['max_open_trades'] = 1 mocker.patch( 'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', @@ -504,7 +506,8 @@ def test_weekly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: ) telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) - + # Move to saturday - so all trades are within that week + time_machine.move_to('2022-06-11') create_mock_trades_usdt(fee) # Try valid data @@ -560,7 +563,7 @@ def test_weekly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: ) -def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: +def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker, time_machine) -> None: default_conf_usdt['max_open_trades'] = 1 mocker.patch( 'freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', @@ -573,7 +576,8 @@ def test_monthly_handle(default_conf_usdt, update, ticker, fee, mocker) -> None: ) telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf_usdt) - + # Move to day within the month so all mock trades fall into this week. + time_machine.move_to('2022-06-11') create_mock_trades_usdt(fee) # Try valid data From 8fd245c28b6d41be9b45a8c9f5aeb6d5ab7d277c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Jun 2022 06:58:06 +0200 Subject: [PATCH 307/449] Update pre-commit filelocktypes --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 685d789ec..f5c1a36f5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: exclude: build_helpers additional_dependencies: - types-cachetools==5.0.1 - - types-filelock==3.2.6 + - types-filelock==3.2.7 - types-requests==2.27.30 - types-tabulate==0.8.9 - types-python-dateutil==2.8.17 From 70966c8a8f0782b1e4d3f94c64b8cecb0e34b71b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 05:08:12 +0000 Subject: [PATCH 308/449] Bump actions/setup-python from 3 to 4 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bbe0bcf6e..551268af7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -127,7 +127,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -211,7 +211,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -263,7 +263,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: "3.10" @@ -282,7 +282,7 @@ jobs: ./tests/test_docs.sh - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: "3.10" @@ -336,7 +336,7 @@ jobs: - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v4 with: python-version: "3.9" From e67d29cd2f85ac2eb029b1c7904ece2cc7cc35a1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Jun 2022 07:10:47 +0200 Subject: [PATCH 309/449] Update more trades to use create_mock_trades --- tests/rpc/test_rpc.py | 179 +++++++++++------------------------------- 1 file changed, 46 insertions(+), 133 deletions(-) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 339a6382f..d20646e60 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -11,7 +11,6 @@ from freqtrade.edge import PairInfo from freqtrade.enums import SignalDirection, State, TradingMode from freqtrade.exceptions import ExchangeError, InvalidOrderException, TemporaryError from freqtrade.persistence import Trade -from freqtrade.persistence.models import Order from freqtrade.persistence.pairlock_middleware import PairLocks from freqtrade.rpc import RPC, RPCException from freqtrade.rpc.fiat_convert import CryptoToFiatConverter @@ -407,8 +406,7 @@ def test_rpc_delete_trade(mocker, default_conf, fee, markets, caplog, is_short): assert stoploss_mock.call_count == 0 -def test_rpc_trade_statistics11(default_conf_usdt, ticker, fee, - mocker) -> None: +def test_rpc_trade_statistics(default_conf_usdt, ticker, fee, mocker) -> None: mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=1.1) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( @@ -463,14 +461,9 @@ def test_rpc_trade_statistics11(default_conf_usdt, ticker, fee, # Test that rpc_trade_statistics can handle trades that lacks # trade.open_rate (it is set to None) -def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, - ticker_sell_up, limit_buy_order, limit_sell_order): - mocker.patch.multiple( - 'freqtrade.rpc.fiat_convert.CoinGeckoAPI', - get_price=MagicMock(return_value={'bitcoin': {'usd': 15000.0}}), - ) +def test_rpc_trade_statistics_closed(mocker, default_conf_usdt, ticker, fee): mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price', - return_value=15000.0) + return_value=1.1) mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -478,46 +471,32 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, get_fee=fee, ) - freqtradebot = get_patched_freqtradebot(mocker, default_conf) + freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt) patch_get_signal(freqtradebot) - stake_currency = default_conf['stake_currency'] - fiat_display_currency = default_conf['fiat_display_currency'] + stake_currency = default_conf_usdt['stake_currency'] + fiat_display_currency = default_conf_usdt['fiat_display_currency'] rpc = RPC(freqtradebot) # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - # Update the ticker with a market going up - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=ticker_sell_up, - get_fee=fee - ) - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - trade.close_date = datetime.utcnow() - trade.is_open = False + create_mock_trades_usdt(fee) for trade in Trade.query.order_by(Trade.id).all(): trade.open_rate = None stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) - assert prec_satoshi(stats['profit_closed_coin'], 0) - assert prec_satoshi(stats['profit_closed_percent_mean'], 0) - assert prec_satoshi(stats['profit_closed_fiat'], 0) - assert prec_satoshi(stats['profit_all_coin'], 0) - assert prec_satoshi(stats['profit_all_percent_mean'], 0) - assert prec_satoshi(stats['profit_all_fiat'], 0) - assert stats['trade_count'] == 1 - assert stats['first_trade_date'] == 'just now' - assert stats['latest_trade_date'] == 'just now' + assert stats['profit_closed_coin'] == 0 + assert stats['profit_closed_percent_mean'] == 0 + assert stats['profit_closed_fiat'] == 0 + assert stats['profit_all_coin'] == 0 + assert stats['profit_all_percent_mean'] == 0 + assert stats['profit_all_fiat'] == 0 + assert stats['trade_count'] == 7 + assert stats['first_trade_date'] == '2 days ago' + assert stats['latest_trade_date'] == '17 minutes ago' assert stats['avg_duration'] == '0:00:00' - assert stats['best_pair'] == 'ETH/BTC' - assert prec_satoshi(stats['best_rate'], 6.2) + assert stats['best_pair'] == 'XRP/USDT' + assert stats['best_rate'] == 10.0 def test_rpc_balance_handle_error(default_conf, mocker): @@ -869,8 +848,7 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None: assert cancel_order_mock.call_count == 3 -def test_performance_handle(default_conf, ticker, limit_buy_order, fee, - limit_sell_order, mocker) -> None: +def test_performance_handle(default_conf_usdt, ticker, fee, mocker) -> None: mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -879,34 +857,21 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee, get_fee=fee, ) - freqtradebot = get_patched_freqtradebot(mocker, default_conf) + freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt) patch_get_signal(freqtradebot) rpc = RPC(freqtradebot) - # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade + create_mock_trades_usdt(fee) - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - - trade.close_date = datetime.utcnow() - trade.is_open = False res = rpc._rpc_performance() - assert len(res) == 1 - assert res[0]['pair'] == 'ETH/BTC' + assert len(res) == 3 + assert res[0]['pair'] == 'XRP/USDT' assert res[0]['count'] == 1 - assert prec_satoshi(res[0]['profit_pct'], 6.2) + assert res[0]['profit_pct'] == 10.0 -def test_enter_tag_performance_handle(default_conf, ticker, limit_buy_order, fee, - limit_sell_order, mocker) -> None: +def test_enter_tag_performance_handle(default_conf, ticker, fee, mocker) -> None: + mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -920,34 +885,22 @@ def test_enter_tag_performance_handle(default_conf, ticker, limit_buy_order, fee rpc = RPC(freqtradebot) # Create some test data + create_mock_trades_usdt(fee) freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - - trade.close_date = datetime.utcnow() - trade.is_open = False res = rpc._rpc_enter_tag_performance(None) - assert len(res) == 1 - assert res[0]['enter_tag'] == 'Other' + assert len(res) == 3 + assert res[0]['enter_tag'] == 'TEST3' assert res[0]['count'] == 1 - assert prec_satoshi(res[0]['profit_pct'], 6.2) + assert res[0]['profit_pct'] == 10.0 - trade.enter_tag = "TEST_TAG" res = rpc._rpc_enter_tag_performance(None) - assert len(res) == 1 - assert res[0]['enter_tag'] == 'TEST_TAG' + assert len(res) == 3 + assert res[0]['enter_tag'] == 'TEST3' assert res[0]['count'] == 1 - assert prec_satoshi(res[0]['profit_pct'], 6.2) + assert res[0]['profit_pct'] == 10.0 def test_enter_tag_performance_handle_2(mocker, default_conf, markets, fee): @@ -979,8 +932,7 @@ def test_enter_tag_performance_handle_2(mocker, default_conf, markets, fee): assert prec_satoshi(res[0]['profit_pct'], 0.5) -def test_exit_reason_performance_handle(default_conf, ticker, limit_buy_order, fee, - limit_sell_order, mocker) -> None: +def test_exit_reason_performance_handle(default_conf_usdt, ticker, fee, mocker) -> None: mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -989,39 +941,22 @@ def test_exit_reason_performance_handle(default_conf, ticker, limit_buy_order, f get_fee=fee, ) - freqtradebot = get_patched_freqtradebot(mocker, default_conf) + freqtradebot = get_patched_freqtradebot(mocker, default_conf_usdt) patch_get_signal(freqtradebot) rpc = RPC(freqtradebot) # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade + create_mock_trades_usdt(fee) - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - - trade.close_date = datetime.utcnow() - trade.is_open = False res = rpc._rpc_exit_reason_performance(None) - assert len(res) == 1 - assert res[0]['exit_reason'] == 'Other' + assert len(res) == 3 + assert res[0]['exit_reason'] == 'roi' assert res[0]['count'] == 1 - assert prec_satoshi(res[0]['profit_pct'], 6.2) + assert res[0]['profit_pct'] == 10.0 - trade.exit_reason = "TEST1" - res = rpc._rpc_exit_reason_performance(None) - - assert len(res) == 1 - assert res[0]['exit_reason'] == 'TEST1' - assert res[0]['count'] == 1 - assert prec_satoshi(res[0]['profit_pct'], 6.2) + assert res[1]['exit_reason'] == 'exit_signal' + assert res[2]['exit_reason'] == 'Other' def test_exit_reason_performance_handle_2(mocker, default_conf, markets, fee): @@ -1053,8 +988,7 @@ def test_exit_reason_performance_handle_2(mocker, default_conf, markets, fee): assert prec_satoshi(res[0]['profit_pct'], 0.5) -def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee, - limit_sell_order, mocker) -> None: +def test_mix_tag_performance_handle(default_conf, ticker, fee, mocker) -> None: mocker.patch('freqtrade.rpc.telegram.Telegram', MagicMock()) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -1068,35 +1002,14 @@ def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee, rpc = RPC(freqtradebot) # Create some test data - freqtradebot.enter_positions() - trade = Trade.query.first() - assert trade + create_mock_trades_usdt(fee) - # Simulate fulfilled LIMIT_BUY order for trade - oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') - trade.update_trade(oobj) - - # Simulate fulfilled LIMIT_SELL order for trade - oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') - trade.update_trade(oobj) - - trade.close_date = datetime.utcnow() - trade.is_open = False res = rpc._rpc_mix_tag_performance(None) - assert len(res) == 1 - assert res[0]['mix_tag'] == 'Other Other' + assert len(res) == 3 + assert res[0]['mix_tag'] == 'TEST3 roi' assert res[0]['count'] == 1 - assert prec_satoshi(res[0]['profit_pct'], 6.2) - - trade.enter_tag = "TESTBUY" - trade.exit_reason = "TESTSELL" - res = rpc._rpc_mix_tag_performance(None) - - assert len(res) == 1 - assert res[0]['mix_tag'] == 'TESTBUY TESTSELL' - assert res[0]['count'] == 1 - assert prec_satoshi(res[0]['profit_pct'], 6.2) + assert res[0]['profit_pct'] == 10.0 def test_mix_tag_performance_handle_2(mocker, default_conf, markets, fee): From ee0b9e3a5c3aa907d8901db89e5c375ccb42b406 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:25:18 +0000 Subject: [PATCH 310/449] Bump mkdocs-material from 8.3.2 to 8.3.4 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.3.2 to 8.3.4. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/8.3.2...8.3.4) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index f351151ab..1b4403b97 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 -mkdocs-material==8.3.2 +mkdocs-material==8.3.4 mdx_truly_sane_lists==1.2 pymdown-extensions==9.4 jinja2==3.1.2 From 71f314d4c45b39a91380c6b1a02876506b6430af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:25:35 +0000 Subject: [PATCH 311/449] Bump ccxt from 1.85.57 to 1.87.12 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.85.57 to 1.87.12. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.85.57...1.87.12) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 05d5a10db..4ebcdaa8b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.4 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.85.57 +ccxt==1.87.12 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From 43b8b0a083d527318f6033b26a395d8c5dbc7e86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:25:53 +0000 Subject: [PATCH 312/449] Bump mypy from 0.960 to 0.961 Bumps [mypy](https://github.com/python/mypy) from 0.960 to 0.961. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.960...v0.961) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index e7d64a2b6..19912d59c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ coveralls==3.3.1 flake8==4.0.1 flake8-tidy-imports==4.8.0 -mypy==0.960 +mypy==0.961 pre-commit==2.19.0 pytest==7.1.2 pytest-asyncio==0.18.3 From cb2f89bca63a73aea5b35f5a6b8d2ae48d5455c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 06:26:23 +0000 Subject: [PATCH 313/449] Bump requests from 2.27.1 to 2.28.0 Bumps [requests](https://github.com/psf/requests) from 2.27.1 to 2.28.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.27.1...v2.28.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 05d5a10db..ba9cecafd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ SQLAlchemy==1.4.37 python-telegram-bot==13.12 arrow==1.2.2 cachetools==4.2.2 -requests==2.27.1 +requests==2.28.0 urllib3==1.26.9 jsonschema==4.6.0 TA-Lib==0.4.24 From fdca583c6760a6ba76f04b076e373d09accf8291 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:07:39 +0000 Subject: [PATCH 314/449] Bump pymdown-extensions from 9.4 to 9.5 Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 9.4 to 9.5. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/9.4...9.5) --- updated-dependencies: - dependency-name: pymdown-extensions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 1b4403b97..1f342ca02 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 mkdocs-material==8.3.4 mdx_truly_sane_lists==1.2 -pymdown-extensions==9.4 +pymdown-extensions==9.5 jinja2==3.1.2 From 850f5d3842008406c9a24611fdb6e40e6c138ae1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:32:39 +0000 Subject: [PATCH 315/449] Bump orjson from 3.7.1 to 3.7.2 Bumps [orjson](https://github.com/ijl/orjson) from 3.7.1 to 3.7.2. - [Release notes](https://github.com/ijl/orjson/releases) - [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md) - [Commits](https://github.com/ijl/orjson/compare/3.7.1...3.7.2) --- updated-dependencies: - dependency-name: orjson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9b7d87e02..b2dbd921e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,7 +28,7 @@ py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.6 # Properly format api responses -orjson==3.7.1 +orjson==3.7.2 # Notify systemd sdnotify==0.3.2 From 35adeb64122a02d52f2515b53ea3bd125c2a8d31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:33:30 +0000 Subject: [PATCH 316/449] Bump plotly from 5.8.0 to 5.8.2 Bumps [plotly](https://github.com/plotly/plotly.py) from 5.8.0 to 5.8.2. - [Release notes](https://github.com/plotly/plotly.py/releases) - [Changelog](https://github.com/plotly/plotly.py/blob/master/CHANGELOG.md) - [Commits](https://github.com/plotly/plotly.py/compare/v5.8.0...v5.8.2) --- updated-dependencies: - dependency-name: plotly dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-plot.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-plot.txt b/requirements-plot.txt index e17efbc71..a2a894c57 100644 --- a/requirements-plot.txt +++ b/requirements-plot.txt @@ -1,4 +1,4 @@ # Include all requirements to run the bot. -r requirements.txt -plotly==5.8.0 +plotly==5.8.2 From 848a5d85c63f7655f958c700e1e82caaa69d2b9f Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Jun 2022 08:50:12 +0000 Subject: [PATCH 317/449] Add small stability fix to test --- tests/test_freqtradebot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 7f9bc6a46..3fd16f925 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3775,6 +3775,7 @@ def test_exit_profit_only( trade = Trade.query.first() assert trade.is_short == is_short oobj = Order.parse_from_ccxt_object(limit_order[eside], limit_order[eside]['symbol'], eside) + trade.update_order(limit_order[eside]) trade.update_trade(oobj) freqtrade.wallets.update() if profit_only: @@ -4063,6 +4064,7 @@ def test_trailing_stop_loss_positive( trade = Trade.query.first() assert trade.is_short == is_short oobj = Order.parse_from_ccxt_object(limit_order[eside], limit_order[eside]['symbol'], eside) + trade.update_order(limit_order[eside]) trade.update_trade(oobj) caplog.set_level(logging.DEBUG) # stop-loss not reached From d5fd1f9c3848469b4ce1fa1039ef533acc09c0f2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Jun 2022 13:24:27 +0000 Subject: [PATCH 318/449] Improve order filled handling --- freqtrade/persistence/trade_model.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 0be9d22c1..79f58591d 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -74,7 +74,7 @@ class Order(_DECL_BASE): @property def safe_filled(self) -> float: - return self.filled or self.amount or 0.0 + return self.filled if self.filled is not None else self.amount or 0.0 @property def safe_fee_base(self) -> float: @@ -847,8 +847,6 @@ class LocalTrade(): tmp_amount = o.safe_amount_after_fee tmp_price = o.average or o.price - if o.filled is not None: - tmp_amount = o.filled if tmp_amount > 0.0 and tmp_price is not None: total_amount += tmp_amount total_stake += tmp_price * tmp_amount From 1ffee96bade938c25d025bd32839fb0a8a6430c9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Jun 2022 19:59:00 +0200 Subject: [PATCH 319/449] Fix protection parameters not loading from parameter file closes #6978 --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index fdccc2f8a..000f74a27 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -73,8 +73,6 @@ class FreqtradeBot(LoggingMixin): PairLocks.timeframe = self.config['timeframe'] - self.protections = ProtectionManager(self.config, self.strategy.protections) - # RPC runs in separate threads, can start handling external commands just after # initialization, even before Freqtradebot has a chance to start its throttling, # so anything in the Freqtradebot instance should be ready (initialized), including @@ -124,6 +122,8 @@ class FreqtradeBot(LoggingMixin): self.last_process = datetime(1970, 1, 1, tzinfo=timezone.utc) self.strategy.ft_bot_start() + # Initialize protections AFTER bot start - otherwise parameters are not loaded. + self.protections = ProtectionManager(self.config, self.strategy.protections) def notify_status(self, msg: str) -> None: """ From 01a68e1060bf0c7a30a8fc9732d035547f7dd11c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 13 Jun 2022 20:48:49 +0200 Subject: [PATCH 320/449] Remove unnecessary check and condition --- freqtrade/persistence/trade_model.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 79f58591d..3222a57b8 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -828,14 +828,6 @@ class LocalTrade(): return float(f"{profit_ratio:.8f}") def recalc_trade_from_orders(self): - # We need at least 2 entry orders for averaging amounts and rates. - # TODO: this condition could probably be removed - if len(self.select_filled_orders(self.entry_side)) < 2: - self.stake_amount = self.amount * self.open_rate / self.leverage - - # Just in case, still recalc open trade value - self.recalc_open_trade_value() - return total_amount = 0.0 total_stake = 0.0 From 6bb342f23a28559eca7c2355edd6e4af73b7e112 Mon Sep 17 00:00:00 2001 From: froggleston Date: Tue, 14 Jun 2022 16:54:27 +0100 Subject: [PATCH 321/449] Add export-filename support --- docs/advanced-backtesting.md | 25 +++++++++++++++++++++++++ freqtrade/commands/analyze_commands.py | 26 ++++++++++++++++---------- freqtrade/commands/arguments.py | 2 +- freqtrade/data/entryexitanalysis.py | 2 +- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/docs/advanced-backtesting.md b/docs/advanced-backtesting.md index 7f2be1f1a..457c487e9 100644 --- a/docs/advanced-backtesting.md +++ b/docs/advanced-backtesting.md @@ -45,6 +45,31 @@ ranging from the simplest (0) to the most detailed per pair, per buy and per sel More options are available by running with the `-h` option. +### Using export-filename + +Normally, `backtesting-analysis` uses the latest backtest results, but if you wanted to go +back to a previous backtest output, you need to supply the `--export-filename` option. +You can supply the same parameter to `backtest-analysis` with the name of the final backtest +output file. This allows you to keep historical versions of backtest results and reanalyse +them at a later date: + +``` bash +freqtrade backtesting -c --timeframe --strategy --timerange= --export=signals --export-filename=/tmp/mystrat_backtest.json +``` + +You should see some output similar to below in the logs with the name of the timestamped +filename that was exported: + +``` +2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "/tmp/mystrat_backtest-2022-06-14_16-28-32.json" +``` + +You can then use that filename in `backtesting-analysis`: + +``` +freqtrade backtesting-analysis -c --export-filename=/tmp/mystrat_backtest-2022-06-14_16-28-32.json +``` + ### Tuning the buy tags and sell tags to display To show only certain buy and sell tags in the displayed output, use the following two options: diff --git a/freqtrade/commands/analyze_commands.py b/freqtrade/commands/analyze_commands.py index 2fa13f683..b6b790788 100755 --- a/freqtrade/commands/analyze_commands.py +++ b/freqtrade/commands/analyze_commands.py @@ -25,17 +25,23 @@ def setup_analyze_configuration(args: Dict[str, Any], method: RunMode) -> Dict[s if method in no_unlimited_runmodes.keys(): from freqtrade.data.btanalysis import get_latest_backtest_filename - btfile = Path(get_latest_backtest_filename(config['user_data_dir'] / 'backtest_results')) - signals_file = f"{btfile.stem}_signals.pkl" + if 'exportfilename' in config: + if config['exportfilename'].is_dir(): + btfile = Path(get_latest_backtest_filename(config['exportfilename'])) + signals_file = f"{config['exportfilename']}/{btfile.stem}_signals.pkl" + else: + if config['exportfilename'].exists(): + btfile = Path(config['exportfilename']) + signals_file = f"{btfile.parent}/{btfile.stem}_signals.pkl" + else: + raise OperationalException(f"{config['exportfilename']} does not exist.") + else: + raise OperationalException('exportfilename not in config.') - if (not (config['user_data_dir'] / 'backtest_results' / signals_file).exists()): + if (not Path(signals_file).exists()): raise OperationalException( - "Cannot find latest backtest signals file. Run backtesting with --export signals." - ) - - if ('strategy' not in config): - raise OperationalException( - "No strategy defined. Use --strategy or supply in config." + (f"Cannot find latest backtest signals file: {signals_file}." + "Run backtesting with `--export signals`.") ) return config @@ -54,7 +60,7 @@ def start_analysis_entries_exits(args: Dict[str, Any]) -> None: logger.info('Starting freqtrade in analysis mode') - process_entry_exit_reasons(Path(config['user_data_dir'], 'backtest_results'), + process_entry_exit_reasons(config['exportfilename'], config['exchange']['pair_whitelist'], config['analysis_groups'], config['enter_reason_list'], diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 6092c630b..1e3e2845a 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -101,7 +101,7 @@ ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperop "print_json", "hyperoptexportfilename", "hyperopt_show_no_header", "disableparamexport", "backtest_breakdown"] -ARGS_ANALYZE_ENTRIES_EXITS = ["analysis_groups", "enter_reason_list", +ARGS_ANALYZE_ENTRIES_EXITS = ["exportfilename", "analysis_groups", "enter_reason_list", "exit_reason_list", "indicator_list"] NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes", diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index 1c21fcc15..d67064bd7 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -20,7 +20,7 @@ def _load_signal_candles(backtest_dir: Path): Path(get_latest_backtest_filename(backtest_dir)).stem + "_signals.pkl" ) else: - scpf = Path(Path(get_latest_backtest_filename(backtest_dir)).stem + "_signals.pkl") + scpf = Path(backtest_dir.parent / f"{backtest_dir.stem}_signals.pkl") try: scp = open(scpf, "rb") From 3c62df6b86c4749991ea751e0b567ea3df7585ac Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jun 2022 06:53:52 +0200 Subject: [PATCH 322/449] Ensure the same timestamp is used for backtest and signal export --- freqtrade/optimize/backtesting.py | 7 ++++--- freqtrade/optimize/optimize_reports.py | 20 ++++++++++---------- freqtrade/rpc/api_server/api_backtest.py | 6 +++++- tests/optimize/test_optimize_reports.py | 14 +++++++------- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 1aad8520a..77eb12419 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -1264,13 +1264,14 @@ class Backtesting: self.results['strategy_comparison'].extend(results['strategy_comparison']) else: self.results = results - + dt_appendix = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") if self.config.get('export', 'none') in ('trades', 'signals'): - store_backtest_stats(self.config['exportfilename'], self.results) + store_backtest_stats(self.config['exportfilename'], self.results, dt_appendix) if (self.config.get('export', 'none') == 'signals' and self.dataprovider.runmode == RunMode.BACKTEST): - store_backtest_signal_candles(self.config['exportfilename'], self.processed_dfs) + store_backtest_signal_candles( + self.config['exportfilename'], self.processed_dfs, dt_appendix) # Results may be mixed up now. Sort them so they follow --strategy-list order. if 'strategy_list' in self.config and len(self.results) > 0: diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index e3dd17411..44b524a4c 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -17,21 +17,21 @@ from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename logger = logging.getLogger(__name__) -def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> None: +def store_backtest_stats( + recordfilename: Path, stats: Dict[str, DataFrame], dtappendix: str) -> None: """ Stores backtest results :param recordfilename: Path object, which can either be a filename or a directory. Filenames will be appended with a timestamp right before the suffix while for directories, /backtest-result-.json will be used as filename :param stats: Dataframe containing the backtesting statistics + :param dtappendix: Datetime to use for the filename """ if recordfilename.is_dir(): - filename = (recordfilename / - f'backtest-result-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.json') + filename = (recordfilename / f'backtest-result-{dtappendix}.json') else: filename = Path.joinpath( - recordfilename.parent, - f'{recordfilename.stem}-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}' + recordfilename.parent, f'{recordfilename.stem}-{dtappendix}' ).with_suffix(recordfilename.suffix) # Store metadata separately. @@ -44,7 +44,8 @@ def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> N file_dump_json(latest_filename, {'latest_backtest': str(filename.name)}) -def store_backtest_signal_candles(recordfilename: Path, candles: Dict[str, Dict]) -> Path: +def store_backtest_signal_candles( + recordfilename: Path, candles: Dict[str, Dict], dtappendix: str) -> Path: """ Stores backtest trade signal candles :param recordfilename: Path object, which can either be a filename or a directory. @@ -52,14 +53,13 @@ def store_backtest_signal_candles(recordfilename: Path, candles: Dict[str, Dict] while for directories, /backtest-result-_signals.pkl will be used as filename :param stats: Dict containing the backtesting signal candles + :param dtappendix: Datetime to use for the filename """ if recordfilename.is_dir(): - filename = (recordfilename / - f'backtest-result-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_signals.pkl') + filename = (recordfilename / f'backtest-result-{dtappendix}_signals.pkl') else: filename = Path.joinpath( - recordfilename.parent, - f'{recordfilename.stem}-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_signals.pkl' + recordfilename.parent, f'{recordfilename.stem}-{dtappendix}_signals.pkl' ) file_dump_joblib(filename, candles) diff --git a/freqtrade/rpc/api_server/api_backtest.py b/freqtrade/rpc/api_server/api_backtest.py index 26b100408..06f04729b 100644 --- a/freqtrade/rpc/api_server/api_backtest.py +++ b/freqtrade/rpc/api_server/api_backtest.py @@ -1,6 +1,7 @@ import asyncio import logging from copy import deepcopy +from datetime import datetime from typing import Any, Dict, List from fastapi import APIRouter, BackgroundTasks, Depends @@ -102,7 +103,10 @@ async def api_start_backtest(bt_settings: BacktestRequest, background_tasks: Bac min_date=min_date, max_date=max_date) if btconfig.get('export', 'none') == 'trades': - store_backtest_stats(btconfig['exportfilename'], ApiServer._bt.results) + store_backtest_stats( + btconfig['exportfilename'], ApiServer._bt.results, + datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + ) logger.info("Backtest finished.") diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 997c0436e..562e12820 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -171,7 +171,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): _backup_file(filename_last, copy_file=True) assert not filename.is_file() - store_backtest_stats(filename, stats) + store_backtest_stats(filename, stats, '2022_01_01_15_05_13') # get real Filename (it's btresult-.json) last_fn = get_latest_backtest_filename(filename_last.parent) @@ -194,7 +194,7 @@ def test_store_backtest_stats(testdatadir, mocker): dump_mock = mocker.patch('freqtrade.optimize.optimize_reports.file_dump_json') - store_backtest_stats(testdatadir, {'metadata': {}}) + store_backtest_stats(testdatadir, {'metadata': {}}, '2022_01_01_15_05_13') assert dump_mock.call_count == 3 assert isinstance(dump_mock.call_args_list[0][0][0], Path) @@ -202,7 +202,7 @@ def test_store_backtest_stats(testdatadir, mocker): dump_mock.reset_mock() filename = testdatadir / 'testresult.json' - store_backtest_stats(filename, {'metadata': {}}) + store_backtest_stats(filename, {'metadata': {}}, '2022_01_01_15_05_13') assert dump_mock.call_count == 3 assert isinstance(dump_mock.call_args_list[0][0][0], Path) # result will be testdatadir / testresult-.json @@ -216,7 +216,7 @@ def test_store_backtest_candles(testdatadir, mocker): candle_dict = {'DefStrat': {'UNITTEST/BTC': pd.DataFrame()}} # mock directory exporting - store_backtest_signal_candles(testdatadir, candle_dict) + store_backtest_signal_candles(testdatadir, candle_dict, '2022_01_01_15_05_13') assert dump_mock.call_count == 1 assert isinstance(dump_mock.call_args_list[0][0][0], Path) @@ -225,7 +225,7 @@ def test_store_backtest_candles(testdatadir, mocker): dump_mock.reset_mock() # mock file exporting filename = Path(testdatadir / 'testresult') - store_backtest_signal_candles(filename, candle_dict) + store_backtest_signal_candles(filename, candle_dict, '2022_01_01_15_05_13') assert dump_mock.call_count == 1 assert isinstance(dump_mock.call_args_list[0][0][0], Path) # result will be testdatadir / testresult-_signals.pkl @@ -238,7 +238,7 @@ def test_write_read_backtest_candles(tmpdir): candle_dict = {'DefStrat': {'UNITTEST/BTC': pd.DataFrame()}} # test directory exporting - stored_file = store_backtest_signal_candles(Path(tmpdir), candle_dict) + stored_file = store_backtest_signal_candles(Path(tmpdir), candle_dict, '2022_01_01_15_05_13') scp = open(stored_file, "rb") pickled_signal_candles = joblib.load(scp) scp.close() @@ -252,7 +252,7 @@ def test_write_read_backtest_candles(tmpdir): # test file exporting filename = Path(tmpdir / 'testresult') - stored_file = store_backtest_signal_candles(filename, candle_dict) + stored_file = store_backtest_signal_candles(filename, candle_dict, '2022_01_01_15_05_13') scp = open(stored_file, "rb") pickled_signal_candles = joblib.load(scp) scp.close() From 29d8aeb9b3c19c5b5c7a37d8d8dc42e6478f6f33 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jun 2022 07:13:47 +0200 Subject: [PATCH 323/449] Don't fail on invalid parameter --- freqtrade/data/entryexitanalysis.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index d67064bd7..999f27955 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -140,14 +140,16 @@ def _do_group_table_output(bigdf, glist): # 4: profit summaries grouped by pair, enter_ and exit_tag (this can get quite large) if g == "4": group_mask = ['pair', 'enter_reason', 'exit_reason'] + if group_mask: + new = bigdf.groupby(group_mask).agg(agg_mask).reset_index() + new.columns = group_mask + agg_cols + new['median_profit_pct'] = new['median_profit_pct'] * 100 + new['mean_profit_pct'] = new['mean_profit_pct'] * 100 + new['total_profit_pct'] = new['total_profit_pct'] * 100 - new = bigdf.groupby(group_mask).agg(agg_mask).reset_index() - new.columns = group_mask + agg_cols - new['median_profit_pct'] = new['median_profit_pct'] * 100 - new['mean_profit_pct'] = new['mean_profit_pct'] * 100 - new['total_profit_pct'] = new['total_profit_pct'] * 100 - - _print_table(new, sortcols) + _print_table(new, sortcols) + else: + logger.warning("Invalid group mask specified.") def _print_results(analysed_trades, stratname, analysis_groups, From c391ca08ded88ff1c4edfd8ab9a40b385b0a16a2 Mon Sep 17 00:00:00 2001 From: froggleston Date: Wed, 15 Jun 2022 11:25:06 +0100 Subject: [PATCH 324/449] Change backtesting-analysis options to space separated lists --- docs/advanced-backtesting.md | 13 +++++----- freqtrade/commands/cli_options.py | 17 +++++++------ freqtrade/data/entryexitanalysis.py | 38 +++++++++++++---------------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/docs/advanced-backtesting.md b/docs/advanced-backtesting.md index 457c487e9..b6b75c47d 100644 --- a/docs/advanced-backtesting.md +++ b/docs/advanced-backtesting.md @@ -28,10 +28,11 @@ backtesting with the `--cache none` option to make sure no cached results are us If all goes well, you should now see a `backtest-result-{timestamp}_signals.pkl` file in the `user_data/backtest_results` folder. -To analyze the entry/exit tags, we now need to use the `freqtrade backtesting-analysis` command: +To analyze the entry/exit tags, we now need to use the `freqtrade backtesting-analysis` command +with `--analysis-groups` option provided with space-separated arguments (default `0 1 2`): ``` bash -freqtrade backtesting-analysis -c --analysis-groups 0,1,2,3,4 +freqtrade backtesting-analysis -c --analysis-groups 0 1 2 3 4 ``` This command will read from the last backtesting results. The `--analysis-groups` option is @@ -75,14 +76,14 @@ freqtrade backtesting-analysis -c --export-filename=/tmp/mystrat_b To show only certain buy and sell tags in the displayed output, use the following two options: ``` ---enter-reason-list : Comma separated list of enter signals to analyse. Default: "all" ---exit-reason-list : Comma separated list of exit signals to analyse. Default: "stop_loss,trailing_stop_loss" +--enter-reason-list : Space-separated list of enter signals to analyse. Default: "all" +--exit-reason-list : Space-separated list of exit signals to analyse. Default: "all" ``` For example: ```bash -freqtrade backtesting-analysis -c --analysis-groups 0,1,2,3,4 --enter-reason-list "enter_tag_a,enter_tag_b" --exit-reason-list "roi,custom_exit_tag_a,stop_loss" +freqtrade backtesting-analysis -c --analysis-groups 0 2 --enter-reason-list enter_tag_a enter_tag_b --exit-reason-list roi custom_exit_tag_a stop_loss ``` ### Outputting signal candle indicators @@ -93,7 +94,7 @@ indicators. To print out a column for a given set of indicators, use the `--indi option: ```bash -freqtrade backtesting-analysis -c --analysis-groups 0,1,2,3,4 --enter-reason-list "enter_tag_a,enter_tag_b" --exit-reason-list "roi,custom_exit_tag_a,stop_loss" --indicator-list "rsi,rsi_1h,bb_lowerband,ema_9,macd,macdsignal" +freqtrade backtesting-analysis -c --analysis-groups 0 2 --enter-reason-list enter_tag_a enter_tag_b --exit-reason-list roi custom_exit_tag_a stop_loss --indicator-list rsi rsi_1h bb_lowerband ema_9 macd macdsignal ``` The indicators have to be present in your strategy's main DataFrame (either for your main diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index e90d3478d..3370ce64b 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -622,28 +622,29 @@ AVAILABLE_CLI_OPTIONS = { "2: by enter_tag and exit_tag, " "3: by pair and enter_tag, " "4: by pair, enter_ and exit_tag (this can get quite large)"), - nargs='?', - default="0,1,2", + nargs='+', + default=['0', '1', '2'], + choices=['0', '1', '2', '3', '4'], ), "enter_reason_list": Arg( "--enter-reason-list", help=("Comma separated list of entry signals to analyse. Default: all. " "e.g. 'entry_tag_a,entry_tag_b'"), - nargs='?', - default='all', + nargs='+', + default=['all'], ), "exit_reason_list": Arg( "--exit-reason-list", help=("Comma separated list of exit signals to analyse. Default: all. " "e.g. 'exit_tag_a,roi,stop_loss,trailing_stop_loss'"), - nargs='?', - default='all', + nargs='+', + default=['all'], ), "indicator_list": Arg( "--indicator-list", help=("Comma separated list of indicators to analyse. " "e.g. 'close,rsi,bb_lowerband,profit_abs'"), - nargs='?', - default='', + nargs='+', + default=[], ), } diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index d67064bd7..6a157debb 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -161,28 +161,24 @@ def _print_results(analysed_trades, stratname, analysis_groups, bigdf = pd.concat([bigdf, trades], ignore_index=True) if bigdf.shape[0] > 0 and ('enter_reason' in bigdf.columns): - if analysis_groups is not None: - glist = analysis_groups.split(",") - _do_group_table_output(bigdf, glist) + if analysis_groups: + _do_group_table_output(bigdf, analysis_groups) - if enter_reason_list is not None and not enter_reason_list == "all": - enter_reason_list = enter_reason_list.split(",") + if enter_reason_list and "all" not in enter_reason_list: bigdf = bigdf.loc[(bigdf['enter_reason'].isin(enter_reason_list))] - if exit_reason_list is not None and not exit_reason_list == "all": - exit_reason_list = exit_reason_list.split(",") + if exit_reason_list and "all" not in exit_reason_list: bigdf = bigdf.loc[(bigdf['exit_reason'].isin(exit_reason_list))] - if indicator_list is not None and indicator_list != "": - if indicator_list == "all": - print(bigdf) - else: - available_inds = [] - for ind in indicator_list.split(","): - if ind in bigdf: - available_inds.append(ind) - ilist = ["pair", "enter_reason", "exit_reason"] + available_inds - _print_table(bigdf[ilist], sortcols=['exit_reason'], show_index=False) + if "all" in indicator_list: + print(bigdf) + elif indicator_list is not None: + available_inds = [] + for ind in indicator_list: + if ind in bigdf: + available_inds.append(ind) + ilist = ["pair", "enter_reason", "exit_reason"] + available_inds + _print_table(bigdf[ilist], sortcols=['exit_reason'], show_index=False) else: print("\\_ No trades to show") @@ -205,10 +201,10 @@ def _print_table(df, sortcols=None, show_index=False): def process_entry_exit_reasons(backtest_dir: Path, pairlist: List[str], - analysis_groups: Optional[str] = "0,1,2", - enter_reason_list: Optional[str] = "all", - exit_reason_list: Optional[str] = "all", - indicator_list: Optional[str] = None): + analysis_groups: Optional[List[str]] = ["0", "1", "2"], + enter_reason_list: Optional[List[str]] = ["all"], + exit_reason_list: Optional[List[str]] = ["all"], + indicator_list: Optional[List[str]] = []): try: backtest_stats = load_backtest_stats(backtest_dir) for strategy_name, results in backtest_stats['strategy'].items(): From 4a5ed5a2731bc78522c2ed3118398f64f538975e Mon Sep 17 00:00:00 2001 From: froggleston Date: Wed, 15 Jun 2022 11:48:57 +0100 Subject: [PATCH 325/449] Fix tests --- tests/data/test_entryexitanalysis.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index 6209110fe..09fbe9957 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -103,8 +103,8 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp # test group 0 and indicator list args = get_args(base_args + - ['--analysis-groups', '0', - '--indicator-list', 'close,rsi,profit_abs'] + ['--analysis-groups', "0", + '--indicator-list', "close", "rsi", "profit_abs"] ) start_analysis_entries_exits(args) captured = capsys.readouterr() @@ -128,7 +128,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '47.0996' in captured.out # test group 1 - args = get_args(base_args + ['--analysis-groups', '1']) + args = get_args(base_args + ['--analysis-groups', "1"]) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'enter_tag_long_a' in captured.out @@ -141,7 +141,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '0' in captured.out # test group 2 - args = get_args(base_args + ['--analysis-groups', '2']) + args = get_args(base_args + ['--analysis-groups', "2"]) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'enter_tag_long_a' in captured.out @@ -156,7 +156,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '2.5' in captured.out # test group 3 - args = get_args(base_args + ['--analysis-groups', '3']) + args = get_args(base_args + ['--analysis-groups', "3"]) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'LTC/BTC' in captured.out @@ -171,7 +171,7 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '2' in captured.out # test group 4 - args = get_args(base_args + ['--analysis-groups', '4']) + args = get_args(base_args + ['--analysis-groups', "4"]) start_analysis_entries_exits(args) captured = capsys.readouterr() assert 'LTC/BTC' in captured.out From e2e6c790be9869e8bb82d9bf58f8a2d8f98c0cec Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jun 2022 16:50:25 +0200 Subject: [PATCH 326/449] Minor doc update --- docs/advanced-backtesting.md | 2 +- docs/utils.md | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/advanced-backtesting.md b/docs/advanced-backtesting.md index b6b75c47d..5c2500f18 100644 --- a/docs/advanced-backtesting.md +++ b/docs/advanced-backtesting.md @@ -51,7 +51,7 @@ More options are available by running with the `-h` option. Normally, `backtesting-analysis` uses the latest backtest results, but if you wanted to go back to a previous backtest output, you need to supply the `--export-filename` option. You can supply the same parameter to `backtest-analysis` with the name of the final backtest -output file. This allows you to keep historical versions of backtest results and reanalyse +output file. This allows you to keep historical versions of backtest results and re-analyse them at a later date: ``` bash diff --git a/docs/utils.md b/docs/utils.md index f87aa2ffc..0dd88b242 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -660,26 +660,31 @@ More details in the [Backtesting analysis](advanced-backtesting.md#analyze-the-b ``` usage: freqtrade backtesting-analysis [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] - [--analysis-groups [ANALYSIS_GROUPS]] - [--enter-reason-list [ENTER_REASON_LIST]] - [--exit-reason-list [EXIT_REASON_LIST]] - [--indicator-list [INDICATOR_LIST]] + [--export-filename PATH] + [--analysis-groups {0,1,2,3,4} [{0,1,2,3,4} ...]] + [--enter-reason-list ENTER_REASON_LIST [ENTER_REASON_LIST ...]] + [--exit-reason-list EXIT_REASON_LIST [EXIT_REASON_LIST ...]] + [--indicator-list INDICATOR_LIST [INDICATOR_LIST ...]] optional arguments: -h, --help show this help message and exit - --analysis-groups [ANALYSIS_GROUPS] + --export-filename PATH, --backtest-filename PATH + Use this filename for backtest results.Requires + `--export` to be set as well. Example: `--export-filen + ame=user_data/backtest_results/backtest_today.json` + --analysis-groups {0,1,2,3,4} [{0,1,2,3,4} ...] grouping output - 0: simple wins/losses by enter tag, 1: by enter_tag, 2: by enter_tag and exit_tag, 3: by pair and enter_tag, 4: by pair, enter_ and exit_tag (this can get quite large) - --enter-reason-list [ENTER_REASON_LIST] + --enter-reason-list ENTER_REASON_LIST [ENTER_REASON_LIST ...] Comma separated list of entry signals to analyse. Default: all. e.g. 'entry_tag_a,entry_tag_b' - --exit-reason-list [EXIT_REASON_LIST] + --exit-reason-list EXIT_REASON_LIST [EXIT_REASON_LIST ...] Comma separated list of exit signals to analyse. Default: all. e.g. 'exit_tag_a,roi,stop_loss,trailing_stop_loss' - --indicator-list [INDICATOR_LIST] + --indicator-list INDICATOR_LIST [INDICATOR_LIST ...] Comma separated list of indicators to analyse. e.g. 'close,rsi,bb_lowerband,profit_abs' From f9e2e87346319bb32e596538a91340b8b4474b09 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jun 2022 20:03:36 +0200 Subject: [PATCH 327/449] Improve some formatting and typehints --- freqtrade/rpc/rpc.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index da5144dab..8b1cdb851 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -512,7 +512,7 @@ class RPC: def _rpc_balance(self, stake_currency: str, fiat_display_currency: str) -> Dict: """ Returns current account balance per crypto """ - currencies = [] + currencies: List[Dict] = [] total = 0.0 try: tickers = self._freqtrade.exchange.get_tickers(cached=True) @@ -547,13 +547,12 @@ class RPC: except (ExchangeError): logger.warning(f" Could not get rate for pair {coin}.") continue - total = total + (est_stake or 0) + total = total + est_stake currencies.append({ 'currency': coin, - # TODO: The below can be simplified if we don't assign None to values. - 'free': balance.free if balance.free is not None else 0, - 'balance': balance.total if balance.total is not None else 0, - 'used': balance.used if balance.used is not None else 0, + 'free': balance.free, + 'balance': balance.total, + 'used': balance.used, 'est_stake': est_stake or 0, 'stake': stake_currency, 'side': 'long', @@ -583,7 +582,6 @@ class RPC: total, stake_currency, fiat_display_currency) if self._fiat_converter else 0 trade_count = len(Trade.get_trades_proxy()) - starting_capital_ratio = 0.0 starting_capital_ratio = (total / starting_capital) - 1 if starting_capital else 0.0 starting_cap_fiat_ratio = (value / starting_cap_fiat) - 1 if starting_cap_fiat else 0.0 @@ -871,7 +869,7 @@ class RPC: else: errors[pair] = { 'error_msg': f"Pair {pair} is not in the current blacklist." - } + } resp = self._rpc_blacklist() resp['errors'] = errors return resp From 8f32fa5cb30efed0fa4f3d81e676951b5554dd8a Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jun 2022 20:13:07 +0200 Subject: [PATCH 328/449] Avoid exception on exchange recycling if __init__ fails --- freqtrade/exchange/exchange.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index c1a9059a7..465cce300 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -93,7 +93,7 @@ class Exchange: :return: None """ self._api: ccxt.Exchange - self._api_async: ccxt_async.Exchange + self._api_async: ccxt_async.Exchange = None self._markets: Dict = {} self._trading_fees: Dict[str, Any] = {} self._leverage_tiers: Dict[str, List[Dict]] = {} From 14a859c190a1fa8b89a13b8d756127546b822ff5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 16 Jun 2022 19:50:13 +0200 Subject: [PATCH 329/449] Improve some documentation around futures / leverage --- docs/leverage.md | 15 ++++++++++++++- docs/stoploss.md | 13 +++++++++++++ docs/strategy-callbacks.md | 3 +++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/leverage.md b/docs/leverage.md index 2ee6f8444..491e6eda0 100644 --- a/docs/leverage.md +++ b/docs/leverage.md @@ -64,7 +64,10 @@ You will also have to pick a "margin mode" (explanation below) - with freqtrade ### Margin mode -The possible values are: `isolated`, or `cross`(*currently unavailable*) +On top of `trading_mode` - you will also have to configure your `margin_mode`. +While freqtrade currently only supports one margin mode, this will change, and by configuring it now you're all set for future updates. + +The possible values are: `isolated`, or `cross`(*currently unavailable*). #### Isolated margin mode @@ -82,6 +85,16 @@ One account is used to share collateral between markets (trading pairs). Margin "margin_mode": "cross" ``` +## Set leverage to use + +Different strategies and risk profiles will require different levels of leverage. +While you could configure one static leverage value - freqtrade offers you the flexibility to adjust this via [strategy leverage callback](strategy-callbacks.md#leverage-callback) - which allows you to use different leverages by pair, or based on some other factor benefitting your strategy result. + +If not implemented, leverage defaults to 1x (no leverage). + +!!! Warning + Higher leverage also equals higher risk - be sure you fully understand the implications of using leverage! + ## Understand `liquidation_buffer` *Defaults to `0.05`* diff --git a/docs/stoploss.md b/docs/stoploss.md index 573fdbd6c..83f787947 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -191,6 +191,19 @@ For example, simplified math: !!! Tip Make sure to have this value (`trailing_stop_positive_offset`) lower than minimal ROI, otherwise minimal ROI will apply first and sell the trade. +## Stoploss and Leverage + +Stoploss should be thought of as "risk on this trade" - so a stoploss of 10% on a 100$ trade means you are willing to lose 10$ (10%) on this trade - which would trigger if the price moves 10% to the downside. + +When using leverage, the same principle is applied - with stoploss defining the risk on the trade (the amount you are willing to lose). + +Therefore, a stoploss of 10% on a 10x trade would trigger on a 1% price move. +If your stake amount (own capital) was 100$ - this trade would be 1000$ at 10x (after leverage). +If price moves 1% - you've lost 10$ of your own capital - therfore stoploss will trigger in this case. + +Make sure to be aware of this, and avoid using too tight stoploss (at 10x leverage, 10% risk may be too little to allow the trade to "breath" a little). + + ## Changing stoploss on open trades A stoploss on an open trade can be changed by changing the value in the configuration or strategy and use the `/reload_config` command (alternatively, completely stopping and restarting the bot also works). diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 410641f44..beffba56b 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -823,3 +823,6 @@ class AwesomeStrategy(IStrategy): """ return 1.0 ``` + +All profit calculations include leverage. Stoploss / ROI also include leverage in their calculation. +Defining a stoploss of 10% at 10x leverage would trigger the stoploss with a 1% move to the downside. From 575b4ead1a04bffc4c3064abcfe85fe77574b7c8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 17 Jun 2022 06:29:17 +0000 Subject: [PATCH 330/449] Update Test with funding_fee 0 --- tests/test_persistence.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index be19a3f5f..836b17a55 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -884,6 +884,17 @@ def test_calc_close_trade_price( ('binance', False, 3, 2.2, 0.0025, 4.684999, 0.23366583, futures, -1), ('binance', True, 1, 2.2, 0.0025, -7.315, -0.12222222, futures, -1), ('binance', True, 3, 2.2, 0.0025, -7.315, -0.36666666, futures, -1), + + # FUTURES, funding_fee=0 + ('binance', False, 1, 2.1, 0.0025, 2.6925, 0.04476309, futures, 0), + ('binance', False, 3, 2.1, 0.0025, 2.6925, 0.13428928, futures, 0), + ('binance', True, 1, 2.1, 0.0025, -3.3074999, -0.05526316, futures, 0), + ('binance', True, 3, 2.1, 0.0025, -3.3074999, -0.16578947, futures, 0), + + ('binance', False, 1, 1.9, 0.0025, -3.2925, -0.05473815, futures, 0), + ('binance', False, 3, 1.9, 0.0025, -3.2925, -0.16421446, futures, 0), + ('binance', True, 1, 1.9, 0.0025, 2.7075, 0.0452381, futures, 0), + ('binance', True, 3, 1.9, 0.0025, 2.7075, 0.13571429, futures, 0), ]) @pytest.mark.usefixtures("init_persistence") def test_calc_profit( From 76cae8e8e3b2710983084acbfa6a0e88fa0e2c81 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 17 Jun 2022 06:53:40 +0000 Subject: [PATCH 331/449] Update tests to always provide rate to profit calculations --- tests/rpc/test_rpc_apiserver.py | 8 ++++---- tests/test_freqtradebot.py | 2 +- tests/test_persistence.py | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 8b3ac18ac..ada1a82ec 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -852,8 +852,8 @@ def test_api_performance(botclient, fee): close_rate=0.265441, ) - trade.close_profit = trade.calc_profit_ratio() - trade.close_profit_abs = trade.calc_profit() + trade.close_profit = trade.calc_profit_ratio(trade.close_rate) + trade.close_profit_abs = trade.calc_profit(trade.close_rate) Trade.query.session.add(trade) trade = Trade( @@ -868,8 +868,8 @@ def test_api_performance(botclient, fee): fee_open=fee.return_value, close_rate=0.391 ) - trade.close_profit = trade.calc_profit_ratio() - trade.close_profit_abs = trade.calc_profit() + trade.close_profit = trade.calc_profit_ratio(trade.close_rate) + trade.close_profit_abs = trade.calc_profit(trade.close_rate) Trade.query.session.add(trade) Trade.commit() diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 3fd16f925..4f3d5f667 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2151,7 +2151,7 @@ def test_handle_trade( assert trade.close_rate == 2.0 if is_short else 2.2 assert trade.close_profit == close_profit - assert trade.calc_profit() == 5.685 + assert trade.calc_profit(trade.close_rate) == 5.685 assert trade.close_date is not None assert trade.exit_reason == 'sell_signal1' diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 836b17a55..de250e3e6 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -606,9 +606,9 @@ def test_calc_open_close_trade_price( trade.close_rate = 2.2 trade.recalc_open_trade_value() assert isclose(trade._calc_open_trade_value(), open_value) - assert isclose(trade.calc_close_trade_value(), close_value) - assert isclose(trade.calc_profit(), round(profit, 8)) - assert pytest.approx(trade.calc_profit_ratio()) == profit_ratio + assert isclose(trade.calc_close_trade_value(trade.close_rate), close_value) + assert isclose(trade.calc_profit(trade.close_rate), round(profit, 8)) + assert pytest.approx(trade.calc_profit_ratio(trade.close_rate)) == profit_ratio @pytest.mark.usefixtures("init_persistence") @@ -660,7 +660,7 @@ def test_calc_close_trade_price_exception(limit_buy_order_usdt, fee): trade.open_order_id = 'something' oobj = Order.parse_from_ccxt_object(limit_buy_order_usdt, 'ADA/USDT', 'buy') trade.update_trade(oobj) - assert trade.calc_close_trade_value() == 0.0 + assert trade.calc_close_trade_value(trade.close_rate) == 0.0 @pytest.mark.usefixtures("init_persistence") From d7770c507b4e655a74226eada048d86fe7d6fdb3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 17 Jun 2022 07:00:42 +0000 Subject: [PATCH 332/449] Remove implicit use of certain rates in profit calculations --- freqtrade/persistence/trade_model.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 3222a57b8..5a89849dd 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -624,8 +624,8 @@ class LocalTrade(): """ self.close_rate = rate self.close_date = self.close_date or datetime.utcnow() - self.close_profit = self.calc_profit_ratio() - self.close_profit_abs = self.calc_profit() + self.close_profit = self.calc_profit_ratio(rate) + self.close_profit_abs = self.calc_profit(rate) self.is_open = False self.exit_order_status = 'closed' self.open_order_id = None @@ -714,10 +714,10 @@ class LocalTrade(): return interest(exchange_name=self.exchange, borrowed=borrowed, rate=rate, hours=hours) - def _calc_base_close(self, amount: Decimal, rate: Optional[float] = None, + def _calc_base_close(self, amount: Decimal, rate: float, fee: Optional[float] = None) -> Decimal: - close_trade = Decimal(amount) * Decimal(rate or self.close_rate) # type: ignore + close_trade = Decimal(amount) * Decimal(rate) fees = close_trade * Decimal(fee or self.fee_close) if self.is_short: @@ -725,15 +725,14 @@ class LocalTrade(): else: return close_trade - fees - def calc_close_trade_value(self, rate: Optional[float] = None, + def calc_close_trade_value(self, rate: float, fee: Optional[float] = None, interest_rate: Optional[float] = None) -> float: """ Calculate the close_rate including fee + :param rate: rate to compare with. :param fee: fee to use on the close rate (optional). If rate is not set self.fee will be used - :param rate: rate to compare with (optional). - If rate is not set self.close_rate will be used :param interest_rate: interest_charge for borrowing this coin (optional). If interest_rate is not set self.interest_rate will be used :return: Price in BTC of the open trade @@ -770,21 +769,20 @@ class LocalTrade(): raise OperationalException( f"{self.trading_mode.value} trading is not yet available using freqtrade") - def calc_profit(self, rate: Optional[float] = None, + def calc_profit(self, rate: float, fee: Optional[float] = None, interest_rate: Optional[float] = None) -> float: """ Calculate the absolute profit in stake currency between Close and Open trade + :param rate: close rate to compare with. :param fee: fee to use on the close rate (optional). If fee is not set self.fee will be used - :param rate: close rate to compare with (optional). - If rate is not set self.close_rate will be used :param interest_rate: interest_charge for borrowing this coin (optional). If interest_rate is not set self.interest_rate will be used :return: profit in stake currency as float """ close_trade_value = self.calc_close_trade_value( - rate=(rate or self.close_rate), + rate=rate, fee=(fee or self.fee_close), interest_rate=(interest_rate or self.interest_rate) ) @@ -795,20 +793,19 @@ class LocalTrade(): profit = close_trade_value - self.open_trade_value return float(f"{profit:.8f}") - def calc_profit_ratio(self, rate: Optional[float] = None, + def calc_profit_ratio(self, rate: float, fee: Optional[float] = None, interest_rate: Optional[float] = None) -> float: """ Calculates the profit as ratio (including fee). - :param rate: rate to compare with (optional). - If rate is not set self.close_rate will be used + :param rate: rate to compare with. :param fee: fee to use on the close rate (optional). :param interest_rate: interest_charge for borrowing this coin (optional). If interest_rate is not set self.interest_rate will be used :return: profit ratio as float """ close_trade_value = self.calc_close_trade_value( - rate=(rate or self.close_rate), + rate=rate, fee=(fee or self.fee_close), interest_rate=(interest_rate or self.interest_rate) ) From 91f9818ae3b1c95ca2547916d7ea70be6c2a84a1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 17 Jun 2022 09:53:29 +0000 Subject: [PATCH 333/449] Simplify trade calculations --- freqtrade/persistence/trade_model.py | 43 +++++++++------------------- tests/test_persistence.py | 2 +- 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 5a89849dd..3ac64ba6b 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -693,10 +693,9 @@ class LocalTrade(): """ self.open_trade_value = self._calc_open_trade_value() - def calculate_interest(self, interest_rate: Optional[float] = None) -> Decimal: + def calculate_interest(self) -> Decimal: """ - :param interest_rate: interest_charge for borrowing this coin(optional). - If interest_rate is not set self.interest_rate will be used + Calculate interest for this trade. Only applicable for Margin trading. """ zero = Decimal(0.0) # If nothing was borrowed @@ -709,7 +708,7 @@ class LocalTrade(): total_seconds = Decimal((now - open_date).total_seconds()) hours = total_seconds / sec_per_hour or zero - rate = Decimal(interest_rate or self.interest_rate) + rate = Decimal(self.interest_rate) borrowed = Decimal(self.borrowed) return interest(exchange_name=self.exchange, borrowed=borrowed, rate=rate, hours=hours) @@ -726,16 +725,13 @@ class LocalTrade(): return close_trade - fees def calc_close_trade_value(self, rate: float, - fee: Optional[float] = None, - interest_rate: Optional[float] = None) -> float: + fee: Optional[float] = None) -> float: """ - Calculate the close_rate including fee + Calculate the Trade's close value including fees :param rate: rate to compare with. :param fee: fee to use on the close rate (optional). - If rate is not set self.fee will be used - :param interest_rate: interest_charge for borrowing this coin (optional). - If interest_rate is not set self.interest_rate will be used - :return: Price in BTC of the open trade + If rate is not set self.close_fee will be used + :return: value in stake currency of the open trade """ if rate is None and not self.close_rate: return 0.0 @@ -748,7 +744,7 @@ class LocalTrade(): elif (trading_mode == TradingMode.MARGIN): - total_interest = self.calculate_interest(interest_rate) + total_interest = self.calculate_interest() if self.is_short: amount = amount + total_interest @@ -769,22 +765,15 @@ class LocalTrade(): raise OperationalException( f"{self.trading_mode.value} trading is not yet available using freqtrade") - def calc_profit(self, rate: float, - fee: Optional[float] = None, - interest_rate: Optional[float] = None) -> float: + def calc_profit(self, rate: float) -> float: """ Calculate the absolute profit in stake currency between Close and Open trade :param rate: close rate to compare with. - :param fee: fee to use on the close rate (optional). - If fee is not set self.fee will be used - :param interest_rate: interest_charge for borrowing this coin (optional). - If interest_rate is not set self.interest_rate will be used - :return: profit in stake currency as float + :return: profit in stake currency as float """ close_trade_value = self.calc_close_trade_value( rate=rate, - fee=(fee or self.fee_close), - interest_rate=(interest_rate or self.interest_rate) + fee=self.fee_close ) if self.is_short: @@ -793,21 +782,15 @@ class LocalTrade(): profit = close_trade_value - self.open_trade_value return float(f"{profit:.8f}") - def calc_profit_ratio(self, rate: float, - fee: Optional[float] = None, - interest_rate: Optional[float] = None) -> float: + def calc_profit_ratio(self, rate: float) -> float: """ Calculates the profit as ratio (including fee). :param rate: rate to compare with. - :param fee: fee to use on the close rate (optional). - :param interest_rate: interest_charge for borrowing this coin (optional). - If interest_rate is not set self.interest_rate will be used :return: profit ratio as float """ close_trade_value = self.calc_close_trade_value( rate=rate, - fee=(fee or self.fee_close), - interest_rate=(interest_rate or self.interest_rate) + fee=self.fee_close ) short_close_zero = (self.is_short and close_trade_value == 0.0) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index de250e3e6..8c12d2ea0 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -813,7 +813,7 @@ def test_calc_close_trade_price( funding_fees=funding_fees ) trade.open_order_id = 'close_trade' - assert round(trade.calc_close_trade_value(rate=close_rate, fee=fee_rate), 8) == result + assert round(trade.calc_close_trade_value(rate=close_rate), 8) == result @pytest.mark.parametrize( From 6bdf9c2a94a53820dc658d6b006f194e16b6e7f7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 17 Jun 2022 11:17:05 +0000 Subject: [PATCH 334/449] Simplify trade profit calculations further --- freqtrade/persistence/trade_model.py | 32 ++++++++++------------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 3ac64ba6b..eb405942a 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -713,24 +713,20 @@ class LocalTrade(): return interest(exchange_name=self.exchange, borrowed=borrowed, rate=rate, hours=hours) - def _calc_base_close(self, amount: Decimal, rate: float, - fee: Optional[float] = None) -> Decimal: + def _calc_base_close(self, amount: Decimal, rate: float, fee: float) -> Decimal: - close_trade = Decimal(amount) * Decimal(rate) - fees = close_trade * Decimal(fee or self.fee_close) + close_trade = amount * Decimal(rate) + fees = close_trade * Decimal(fee) if self.is_short: return close_trade + fees else: return close_trade - fees - def calc_close_trade_value(self, rate: float, - fee: Optional[float] = None) -> float: + def calc_close_trade_value(self, rate: float) -> float: """ Calculate the Trade's close value including fees :param rate: rate to compare with. - :param fee: fee to use on the close rate (optional). - If rate is not set self.close_fee will be used :return: value in stake currency of the open trade """ if rate is None and not self.close_rate: @@ -740,7 +736,7 @@ class LocalTrade(): trading_mode = self.trading_mode or TradingMode.SPOT if trading_mode == TradingMode.SPOT: - return float(self._calc_base_close(amount, rate, fee)) + return float(self._calc_base_close(amount, rate, self.fee_close)) elif (trading_mode == TradingMode.MARGIN): @@ -748,19 +744,19 @@ class LocalTrade(): if self.is_short: amount = amount + total_interest - return float(self._calc_base_close(amount, rate, fee)) + return float(self._calc_base_close(amount, rate, self.fee_close)) else: # Currency already owned for longs, no need to purchase - return float(self._calc_base_close(amount, rate, fee) - total_interest) + return float(self._calc_base_close(amount, rate, self.fee_close) - total_interest) elif (trading_mode == TradingMode.FUTURES): funding_fees = self.funding_fees or 0.0 # Positive funding_fees -> Trade has gained from fees. # Negative funding_fees -> Trade had to pay the fees. if self.is_short: - return float(self._calc_base_close(amount, rate, fee)) - funding_fees + return float(self._calc_base_close(amount, rate, self.fee_close)) - funding_fees else: - return float(self._calc_base_close(amount, rate, fee)) + funding_fees + return float(self._calc_base_close(amount, rate, self.fee_close)) + funding_fees else: raise OperationalException( f"{self.trading_mode.value} trading is not yet available using freqtrade") @@ -771,10 +767,7 @@ class LocalTrade(): :param rate: close rate to compare with. :return: profit in stake currency as float """ - close_trade_value = self.calc_close_trade_value( - rate=rate, - fee=self.fee_close - ) + close_trade_value = self.calc_close_trade_value(rate) if self.is_short: profit = self.open_trade_value - close_trade_value @@ -788,10 +781,7 @@ class LocalTrade(): :param rate: rate to compare with. :return: profit ratio as float """ - close_trade_value = self.calc_close_trade_value( - rate=rate, - fee=self.fee_close - ) + close_trade_value = self.calc_close_trade_value(rate) short_close_zero = (self.is_short and close_trade_value == 0.0) long_close_zero = (not self.is_short and self.open_trade_value == 0.0) From fda8248d41bce429415cb20292550df6d7e5e654 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 17 Jun 2022 22:43:24 +0200 Subject: [PATCH 335/449] Gateio allow market orders on futures markets --- freqtrade/exchange/gateio.py | 1 - tests/exchange/test_gateio.py | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index 4147e8290..f69a0dc02 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -40,7 +40,6 @@ class Gateio(Exchange): ] def validate_ordertypes(self, order_types: Dict) -> None: - super().validate_ordertypes(order_types) if self.trading_mode != TradingMode.FUTURES: if any(v == 'market' for k, v in order_types.items()): diff --git a/tests/exchange/test_gateio.py b/tests/exchange/test_gateio.py index 92f8186a6..cbd4776fb 100644 --- a/tests/exchange/test_gateio.py +++ b/tests/exchange/test_gateio.py @@ -33,6 +33,12 @@ def test_validate_order_types_gateio(default_conf, mocker): match=r'Exchange .* does not support market orders.'): ExchangeResolver.load_exchange('gateio', default_conf, True) + # market-orders supported on futures markets. + default_conf['trading_mode'] = 'futures' + default_conf['margin_mode'] = 'isolated' + ex = ExchangeResolver.load_exchange('gateio', default_conf, True) + assert ex + @pytest.mark.usefixtures("init_persistence") def test_fetch_stoploss_order_gateio(default_conf, mocker): From 616bf315cbf8647f5f9114aee74e648f747b9a27 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 17 Jun 2022 23:02:39 +0200 Subject: [PATCH 336/449] gateio: futures market orders require IOC to be set. --- freqtrade/exchange/gateio.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index f69a0dc02..fd9a2b2b3 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -3,6 +3,7 @@ import logging from datetime import datetime from typing import Dict, List, Optional, Tuple +from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, TradingMode from freqtrade.exceptions import OperationalException from freqtrade.exchange import Exchange @@ -24,6 +25,8 @@ class Gateio(Exchange): _ft_has: Dict = { "ohlcv_candle_limit": 1000, "ohlcv_volume_currency": "quote", + "time_in_force_parameter": "timeInForce", + "order_time_in_force": ['gtc', 'ioc'], "stoploss_order_types": {"limit": "limit"}, "stoploss_on_exchange": True, } @@ -46,6 +49,27 @@ class Gateio(Exchange): raise OperationalException( f'Exchange {self.name} does not support market orders.') + def _get_params( + self, + side: BuySell, + ordertype: str, + leverage: float, + reduceOnly: bool, + time_in_force: str = 'gtc', + ) -> Dict: + params = super()._get_params( + side=side, + ordertype=ordertype, + leverage=leverage, + reduceOnly=reduceOnly, + time_in_force=time_in_force, + ) + if ordertype == 'market' and self.trading_mode == TradingMode.FUTURES: + params['type'] = 'market' + param = self._ft_has.get('time_in_force_parameter', '') + params.update({param: 'ioc'}) + return params + def get_trades_for_order(self, order_id: str, pair: str, since: datetime, params: Optional[Dict] = None) -> List: trades = super().get_trades_for_order(order_id, pair, since, params) @@ -60,7 +84,8 @@ class Gateio(Exchange): pair_fees = self._trading_fees.get(pair, {}) if pair_fees: for idx, trade in enumerate(trades): - if trade.get('fee', {}).get('cost') is None: + fee = trade.get('fee', {}) + if fee and fee.get('cost') is None: takerOrMaker = trade.get('takerOrMaker', 'taker') if pair_fees.get(takerOrMaker) is not None: trades[idx]['fee'] = { From 017fd03180e09549c0fc4604e19581bf54a66de1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 09:05:22 +0200 Subject: [PATCH 337/449] Fix but with late entries in backtesting --- freqtrade/data/history/history_utils.py | 2 +- freqtrade/optimize/backtesting.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index bead59814..c972c841c 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -221,7 +221,7 @@ def _download_pair_history(pair: str, *, prepend=prepend) logger.info(f'({process}) - Download history data for "{pair}", {timeframe}, ' - f'{candle_type} and store in {datadir}.' + f'{candle_type} and store in {datadir}. ' f'From {format_ms_time(since_ms) if since_ms else "start"} to ' f'{format_ms_time(until_ms) if until_ms else "now"}' ) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 77eb12419..f7d92081f 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -1078,6 +1078,8 @@ class Backtesting: open_trade_count += 1 # logger.debug(f"{pair} - Emulate creation of new trade: {trade}.") open_trades[pair].append(trade) + LocalTrade.add_bt_trade(trade) + self.wallets.update() for trade in list(open_trades[pair]): # 3. Process entry orders. @@ -1085,7 +1087,6 @@ class Backtesting: if order and self._get_order_filled(order.price, row): order.close_bt_order(current_time, trade) trade.open_order_id = None - LocalTrade.add_bt_trade(trade) self.wallets.update() # 4. Create exit orders (if any) From d62273294d4cb2ba23e94f733a08dfa02000dee3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 09:10:33 +0200 Subject: [PATCH 338/449] Update /help for /fx to align with actual command name closes #6985 --- docs/telegram-usage.md | 5 +++-- freqtrade/rpc/telegram.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 6e21d3689..773a1b67a 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -171,8 +171,8 @@ official commands. You can ask at any moment for help with `/help`. | `/locks` | Show currently locked pairs. | `/unlock ` | Remove the lock for this pair (or for this lock id). | `/profit []` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default) -| `/forceexit ` | Instantly exits the given trade (Ignoring `minimum_roi`). -| `/forceexit all` | Instantly exits all open trades (Ignoring `minimum_roi`). +| `/forceexit | /fx ` | Instantly exits the given trade (Ignoring `minimum_roi`). +| `/forceexit all | /fx all` | Instantly exits all open trades (Ignoring `minimum_roi`). | `/fx` | alias for `/forceexit` | `/forcelong [rate]` | Instantly buys the given pair. Rate is optional and only applies to limit orders. (`force_entry_enable` must be set to True) | `/forceshort [rate]` | Instantly shorts the given pair. Rate is optional and only applies to limit orders. This will only work on non-spot markets. (`force_entry_enable` must be set to True) @@ -281,6 +281,7 @@ Starting capital is either taken from the `available_capital` setting, or calcul !!! Tip You can get a list of all open trades by calling `/forceexit` without parameter, which will show a list of buttons to simply exit a trade. + This command has an alias in `/fx` - which has the same capabilities, but is faster to type in "emergency" situations. ### /forcelong [rate] | /forceshort [rate] diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 2e1d23621..7f5da8872 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -1395,7 +1395,7 @@ class Telegram(RPCHandler): "*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" "*/forceexit |all:* `Instantly exits the given trade or all trades, " "regardless of profit`\n" - "*/fe |all:* `Alias to /forceexit`\n" + "*/fx |all:* `Alias to /forceexit`\n" f"{force_enter_text if self._config.get('force_entry_enable', False) else ''}" "*/delete :* `Instantly delete the given trade in the database`\n" "*/whitelist:* `Show current whitelist` \n" From 03815cb81bde3f568f3319760c577b8229878eb0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 09:23:16 +0200 Subject: [PATCH 339/449] Use fstrings in telegram messaging --- freqtrade/rpc/telegram.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 7f5da8872..c595018d4 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -326,33 +326,33 @@ class Telegram(RPCHandler): elif msg_type in (RPCMessageType.ENTRY_CANCEL, RPCMessageType.EXIT_CANCEL): msg['message_side'] = 'enter' if msg_type in [RPCMessageType.ENTRY_CANCEL] else 'exit' - message = ("\N{WARNING SIGN} *{exchange}:* " - "Cancelling {message_side} Order for {pair} (#{trade_id}). " - "Reason: {reason}.".format(**msg)) + message = (f"\N{WARNING SIGN} *{msg['exchange']}:* " + f"Cancelling {msg['message_side']} Order for {msg['pair']} " + f"(#{msg['trade_id']}). Reason: {msg['reason']}.") elif msg_type == RPCMessageType.PROTECTION_TRIGGER: message = ( - "*Protection* triggered due to {reason}. " - "`{pair}` will be locked until `{lock_end_time}`." - ).format(**msg) + f"*Protection* triggered due to {msg['reason']}. " + f"`{msg['pair']}` will be locked until `{msg['lock_end_time']}`." + ) elif msg_type == RPCMessageType.PROTECTION_TRIGGER_GLOBAL: message = ( - "*Protection* triggered due to {reason}. " - "*All pairs* will be locked until `{lock_end_time}`." - ).format(**msg) + f"*Protection* triggered due to {msg['reason']}. " + f"*All pairs* will be locked until `{msg['lock_end_time']}`." + ) elif msg_type == RPCMessageType.STATUS: - message = '*Status:* `{status}`'.format(**msg) + message = f"*Status:* `{msg['status']}`" elif msg_type == RPCMessageType.WARNING: - message = '\N{WARNING SIGN} *Warning:* `{status}`'.format(**msg) + message = f"\N{WARNING SIGN} *Warning:* `{msg['status']}`" elif msg_type == RPCMessageType.STARTUP: - message = '{status}'.format(**msg) + message = f"{msg['status']}" else: - raise NotImplementedError('Unknown message type: {}'.format(msg_type)) + raise NotImplementedError(f"Unknown message type: {msg_type}") return message def send_msg(self, msg: Dict[str, Any]) -> None: @@ -867,7 +867,7 @@ class Telegram(RPCHandler): :return: None """ msg = self._rpc._rpc_start() - self._send_msg('Status: `{status}`'.format(**msg)) + self._send_msg(f"Status: `{msg['status']}`") @authorized_only def _stop(self, update: Update, context: CallbackContext) -> None: @@ -879,7 +879,7 @@ class Telegram(RPCHandler): :return: None """ msg = self._rpc._rpc_stop() - self._send_msg('Status: `{status}`'.format(**msg)) + self._send_msg(f"Status: `{msg['status']}`") @authorized_only def _reload_config(self, update: Update, context: CallbackContext) -> None: @@ -891,7 +891,7 @@ class Telegram(RPCHandler): :return: None """ msg = self._rpc._rpc_reload_config() - self._send_msg('Status: `{status}`'.format(**msg)) + self._send_msg(f"Status: `{msg['status']}`") @authorized_only def _stopbuy(self, update: Update, context: CallbackContext) -> None: @@ -903,7 +903,7 @@ class Telegram(RPCHandler): :return: None """ msg = self._rpc._rpc_stopbuy() - self._send_msg('Status: `{status}`'.format(**msg)) + self._send_msg(f"Status: `{msg['status']}`") @authorized_only def _force_exit(self, update: Update, context: CallbackContext) -> None: @@ -1065,9 +1065,9 @@ class Telegram(RPCHandler): trade_id = int(context.args[0]) msg = self._rpc._rpc_delete(trade_id) self._send_msg(( - '`{result_msg}`\n' + f"`{msg['result_msg']}`\n" 'Please make sure to take care of this asset on the exchange manually.' - ).format(**msg)) + )) except RPCException as e: self._send_msg(str(e)) From d77ce468ea8fd196b09b36aafc98dcde8bebbfe5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 09:35:19 +0200 Subject: [PATCH 340/449] Add "dry" hint to buy/sell messages part of #6962 --- freqtrade/rpc/telegram.py | 14 +++++++++++--- tests/rpc/test_rpc_telegram.py | 19 +++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index c595018d4..15e919e30 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -235,6 +235,14 @@ class Telegram(RPCHandler): # This can take up to `timeout` from the call to `start_polling`. self._updater.stop() + def _exchange_from_msg(self, msg: Dict[str, Any]) -> str: + """ + Extracts the exchange name from the given message. + :param msg: The message to extract the exchange name from. + :return: The exchange name. + """ + return f"{msg['exchange']}{' (dry)' if self._config['dry_run'] else ''}" + def _format_entry_msg(self, msg: Dict[str, Any]) -> str: if self._rpc._fiat_converter: msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount( @@ -247,7 +255,7 @@ class Telegram(RPCHandler): entry_side = ({'enter': 'Long', 'entered': 'Longed'} if msg['direction'] == 'Long' else {'enter': 'Short', 'entered': 'Shorted'}) message = ( - f"{emoji} *{msg['exchange']}:*" + f"{emoji} *{self._exchange_from_msg(msg)}:*" f" {entry_side['entered'] if is_fill else entry_side['enter']} {msg['pair']}" f" (#{msg['trade_id']})\n" ) @@ -296,7 +304,7 @@ class Telegram(RPCHandler): msg['profit_extra'] = '' is_fill = msg['type'] == RPCMessageType.EXIT_FILL message = ( - f"{msg['emoji']} *{msg['exchange']}:* " + f"{msg['emoji']} *{self._exchange_from_msg(msg)}:* " f"{'Exited' if is_fill else 'Exiting'} {msg['pair']} (#{msg['trade_id']})\n" f"*{'Profit' if is_fill else 'Unrealized Profit'}:* " f"`{msg['profit_ratio']:.2%}{msg['profit_extra']}`\n" @@ -326,7 +334,7 @@ class Telegram(RPCHandler): elif msg_type in (RPCMessageType.ENTRY_CANCEL, RPCMessageType.EXIT_CANCEL): msg['message_side'] = 'enter' if msg_type in [RPCMessageType.ENTRY_CANCEL] else 'exit' - message = (f"\N{WARNING SIGN} *{msg['exchange']}:* " + message = (f"\N{WARNING SIGN} *{self._exchange_from_msg(msg)}:* " f"Cancelling {msg['message_side']} Order for {msg['pair']} " f"(#{msg['trade_id']}). Reason: {msg['reason']}.") diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 3bd817ac7..d6845be57 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1680,7 +1680,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type, leverage_text = f'*Leverage:* `{leverage}`\n' if leverage and leverage != 1.0 else '' assert msg_mock.call_args[0][0] == ( - f'\N{LARGE BLUE CIRCLE} *Binance:* {enter} ETH/BTC (#1)\n' + f'\N{LARGE BLUE CIRCLE} *Binance (dry):* {enter} ETH/BTC (#1)\n' f'*Enter Tag:* `{enter_signal}`\n' '*Amount:* `1333.33333333`\n' f'{leverage_text}' @@ -1720,7 +1720,7 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker, message_type, en 'pair': 'ETH/BTC', 'reason': CANCEL_REASON['TIMEOUT'] }) - assert (msg_mock.call_args[0][0] == '\N{WARNING SIGN} *Binance:* ' + assert (msg_mock.call_args[0][0] == '\N{WARNING SIGN} *Binance (dry):* ' 'Cancelling enter Order for ETH/BTC (#1). ' 'Reason: cancelled due to timeout.') @@ -1782,7 +1782,7 @@ def test_send_msg_entry_fill_notification(default_conf, mocker, message_type, en }) leverage_text = f'*Leverage:* `{leverage}`\n' if leverage != 1.0 else '' assert msg_mock.call_args[0][0] == ( - f'\N{CHECK MARK} *Binance:* {entered}ed ETH/BTC (#1)\n' + f'\N{CHECK MARK} *Binance (dry):* {entered}ed ETH/BTC (#1)\n' f'*Enter Tag:* `{enter_signal}`\n' '*Amount:* `1333.33333333`\n' f"{leverage_text}" @@ -1820,7 +1820,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'close_date': arrow.utcnow(), }) assert msg_mock.call_args[0][0] == ( - '\N{WARNING SIGN} *Binance:* Exiting KEY/ETH (#1)\n' + '\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n' '*Unrealized Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n' '*Enter Tag:* `buy_signal1`\n' '*Exit Reason:* `stop_loss`\n' @@ -1854,7 +1854,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None: 'close_date': arrow.utcnow(), }) assert msg_mock.call_args[0][0] == ( - '\N{WARNING SIGN} *Binance:* Exiting KEY/ETH (#1)\n' + '\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n' '*Unrealized Profit:* `-57.41%`\n' '*Enter Tag:* `buy_signal1`\n' '*Exit Reason:* `stop_loss`\n' @@ -1883,10 +1883,12 @@ def test_send_msg_sell_cancel_notification(default_conf, mocker) -> None: 'reason': 'Cancelled on exchange' }) assert msg_mock.call_args[0][0] == ( - '\N{WARNING SIGN} *Binance:* Cancelling exit Order for KEY/ETH (#1).' + '\N{WARNING SIGN} *Binance (dry):* Cancelling exit Order for KEY/ETH (#1).' ' Reason: Cancelled on exchange.') msg_mock.reset_mock() + # Test with live mode (no dry appendix) + telegram._config['dry_run'] = False telegram.send_msg({ 'type': RPCMessageType.EXIT_CANCEL, 'trade_id': 1, @@ -1935,7 +1937,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker, direction, leverage_text = f'*Leverage:* `{leverage}`\n' if leverage and leverage != 1.0 else '' assert msg_mock.call_args[0][0] == ( - '\N{WARNING SIGN} *Binance:* Exited KEY/ETH (#1)\n' + '\N{WARNING SIGN} *Binance (dry):* Exited KEY/ETH (#1)\n' '*Profit:* `-57.41%`\n' f'*Enter Tag:* `{enter_signal}`\n' '*Exit Reason:* `stop_loss`\n' @@ -1991,6 +1993,7 @@ def test_send_msg_unknown_type(default_conf, mocker) -> None: def test_send_msg_buy_notification_no_fiat( default_conf, mocker, message_type, enter, enter_signal, leverage) -> None: del default_conf['fiat_display_currency'] + default_conf['dry_run'] = False telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) telegram.send_msg({ @@ -2060,7 +2063,7 @@ def test_send_msg_sell_notification_no_fiat( leverage_text = f'*Leverage:* `{leverage}`\n' if leverage and leverage != 1.0 else '' assert msg_mock.call_args[0][0] == ( - '\N{WARNING SIGN} *Binance:* Exiting KEY/ETH (#1)\n' + '\N{WARNING SIGN} *Binance (dry):* Exiting KEY/ETH (#1)\n' '*Unrealized Profit:* `-57.41%`\n' f'*Enter Tag:* `{enter_signal}`\n' '*Exit Reason:* `stop_loss`\n' From 6a15d36d14525ff20083a788848230ee3150fa45 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 11:14:28 +0200 Subject: [PATCH 341/449] Add Drawdown and profit_factor to /profit #6816 --- freqtrade/optimize/optimize_reports.py | 2 ++ freqtrade/rpc/api_server/api_schemas.py | 3 +++ freqtrade/rpc/rpc.py | 23 +++++++++++++++++++++++ freqtrade/rpc/telegram.py | 11 ++++++++--- tests/rpc/test_rpc_apiserver.py | 15 ++++++++++++--- tests/rpc/test_rpc_telegram.py | 5 +++-- 6 files changed, 51 insertions(+), 8 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 44b524a4c..79cb8a2bd 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -497,8 +497,10 @@ def generate_strategy_stats(pairlist: List[str], (drawdown_abs, drawdown_start, drawdown_end, high_val, low_val, max_drawdown) = calculate_max_drawdown( results, value_col='profit_abs', starting_balance=start_balance) + # max_relative_drawdown = Underwater (_, _, _, _, _, max_relative_drawdown) = calculate_max_drawdown( results, value_col='profit_abs', starting_balance=start_balance, relative=True) + strat_stats.update({ 'max_drawdown': max_drawdown_legacy, # Deprecated - do not use 'max_drawdown_account': max_drawdown, diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 11fdc0121..fda2d7ea0 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -104,6 +104,9 @@ class Profit(BaseModel): best_pair_profit_ratio: float winning_trades: int losing_trades: int + profit_factor: float + max_drawdown: float + max_drawdown_abs: float class SellReason(BaseModel): diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 8b1cdb851..bae90b3bc 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -18,6 +18,7 @@ from freqtrade import __version__ from freqtrade.configuration.timerange import TimeRange from freqtrade.constants import CANCEL_REASON, DATETIME_PRINT_FORMAT from freqtrade.data.history import load_data +from freqtrade.data.metrics import calculate_max_drawdown from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, SignalDirection, State, TradingMode) from freqtrade.exceptions import ExchangeError, PricingError @@ -415,6 +416,8 @@ class RPC: durations = [] winning_trades = 0 losing_trades = 0 + winning_profit = 0.0 + losing_profit = 0.0 for trade in trades: current_rate: float = 0.0 @@ -430,8 +433,10 @@ class RPC: profit_closed_ratio.append(profit_ratio) if trade.close_profit >= 0: winning_trades += 1 + winning_profit += trade.close_profit_abs else: losing_trades += 1 + losing_profit += trade.close_profit_abs else: # Get current rate try: @@ -470,6 +475,21 @@ class RPC: profit_closed_ratio_fromstart = profit_closed_coin_sum / starting_balance profit_all_ratio_fromstart = profit_all_coin_sum / starting_balance + profit_factor = winning_profit / abs(losing_profit) if losing_profit else float('inf') + + trades_df = DataFrame([{'close_date': trade.close_date.strftime(DATETIME_PRINT_FORMAT), + 'profit_abs': trade.close_profit_abs} + for trade in trades if not trade.is_open]) + max_drawdown_abs = 0.0 + max_drawdown = 0.0 + if len(trades_df) > 0: + try: + (max_drawdown_abs, _, _, _, _, max_drawdown) = calculate_max_drawdown( + trades_df, value_col='profit_abs', starting_balance=starting_balance) + except ValueError: + # ValueError if no losing trade. + pass + profit_all_fiat = self._fiat_converter.convert_amount( profit_all_coin_sum, stake_currency, @@ -508,6 +528,9 @@ class RPC: 'best_pair_profit_ratio': best_pair[1] if best_pair else 0, 'winning_trades': winning_trades, 'losing_trades': losing_trades, + 'profit_factor': profit_factor, + 'max_drawdown': max_drawdown, + 'max_drawdown_abs': max_drawdown_abs, } def _rpc_balance(self, stake_currency: str, fiat_display_currency: str) -> Dict: diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 15e919e30..a7130d691 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -730,12 +730,17 @@ class Telegram(RPCHandler): f"*Total Trade Count:* `{trade_count}`\n" f"*{'First Trade opened' if not timescale else 'Showing Profit since'}:* " f"`{first_trade_date}`\n" - f"*Latest Trade opened:* `{latest_trade_date}\n`" + f"*Latest Trade opened:* `{latest_trade_date}`\n" f"*Win / Loss:* `{stats['winning_trades']} / {stats['losing_trades']}`" ) if stats['closed_trade_count'] > 0: - markdown_msg += (f"\n*Avg. Duration:* `{avg_duration}`\n" - f"*Best Performing:* `{best_pair}: {best_pair_profit_ratio:.2%}`") + markdown_msg += ( + f"\n*Avg. Duration:* `{avg_duration}`\n" + f"*Best Performing:* `{best_pair}: {best_pair_profit_ratio:.2%}`\n" + f"*Profit factor:* `{stats['profit_factor']:.2f}`\n" + f"*Max Drawdown:* `{stats['max_drawdown']:.2%} " + f"({round_coin_value(stats['max_drawdown_abs'], stake_cur)})`" + ) self._send_msg(markdown_msg, reload_able=True, callback_path="update_profit", query=update.callback_query) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index ada1a82ec..afbc92c5d 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -724,7 +724,9 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): 'profit_closed_fiat': -83.19455985, 'profit_closed_ratio_mean': -0.0075, 'profit_closed_percent_mean': -0.75, 'profit_closed_ratio_sum': -0.015, 'profit_closed_percent_sum': -1.5, 'profit_closed_ratio': -6.739057628404269e-06, - 'profit_closed_percent': -0.0, 'winning_trades': 0, 'losing_trades': 2} + 'profit_closed_percent': -0.0, 'winning_trades': 0, 'losing_trades': 2, + 'profit_factor': 0.0, + } ), ( False, @@ -737,7 +739,9 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): 'profit_closed_fiat': 9.124559849999999, 'profit_closed_ratio_mean': 0.0075, 'profit_closed_percent_mean': 0.75, 'profit_closed_ratio_sum': 0.015, 'profit_closed_percent_sum': 1.5, 'profit_closed_ratio': 7.391275897987988e-07, - 'profit_closed_percent': 0.0, 'winning_trades': 2, 'losing_trades': 0} + 'profit_closed_percent': 0.0, 'winning_trades': 2, 'losing_trades': 0, + 'profit_factor': None, + } ), ( None, @@ -750,7 +754,9 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): 'profit_closed_fiat': -67.02260985, 'profit_closed_ratio_mean': 0.0025, 'profit_closed_percent_mean': 0.25, 'profit_closed_ratio_sum': 0.005, 'profit_closed_percent_sum': 0.5, 'profit_closed_ratio': -5.429078808526421e-06, - 'profit_closed_percent': -0.0, 'winning_trades': 1, 'losing_trades': 1} + 'profit_closed_percent': -0.0, 'winning_trades': 1, 'losing_trades': 1, + 'profit_factor': 0.02775724835771106, + } ) ]) def test_api_profit(botclient, mocker, ticker, fee, markets, is_short, expected): @@ -803,6 +809,9 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, is_short, expected) 'closed_trade_count': 2, 'winning_trades': expected['winning_trades'], 'losing_trades': expected['losing_trades'], + 'profit_factor': expected['profit_factor'], + 'max_drawdown': ANY, + 'max_drawdown_abs': ANY, } diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index d6845be57..65917a6e2 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -704,11 +704,12 @@ def test_profit_handle(default_conf_usdt, update, ticker_usdt, ticker_sell_up, f assert '∙ `6.253 USD`' in msg_mock.call_args_list[-1][0][0] assert '*Best Performing:* `ETH/USDT: 9.45%`' in msg_mock.call_args_list[-1][0][0] + assert '*Max Drawdown:*' in msg_mock.call_args_list[-1][0][0] + assert '*Profit factor:*' in msg_mock.call_args_list[-1][0][0] @pytest.mark.parametrize('is_short', [True, False]) -def test_telegram_stats(default_conf, update, ticker, ticker_sell_up, fee, - limit_buy_order, limit_sell_order, mocker, is_short) -> None: +def test_telegram_stats(default_conf, update, ticker, fee, mocker, is_short) -> None: mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) mocker.patch.multiple( 'freqtrade.exchange.Exchange', From 40c9abc7e1b2120d80884f00f260ce635a52d74a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 11:40:32 +0200 Subject: [PATCH 342/449] Add trading volume to /profit output --- freqtrade/persistence/trade_model.py | 16 ++++++++++++++++ freqtrade/rpc/rpc.py | 2 ++ freqtrade/rpc/telegram.py | 1 + tests/rpc/test_rpc_telegram.py | 1 + 4 files changed, 20 insertions(+) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index eb405942a..3a52c0660 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -1352,3 +1352,19 @@ class Trade(_DECL_BASE, LocalTrade): .group_by(Trade.pair) \ .order_by(desc('profit_sum')).first() return best_pair + + @staticmethod + def get_trading_volume(start_date: datetime = datetime.fromtimestamp(0)) -> float: + """ + Get Trade volume based on Orders + NOTE: Not supported in Backtesting. + :returns: Tuple containing (pair, profit_sum) + """ + trading_volume = Order.query.with_entities( + func.sum(Order.cost).label('volume') + ).filter( + (Order.order_filled_date >= start_date) + & (Order.status == 'closed') + ) \ + .scalar() + return trading_volume diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index bae90b3bc..31fe4c469 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -452,6 +452,7 @@ class RPC: profit_all_ratio.append(profit_ratio) best_pair = Trade.get_best_pair(start_date) + trading_volume = Trade.get_trading_volume(start_date) # Prepare data to display profit_closed_coin_sum = round(sum(profit_closed_coin), 8) @@ -531,6 +532,7 @@ class RPC: 'profit_factor': profit_factor, 'max_drawdown': max_drawdown, 'max_drawdown_abs': max_drawdown_abs, + 'trading_volume': trading_volume, } def _rpc_balance(self, stake_currency: str, fiat_display_currency: str) -> Dict: diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index a7130d691..58bfc6bf7 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -737,6 +737,7 @@ class Telegram(RPCHandler): markdown_msg += ( f"\n*Avg. Duration:* `{avg_duration}`\n" f"*Best Performing:* `{best_pair}: {best_pair_profit_ratio:.2%}`\n" + f"*Trading volume:* `{round_coin_value(stats['trading_volume'], stake_cur)}`\n" f"*Profit factor:* `{stats['profit_factor']:.2f}`\n" f"*Max Drawdown:* `{stats['max_drawdown']:.2%} " f"({round_coin_value(stats['max_drawdown_abs'], stake_cur)})`" diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 65917a6e2..e36d98083 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -706,6 +706,7 @@ def test_profit_handle(default_conf_usdt, update, ticker_usdt, ticker_sell_up, f assert '*Best Performing:* `ETH/USDT: 9.45%`' in msg_mock.call_args_list[-1][0][0] assert '*Max Drawdown:*' in msg_mock.call_args_list[-1][0][0] assert '*Profit factor:*' in msg_mock.call_args_list[-1][0][0] + assert '*Trading volume:* `60 USDT`' in msg_mock.call_args_list[-1][0][0] @pytest.mark.parametrize('is_short', [True, False]) From b7e4dea6c5d6004e51a823f4bacdb5ac200d3016 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 11:43:50 +0200 Subject: [PATCH 343/449] Document new Profit metrics --- docs/telegram-usage.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 773a1b67a..95e7eaa16 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -270,10 +270,15 @@ Return a summary of your profit/loss and performance. > **Latest Trade opened:** `2 minutes ago` > **Avg. Duration:** `2:33:45` > **Best Performing:** `PAY/BTC: 50.23%` +> **Trading volume:** `0.5 BTC` +> **Profit factor:** `1.04` +> **Max Drawdown:** `9.23% (0.01255 BTC)` The relative profit of `1.2%` is the average profit per trade. The relative profit of `15.2 Σ%` is be based on the starting capital - so in this case, the starting capital was `0.00485701 * 1.152 = 0.00738 BTC`. Starting capital is either taken from the `available_capital` setting, or calculated by using current wallet size - profits. +Profit Factor is calculated as gross profits / gross losses - and should serve as an overall metric for the strategy. +Max drawdown corresponds to the backtesting metric `Absolute Drawdown (Account)` - calculated as `(Absolute Drawdown) / (DrawdownHigh + startingBalance)`. ### /forceexit From 8c46d19071d96dae2eca4800e982b0e668e461d6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 16:27:54 +0200 Subject: [PATCH 344/449] Fix backtesting bug balance was never released on cancelled trades --- freqtrade/optimize/backtesting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index f7d92081f..6eeefbfac 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -1055,6 +1055,7 @@ class Backtesting: # Close trade open_trade_count -= 1 open_trades[pair].remove(t) + LocalTrade.trades_open.remove(t) self.wallets.update() # 2. Process entries. From 53bfa7931d1e4ac02a76a5b9be17d4fd6c55725a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 16:32:22 +0200 Subject: [PATCH 345/449] Add rudimentary test for prior bug Test fails without the fix in 8c46d19071d96dae2eca4800e982b0e668e461d6 --- tests/optimize/test_backtest_detail.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 4b4c446e0..a18196507 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -7,6 +7,7 @@ import pytest from freqtrade.data.history import get_timerange from freqtrade.enums import ExitType from freqtrade.optimize.backtesting import Backtesting +from freqtrade.persistence.trade_model import LocalTrade from tests.conftest import patch_exchange from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe, _get_frame_time_from_offset, tests_timeframe) @@ -964,5 +965,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) assert res.open_date == _get_frame_time_from_offset(trade.open_tick) assert res.close_date == _get_frame_time_from_offset(trade.close_tick) assert res.is_short == trade.is_short + assert len(LocalTrade.trades) == len(data.trades) + assert len(LocalTrade.trades_open) == 0 backtesting.cleanup() del backtesting From 474e6705e622aa7372c7a9b203df8553dbdcded3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 16:27:43 +0200 Subject: [PATCH 346/449] Add Profit factor to backtesting --- docs/backtesting.md | 4 ++++ docs/telegram-usage.md | 6 +++--- freqtrade/optimize/optimize_reports.py | 6 ++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 76718d206..50fc96923 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -300,6 +300,7 @@ A backtesting result will look like that: | Absolute profit | 0.00762792 BTC | | Total profit % | 76.2% | | CAGR % | 460.87% | +| Profit factor | 1.11 | | Avg. stake amount | 0.001 BTC | | Total trade volume | 0.429 BTC | | | | @@ -399,6 +400,7 @@ It contains some useful key metrics about performance of your strategy on backte | Absolute profit | 0.00762792 BTC | | Total profit % | 76.2% | | CAGR % | 460.87% | +| Profit factor | 1.11 | | Avg. stake amount | 0.001 BTC | | Total trade volume | 0.429 BTC | | | | @@ -444,6 +446,8 @@ It contains some useful key metrics about performance of your strategy on backte - `Final balance`: Final balance - starting balance + absolute profit. - `Absolute profit`: Profit made in stake currency. - `Total profit %`: Total profit. Aligned to the `TOTAL` row's `Tot Profit %` from the first table. Calculated as `(End capital − Starting capital) / Starting capital`. +- `CAGR %`: Compound annual growth rate. +- `Profit factor`: profit / loss. - `Avg. stake amount`: Average stake amount, either `stake_amount` or the average when using dynamic stake amount. - `Total trade volume`: Volume generated on the exchange to reach the above profit. - `Best Pair` / `Worst Pair`: Best and worst performing pair, and it's corresponding `Cum Profit %`. diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 95e7eaa16..2145797b4 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -275,9 +275,9 @@ Return a summary of your profit/loss and performance. > **Max Drawdown:** `9.23% (0.01255 BTC)` The relative profit of `1.2%` is the average profit per trade. -The relative profit of `15.2 Σ%` is be based on the starting capital - so in this case, the starting capital was `0.00485701 * 1.152 = 0.00738 BTC`. -Starting capital is either taken from the `available_capital` setting, or calculated by using current wallet size - profits. -Profit Factor is calculated as gross profits / gross losses - and should serve as an overall metric for the strategy. +The relative profit of `15.2 Σ%` is be based on the starting capital - so in this case, the starting capital was `0.00485701 * 1.152 = 0.00738 BTC`. +Starting capital is either taken from the `available_capital` setting, or calculated by using current wallet size - profits. +Profit Factor is calculated as gross profits / gross losses - and should serve as an overall metric for the strategy. Max drawdown corresponds to the backtesting metric `Absolute Drawdown (Account)` - calculated as `(Absolute Drawdown) / (DrawdownHigh + startingBalance)`. ### /forceexit diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 79cb8a2bd..44ac4a5b3 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -416,6 +416,9 @@ def generate_strategy_stats(pairlist: List[str], key=lambda x: x['profit_sum']) if len(pair_results) > 1 else None worst_pair = min([pair for pair in pair_results if pair['key'] != 'TOTAL'], key=lambda x: x['profit_sum']) if len(pair_results) > 1 else None + winning_profit = results.loc[results['profit_abs'] > 0, 'profit_abs'].sum() + losing_profit = results.loc[results['profit_abs'] < 0, 'profit_abs'].sum() + profit_factor = winning_profit / abs(losing_profit) if losing_profit else 0.0 backtest_days = (max_date - min_date).days or 1 strat_stats = { @@ -443,6 +446,7 @@ def generate_strategy_stats(pairlist: List[str], 'profit_total_long_abs': results.loc[~results['is_short'], 'profit_abs'].sum(), 'profit_total_short_abs': results.loc[results['is_short'], 'profit_abs'].sum(), 'cagr': calculate_cagr(backtest_days, start_balance, content['final_balance']), + 'profit_factor': profit_factor, 'backtest_start': min_date.strftime(DATETIME_PRINT_FORMAT), 'backtest_start_ts': int(min_date.timestamp() * 1000), 'backtest_end': max_date.strftime(DATETIME_PRINT_FORMAT), @@ -779,6 +783,8 @@ def text_table_add_metrics(strat_results: Dict) -> str: strat_results['stake_currency'])), ('Total profit %', f"{strat_results['profit_total']:.2%}"), ('CAGR %', f"{strat_results['cagr']:.2%}" if 'cagr' in strat_results else 'N/A'), + ('Profit factor', f'{strat_results["profit_factor"]:.2f}' if 'profit_factor' + in strat_results else 'N/A'), ('Trades per day', strat_results['trades_per_day']), ('Avg. daily profit %', f"{(strat_results['profit_total'] / strat_results['backtest_days']):.2%}"), From 0168343b7656eb572c0bda50daa774e2f9549e5f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 16:53:25 +0200 Subject: [PATCH 347/449] Add trading-volume to api schema --- freqtrade/persistence/trade_model.py | 7 +++---- freqtrade/rpc/api_server/api_schemas.py | 1 + tests/conftest_trades.py | 14 ++++++++++++++ tests/rpc/test_rpc_apiserver.py | 7 ++++--- tests/test_persistence.py | 1 + 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 3a52c0660..39ebd75b4 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -1363,8 +1363,7 @@ class Trade(_DECL_BASE, LocalTrade): trading_volume = Order.query.with_entities( func.sum(Order.cost).label('volume') ).filter( - (Order.order_filled_date >= start_date) - & (Order.status == 'closed') - ) \ - .scalar() + Order.order_filled_date >= start_date, + Order.status == 'closed' + ).scalar() return trading_volume diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index fda2d7ea0..7566e2ac0 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -107,6 +107,7 @@ class Profit(BaseModel): profit_factor: float max_drawdown: float max_drawdown_abs: float + trading_volume: Optional[float] class SellReason(BaseModel): diff --git a/tests/conftest_trades.py b/tests/conftest_trades.py index 006eab98f..1a8cf3183 100644 --- a/tests/conftest_trades.py +++ b/tests/conftest_trades.py @@ -29,6 +29,7 @@ def mock_order_1(is_short: bool): 'average': 0.123, 'amount': 123.0, 'filled': 123.0, + 'cost': 15.129, 'remaining': 0.0, } @@ -65,6 +66,7 @@ def mock_order_2(is_short: bool): 'price': 0.123, 'amount': 123.0, 'filled': 123.0, + 'cost': 15.129, 'remaining': 0.0, } @@ -79,6 +81,7 @@ def mock_order_2_sell(is_short: bool): 'price': 0.128, 'amount': 123.0, 'filled': 123.0, + 'cost': 15.129, 'remaining': 0.0, } @@ -126,6 +129,7 @@ def mock_order_3(is_short: bool): 'price': 0.05, 'amount': 123.0, 'filled': 123.0, + 'cost': 15.129, 'remaining': 0.0, } @@ -141,6 +145,7 @@ def mock_order_3_sell(is_short: bool): 'average': 0.06, 'amount': 123.0, 'filled': 123.0, + 'cost': 15.129, 'remaining': 0.0, } @@ -186,6 +191,7 @@ def mock_order_4(is_short: bool): 'price': 0.123, 'amount': 123.0, 'filled': 0.0, + 'cost': 15.129, 'remaining': 123.0, } @@ -225,6 +231,7 @@ def mock_order_5(is_short: bool): 'price': 0.123, 'amount': 123.0, 'filled': 123.0, + 'cost': 15.129, 'remaining': 0.0, } @@ -239,6 +246,7 @@ def mock_order_5_stoploss(is_short: bool): 'price': 0.123, 'amount': 123.0, 'filled': 0.0, + 'cost': 0.0, 'remaining': 123.0, } @@ -281,6 +289,7 @@ def mock_order_6(is_short: bool): 'price': 0.15, 'amount': 2.0, 'filled': 2.0, + 'cost': 0.3, 'remaining': 0.0, } @@ -295,6 +304,7 @@ def mock_order_6_sell(is_short: bool): 'price': 0.15 if is_short else 0.20, 'amount': 2.0, 'filled': 0.0, + 'cost': 0.0, 'remaining': 2.0, } @@ -337,6 +347,7 @@ def short_order(): 'price': 0.123, 'amount': 123.0, 'filled': 123.0, + 'cost': 15.129, 'remaining': 0.0, } @@ -351,6 +362,7 @@ def exit_short_order(): 'price': 0.128, 'amount': 123.0, 'filled': 123.0, + 'cost': 15.744, 'remaining': 0.0, } @@ -424,6 +436,7 @@ def leverage_order(): 'amount': 123.0, 'filled': 123.0, 'remaining': 0.0, + 'cost': 15.129, 'leverage': 5.0 } @@ -439,6 +452,7 @@ def leverage_order_sell(): 'amount': 123.0, 'filled': 123.0, 'remaining': 0.0, + 'cost': 15.744, 'leverage': 5.0 } diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index afbc92c5d..b0ff5e1b2 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -725,7 +725,7 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): 'profit_closed_percent_mean': -0.75, 'profit_closed_ratio_sum': -0.015, 'profit_closed_percent_sum': -1.5, 'profit_closed_ratio': -6.739057628404269e-06, 'profit_closed_percent': -0.0, 'winning_trades': 0, 'losing_trades': 2, - 'profit_factor': 0.0, + 'profit_factor': 0.0, 'trading_volume': 91.074, } ), ( @@ -740,7 +740,7 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): 'profit_closed_percent_mean': 0.75, 'profit_closed_ratio_sum': 0.015, 'profit_closed_percent_sum': 1.5, 'profit_closed_ratio': 7.391275897987988e-07, 'profit_closed_percent': 0.0, 'winning_trades': 2, 'losing_trades': 0, - 'profit_factor': None, + 'profit_factor': None, 'trading_volume': 91.074, } ), ( @@ -755,7 +755,7 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): 'profit_closed_percent_mean': 0.25, 'profit_closed_ratio_sum': 0.005, 'profit_closed_percent_sum': 0.5, 'profit_closed_ratio': -5.429078808526421e-06, 'profit_closed_percent': -0.0, 'winning_trades': 1, 'losing_trades': 1, - 'profit_factor': 0.02775724835771106, + 'profit_factor': 0.02775724835771106, 'trading_volume': 91.074, } ) ]) @@ -812,6 +812,7 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, is_short, expected) 'profit_factor': expected['profit_factor'], 'max_drawdown': ANY, 'max_drawdown_abs': ANY, + 'trading_volume': expected['trading_volume'], } diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 8c12d2ea0..357233dfa 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -2269,6 +2269,7 @@ def test_Trade_object_idem(): 'get_exit_reason_performance', 'get_enter_tag_performance', 'get_mix_tag_performance', + 'get_trading_volume', ) From 0809f9aef69776805912bf8b32621a0a3d481959 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 18 Jun 2022 17:44:15 +0200 Subject: [PATCH 348/449] Add offset to trade response --- freqtrade/rpc/api_server/api_schemas.py | 1 + freqtrade/rpc/rpc.py | 1 + tests/rpc/test_rpc_apiserver.py | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 7566e2ac0..333f2fe6e 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -283,6 +283,7 @@ class OpenTradeSchema(TradeSchema): class TradeResponse(BaseModel): trades: List[TradeSchema] trades_count: int + offset: int total_trades: int diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 31fe4c469..dbbb78c98 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -365,6 +365,7 @@ class RPC: return { "trades": output, "trades_count": len(output), + "offset": offset, "total_trades": Trade.get_trades([Trade.is_open.is_(False)]).count(), } diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index b0ff5e1b2..c0de54c6d 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -578,9 +578,10 @@ def test_api_trades(botclient, mocker, fee, markets, is_short): ) rc = client_get(client, f"{BASE_URI}/trades") assert_response(rc) - assert len(rc.json()) == 3 + assert len(rc.json()) == 4 assert rc.json()['trades_count'] == 0 assert rc.json()['total_trades'] == 0 + assert rc.json()['offset'] == 0 create_mock_trades(fee, is_short=is_short) Trade.query.session.flush() From 0d967f93baf69e08bda264df0702f4a433abf64b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Jun 2022 16:13:00 +0200 Subject: [PATCH 349/449] Improve performance of some RPC calls These don't need orders to be loaded. As a side-effect, this will also reduce the strain on the database. --- freqtrade/persistence/trade_model.py | 13 +++++++++---- freqtrade/rpc/rpc.py | 5 +++-- tests/test_persistence.py | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 39ebd75b4..0c8c985c8 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String, UniqueConstraint, desc, func) -from sqlalchemy.orm import Query, relationship +from sqlalchemy.orm import Query, lazyload, relationship from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, BuySell, LongShort from freqtrade.enums import ExitType, TradingMode @@ -1115,7 +1115,7 @@ class Trade(_DECL_BASE, LocalTrade): ) @staticmethod - def get_trades(trade_filter=None) -> Query: + def get_trades(trade_filter=None, include_orders: bool = True) -> Query: """ Helper function to query Trades using filters. NOTE: Not supported in Backtesting. @@ -1130,9 +1130,14 @@ class Trade(_DECL_BASE, LocalTrade): if trade_filter is not None: if not isinstance(trade_filter, list): trade_filter = [trade_filter] - return Trade.query.filter(*trade_filter) + this_query = Trade.query.filter(*trade_filter) else: - return Trade.query + this_query = Trade.query + if not include_orders: + # Don't load order relations + # Consider using noload or raiseload instead of lazyload + this_query = this_query.options(lazyload(Trade.orders)) + return this_query @staticmethod def get_open_order_trades() -> List['Trade']: diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index dbbb78c98..c42a6f683 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -380,7 +380,7 @@ class RPC: return 'losses' else: return 'draws' - trades: List[Trade] = Trade.get_trades([Trade.is_open.is_(False)]) + trades: List[Trade] = Trade.get_trades([Trade.is_open.is_(False)], include_orders=False) # Sell reason exit_reasons = {} for trade in trades: @@ -408,7 +408,8 @@ class RPC: """ Returns cumulative profit statistics """ trade_filter = ((Trade.is_open.is_(False) & (Trade.close_date >= start_date)) | Trade.is_open.is_(True)) - trades: List[Trade] = Trade.get_trades(trade_filter).order_by(Trade.id).all() + trades: List[Trade] = Trade.get_trades( + trade_filter, include_orders=False).order_by(Trade.id).all() profit_all_coin = [] profit_all_ratio = [] diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 357233dfa..deaad258b 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -2075,6 +2075,24 @@ def test_get_trades_proxy(fee, use_db, is_short): Trade.use_db = True +@pytest.mark.usefixtures("init_persistence") +@pytest.mark.parametrize('is_short', [True, False]) +def test_get_trades__query(fee, is_short): + query = Trade.get_trades([]) + # without orders there should be no join issued. + query1 = Trade.get_trades([], include_orders=False) + + assert "JOIN orders" in str(query) + assert "JOIN orders" not in str(query1) + + create_mock_trades(fee, is_short) + query = Trade.get_trades([]) + query1 = Trade.get_trades([], include_orders=False) + + assert "JOIN orders" in str(query) + assert "JOIN orders" not in str(query1) + + def test_get_trades_backtest(): Trade.use_db = False with pytest.raises(NotImplementedError, match=r"`Trade.get_trades\(\)` not .*"): From 8406010260e3d79be0638b375b63fd447d4711da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jun 2022 03:01:26 +0000 Subject: [PATCH 350/449] Bump types-cachetools from 5.0.1 to 5.0.2 Bumps [types-cachetools](https://github.com/python/typeshed) from 5.0.1 to 5.0.2. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-cachetools dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 19912d59c..53c85f176 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -22,7 +22,7 @@ time-machine==2.7.0 nbconvert==6.5.0 # mypy types -types-cachetools==5.0.1 +types-cachetools==5.0.2 types-filelock==3.2.7 types-requests==2.27.30 types-tabulate==0.8.9 From 55fb7656dfdafebf754d6a5b14c8bdd0eca2eb29 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Jun 2022 06:58:41 +0200 Subject: [PATCH 351/449] Update pre-commit cachetools --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f5c1a36f5..e057627cf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - id: mypy exclude: build_helpers additional_dependencies: - - types-cachetools==5.0.1 + - types-cachetools==5.0.2 - types-filelock==3.2.7 - types-requests==2.27.30 - types-tabulate==0.8.9 From 0804fc7a3af91c25b291bd991132cf77d8d42946 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Jun 2022 07:01:35 +0200 Subject: [PATCH 352/449] CI should run ccxt tests only once --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 551268af7..2f67ec5fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: - name: Tests incl. ccxt compatibility tests run: | pytest --random-order --cov=freqtrade --cov-config=.coveragerc --longrun - if: matrix.python-version == '3.9' + if: matrix.python-version == '3.9' and matrix.os == 'ubuntu-22.04' - name: Coveralls if: (runner.os == 'Linux' && matrix.python-version == '3.9') From f9668ede4a54edda390197b3261504b3d526c77d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Jun 2022 07:02:12 +0200 Subject: [PATCH 353/449] Fix CI Syntax error --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f67ec5fe..81a18c4c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: - name: Tests incl. ccxt compatibility tests run: | pytest --random-order --cov=freqtrade --cov-config=.coveragerc --longrun - if: matrix.python-version == '3.9' and matrix.os == 'ubuntu-22.04' + if: matrix.python-version == '3.9' && matrix.os == 'ubuntu-22.04' - name: Coveralls if: (runner.os == 'Linux' && matrix.python-version == '3.9') From 50c19ece53644808adf80a95eebefdf6fe3f4c6d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Jun 2022 07:05:51 +0200 Subject: [PATCH 354/449] Fix ccxt test gateio flukyness --- tests/exchange/test_ccxt_compat.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index e016873cb..50154bcaf 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -199,8 +199,13 @@ class TestCCXTExchange(): l2 = exchange.fetch_l2_order_book(pair) assert 'asks' in l2 assert 'bids' in l2 + assert len(l2['asks']) >= 1 + assert len(l2['bids']) >= 1 l2_limit_range = exchange._ft_has['l2_limit_range'] l2_limit_range_required = exchange._ft_has['l2_limit_range_required'] + if exchangename == 'gateio': + # TODO: Gateio is unstable here at the moment, ignoring the limit partially. + return for val in [1, 2, 5, 25, 100]: l2 = exchange.fetch_l2_order_book(pair, val) if not l2_limit_range or val in l2_limit_range: From 996372b8f6c18b9721034bd6abfd41532f3e2b62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jun 2022 05:06:39 +0000 Subject: [PATCH 355/449] Bump colorama from 0.4.4 to 0.4.5 Bumps [colorama](https://github.com/tartley/colorama) from 0.4.4 to 0.4.5. - [Release notes](https://github.com/tartley/colorama/releases) - [Changelog](https://github.com/tartley/colorama/blob/master/CHANGELOG.rst) - [Commits](https://github.com/tartley/colorama/compare/0.4.4...0.4.5) --- updated-dependencies: - dependency-name: colorama dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b2dbd921e..bd28e3768 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,7 +41,7 @@ aiofiles==0.8.0 psutil==5.9.1 # Support for colorized terminal output -colorama==0.4.4 +colorama==0.4.5 # Building config files interactively questionary==1.10.0 prompt-toolkit==3.0.29 From e1e3a903f98aebd0d2db6b9c6e0e5f51b70075c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jun 2022 05:07:35 +0000 Subject: [PATCH 356/449] Bump ccxt from 1.87.12 to 1.88.15 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.87.12 to 1.88.15. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.87.12...1.88.15) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b2dbd921e..ec244806d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.22.4 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.87.12 +ccxt==1.88.15 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From 1cd2b0504a9e1c684326ab59a6dcb6f2a8eb85a7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Jun 2022 07:15:15 +0200 Subject: [PATCH 357/449] Run regular tests for 3.9 under other ubuntu systems --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81a18c4c9..818d250ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: - name: Tests run: | pytest --random-order --cov=freqtrade --cov-config=.coveragerc - if: matrix.python-version != '3.9' + if: matrix.python-version != '3.9' && matrix.os != 'ubuntu-22.04' - name: Tests incl. ccxt compatibility tests run: | From 3189b284c014c4624ba27fc8abbde982c5b36c0c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Jun 2022 08:04:34 +0200 Subject: [PATCH 358/449] Fix tests condition --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 818d250ca..4fe1ad853 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: - name: Tests run: | pytest --random-order --cov=freqtrade --cov-config=.coveragerc - if: matrix.python-version != '3.9' && matrix.os != 'ubuntu-22.04' + if: matrix.python-version != '3.9' || matrix.os != 'ubuntu-22.04' - name: Tests incl. ccxt compatibility tests run: | From 15fac746a8129e00acb86246e16b00fb7daea89f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jun 2022 06:59:58 +0000 Subject: [PATCH 359/449] Bump mkdocs-material from 8.3.4 to 8.3.6 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.3.4 to 8.3.6. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/8.3.4...8.3.6) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 1f342ca02..6477ad23f 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 -mkdocs-material==8.3.4 +mkdocs-material==8.3.6 mdx_truly_sane_lists==1.2 pymdown-extensions==9.5 jinja2==3.1.2 From 405ea74f168ede4d85a4a3d9bf8f6e862ada6b75 Mon Sep 17 00:00:00 2001 From: Surfer Admin Date: Tue, 21 Jun 2022 14:06:41 -0400 Subject: [PATCH 360/449] stopPrice --- .gitignore | 5 ++ freqtrade/templates/sample_strategy.py | 27 ++------ .../templates/strategy_analysis_example.ipynb | 61 ++++++++++++++++--- 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 97f77f779..5042dfb9b 100644 --- a/.gitignore +++ b/.gitignore @@ -105,3 +105,8 @@ target/ !config_examples/config_ftx.example.json !config_examples/config_full.example.json !config_examples/config_kraken.example.json +doc/doc-filelist.js +.gitignore +.gitignore +doc/doc-style.css +doc/doc-script.js diff --git a/freqtrade/templates/sample_strategy.py b/freqtrade/templates/sample_strategy.py index 1b375714a..1b49f82c9 100644 --- a/freqtrade/templates/sample_strategy.py +++ b/freqtrade/templates/sample_strategy.py @@ -178,29 +178,10 @@ class SampleStrategy(IStrategy): # RSI dataframe['rsi'] = ta.RSI(dataframe) - # # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy) - # rsi = 0.1 * (dataframe['rsi'] - 50) - # dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) - - # # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy) - # dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) - - # # Stochastic Slow - # stoch = ta.STOCH(dataframe) - # dataframe['slowd'] = stoch['slowd'] - # dataframe['slowk'] = stoch['slowk'] - - # Stochastic Fast - stoch_fast = ta.STOCHF(dataframe) - dataframe['fastd'] = stoch_fast['fastd'] - dataframe['fastk'] = stoch_fast['fastk'] - - # # Stochastic RSI - # Please read https://github.com/freqtrade/freqtrade/issues/2961 before using this. - # STOCHRSI is NOT aligned with tradingview, which may result in non-expected results. - # stoch_rsi = ta.STOCHRSI(dataframe) - # dataframe['fastd_rsi'] = stoch_rsi['fastd'] - # dataframe['fastk_rsi'] = stoch_rsi['fastk'] + # Stochastic RSI + stoch_rsi = ta.STOCHRSI(dataframe) + dataframe['fastd_rsi'] = stoch_rsi['fastd'] + dataframe['fastk_rsi'] = stoch_rsi['fastk'] # MACD macd = ta.MACD(dataframe) diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index 93e4b83ae..33182dbf0 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -19,9 +19,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "OperationalException", + "evalue": "Directory `/Users/surfer/Software/MMM/develop/freqtrade/freqtrade/templates/user_data` does not exist. Please use `freqtrade create-userdir` to create a user directory", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mOperationalException\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [2]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mfreqtrade\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mconfiguration\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m Configuration\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# Customize these according to your needs.\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \n\u001b[1;32m 6\u001b[0m \u001b[38;5;66;03m# Initialize empty configuration object\u001b[39;00m\n\u001b[0;32m----> 7\u001b[0m config \u001b[38;5;241m=\u001b[39m \u001b[43mConfiguration\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_files\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;66;03m# Optionally, use existing configuration file\u001b[39;00m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# config = Configuration.from_files([\"config.json\"])\u001b[39;00m\n\u001b[1;32m 10\u001b[0m \n\u001b[1;32m 11\u001b[0m \u001b[38;5;66;03m# Define some constants\u001b[39;00m\n\u001b[1;32m 12\u001b[0m config[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtimeframe\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m1m\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:60\u001b[0m, in \u001b[0;36mConfiguration.from_files\u001b[0;34m(files)\u001b[0m\n\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# Keep this method as staticmethod, so it can be used from interactive environments\u001b[39;00m\n\u001b[1;32m 59\u001b[0m c \u001b[38;5;241m=\u001b[39m Configuration({\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mconfig\u001b[39m\u001b[38;5;124m'\u001b[39m: files}, RunMode\u001b[38;5;241m.\u001b[39mOTHER)\n\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_config\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:42\u001b[0m, in \u001b[0;36mConfiguration.get_config\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;124;03mReturn the config. Use this method to get the bot config\u001b[39;00m\n\u001b[1;32m 39\u001b[0m \u001b[38;5;124;03m:return: Dict: Bot config\u001b[39;00m\n\u001b[1;32m 40\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconfig \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 42\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconfig \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload_config\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 44\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconfig\n", + "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:92\u001b[0m, in \u001b[0;36mConfiguration.load_config\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 88\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_common_options(config)\n\u001b[1;32m 90\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_trading_options(config)\n\u001b[0;32m---> 92\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_process_optimize_options\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 94\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_plot_options(config)\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_data_options(config)\n", + "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:249\u001b[0m, in \u001b[0;36mConfiguration._process_optimize_options\u001b[0;34m(self, config)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_args_to_config(config, argname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mfee\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 243\u001b[0m logstring\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mParameter --fee detected, \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 244\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124msetting fee to: \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m ...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_args_to_config(config, argname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtimerange\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 247\u001b[0m logstring\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mParameter --timerange detected: \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m ...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m--> 249\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_process_datadir_options\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 251\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_args_to_config(config, argname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mstrategy_list\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 252\u001b[0m logstring\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mUsing strategy list of \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m strategies\u001b[39m\u001b[38;5;124m'\u001b[39m, logfun\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mlen\u001b[39m)\n\u001b[1;32m 254\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_args_to_config(\n\u001b[1;32m 255\u001b[0m config,\n\u001b[1;32m 256\u001b[0m argname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrecursive_strategy_search\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 257\u001b[0m logstring\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mRecursively searching for a strategy in the strategies folder.\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 258\u001b[0m )\n", + "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:180\u001b[0m, in \u001b[0;36mConfiguration._process_datadir_options\u001b[0;34m(self, config)\u001b[0m\n\u001b[1;32m 177\u001b[0m config\u001b[38;5;241m.\u001b[39mupdate({\u001b[38;5;124m'\u001b[39m\u001b[38;5;124muser_data_dir\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;28mstr\u001b[39m(Path\u001b[38;5;241m.\u001b[39mcwd() \u001b[38;5;241m/\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124muser_data\u001b[39m\u001b[38;5;124m'\u001b[39m)})\n\u001b[1;32m 179\u001b[0m \u001b[38;5;66;03m# reset to user_data_dir so this contains the absolute path.\u001b[39;00m\n\u001b[0;32m--> 180\u001b[0m config[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124muser_data_dir\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[43mcreate_userdata_dir\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43muser_data_dir\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreate_dir\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 181\u001b[0m logger\u001b[38;5;241m.\u001b[39minfo(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mUsing user-data directory: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m ...\u001b[39m\u001b[38;5;124m'\u001b[39m, config[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124muser_data_dir\u001b[39m\u001b[38;5;124m'\u001b[39m])\n\u001b[1;32m 183\u001b[0m config\u001b[38;5;241m.\u001b[39mupdate({\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdatadir\u001b[39m\u001b[38;5;124m'\u001b[39m: create_datadir(config, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdatadir\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m))})\n", + "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/directory_operations.py:61\u001b[0m, in \u001b[0;36mcreate_userdata_dir\u001b[0;34m(directory, create_dir)\u001b[0m\n\u001b[1;32m 59\u001b[0m logger\u001b[38;5;241m.\u001b[39minfo(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCreated user-data directory: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfolder\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 60\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m---> 61\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m OperationalException(\n\u001b[1;32m 62\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDirectory `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfolder\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m` does not exist. \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 63\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPlease use `freqtrade create-userdir` to create a user directory\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 65\u001b[0m \u001b[38;5;66;03m# Create required subdirectories\u001b[39;00m\n\u001b[1;32m 66\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m sub_dirs:\n", + "\u001b[0;31mOperationalException\u001b[0m: Directory `/Users/surfer/Software/MMM/develop/freqtrade/freqtrade/templates/user_data` does not exist. Please use `freqtrade create-userdir` to create a user directory" + ] + } + ], "source": [ "from pathlib import Path\n", "from freqtrade.configuration import Configuration\n", @@ -34,9 +52,9 @@ "# config = Configuration.from_files([\"config.json\"])\n", "\n", "# Define some constants\n", - "config[\"timeframe\"] = \"5m\"\n", + "config[\"timeframe\"] = \"1m\"\n", "# Name of the strategy class\n", - "config[\"strategy\"] = \"SampleStrategy\"\n", + "config[\"strategy\"] = \"MMMOracle\"\n", "# Location of the data\n", "data_location = Path(config['user_data_dir'], 'data', 'binance')\n", "# Pair to analyze - Only use one pair here\n", @@ -136,9 +154,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'config' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Input \u001b[0;32mIn [3]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mfreqtrade\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdata\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mbtanalysis\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m load_backtest_data, load_backtest_stats\n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# if backtest_dir points to a directory, it'll automatically load the last backtest file.\u001b[39;00m\n\u001b[0;32m----> 4\u001b[0m backtest_dir \u001b[38;5;241m=\u001b[39m \u001b[43mconfig\u001b[49m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser_data_dir\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m/\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbacktest_results\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", + "\u001b[0;31mNameError\u001b[0m: name 'config' is not defined" + ] + } + ], "source": [ "from freqtrade.data.btanalysis import load_backtest_data, load_backtest_stats\n", "\n", @@ -247,9 +277,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "Series([], Name: exit_reason, dtype: int64)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from freqtrade.data.btanalysis import load_trades_from_db\n", "\n", @@ -363,7 +404,7 @@ "metadata": { "file_extension": ".py", "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -377,7 +418,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.7" }, "mimetype": "text/x-python", "name": "python", From 53e5483daadfac741e21987be8f78b949ad6e808 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 22 Jun 2022 06:30:30 +0200 Subject: [PATCH 361/449] Store StopPrice for dry-run orders closes #6996 --- freqtrade/exchange/binance.py | 13 +++++++++---- freqtrade/exchange/gateio.py | 6 ++++-- freqtrade/exchange/huobi.py | 8 +++++++- freqtrade/exchange/kucoin.py | 5 ++++- freqtrade/persistence/migrations.py | 11 ++++++----- freqtrade/persistence/trade_model.py | 3 +++ tests/exchange/test_kucoin.py | 4 ++-- tests/test_persistence.py | 2 ++ 8 files changed, 37 insertions(+), 15 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 03546dcf9..37a3c419d 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -52,10 +52,15 @@ class Binance(Exchange): ordertype = 'stop' if self.trading_mode == TradingMode.FUTURES else 'stop_loss_limit' - return order['type'] == ordertype and ( - (side == "sell" and stop_loss > float(order['stopPrice'])) or - (side == "buy" and stop_loss < float(order['stopPrice'])) - ) + return ( + order.get('stopPrice', None) is None + or ( + order['type'] == ordertype + and ( + (side == "sell" and stop_loss > float(order['stopPrice'])) or + (side == "buy" and stop_loss < float(order['stopPrice'])) + ) + )) def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: tickers = super().get_tickers(symbols=symbols, cached=cached) diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index fd9a2b2b3..bf50167da 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -114,5 +114,7 @@ class Gateio(Exchange): Verify stop_loss against stoploss-order value (limit or price) Returns True if adjustment is necessary. """ - return ((side == "sell" and stop_loss > float(order['stopPrice'])) or - (side == "buy" and stop_loss < float(order['stopPrice']))) + return (order.get('stopPrice', None) is None or ( + side == "sell" and stop_loss > float(order['stopPrice'])) or + (side == "buy" and stop_loss < float(order['stopPrice'])) + ) diff --git a/freqtrade/exchange/huobi.py b/freqtrade/exchange/huobi.py index 71c4d1cf6..736515dec 100644 --- a/freqtrade/exchange/huobi.py +++ b/freqtrade/exchange/huobi.py @@ -27,7 +27,13 @@ class Huobi(Exchange): Verify stop_loss against stoploss-order value (limit or price) Returns True if adjustment is necessary. """ - return order['type'] == 'stop' and stop_loss > float(order['stopPrice']) + return ( + order.get('stopPrice', None) is None + or ( + order['type'] == 'stop' + and stop_loss > float(order['stopPrice']) + ) + ) def _get_stop_params(self, ordertype: str, stop_price: float) -> Dict: diff --git a/freqtrade/exchange/kucoin.py b/freqtrade/exchange/kucoin.py index f23189b3c..21eaa4bc3 100644 --- a/freqtrade/exchange/kucoin.py +++ b/freqtrade/exchange/kucoin.py @@ -33,7 +33,10 @@ class Kucoin(Exchange): Verify stop_loss against stoploss-order value (limit or price) Returns True if adjustment is necessary. """ - return order['info'].get('stop') is not None and stop_loss > float(order['stopPrice']) + return ( + order.get('stopPrice', None) is None + or stop_loss > float(order['stopPrice']) + ) def _get_stop_params(self, ordertype: str, stop_price: float) -> Dict: diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index b0fdf0412..f8fc5d619 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -201,16 +201,18 @@ def migrate_orders_table(engine, table_back_name: str, cols_order: List): ft_fee_base = get_column_def(cols_order, 'ft_fee_base', 'null') average = get_column_def(cols_order, 'average', 'null') + stop_price = get_column_def(cols_order, 'stop_price', 'null') # sqlite does not support literals for booleans with engine.begin() as connection: connection.execute(text(f""" insert into orders (id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id, status, symbol, order_type, side, price, amount, filled, average, remaining, cost, - order_date, order_filled_date, order_update_date, ft_fee_base) + stop_price, order_date, order_filled_date, order_update_date, ft_fee_base) select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id, status, symbol, order_type, side, price, amount, filled, {average} average, remaining, - cost, order_date, order_filled_date, order_update_date, {ft_fee_base} ft_fee_base + cost, {stop_price} stop_price, order_date, order_filled_date, + order_update_date, {ft_fee_base} ft_fee_base from {table_back_name} """)) @@ -294,9 +296,8 @@ def check_migrate(engine, decl_base, previous_tables) -> None: # Check if migration necessary # Migrates both trades and orders table! - # if ('orders' not in previous_tables - # or not has_column(cols_orders, 'leverage')): - if not has_column(cols_trades, 'base_currency'): + if not has_column(cols_orders, 'stop_price'): + # if not has_column(cols_trades, 'base_currency'): logger.info(f"Running database migration for trades - " f"backup: {table_back_name}, {order_table_bak_name}") migrate_trades_and_orders_table( diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 0c8c985c8..324002685 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -57,6 +57,7 @@ class Order(_DECL_BASE): filled = Column(Float, nullable=True) remaining = Column(Float, nullable=True) cost = Column(Float, nullable=True) + stop_price = Column(Float, nullable=True) order_date = Column(DateTime, nullable=True, default=datetime.utcnow) order_filled_date = Column(DateTime, nullable=True) order_update_date = Column(DateTime, nullable=True) @@ -107,6 +108,7 @@ class Order(_DECL_BASE): self.average = order.get('average', self.average) self.remaining = order.get('remaining', self.remaining) self.cost = order.get('cost', self.cost) + self.stop_price = order.get('stopPrice', self.stop_price) if 'timestamp' in order and order['timestamp'] is not None: self.order_date = datetime.fromtimestamp(order['timestamp'] / 1000, tz=timezone.utc) @@ -130,6 +132,7 @@ class Order(_DECL_BASE): 'side': self.ft_order_side, 'filled': self.filled, 'remaining': self.remaining, + 'stopPrice': self.stop_price, 'datetime': self.order_date_utc.strftime('%Y-%m-%dT%H:%M:%S.%f'), 'timestamp': int(self.order_date_utc.timestamp() * 1000), 'status': self.status, diff --git a/tests/exchange/test_kucoin.py b/tests/exchange/test_kucoin.py index 8af1e83a3..ebaf5ae81 100644 --- a/tests/exchange/test_kucoin.py +++ b/tests/exchange/test_kucoin.py @@ -123,5 +123,5 @@ def test_stoploss_adjust_kucoin(mocker, default_conf): assert exchange.stoploss_adjust(1501, order, 'sell') assert not exchange.stoploss_adjust(1499, order, 'sell') # Test with invalid order case - order['info']['stop'] = None - assert not exchange.stoploss_adjust(1501, order, 'sell') + order['stopPrice'] = None + assert exchange.stoploss_adjust(1501, order, 'sell') diff --git a/tests/test_persistence.py b/tests/test_persistence.py index deaad258b..c52e06c82 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -2717,5 +2717,7 @@ def test_order_to_ccxt(limit_buy_order_open): del raw_order['fee'] del raw_order['datetime'] del raw_order['info'] + assert raw_order['stopPrice'] is None + del raw_order['stopPrice'] del limit_buy_order_open['datetime'] assert raw_order == limit_buy_order_open From 90feccf33c4d554c0ea8cbfe31a8b9419b8b24f3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Jun 2022 07:17:24 +0200 Subject: [PATCH 362/449] slightly update custom dockerfile with add. comment closes #6994 --- docker/Dockerfile.custom | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/Dockerfile.custom b/docker/Dockerfile.custom index 3b55fcb0e..6e321f14d 100644 --- a/docker/Dockerfile.custom +++ b/docker/Dockerfile.custom @@ -7,4 +7,5 @@ FROM freqtradeorg/freqtrade:develop # The below dependency - pyti - serves as an example. Please use whatever you need! RUN pip install --user pyti +# Switch back to user (only if you required root above) # USER ftuser From ddc355feb6758f019bb0cdbfb9dfe76bdadd34da Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Jun 2022 08:07:22 +0000 Subject: [PATCH 363/449] Bump numpy from 1.22.4 to 1.23.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 40b5d660d..b62238024 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy==1.22.4 +numpy==1.23.0 pandas==1.4.2 pandas-ta==0.3.14b From 2b07d346118b98bd976200233c57687e9ca28199 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Jun 2022 20:47:51 +0200 Subject: [PATCH 364/449] Revert several undesired changes --- freqtrade/exchange/exchange.py | 8 ++++---- freqtrade/freqtradebot.py | 6 +++--- freqtrade/optimize/backtesting.py | 2 +- freqtrade/plugins/pairlist/PriceFilter.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 4fa8f1def..4febe5652 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -383,8 +383,8 @@ class Exchange: Ensures that Configured mode aligns to """ return ( - market.get('quote') is not None - and market.get('base') is not None + market.get('quote', None) is not None + and market.get('base', None) is not None and (self.precisionMode != TICK_SIZE # Too low precision will falsify calculations or market.get('precision', {}).get('price') > 1e-11) @@ -1599,7 +1599,7 @@ class Exchange: def get_fee(self, symbol: str, type: str = '', side: str = '', amount: float = 1, price: float = 1, taker_or_maker: str = 'maker') -> float: try: - if self._config['dry_run'] and self._config.get('fee') is not None: + if self._config['dry_run'] and self._config.get('fee', None) is not None: return self._config['fee'] # validate that markets are loaded before trying to get fee if self._api.markets is None or len(self._api.markets) == 0: @@ -1660,7 +1660,7 @@ class Exchange: fee_to_quote_rate = safe_value_fallback2(tick, tick, 'last', 'ask') except ExchangeError: - fee_to_quote_rate = self._config['exchange'].get('unknown_fee_rate') + fee_to_quote_rate = self._config['exchange'].get('unknown_fee_rate', None) if not fee_to_quote_rate: return None return round((self._contracts_to_amount( diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index affc6f360..ee535e9c3 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -855,7 +855,7 @@ class FreqtradeBot(LoggingMixin): 'order_type': order_type, 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], - 'fiat_currency': self.config.get('fiat_display_currency'), + 'fiat_currency': self.config.get('fiat_display_currency', None), 'amount': safe_value_fallback(order, 'filled', 'amount') or trade.amount, 'open_date': trade.open_date or datetime.utcnow(), 'current_rate': current_rate, @@ -884,7 +884,7 @@ class FreqtradeBot(LoggingMixin): 'order_type': order_type, 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], - 'fiat_currency': self.config.get('fiat_display_currency'), + 'fiat_currency': self.config.get('fiat_display_currency', None), 'amount': trade.amount, 'open_date': trade.open_date, 'current_rate': current_rate, @@ -1590,7 +1590,7 @@ class FreqtradeBot(LoggingMixin): 'open_date': trade.open_date, 'close_date': trade.close_date or datetime.now(timezone.utc), 'stake_currency': self.config['stake_currency'], - 'fiat_currency': self.config.get('fiat_display_currency'), + 'fiat_currency': self.config.get('fiat_display_currency', None), 'reason': reason, } diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 6f566a346..cacb87745 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -123,7 +123,7 @@ class Backtesting: if len(self.pairlists.whitelist) == 0: raise OperationalException("No pair in whitelist.") - if config.get('fee') is not None: + if config.get('fee', None) is not None: self.fee = config['fee'] else: self.fee = self.exchange.get_fee(symbol=self.pairlists.whitelist[0]) diff --git a/freqtrade/plugins/pairlist/PriceFilter.py b/freqtrade/plugins/pairlist/PriceFilter.py index 4c5db52b1..009789eaf 100644 --- a/freqtrade/plugins/pairlist/PriceFilter.py +++ b/freqtrade/plugins/pairlist/PriceFilter.py @@ -70,7 +70,7 @@ class PriceFilter(IPairList): :param ticker: ticker dict as returned from ccxt.fetch_tickers() :return: True if the pair can stay, false if it should be removed """ - if ticker.get('last') is None or ticker.get('last') == 0: + if ticker.get('last', None) is None or ticker.get('last') == 0: self.log_once(f"Removed {pair} from whitelist, because " "ticker['last'] is empty (Usually no trade in the last 24h).", logger.info) From b5d0bc997d6c03b5e8dd0a2a10de4ec58062b2a8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jun 2022 17:25:33 +0200 Subject: [PATCH 365/449] Clarify stoploss behavior when not defining offset closes #6828 --- docs/stoploss.md | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 83f787947..6ddb485a4 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -130,7 +130,7 @@ In summary: The stoploss will be adjusted to be always be -10% of the highest ob ### Trailing stop loss, custom positive loss -It is also possible to have a default stop loss, when you are in the red with your buy (buy - fee), but once you hit positive result the system will utilize a new stop loss, which can have a different value. +You could also have a default stop loss when you are in the red with your buy (buy - fee), but once you hit a positive result (or an offset you define) the system will utilize a new stop loss, which can have a different value. For example, your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. !!! Note @@ -142,6 +142,8 @@ Both values require `trailing_stop` to be set to true and `trailing_stop_positiv stoploss = -0.10 trailing_stop = True trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0 + trailing_only_offset_is_reached = False # Default - not necessary for this example ``` For example, simplified math: @@ -156,11 +158,31 @@ For example, simplified math: The 0.02 would translate to a -2% stop loss. Before this, `stoploss` is used for the trailing stoploss. +!!! Tip "Use an offset to change your stoploss" + Use `trailing_stop_positive_offset` to ensure that your new trailing stoploss will be in profit by setting `trailing_stop_positive_offset` higher than `trailing_stop_positive`. Your first new stoploss value will then already have locked in profits. + + Example with simplified math: + + ``` python + stoploss = -0.10 + trailing_stop = True + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.03 + ``` + + * the bot buys an asset at a price of 100$ + * the stop loss is defined at -10%, so the stop loss would get triggered once the asset drops below 90$ + * assuming the asset now increases to 102$ + * the stoploss will now be at 91.8$ - 10% below the highest observed rate + * assuming the asset now increases to 103.5$ (above the offset configured) + * the stop loss will now be -2% of 103$ = 101.42$ + * now the asset drops in value to 102\$, the stop loss will still be 101.42$ and would trigger once price breaks below 101.42$ + ### Trailing stop loss only once the trade has reached a certain offset -It is also possible to use a static stoploss until the offset is reached, and then trail the trade to take profits once the market turns. +You can also keep a static stoploss until the offset is reached, and then trail the trade to take profits once the market turns. -If `"trailing_only_offset_is_reached": true` then the trailing stoploss is only activated once the offset is reached. Until then, the stoploss remains at the configured `stoploss`. +If `trailing_only_offset_is_reached = True` then the trailing stoploss is only activated once the offset is reached. Until then, the stoploss remains at the configured `stoploss`. This option can be used with or without `trailing_stop_positive`, but uses `trailing_stop_positive_offset` as offset. ``` python @@ -203,7 +225,6 @@ If price moves 1% - you've lost 10$ of your own capital - therfore stoploss will Make sure to be aware of this, and avoid using too tight stoploss (at 10x leverage, 10% risk may be too little to allow the trade to "breath" a little). - ## Changing stoploss on open trades A stoploss on an open trade can be changed by changing the value in the configuration or strategy and use the `/reload_config` command (alternatively, completely stopping and restarting the bot also works). From 92dbb0d3660efd602e9851f7b9c35126fc5b5620 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 03:02:07 +0000 Subject: [PATCH 366/449] Bump uvicorn from 0.17.6 to 0.18.1 Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.17.6 to 0.18.1. - [Release notes](https://github.com/encode/uvicorn/releases) - [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md) - [Commits](https://github.com/encode/uvicorn/compare/0.17.6...0.18.1) --- updated-dependencies: - dependency-name: uvicorn dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b62238024..7781b43e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,7 +35,7 @@ sdnotify==0.3.2 # API Server fastapi==0.78.0 -uvicorn==0.17.6 +uvicorn==0.18.1 pyjwt==2.4.0 aiofiles==0.8.0 psutil==5.9.1 From 4840c7d2fd9f98757fe76ebe90f75f14afb5b814 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 03:02:16 +0000 Subject: [PATCH 367/449] Bump pytest-mock from 3.7.0 to 3.8.1 Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.7.0 to 3.8.1. - [Release notes](https://github.com/pytest-dev/pytest-mock/releases) - [Changelog](https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.7.0...v3.8.1) --- updated-dependencies: - dependency-name: pytest-mock dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 53c85f176..29e21e116 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -12,7 +12,7 @@ pre-commit==2.19.0 pytest==7.1.2 pytest-asyncio==0.18.3 pytest-cov==3.0.0 -pytest-mock==3.7.0 +pytest-mock==3.8.1 pytest-random-order==1.0.4 isort==5.10.1 # For datetime mocking From 45db2347dcd4545fa882cd32fffc9f5d9b936640 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 03:02:29 +0000 Subject: [PATCH 368/449] Bump mkdocs-material from 8.3.6 to 8.3.8 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.3.6 to 8.3.8. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/8.3.6...8.3.8) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 6477ad23f..fe00705b9 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 -mkdocs-material==8.3.6 +mkdocs-material==8.3.8 mdx_truly_sane_lists==1.2 pymdown-extensions==9.5 jinja2==3.1.2 From 963f38a69077524a7ce60e2099ae2c641f57c4a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 03:02:46 +0000 Subject: [PATCH 369/449] Bump sqlalchemy from 1.4.37 to 1.4.39 Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.37 to 1.4.39. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: sqlalchemy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b62238024..7e1bc79e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ ccxt==1.88.15 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 -SQLAlchemy==1.4.37 +SQLAlchemy==1.4.39 python-telegram-bot==13.12 arrow==1.2.2 cachetools==4.2.2 From 8b7dc031f7db50a35731d4b8d92d9196153ae639 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 03:02:51 +0000 Subject: [PATCH 370/449] Bump plotly from 5.8.2 to 5.9.0 Bumps [plotly](https://github.com/plotly/plotly.py) from 5.8.2 to 5.9.0. - [Release notes](https://github.com/plotly/plotly.py/releases) - [Changelog](https://github.com/plotly/plotly.py/blob/master/CHANGELOG.md) - [Commits](https://github.com/plotly/plotly.py/compare/v5.8.2...v5.9.0) --- updated-dependencies: - dependency-name: plotly dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-plot.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-plot.txt b/requirements-plot.txt index a2a894c57..0f6ae94c2 100644 --- a/requirements-plot.txt +++ b/requirements-plot.txt @@ -1,4 +1,4 @@ # Include all requirements to run the bot. -r requirements.txt -plotly==5.8.2 +plotly==5.9.0 From efee148e43e21d0bc90af95ab8e7635bd5624502 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 03:02:53 +0000 Subject: [PATCH 371/449] Bump types-cachetools from 5.0.2 to 5.2.1 Bumps [types-cachetools](https://github.com/python/typeshed) from 5.0.2 to 5.2.1. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-cachetools dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 53c85f176..c3edec904 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -22,7 +22,7 @@ time-machine==2.7.0 nbconvert==6.5.0 # mypy types -types-cachetools==5.0.2 +types-cachetools==5.2.1 types-filelock==3.2.7 types-requests==2.27.30 types-tabulate==0.8.9 From 6510c8d330efedd5f7dad2d48bf566db211f4ce3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 03:03:00 +0000 Subject: [PATCH 372/449] Bump tabulate from 0.8.9 to 0.8.10 Bumps [tabulate](https://github.com/astanin/python-tabulate) from 0.8.9 to 0.8.10. - [Release notes](https://github.com/astanin/python-tabulate/releases) - [Changelog](https://github.com/astanin/python-tabulate/blob/master/CHANGELOG) - [Commits](https://github.com/astanin/python-tabulate/compare/v0.8.9...v0.8.10) --- updated-dependencies: - dependency-name: tabulate dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b62238024..8f63c5add 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ urllib3==1.26.9 jsonschema==4.6.0 TA-Lib==0.4.24 technical==1.3.0 -tabulate==0.8.9 +tabulate==0.8.10 pycoingecko==2.2.0 jinja2==3.1.2 tables==3.7.0 From 0ef2c812db844c9706116ce5b0381e090e62c1e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 05:38:31 +0000 Subject: [PATCH 373/449] Bump ccxt from 1.88.15 to 1.89.14 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.88.15 to 1.89.14. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.88.15...1.89.14) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7e1bc79e9..daf8ebd6c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.23.0 pandas==1.4.2 pandas-ta==0.3.14b -ccxt==1.88.15 +ccxt==1.89.14 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From 9a9d1a89742036169332b4fe37bdeec1dd02293c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 05:39:04 +0000 Subject: [PATCH 374/449] Bump orjson from 3.7.2 to 3.7.3 Bumps [orjson](https://github.com/ijl/orjson) from 3.7.2 to 3.7.3. - [Release notes](https://github.com/ijl/orjson/releases) - [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md) - [Commits](https://github.com/ijl/orjson/compare/3.7.2...3.7.3) --- updated-dependencies: - dependency-name: orjson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7e1bc79e9..cf47a80ce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ urllib3==1.26.9 jsonschema==4.6.0 TA-Lib==0.4.24 technical==1.3.0 -tabulate==0.8.9 +tabulate==0.8.10 pycoingecko==2.2.0 jinja2==3.1.2 tables==3.7.0 @@ -28,7 +28,7 @@ py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.6 # Properly format api responses -orjson==3.7.2 +orjson==3.7.3 # Notify systemd sdnotify==0.3.2 From 01185ab48391cf702f187a4dee47417de699ae9f Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Jun 2022 07:59:26 +0200 Subject: [PATCH 375/449] update cachetools precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e057627cf..983df6fad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - id: mypy exclude: build_helpers additional_dependencies: - - types-cachetools==5.0.2 + - types-cachetools==5.2.1 - types-filelock==3.2.7 - types-requests==2.27.30 - types-tabulate==0.8.9 From 82ef97af7e16c82ae9ba342fd5b4e945bb590649 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 07:44:33 +0000 Subject: [PATCH 376/449] Bump pandas from 1.4.2 to 1.4.3 Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.4.2 to 1.4.3. - [Release notes](https://github.com/pandas-dev/pandas/releases) - [Changelog](https://github.com/pandas-dev/pandas/blob/main/RELEASE.md) - [Commits](https://github.com/pandas-dev/pandas/compare/v1.4.2...v1.4.3) --- updated-dependencies: - dependency-name: pandas dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e64ddca05..178d852b0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ numpy==1.23.0 -pandas==1.4.2 +pandas==1.4.3 pandas-ta==0.3.14b ccxt==1.89.14 From d60127a6d8b159ae56e3a4d1ff13a9e225cc0b0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 09:59:07 +0000 Subject: [PATCH 377/449] Bump time-machine from 2.7.0 to 2.7.1 Bumps [time-machine](https://github.com/adamchainz/time-machine) from 2.7.0 to 2.7.1. - [Release notes](https://github.com/adamchainz/time-machine/releases) - [Changelog](https://github.com/adamchainz/time-machine/blob/main/HISTORY.rst) - [Commits](https://github.com/adamchainz/time-machine/compare/2.7.0...2.7.1) --- updated-dependencies: - dependency-name: time-machine dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index ebfbafe07..03773faf6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -16,7 +16,7 @@ pytest-mock==3.8.1 pytest-random-order==1.0.4 isort==5.10.1 # For datetime mocking -time-machine==2.7.0 +time-machine==2.7.1 # Convert jupyter notebooks to markdown documents nbconvert==6.5.0 From f6e058a327a5e9a3db6e388266d79879186e2cb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 09:59:19 +0000 Subject: [PATCH 378/449] Bump types-requests from 2.27.30 to 2.28.0 Bumps [types-requests](https://github.com/python/typeshed) from 2.27.30 to 2.28.0. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index ebfbafe07..925bf1929 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -24,6 +24,6 @@ nbconvert==6.5.0 # mypy types types-cachetools==5.2.1 types-filelock==3.2.7 -types-requests==2.27.30 +types-requests==2.28.0 types-tabulate==0.8.9 types-python-dateutil==2.8.17 From 0c69a0886392114ca65981c923fa357bf53ebd07 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Jun 2022 12:09:27 +0200 Subject: [PATCH 379/449] update requests precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 983df6fad..958312d6c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: additional_dependencies: - types-cachetools==5.2.1 - types-filelock==3.2.7 - - types-requests==2.27.30 + - types-requests==2.28.0 - types-tabulate==0.8.9 - types-python-dateutil==2.8.17 # stages: [push] From 8b1798522c17b2f651d4d0653247458ff51709da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 13:18:58 +0000 Subject: [PATCH 380/449] Bump types-tabulate from 0.8.9 to 0.8.11 Bumps [types-tabulate](https://github.com/python/typeshed) from 0.8.9 to 0.8.11. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-tabulate dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 852890979..16bb8c47b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -25,5 +25,5 @@ nbconvert==6.5.0 types-cachetools==5.2.1 types-filelock==3.2.7 types-requests==2.28.0 -types-tabulate==0.8.9 +types-tabulate==0.8.11 types-python-dateutil==2.8.17 From 74471e41dbceda78e829e2e377a2773617732e47 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Jun 2022 18:23:00 +0200 Subject: [PATCH 381/449] update tabulate precommit types --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 958312d6c..71e230a39 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - types-cachetools==5.2.1 - types-filelock==3.2.7 - types-requests==2.28.0 - - types-tabulate==0.8.9 + - types-tabulate==0.8.11 - types-python-dateutil==2.8.17 # stages: [push] From f2bc35e058cd608a8100c67ed32f626a49451ae9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 20:06:56 +0000 Subject: [PATCH 382/449] Bump types-python-dateutil from 2.8.17 to 2.8.18 Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.17 to 2.8.18. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-python-dateutil dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 16bb8c47b..50cb98fa1 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -26,4 +26,4 @@ types-cachetools==5.2.1 types-filelock==3.2.7 types-requests==2.28.0 types-tabulate==0.8.11 -types-python-dateutil==2.8.17 +types-python-dateutil==2.8.18 From 86f407702419cb23e2c0aa127b1646daed71d363 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Jun 2022 07:37:54 +0200 Subject: [PATCH 383/449] update dateutil precommit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 71e230a39..59e7f6894 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - types-filelock==3.2.7 - types-requests==2.28.0 - types-tabulate==0.8.11 - - types-python-dateutil==2.8.17 + - types-python-dateutil==2.8.18 # stages: [push] - repo: https://github.com/pycqa/isort From 906c7b92fe997c0cb8fcbec3f450b1a601479dba Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 3 Jul 2022 11:05:15 +0200 Subject: [PATCH 384/449] Add enhance testcase to show problematic exit_reason behavior --- tests/test_freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 4f3d5f667..4963e2b0a 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3951,9 +3951,9 @@ def test_ignore_roi_if_entry_signal(default_conf_usdt, limit_order, limit_order_ # Test if entry-signal is absent (should sell due to roi = true) if is_short: - patch_get_signal(freqtrade, enter_long=False, exit_short=False) + patch_get_signal(freqtrade, enter_long=False, exit_short=False, exit_tag='something') else: - patch_get_signal(freqtrade, enter_long=False, exit_long=False) + patch_get_signal(freqtrade, enter_long=False, exit_long=False, exit_tag='something') assert freqtrade.handle_trade(trade) is True assert trade.exit_reason == ExitType.ROI.value From f2fdc21374beee7e06f2d3077c5c3f33b5080a3c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 3 Jul 2022 11:07:05 +0200 Subject: [PATCH 385/449] Only use exit_tag if exit_type i exit_signal closes #7027 --- freqtrade/freqtradebot.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index ee535e9c3..db81a81ba 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1125,9 +1125,10 @@ class FreqtradeBot(LoggingMixin): ) for should_exit in exits: if should_exit.exit_flag: + exit_tag1 = exit_tag if should_exit.exit_type == ExitType.EXIT_SIGNAL else None logger.info(f'Exit for {trade.pair} detected. Reason: {should_exit.exit_type}' - f'{f" Tag: {exit_tag}" if exit_tag is not None else ""}') - exited = self.execute_trade_exit(trade, exit_rate, should_exit, exit_tag=exit_tag) + f'{f" Tag: {exit_tag1}" if exit_tag1 is not None else ""}') + exited = self.execute_trade_exit(trade, exit_rate, should_exit, exit_tag=exit_tag1) if exited: return True return False From c5e6520fee43582496efa2c28b9b21ba2d403235 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 3 Jul 2022 13:35:26 +0200 Subject: [PATCH 386/449] Reorder methods in freqtradebot --- freqtrade/freqtradebot.py | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index db81a81ba..b30c9b965 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -959,6 +959,29 @@ class FreqtradeBot(LoggingMixin): logger.debug(f'Found no {exit_signal_type} signal for %s.', trade) return False + def _check_and_execute_exit(self, trade: Trade, exit_rate: float, + enter: bool, exit_: bool, exit_tag: Optional[str]) -> bool: + """ + Check and execute trade exit + """ + exits: List[ExitCheckTuple] = self.strategy.should_exit( + trade, + exit_rate, + datetime.now(timezone.utc), + enter=enter, + exit_=exit_, + force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0 + ) + for should_exit in exits: + if should_exit.exit_flag: + exit_tag1 = exit_tag if should_exit.exit_type == ExitType.EXIT_SIGNAL else None + logger.info(f'Exit for {trade.pair} detected. Reason: {should_exit.exit_type}' + f'{f" Tag: {exit_tag1}" if exit_tag1 is not None else ""}') + exited = self.execute_trade_exit(trade, exit_rate, should_exit, exit_tag=exit_tag1) + if exited: + return True + return False + def create_stoploss_order(self, trade: Trade, stop_price: float) -> bool: """ Abstracts creating stoploss orders from the logic. @@ -1110,29 +1133,6 @@ class FreqtradeBot(LoggingMixin): logger.warning(f"Could not create trailing stoploss order " f"for pair {trade.pair}.") - def _check_and_execute_exit(self, trade: Trade, exit_rate: float, - enter: bool, exit_: bool, exit_tag: Optional[str]) -> bool: - """ - Check and execute trade exit - """ - exits: List[ExitCheckTuple] = self.strategy.should_exit( - trade, - exit_rate, - datetime.now(timezone.utc), - enter=enter, - exit_=exit_, - force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0 - ) - for should_exit in exits: - if should_exit.exit_flag: - exit_tag1 = exit_tag if should_exit.exit_type == ExitType.EXIT_SIGNAL else None - logger.info(f'Exit for {trade.pair} detected. Reason: {should_exit.exit_type}' - f'{f" Tag: {exit_tag1}" if exit_tag1 is not None else ""}') - exited = self.execute_trade_exit(trade, exit_rate, should_exit, exit_tag=exit_tag1) - if exited: - return True - return False - def manage_open_orders(self) -> None: """ Management of open orders on exchange. Unfilled orders might be cancelled if timeout From 07aa372e2a10b2afe3d899d4da3e63c004513788 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 3 Jul 2022 14:10:08 +0200 Subject: [PATCH 387/449] Ensure bot_loop_start is called in hyperopt, too closes #7001 --- docs/bot-basics.md | 5 ++++- freqtrade/optimize/backtesting.py | 3 +-- tests/optimize/test_hyperopt.py | 1 + tests/strategy/strats/hyperoptable_strategy.py | 5 +++++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/bot-basics.md b/docs/bot-basics.md index 1acbca565..14823722e 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -20,7 +20,9 @@ All profit calculations of Freqtrade include fees. For Backtesting / Hyperopt / ## Bot execution logic Starting freqtrade in dry-run or live mode (using `freqtrade trade`) will start the bot and start the bot iteration loop. -By default, loop runs every few seconds (`internals.process_throttle_secs`) and does roughly the following in the following sequence: +This will also run the `bot_start()` callback. + +By default, the bot loop runs every few seconds (`internals.process_throttle_secs`) and performs the following actions: * Fetch open trades from persistence. * Calculate current list of tradable pairs. @@ -54,6 +56,7 @@ This loop will be repeated again and again until the bot is stopped. [backtesting](backtesting.md) or [hyperopt](hyperopt.md) do only part of the above logic, since most of the trading operations are fully simulated. * Load historic data for configured pairlist. +* Calls `bot_start()` once. * Calls `bot_loop_start()` once. * Calculate indicators (calls `populate_indicators()` once per pair). * Calculate entry / exit signals (calls `populate_entry_trend()` and `populate_exit_trend()` once per pair). diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index cacb87745..030d7bdf0 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -189,6 +189,7 @@ class Backtesting: self.strategy.order_types['stoploss_on_exchange'] = False self.strategy.ft_bot_start() + strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)() def _load_protections(self, strategy: IStrategy): if self.config.get('enable_protections', False): @@ -1140,8 +1141,6 @@ class Backtesting: backtest_start_time = datetime.now(timezone.utc) self._set_strategy(strat) - strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)() - # Use max_open_trades in backtesting, except --disable-max-market-positions is set if self.config.get('use_max_market_positions', True): # Must come from strategy config, as the strategy may modify this setting. diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 9f3c5845f..1ad8b33cf 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -861,6 +861,7 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None: hyperopt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0) assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto) assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter) + assert hyperopt.backtesting.strategy.bot_loop_started is True assert hyperopt.backtesting.strategy.buy_rsi.in_space is True assert hyperopt.backtesting.strategy.buy_rsi.value == 35 diff --git a/tests/strategy/strats/hyperoptable_strategy.py b/tests/strategy/strats/hyperoptable_strategy.py index 28ecf617a..876b31b14 100644 --- a/tests/strategy/strats/hyperoptable_strategy.py +++ b/tests/strategy/strats/hyperoptable_strategy.py @@ -44,6 +44,11 @@ class HyperoptableStrategy(StrategyTestV2): }) return prot + bot_loop_started = False + + def bot_loop_start(self): + self.bot_loop_started = True + def bot_start(self, **kwargs) -> None: """ Parameters can also be defined here ... From 92d189a84f8c8eaa4d7b727aeb890a46adab7b40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 03:02:30 +0000 Subject: [PATCH 388/449] Bump orjson from 3.7.3 to 3.7.6 Bumps [orjson](https://github.com/ijl/orjson) from 3.7.3 to 3.7.6. - [Release notes](https://github.com/ijl/orjson/releases) - [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md) - [Commits](https://github.com/ijl/orjson/compare/3.7.3...3.7.6) --- updated-dependencies: - dependency-name: orjson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 961cfc774..d2213f71a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,7 +28,7 @@ py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.6 # Properly format api responses -orjson==3.7.3 +orjson==3.7.6 # Notify systemd sdnotify==0.3.2 From b16bb23cc8c221ba05d15bb4d918fe8b8e3e9714 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 03:02:34 +0000 Subject: [PATCH 389/449] Bump prompt-toolkit from 3.0.29 to 3.0.30 Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.29 to 3.0.30. - [Release notes](https://github.com/prompt-toolkit/python-prompt-toolkit/releases) - [Changelog](https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/CHANGELOG) - [Commits](https://github.com/prompt-toolkit/python-prompt-toolkit/compare/3.0.29...3.0.30) --- updated-dependencies: - dependency-name: prompt-toolkit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 961cfc774..e6d5d171f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -44,7 +44,7 @@ psutil==5.9.1 colorama==0.4.5 # Building config files interactively questionary==1.10.0 -prompt-toolkit==3.0.29 +prompt-toolkit==3.0.30 # Extensions to datetime library python-dateutil==2.8.2 From 0555d7783c59c41283b21a9d67271b3d4ebc9576 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 03:02:40 +0000 Subject: [PATCH 390/449] Bump python-telegram-bot from 13.12 to 13.13 Bumps [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) from 13.12 to 13.13. - [Release notes](https://github.com/python-telegram-bot/python-telegram-bot/releases) - [Changelog](https://github.com/python-telegram-bot/python-telegram-bot/blob/v13.13/CHANGES.rst) - [Commits](https://github.com/python-telegram-bot/python-telegram-bot/compare/v13.12...v13.13) --- updated-dependencies: - dependency-name: python-telegram-bot dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 961cfc774..b30f4ddfd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ ccxt==1.89.14 cryptography==37.0.2 aiohttp==3.8.1 SQLAlchemy==1.4.39 -python-telegram-bot==13.12 +python-telegram-bot==13.13 arrow==1.2.2 cachetools==4.2.2 requests==2.28.0 From 9a8d03b1f58d7abcbbca8d8510b5da0dc732643d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 03:03:02 +0000 Subject: [PATCH 391/449] Bump uvicorn from 0.18.1 to 0.18.2 Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.18.1 to 0.18.2. - [Release notes](https://github.com/encode/uvicorn/releases) - [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md) - [Commits](https://github.com/encode/uvicorn/compare/0.18.1...0.18.2) --- updated-dependencies: - dependency-name: uvicorn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 961cfc774..2cfdf527e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,7 +35,7 @@ sdnotify==0.3.2 # API Server fastapi==0.78.0 -uvicorn==0.18.1 +uvicorn==0.18.2 pyjwt==2.4.0 aiofiles==0.8.0 psutil==5.9.1 From dd21d963fc48b0fea6b26867d8414f375df22548 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 05:09:28 +0000 Subject: [PATCH 392/449] Bump ccxt from 1.89.14 to 1.89.96 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.89.14 to 1.89.96. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.89.14...1.89.96) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b30f4ddfd..bbbd61bfc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.23.0 pandas==1.4.3 pandas-ta==0.3.14b -ccxt==1.89.14 +ccxt==1.89.96 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From 0a8a0c66b4877a40efa6c8a92c8d00ca9d369c9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 05:10:00 +0000 Subject: [PATCH 393/449] Bump requests from 2.28.0 to 2.28.1 Bumps [requests](https://github.com/psf/requests) from 2.28.0 to 2.28.1. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.28.0...v2.28.1) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2e0dfe6d6..5a5cc1307 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ SQLAlchemy==1.4.39 python-telegram-bot==13.13 arrow==1.2.2 cachetools==4.2.2 -requests==2.28.0 +requests==2.28.1 urllib3==1.26.9 jsonschema==4.6.0 TA-Lib==0.4.24 From 5820fc3b44e5886486cf238cff2a3ca28bbca9c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 05:55:44 +0000 Subject: [PATCH 394/449] Bump jsonschema from 4.6.0 to 4.6.1 Bumps [jsonschema](https://github.com/python-jsonschema/jsonschema) from 4.6.0 to 4.6.1. - [Release notes](https://github.com/python-jsonschema/jsonschema/releases) - [Changelog](https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst) - [Commits](https://github.com/python-jsonschema/jsonschema/compare/v4.6.0...v4.6.1) --- updated-dependencies: - dependency-name: jsonschema dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0aec2c5b8..04c31dddf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ arrow==1.2.2 cachetools==4.2.2 requests==2.28.1 urllib3==1.26.9 -jsonschema==4.6.0 +jsonschema==4.6.1 TA-Lib==0.4.24 technical==1.3.0 tabulate==0.8.10 From 6da3fa08e4644c3e5618c36ed7fde919d0eae239 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 4 Jul 2022 11:14:59 +0200 Subject: [PATCH 395/449] Update migrations to also support Postgres closes #7038 --- freqtrade/persistence/migrations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index f8fc5d619..8373b3376 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -255,8 +255,8 @@ def fix_old_dry_orders(engine): text( """ update orders - set ft_is_open = 0 - where ft_is_open = 1 and (ft_trade_id, order_id) not in ( + set ft_is_open = false + where ft_is_open = true and (ft_trade_id, order_id) not in ( select id, stoploss_order_id from trades where stoploss_order_id is not null ) and ft_order_side = 'stoploss' and order_id like 'dry_%' @@ -267,8 +267,8 @@ def fix_old_dry_orders(engine): text( """ update orders - set ft_is_open = 0 - where ft_is_open = 1 + set ft_is_open = false + where ft_is_open = true and (ft_trade_id, order_id) not in ( select id, open_order_id from trades where open_order_id is not null ) and ft_order_side != 'stoploss' From fe8083c7f8835d77ff1d7c681f10b780a2cb94b6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 4 Jul 2022 17:17:01 +0200 Subject: [PATCH 396/449] Improve test for dry-run orderclosing --- tests/test_persistence.py | 59 +++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index c52e06c82..a09711048 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -1200,7 +1200,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): 0.00258580, {stake}, {amount}, '2019-11-28 12:44:24.000000', 0.0, 0.0, 0.0, '5m', - 'buy_order', 'stop_order_id222') + 'buy_order', 'dry_stop_order_id222') """.format(fee=fee.return_value, stake=default_conf.get("stake_amount"), amount=amount @@ -1226,7 +1226,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): 'buy', 'ETC/BTC', 0, - 'buy_order', + 'dry_buy_order', 'closed', 'ETC/BTC', 'limit', @@ -1238,12 +1238,44 @@ def test_migrate_new(mocker, default_conf, fee, caplog): {amount * 0.00258580} ), ( + 1, + 'buy', + 'ETC/BTC', + 1, + 'dry_buy_order22', + 'canceled', + 'ETC/BTC', + 'limit', + 'buy', + 0.00258580, + {amount}, + {amount}, + 0, + {amount * 0.00258580} + ), + ( 1, 'stoploss', 'ETC/BTC', + 1, + 'dry_stop_order_id11X', + 'canceled', + 'ETC/BTC', + 'limit', + 'sell', + 0.00258580, + {amount}, + {amount}, 0, - 'stop_order_id222', - 'closed', + {amount * 0.00258580} + ), + ( + 1, + 'stoploss', + 'ETC/BTC', + 1, + 'dry_stop_order_id222', + 'open', 'ETC/BTC', 'limit', 'sell', @@ -1292,7 +1324,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): assert trade.exit_reason is None assert trade.strategy is None assert trade.timeframe == '5m' - assert trade.stoploss_order_id == 'stop_order_id222' + assert trade.stoploss_order_id == 'dry_stop_order_id222' assert trade.stoploss_last_update is None assert log_has("trying trades_bak1", caplog) assert log_has("trying trades_bak2", caplog) @@ -1302,12 +1334,21 @@ def test_migrate_new(mocker, default_conf, fee, caplog): assert trade.close_profit_abs is None orders = trade.orders - assert len(orders) == 2 - assert orders[0].order_id == 'buy_order' + assert len(orders) == 4 + assert orders[0].order_id == 'dry_buy_order' assert orders[0].ft_order_side == 'buy' - assert orders[1].order_id == 'stop_order_id222' - assert orders[1].ft_order_side == 'stoploss' + assert orders[-1].order_id == 'dry_stop_order_id222' + assert orders[-1].ft_order_side == 'stoploss' + assert orders[-1].ft_is_open is True + + assert orders[1].order_id == 'dry_buy_order22' + assert orders[1].ft_order_side == 'buy' + assert orders[1].ft_is_open is False + + assert orders[2].order_id == 'dry_stop_order_id11X' + assert orders[2].ft_order_side == 'stoploss' + assert orders[2].ft_is_open is False def test_migrate_too_old(mocker, default_conf, fee, caplog): From 6f0721ae2b1a7fe47f8844887e72472af46f4ad3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 4 Jul 2022 17:17:39 +0200 Subject: [PATCH 397/449] Update dry-order-fix to use sqlalchemy internals --- freqtrade/persistence/migrations.py | 53 +++++++++++++++-------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index 8373b3376..2a8e34cdf 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -1,9 +1,10 @@ import logging from typing import List -from sqlalchemy import inspect, text +from sqlalchemy import inspect, select, text, tuple_, update from freqtrade.exceptions import OperationalException +from freqtrade.persistence.trade_model import Order, Trade logger = logging.getLogger(__name__) @@ -251,31 +252,31 @@ def set_sqlite_to_wal(engine): def fix_old_dry_orders(engine): with engine.begin() as connection: - connection.execute( - text( - """ - update orders - set ft_is_open = false - where ft_is_open = true and (ft_trade_id, order_id) not in ( - select id, stoploss_order_id from trades where stoploss_order_id is not null - ) and ft_order_side = 'stoploss' - and order_id like 'dry_%' - """ - ) - ) - connection.execute( - text( - """ - update orders - set ft_is_open = false - where ft_is_open = true - and (ft_trade_id, order_id) not in ( - select id, open_order_id from trades where open_order_id is not null - ) and ft_order_side != 'stoploss' - and order_id like 'dry_%' - """ - ) - ) + stmt = update(Order).where( + Order.ft_is_open.is_(True), + tuple_(Order.ft_trade_id, Order.order_id).not_in( + select( + Trade.id, Trade.stoploss_order_id + ).where(Trade.stoploss_order_id.is_not(None)) + ), + Order.ft_order_side == 'stoploss', + Order.order_id.like('dry%'), + + ).values(ft_is_open=False) + connection.execute(stmt) + + stmt = update(Order).where( + Order.ft_is_open.is_(True), + tuple_(Order.ft_trade_id, Order.order_id).not_in( + select( + Trade.id, Trade.open_order_id + ).where(Trade.open_order_id.is_not(None)) + ), + Order.ft_order_side != 'stoploss', + Order.order_id.like('dry%') + + ).values(ft_is_open=False) + connection.execute(stmt) def check_migrate(engine, decl_base, previous_tables) -> None: From 647f9b5460e9b1cf247e63bd6ff2c857d8f802a8 Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 5 Jul 2022 12:49:09 +0200 Subject: [PATCH 398/449] replace the word abortion with rejected in log messages --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index b30c9b965..4897a279c 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -634,7 +634,7 @@ class FreqtradeBot(LoggingMixin): pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested, time_in_force=time_in_force, current_time=datetime.now(timezone.utc), entry_tag=enter_tag, side=trade_side): - logger.info(f"User requested abortion of buying {pair}") + logger.info(f"User rejected entry for {pair}.") return False order = self.exchange.create_order( pair=pair, @@ -1465,7 +1465,7 @@ class FreqtradeBot(LoggingMixin): time_in_force=time_in_force, exit_reason=exit_reason, sell_reason=exit_reason, # sellreason -> compatibility current_time=datetime.now(timezone.utc)): - logger.info(f"User requested abortion of {trade.pair} exit.") + logger.info(f"User rejected exit for {trade.pair}.") return False try: From 514f7d491c6ecab3abb4b9ea69457d2d67e3a25a Mon Sep 17 00:00:00 2001 From: robcaulk Date: Tue, 5 Jul 2022 12:58:43 +0200 Subject: [PATCH 399/449] change rejected to denied --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 4897a279c..f242e001b 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -634,7 +634,7 @@ class FreqtradeBot(LoggingMixin): pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested, time_in_force=time_in_force, current_time=datetime.now(timezone.utc), entry_tag=enter_tag, side=trade_side): - logger.info(f"User rejected entry for {pair}.") + logger.info(f"User denied entry for {pair}.") return False order = self.exchange.create_order( pair=pair, @@ -1465,7 +1465,7 @@ class FreqtradeBot(LoggingMixin): time_in_force=time_in_force, exit_reason=exit_reason, sell_reason=exit_reason, # sellreason -> compatibility current_time=datetime.now(timezone.utc)): - logger.info(f"User rejected exit for {trade.pair}.") + logger.info(f"User denied exit for {trade.pair}.") return False try: From dbc3376fe900563d86748a6549c862af9a65c444 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 5 Jul 2022 20:46:09 +0200 Subject: [PATCH 400/449] Add alias for gate to gateio --- freqtrade/exchange/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index 841f45cd0..f2d460bfe 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -46,6 +46,7 @@ MAP_EXCHANGE_CHILDCLASS = { 'binanceje': 'binance', 'binanceusdm': 'binance', 'okex': 'okx', + 'gate': 'gateio', } SUPPORTED_EXCHANGES = [ From 2dc46ca0b8cfc4c78d4eb387cbb50046e736c8bf Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 6 Jul 2022 07:07:28 +0200 Subject: [PATCH 401/449] Add cost to partial test buy order --- tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/conftest.py b/tests/conftest.py index e9161d77e..2e447c281 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1694,6 +1694,7 @@ def limit_buy_order_old_partial(): 'price': 0.00001099, 'amount': 90.99181073, 'filled': 23.0, + 'cost': 90.99181073 * 23.0, 'remaining': 67.99181073, 'status': 'open' } From b39508f64da470e7f05f9af3a50bf1f644a1b737 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 7 Jul 2022 19:44:54 +0200 Subject: [PATCH 402/449] remove loadMarkets from "required" section, it's now implied that all ccxt exchanges provide this method. --- freqtrade/exchange/common.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index f2d460bfe..e5b6533c4 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -68,7 +68,6 @@ EXCHANGE_HAS_REQUIRED = [ 'fetchBalance', # Public endpoints - 'loadMarkets', 'fetchOHLCV', ] From e52f82b565fa713951ffc70b84215aab217a1d73 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 8 Jul 2022 19:44:20 +0200 Subject: [PATCH 403/449] Add leverage to custom_stake_amount callback closes #7047 --- docs/strategy-callbacks.md | 10 ++++++---- freqtrade/freqtradebot.py | 2 +- freqtrade/optimize/backtesting.py | 2 +- freqtrade/strategy/interface.py | 4 +++- .../subtemplates/strategy_methods_advanced.j2 | 6 ++++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index beffba56b..f584bd1bb 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -82,8 +82,9 @@ Called before entering a trade, makes it possible to manage your position size w ```python class AwesomeStrategy(IStrategy): def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, - proposed_stake: float, min_stake: float, max_stake: float, - entry_tag: Optional[str], side: str, **kwargs) -> float: + proposed_stake: float, min_stake: Optional[float], max_stake: float, + leverage: float, entry_tag: Optional[str], side: str, + **kwargs) -> float: dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) current_candle = dataframe.iloc[-1].squeeze() @@ -673,9 +674,10 @@ class DigDeeperStrategy(IStrategy): max_dca_multiplier = 5.5 # This is called when placing the initial order (opening trade) - def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, +def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: Optional[float], max_stake: float, - entry_tag: Optional[str], side: str, **kwargs) -> float: + leverage: float, entry_tag: Optional[str], side: str, + **kwargs) -> float: # We need to leave most of the funds for possible further DCA orders # This also applies to fixed stakes diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index f242e001b..d1404807d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -814,7 +814,7 @@ class FreqtradeBot(LoggingMixin): pair=pair, current_time=datetime.now(timezone.utc), current_rate=enter_limit_requested, proposed_stake=stake_amount, min_stake=min_stake_amount, max_stake=min(max_stake_amount, stake_available), - entry_tag=entry_tag, side=trade_side + leverage=leverage, entry_tag=entry_tag, side=trade_side ) stake_amount = self.wallets.validate_stake_amount( diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 030d7bdf0..da28a8d93 100755 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -722,7 +722,7 @@ class Backtesting: pair=pair, current_time=current_time, current_rate=propose_rate, proposed_stake=stake_amount, min_stake=min_stake_amount, max_stake=min(stake_available, max_stake_amount), - entry_tag=entry_tag, side=direction) + leverage=leverage, entry_tag=entry_tag, side=direction) stake_amount_val = self.wallets.validate_stake_amount( pair=pair, diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index d4ccfc5db..c60817c99 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -442,7 +442,8 @@ class IStrategy(ABC, HyperStrategyMixin): def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: Optional[float], max_stake: float, - entry_tag: Optional[str], side: str, **kwargs) -> float: + leverage: float, entry_tag: Optional[str], side: str, + **kwargs) -> float: """ Customize stake size for each new trade. @@ -452,6 +453,7 @@ class IStrategy(ABC, HyperStrategyMixin): :param proposed_stake: A stake amount proposed by the bot. :param min_stake: Minimal stake size allowed by exchange. :param max_stake: Balance available for trading. + :param leverage: Leverage selected for this trade. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param side: 'long' or 'short' - indicating the direction of the proposed trade :return: A stake size, which is between min_stake and max_stake. diff --git a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 index 815ca7cd3..989f1d37a 100644 --- a/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/subtemplates/strategy_methods_advanced.j2 @@ -79,9 +79,10 @@ def custom_exit_price(self, pair: str, trade: 'Trade', """ return proposed_rate -def custom_stake_amount(self, pair: str, current_time: 'datetime', current_rate: float, +def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: Optional[float], max_stake: float, - entry_tag: 'Optional[str]', side: str, **kwargs) -> float: + leverage: float, entry_tag: Optional[str], side: str, + **kwargs) -> float: """ Customize stake size for each new trade. @@ -91,6 +92,7 @@ def custom_stake_amount(self, pair: str, current_time: 'datetime', current_rate: :param proposed_stake: A stake amount proposed by the bot. :param min_stake: Minimal stake size allowed by exchange. :param max_stake: Balance available for trading. + :param leverage: Leverage selected for this trade. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param side: 'long' or 'short' - indicating the direction of the proposed trade :return: A stake size, which is between min_stake and max_stake. From 2499276fca84123700d34eb023a938651b57c111 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 6 Jul 2022 19:15:55 +0200 Subject: [PATCH 404/449] Refactor calculate_fee_rate to take separate parameters instead of an "Order" we passed in a trade object anyway --- freqtrade/exchange/exchange.py | 49 +++++++++++++++++++++------------ freqtrade/freqtradebot.py | 7 +++-- tests/exchange/test_exchange.py | 5 ++-- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 4febe5652..ced1c71fb 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1631,27 +1631,30 @@ class Exchange: and order['fee']['cost'] is not None ) - def calculate_fee_rate(self, order: Dict) -> Optional[float]: + def calculate_fee_rate( + self, fee: Dict, symbol: str, cost: float, amount: float) -> Optional[float]: """ Calculate fee rate if it's not given by the exchange. - :param order: Order or trade (one trade) dict + :param fee: ccxt Fee dict - must contain cost / currency / rate + :param symbol: Symbol of the order + :param cost: Total cost of the order + :param amount: Amount of the order """ - if order['fee'].get('rate') is not None: - return order['fee'].get('rate') - fee_curr = order['fee']['currency'] + if fee.get('rate') is not None: + return fee.get('rate') + fee_curr = fee['currency'] # Calculate fee based on order details - if fee_curr in self.get_pair_base_currency(order['symbol']): + if fee_curr in self.get_pair_base_currency(symbol): # Base currency - divide by amount - return round( - order['fee']['cost'] / safe_value_fallback2(order, order, 'filled', 'amount'), 8) - elif fee_curr in self.get_pair_quote_currency(order['symbol']): + return round(fee['cost'] / amount, 8) + elif fee_curr in self.get_pair_quote_currency(symbol): # Quote currency - divide by cost return round(self._contracts_to_amount( - order['symbol'], order['fee']['cost']) / order['cost'], - 8) if order['cost'] else None + symbol, fee['cost']) / cost, + 8) if cost else None else: # If Fee currency is a different currency - if not order['cost']: + if not cost: # If cost is None or 0.0 -> falsy, return None return None try: @@ -1664,18 +1667,28 @@ class Exchange: if not fee_to_quote_rate: return None return round((self._contracts_to_amount( - order['symbol'], order['fee']['cost']) * fee_to_quote_rate) / order['cost'], 8) + symbol, fee['cost']) * fee_to_quote_rate) / cost, 8) - def extract_cost_curr_rate(self, order: Dict) -> Tuple[float, str, Optional[float]]: + def extract_cost_curr_rate(self, fee: Dict, symbol: str, cost: float, + amount: float) -> Tuple[float, str, Optional[float]]: """ Extract tuple of cost, currency, rate. Requires order_has_fee to run first! - :param order: Order or trade (one trade) dict + :param fee: ccxt Fee dict - must contain cost / currency / rate + :param symbol: Symbol of the order + :param cost: Total cost of the order + :param amount: Amount of the order :return: Tuple with cost, currency, rate of the given fee dict """ - return (order['fee']['cost'], - order['fee']['currency'], - self.calculate_fee_rate(order)) + return (fee['cost'], + fee['currency'], + self.calculate_fee_rate( + fee, + symbol, + cost, + amount + ) + ) # Historic data diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d1404807d..e0532a17d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1742,7 +1742,8 @@ class FreqtradeBot(LoggingMixin): trade_base_currency = self.exchange.get_pair_base_currency(trade.pair) # use fee from order-dict if possible if self.exchange.order_has_fee(order): - fee_cost, fee_currency, fee_rate = self.exchange.extract_cost_curr_rate(order) + fee_cost, fee_currency, fee_rate = self.exchange.extract_cost_curr_rate( + order['fee'], order['symbol'], order['cost'], order_obj.safe_filled) logger.info(f"Fee for Trade {trade} [{order_obj.ft_order_side}]: " f"{fee_cost:.8g} {fee_currency} - rate: {fee_rate}") if fee_rate is None or fee_rate < 0.02: @@ -1780,7 +1781,9 @@ class FreqtradeBot(LoggingMixin): for exectrade in trades: amount += exectrade['amount'] if self.exchange.order_has_fee(exectrade): - fee_cost_, fee_currency, fee_rate_ = self.exchange.extract_cost_curr_rate(exectrade) + fee_cost_, fee_currency, fee_rate_ = self.exchange.extract_cost_curr_rate( + exectrade['fee'], exectrade['symbol'], exectrade['cost'], exectrade['amount'] + ) fee_cost += fee_cost_ if fee_rate_ is not None: fee_rate_array.append(fee_rate_) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 708a0e889..0dc1b1741 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3544,7 +3544,7 @@ def test_order_has_fee(order, expected) -> None: def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None: mocker.patch('freqtrade.exchange.Exchange.calculate_fee_rate', MagicMock(return_value=0.01)) ex = get_patched_exchange(mocker, default_conf) - assert ex.extract_cost_curr_rate(order) == expected + assert ex.extract_cost_curr_rate(order['fee'], order['symbol'], cost=20, amount=1) == expected @pytest.mark.parametrize("order,unknown_fee_rate,expected", [ @@ -3590,7 +3590,8 @@ def test_calculate_fee_rate(mocker, default_conf, order, expected, unknown_fee_r ex = get_patched_exchange(mocker, default_conf) - assert ex.calculate_fee_rate(order) == expected + assert ex.calculate_fee_rate(order['fee'], order['symbol'], + cost=order['cost'], amount=order['amount']) == expected @pytest.mark.parametrize('retrycount,max_retries,expected', [ From 81f7d77d7440e8a64d3ff2bf0b7b8ef7eb0ff7a0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 7 Jul 2022 07:08:49 +0200 Subject: [PATCH 405/449] Allow fee currency to be empty for futures --- freqtrade/exchange/exchange.py | 22 +++++++++++++--------- tests/exchange/test_exchange.py | 6 ++++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index ced1c71fb..cdfd8aa79 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1615,8 +1615,7 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - @staticmethod - def order_has_fee(order: Dict) -> bool: + def order_has_fee(self, order: Dict) -> bool: """ Verifies if the passed in order dict has the needed keys to extract fees, and that these keys (currency, cost) are not empty. @@ -1627,7 +1626,8 @@ class Exchange: return False return ('fee' in order and order['fee'] is not None and (order['fee'].keys() >= {'currency', 'cost'}) - and order['fee']['currency'] is not None + and (order['fee']['currency'] is not None + or self.trading_mode == TradingMode.FUTURES) and order['fee']['cost'] is not None ) @@ -1642,16 +1642,20 @@ class Exchange: """ if fee.get('rate') is not None: return fee.get('rate') - fee_curr = fee['currency'] + fee_curr = fee.get('currency') + if fee_curr is None: + # Auto-currency only in futures mode + if self.trading_mode == TradingMode.FUTURES: + fee_curr = self.get_pair_quote_currency(symbol) + else: + return None # Calculate fee based on order details - if fee_curr in self.get_pair_base_currency(symbol): + if fee_curr == self.get_pair_base_currency(symbol): # Base currency - divide by amount return round(fee['cost'] / amount, 8) - elif fee_curr in self.get_pair_quote_currency(symbol): + elif fee_curr == self.get_pair_quote_currency(symbol): # Quote currency - divide by cost - return round(self._contracts_to_amount( - symbol, fee['cost']) / cost, - 8) if cost else None + return round(self._contracts_to_amount(symbol, fee['cost']) / cost, 8) if cost else None else: # If Fee currency is a different currency if not cost: diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 0dc1b1741..f1d430437 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3529,8 +3529,10 @@ def test_market_is_active(market, expected_result) -> None: ({'fee': {'currency': 'ETH/BTC', 'cost': None}}, False), ({'fee': {'currency': 'ETH/BTC', 'cost': 0.01}}, True), ]) -def test_order_has_fee(order, expected) -> None: - assert Exchange.order_has_fee(order) == expected +def test_order_has_fee(mocker, default_conf, order, expected) -> None: + ex = get_patched_exchange(mocker, default_conf) + + assert ex.order_has_fee(order) == expected @pytest.mark.parametrize("order,expected", [ From 5b733a723df398e67a9e2fb8d233cbfbe0b0389f Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 7 Jul 2022 19:40:16 +0200 Subject: [PATCH 406/449] use "fees" for trades responses --- freqtrade/exchange/exchange.py | 6 +----- freqtrade/freqtradebot.py | 9 ++++++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index cdfd8aa79..c192ca830 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1644,11 +1644,7 @@ class Exchange: return fee.get('rate') fee_curr = fee.get('currency') if fee_curr is None: - # Auto-currency only in futures mode - if self.trading_mode == TradingMode.FUTURES: - fee_curr = self.get_pair_quote_currency(symbol) - else: - return None + return None # Calculate fee based on order details if fee_curr == self.get_pair_base_currency(symbol): # Base currency - divide by amount diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index e0532a17d..3fd134078 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1777,12 +1777,19 @@ class FreqtradeBot(LoggingMixin): fee_abs = 0.0 fee_cost = 0.0 trade_base_currency = self.exchange.get_pair_base_currency(trade.pair) + fee_rate_array: List[float] = [] for exectrade in trades: amount += exectrade['amount'] if self.exchange.order_has_fee(exectrade): + # Prefer singular fee + fees = [exectrade['fee']] + else: + fees = exectrade.get('fees', []) + for fee in fees: + fee_cost_, fee_currency, fee_rate_ = self.exchange.extract_cost_curr_rate( - exectrade['fee'], exectrade['symbol'], exectrade['cost'], exectrade['amount'] + fee, exectrade['symbol'], exectrade['cost'], exectrade['amount'] ) fee_cost += fee_cost_ if fee_rate_ is not None: From b7167ec88088a3541e6958233d98f8c4869053b3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 9 Jul 2022 08:24:29 +0200 Subject: [PATCH 407/449] Fix wrong fee calclulation for gateio futures --- freqtrade/exchange/exchange.py | 11 ++++++++--- freqtrade/exchange/gateio.py | 3 ++- freqtrade/exchange/okx.py | 1 + freqtrade/freqtradebot.py | 1 - freqtrade/persistence/trade_model.py | 2 +- tests/exchange/test_exchange.py | 3 +++ 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index c192ca830..fdf323582 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -77,6 +77,7 @@ class Exchange: "mark_ohlcv_price": "mark", "mark_ohlcv_timeframe": "8h", "ccxt_futures_name": "swap", + "fee_cost_in_contracts": False, # Fee cost needs contract conversion "needs_trading_fees": False, # use fetch_trading_fees to cache fees } _ft_has: Dict = {} @@ -1645,13 +1646,18 @@ class Exchange: fee_curr = fee.get('currency') if fee_curr is None: return None + fee_cost = fee['cost'] + if self._ft_has['fee_cost_in_contracts']: + # Convert cost via "contracts" conversion + fee_cost = self._contracts_to_amount(symbol, fee['cost']) + # Calculate fee based on order details if fee_curr == self.get_pair_base_currency(symbol): # Base currency - divide by amount return round(fee['cost'] / amount, 8) elif fee_curr == self.get_pair_quote_currency(symbol): # Quote currency - divide by cost - return round(self._contracts_to_amount(symbol, fee['cost']) / cost, 8) if cost else None + return round(fee_cost / cost, 8) if cost else None else: # If Fee currency is a different currency if not cost: @@ -1666,8 +1672,7 @@ class Exchange: fee_to_quote_rate = self._config['exchange'].get('unknown_fee_rate', None) if not fee_to_quote_rate: return None - return round((self._contracts_to_amount( - symbol, fee['cost']) * fee_to_quote_rate) / cost, 8) + return round((fee_cost * fee_to_quote_rate) / cost, 8) def extract_cost_curr_rate(self, fee: Dict, symbol: str, cost: float, amount: float) -> Tuple[float, str, Optional[float]]: diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index bf50167da..b9de212de 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -32,7 +32,8 @@ class Gateio(Exchange): } _ft_has_futures: Dict = { - "needs_trading_fees": True + "needs_trading_fees": True, + "fee_cost_in_contracts": False, # Set explicitly to false for clarity } _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 012f51080..afd7a672f 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -28,6 +28,7 @@ class Okx(Exchange): } _ft_has_futures: Dict = { "tickers_have_quoteVolume": False, + "fee_cost_in_contracts": True, } _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3fd134078..469bfda7e 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1777,7 +1777,6 @@ class FreqtradeBot(LoggingMixin): fee_abs = 0.0 fee_cost = 0.0 trade_base_currency = self.exchange.get_pair_base_currency(trade.pair) - fee_rate_array: List[float] = [] for exectrade in trades: amount += exectrade['amount'] diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 324002685..5f302de71 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -821,7 +821,7 @@ class LocalTrade(): self.open_rate = total_stake / total_amount self.stake_amount = total_stake / (self.leverage or 1.0) self.amount = total_amount - self.fee_open_cost = self.fee_open * self.stake_amount + self.fee_open_cost = self.fee_open * total_stake self.recalc_open_trade_value() if self.stop_loss_pct is not None and self.open_rate is not None: self.adjust_stop_loss(self.open_rate, self.stop_loss_pct) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index f1d430437..6fce0bb8f 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3584,6 +3584,9 @@ def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None: 'fee': {'currency': 'POINT', 'cost': 2.0, 'rate': None}}, 1, 4.0), ({'symbol': 'POINT/BTC', 'amount': 0.04, 'cost': 0.5, 'fee': {'currency': 'POINT', 'cost': 2.0, 'rate': None}}, 2, 8.0), + # Missing currency + ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05, + 'fee': {'currency': None, 'cost': 0.005}}, None, None), ]) def test_calculate_fee_rate(mocker, default_conf, order, expected, unknown_fee_rate) -> None: mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'last': 0.081}) From c98e7ea0558f1093b4ebdeecb8755ff3f60b58fc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 9 Jul 2022 08:57:15 +0200 Subject: [PATCH 408/449] Revert allowing empty currency for futures --- freqtrade/exchange/exchange.py | 6 +++--- tests/exchange/test_exchange.py | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index fdf323582..cd13964c4 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1616,7 +1616,8 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - def order_has_fee(self, order: Dict) -> bool: + @staticmethod + def order_has_fee(order: Dict) -> bool: """ Verifies if the passed in order dict has the needed keys to extract fees, and that these keys (currency, cost) are not empty. @@ -1627,8 +1628,7 @@ class Exchange: return False return ('fee' in order and order['fee'] is not None and (order['fee'].keys() >= {'currency', 'cost'}) - and (order['fee']['currency'] is not None - or self.trading_mode == TradingMode.FUTURES) + and order['fee']['currency'] is not None and order['fee']['cost'] is not None ) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 6fce0bb8f..acd48b3fd 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -3529,10 +3529,8 @@ def test_market_is_active(market, expected_result) -> None: ({'fee': {'currency': 'ETH/BTC', 'cost': None}}, False), ({'fee': {'currency': 'ETH/BTC', 'cost': 0.01}}, True), ]) -def test_order_has_fee(mocker, default_conf, order, expected) -> None: - ex = get_patched_exchange(mocker, default_conf) - - assert ex.order_has_fee(order) == expected +def test_order_has_fee(order, expected) -> None: + assert Exchange.order_has_fee(order) == expected @pytest.mark.parametrize("order,expected", [ From aab59a8cafef0b9236f6bd92a6f0c2b98c7f5232 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 9 Jul 2022 09:00:12 +0200 Subject: [PATCH 409/449] Bump ccxt to required version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2ccadea30..693d408c6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.23.0 pandas==1.4.3 pandas-ta==0.3.14b -ccxt==1.89.96 +ccxt==1.90.38 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From ea5f41aa6d5905485c8ca5fbc33702bbfc1bd534 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 10 Jul 2022 09:06:19 +0200 Subject: [PATCH 410/449] Version bump ccxt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 693d408c6..2bce619d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.23.0 pandas==1.4.3 pandas-ta==0.3.14b -ccxt==1.90.38 +ccxt==1.90.40 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From 9313a2d294c6e7bf6f114315720ba7092cb81282 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 10 Jul 2022 10:11:39 +0200 Subject: [PATCH 411/449] Update leverage tiers to latest version --- docs/developer.md | 2 +- .../exchange/binance_leverage_tiers.json | 24876 ++++++++-------- 2 files changed, 12845 insertions(+), 12033 deletions(-) diff --git a/docs/developer.md b/docs/developer.md index ce7fb37e1..0209d220a 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -334,7 +334,7 @@ lev_tiers = exchange.fetch_leverage_tiers() # Assumes this is running in the root of the repository. file = Path('freqtrade/exchange/binance_leverage_tiers.json') -json.dump(lev_tiers, file.open('w'), indent=2) +json.dump(dict(sorted(lev_tiers.items())), file.open('w'), indent=2) ``` diff --git a/freqtrade/exchange/binance_leverage_tiers.json b/freqtrade/exchange/binance_leverage_tiers.json index 126b3b62f..1cf6ba079 100644 --- a/freqtrade/exchange/binance_leverage_tiers.json +++ b/freqtrade/exchange/binance_leverage_tiers.json @@ -1,201 +1,87 @@ { - "RAY/USDT": [ + "1000LUNC/BUSD": [ { "tier": 1.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", + "initialLeverage": "20", + "notionalCap": "25000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.025", "cum": "0.0" } }, { "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { - "bracket": "3", + "bracket": "2", "initialLeverage": "10", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "API3/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "625.0" } }, { "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 100000.0, "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { - "bracket": "4", + "bracket": "3", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5625.0" } }, { - "tier": 5.0, - "currency": "USDT", + "tier": 4.0, + "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "5", + "bracket": "4", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11875.0" } }, { - "tier": 6.0, - "currency": "USDT", + "tier": 5.0, + "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "5", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386875.0" } } ], - "SUSHI/USDT": [ + "1000SHIB/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -296,20 +182,754 @@ "tier": 7.0, "currency": "USDT", "minNotional": 2000000.0, - "maxNotional": 50000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "50000000", + "notionalCap": "30000000", "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } } ], - "CVC/USDT": [ + "1000XEC/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "1INCH/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.012, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.012", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "65.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "690.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5690.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11940.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386940.0" + } + } + ], + "AAVE/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ADA/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "100000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2500.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27500.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "4", + "initialLeverage": "3", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.15", + "cum": "77500.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "277500.0" + } + }, + { + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.5", + "cum": "1527500.0" + } + } + ], + "ADA/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.0065, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.0065", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "35.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "535.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8035.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58035.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108035.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "7", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.15", + "cum": "233035.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1233035.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "50000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.5", + "cum": "6233035.0" + } + } + ], + "ALGO/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ALICE/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ALPHA/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -390,6 +1010,2128 @@ "cum": "11950.0" } }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ANC/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "ANKR/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.012, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.012", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "65.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "690.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5690.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11940.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386940.0" + } + } + ], + "ANT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "APE/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "APE/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.5", + "cum": "654500.0" + } + } + ], + "API3/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "AR/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ARPA/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ATA/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ATOM/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "AUDIO/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "AVAX/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "AVAX/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "7000.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "57000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "107000.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.25", + "cum": "732000.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.5", + "cum": "3232000.0" + } + } + ], + "AXS/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "2", + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "500.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8000.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108000.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.1665, + "maxLeverage": 3.0, + "info": { + "bracket": "6", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.1665", + "cum": "315500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 15000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "15000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1150500.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 15000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "8", + "initialLeverage": "1", + "notionalCap": "20000000", + "notionalFloor": "15000000", + "maintMarginRatio": "0.5", + "cum": "4900500.0" + } + } + ], + "BAKE/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BAL/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BAND/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BAT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BCH/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.0065, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.0065", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "35.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "535.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8035.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58035.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108035.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "7", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.15", + "cum": "233035.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1233035.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "50000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.5", + "cum": "6233035.0" + } + } + ], + "BEL/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BLZ/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, { "tier": 6.0, "currency": "USDT", @@ -407,214 +3149,262 @@ } } ], - "BTS/USDT": [ + "BNB/BUSD": [ { "tier": 1.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", + "initialLeverage": "20", + "notionalCap": "100000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.025", "cum": "0.0" } }, { "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2500.0" } }, { "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27500.0" } }, { "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" + "initialLeverage": "3", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.15", + "cum": "77500.0" } }, { "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "277500.0" } }, { "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "1527500.0" } } ], - "HOT/USDT": [ + "BNB/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.0065, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", + "initialLeverage": "75", + "notionalCap": "10000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.0065", "cum": "0.0" } }, { "tier": 2.0, "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "35.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "535.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8035.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58035.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108035.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "7", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.15", + "cum": "233035.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1233035.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "9", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", + "notionalCap": "50000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "6233035.0" } } ], - "ZRX/USDT": [ + "BNX/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", - "notionalCap": "5000", + "notionalCap": "50000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -623,277 +3413,97 @@ { "tier": 2.0, "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "750.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, + "minNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", + "notionalCap": "250000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "4500.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 250000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "17000.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, + "minNotional": 500000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", + "initialLeverage": "4", "notionalCap": "1000000", - "notionalFloor": "250000", + "notionalFloor": "500000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "29500.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "QTUM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" } }, { - "tier": 6.0, + "tier": 7.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "minNotional": 2000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "IOTA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "654500.0" } } ], @@ -1059,7 +3669,479 @@ } } ], - "WAVES/USDT": [ + "BTC/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.004, + "maxLeverage": 125.0, + "info": { + "bracket": "1", + "initialLeverage": "125", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.004", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.005, + "maxLeverage": 100.0, + "info": { + "bracket": "2", + "initialLeverage": "100", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.005", + "cum": "50.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "3", + "initialLeverage": "50", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.01", + "cum": "1300.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "10000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.025", + "cum": "16300.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.05", + "cum": "266300.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "50000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.1", + "cum": "1266300.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 50000000.0, + "maxNotional": 100000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "100000000", + "notionalFloor": "50000000", + "maintMarginRatio": "0.125", + "cum": "2516300.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 100000000.0, + "maxNotional": 200000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "8", + "initialLeverage": "3", + "notionalCap": "200000000", + "notionalFloor": "100000000", + "maintMarginRatio": "0.15", + "cum": "5016300.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 200000000.0, + "maxNotional": 300000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "9", + "initialLeverage": "2", + "notionalCap": "300000000", + "notionalFloor": "200000000", + "maintMarginRatio": "0.25", + "cum": "2.50163E7" + } + }, + { + "tier": 10.0, + "currency": "USDT", + "minNotional": 300000000.0, + "maxNotional": 9.223372036854776e+18, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "10", + "initialLeverage": "1", + "notionalCap": "9223372036854775807", + "notionalFloor": "300000000", + "maintMarginRatio": "0.5", + "cum": "1.000163E8" + } + } + ], + "BTCDOM/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BTCSTUSDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 9.223372036854776e+18, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "9223372036854775807", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BTCUSDT_220930": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 375000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "375000", + "notionalFloor": "0", + "maintMarginRatio": "0.02", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 375000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "2000000", + "notionalFloor": "375000", + "maintMarginRatio": "0.05", + "cum": "11250.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "4000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.1", + "cum": "111250.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "4", + "initialLeverage": "4", + "notionalCap": "10000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.125", + "cum": "211250.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "5", + "initialLeverage": "3", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.15", + "cum": "461250.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 40000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "40000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.25", + "cum": "2461250.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 40000000.0, + "maxNotional": 400000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "400000000", + "notionalFloor": "40000000", + "maintMarginRatio": "0.5", + "cum": "1.246125E7" + } + } + ], + "BTS/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -1144,166 +4226,314 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "ADA/USDT": [ + "C98/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", + "initialLeverage": "25", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.0065", + "maintMarginRatio": "0.01", "cum": "0.0" } }, { "tier": 2.0, "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, "info": { "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 2000000.0, + "minNotional": 1000000.0, "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "9", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalCap": "5000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "6233035.0" + "cum": "386950.0" } } ], - "LIT/USDT": [ + "CELO/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "CELR/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "CHR/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -1388,312 +4618,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "XTZ/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, - "info": { - "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", - "notionalFloor": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6233035.0" - } - } - ], - "BNB/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, - "info": { - "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", - "notionalFloor": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6233035.0" - } - } - ], - "AKRO/USDT": [ + "CHZ/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -1791,6 +4729,610 @@ } } ], + "COMP/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "COTI/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "CRV/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.5", + "cum": "654500.0" + } + } + ], + "CTK/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "CTSI/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "CVC/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], "DAR/USDT": [ { "tier": 1.0, @@ -1876,20 +5418,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "HNT/USDT": [ + "DASH/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -1974,19 +5516,1503 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], + "DEFI/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "DENT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "DGB/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "DODO/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "DOGE/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "100000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2500.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27500.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "4", + "initialLeverage": "3", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.15", + "cum": "77500.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "277500.0" + } + }, + { + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.5", + "cum": "1527500.0" + } + } + ], + "DOGE/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "7000.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "57000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "107000.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.25", + "cum": "732000.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.5", + "cum": "3232000.0" + } + } + ], + "DOT/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "DOT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.0065, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.0065", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "35.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "535.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8035.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58035.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108035.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "7", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.15", + "cum": "233035.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "50000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1233035.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 50000000.0, + "maxNotional": 100000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "100000000", + "notionalFloor": "50000000", + "maintMarginRatio": "0.5", + "cum": "1.3733035E7" + } + } + ], + "DUSK/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "DYDX/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "4000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.5", + "cum": "1154500.0" + } + } + ], + "EGLD/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "50000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ENJ/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.5", + "cum": "654500.0" + } + } + ], + "ENS/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "EOS/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.0065, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.0065", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "35.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "535.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8035.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58035.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108035.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "7", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.15", + "cum": "233035.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1233035.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "50000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.5", + "cum": "6233035.0" + } + } + ], "ETC/USDT": [ { "tier": 1.0, @@ -2133,345 +7159,165 @@ } } ], - "XMR/USDT": [ + "ETH/BUSD": [ { "tier": 1.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.004, + "maxLeverage": 50.0, "info": { "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", + "initialLeverage": "50", + "notionalCap": "25000", "notionalFloor": "0", - "maintMarginRatio": "0.0065", + "maintMarginRatio": "0.004", "cum": "0.0" } }, { "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.005, + "maxLeverage": 25.0, "info": { "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" + "initialLeverage": "25", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.005", + "cum": "25.0" } }, { "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 20.0, "info": { "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" + "initialLeverage": "20", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.01", + "cum": "525.0" } }, { "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" + "notionalCap": "1500000", + "notionalFloor": "500000", + "maintMarginRatio": "0.025", + "cum": "8025.0" } }, { "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "currency": "BUSD", + "minNotional": 1500000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 6.0, "info": { "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" + "initialLeverage": "6", + "notionalCap": "4000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.05", + "cum": "45525.0" } }, { "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "currency": "BUSD", + "minNotional": 4000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" + "initialLeverage": "5", + "notionalCap": "10000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.1", + "cum": "245525.0" } }, { "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, + "currency": "BUSD", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" + "initialLeverage": "4", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.125", + "cum": "495525.0" } }, { "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "currency": "BUSD", + "minNotional": 20000000.0, + "maxNotional": 40000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, "info": { "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" + "initialLeverage": "3", + "notionalCap": "40000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.15", + "cum": "995525.0" } }, { "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6233035.0" - } - } - ], - "YFI/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "FTT/BUSD": [ - { - "tier": 1.0, "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "100000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "500000", - "notionalFloor": "100000", - "maintMarginRatio": "0.05", - "cum": "2500.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.1", - "cum": "27500.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "4", - "initialLeverage": "3", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.15", - "cum": "77500.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 40000000.0, + "maxNotional": 150000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { - "bracket": "5", + "bracket": "9", "initialLeverage": "2", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "150000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.25", - "cum": "277500.0" + "cum": "4995525.0" } }, { - "tier": 6.0, + "tier": 10.0, "currency": "BUSD", - "minNotional": 5000000.0, - "maxNotional": 30000000.0, + "minNotional": 150000000.0, + "maxNotional": 500000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "10", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "5000000", + "notionalCap": "500000000", + "notionalFloor": "150000000", "maintMarginRatio": "0.5", - "cum": "1527500.0" + "cum": "4.2495525E7" } } ], @@ -2637,7 +7483,1281 @@ } } ], - "ALICE/USDT": [ + "ETHUSDT_220930": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 375000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "375000", + "notionalFloor": "0", + "maintMarginRatio": "0.02", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 375000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "2000000", + "notionalFloor": "375000", + "maintMarginRatio": "0.05", + "cum": "11250.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "4000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.1", + "cum": "111250.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "4", + "initialLeverage": "4", + "notionalCap": "10000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.125", + "cum": "211250.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "5", + "initialLeverage": "3", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.15", + "cum": "461250.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 40000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "40000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.25", + "cum": "2461250.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 40000000.0, + "maxNotional": 400000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "400000000", + "notionalFloor": "40000000", + "maintMarginRatio": "0.5", + "cum": "1.246125E7" + } + } + ], + "FIL/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "2", + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "500.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8000.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108000.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.1665, + "maxLeverage": 3.0, + "info": { + "bracket": "6", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.1665", + "cum": "315500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1150500.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "8", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.5", + "cum": "6150500.0" + } + } + ], + "FLM/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "FLOW/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "FTM/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "FTM/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "4000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.5", + "cum": "1154500.0" + } + } + ], + "FTT/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "100000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2500.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27500.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "4", + "initialLeverage": "3", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.15", + "cum": "77500.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "277500.0" + } + }, + { + "tier": 6.0, + "currency": "BUSD", + "minNotional": 5000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.5", + "cum": "1527500.0" + } + } + ], + "FTT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "GAL/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "GAL/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "GALA/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "GALA/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "GMT/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "GMT/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -2751,7 +8871,579 @@ } } ], - "ALPHA/USDT": [ + "GRT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "GTC/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "HBAR/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "HNT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "HOT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ICP/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "ICP/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -2849,7 +9541,105 @@ } } ], - "WOO/USDT": [ + "ICX/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "IMX/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -2934,20 +9724,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "SFP/USDT": [ + "IOST/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -3032,13 +9822,3425 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "IOTA/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "IOTX/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "JASMY/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "KAVA/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "KLAY/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "KNC/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "KSM/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "LINA/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "LINK/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "LINK/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.0065, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.0065", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "35.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "535.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8035.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58035.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108035.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "7", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.15", + "cum": "233035.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1233035.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "50000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.5", + "cum": "6233035.0" + } + } + ], + "LIT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "LPT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "LRC/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "LTC/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "LTC/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.0065, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.0065", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "35.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "535.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8035.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58035.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108035.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "7", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.15", + "cum": "233035.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1233035.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 50000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "50000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.5", + "cum": "6233035.0" + } + } + ], + "LUNA2/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "MANA/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.5", + "cum": "654500.0" + } + } + ], + "MASK/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "MATIC/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "123250.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "373250.0" + } + } + ], + "MKR/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "MTL/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "NEAR/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "NEAR/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "250000", + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "500000", + "notionalFloor": "250000", + "maintMarginRatio": "0.1", + "cum": "17000.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.5", + "cum": "654500.0" + } + } + ], + "NEO/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "NKN/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "OCEAN/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "OGN/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "OMG/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ONE/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ONT/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "OP/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "PEOPLE/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "QTUM/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "RAY/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" @@ -3130,20 +13332,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "BAT/USDT": [ + "REN/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -3228,279 +13430,19 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "DOGE/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "7000.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "57000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "107000.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.25", - "cum": "732000.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.5", - "cum": "3232000.0" - } - } - ], - "TRX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, - "info": { - "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", - "notionalFloor": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6233035.0" - } - } - ], "RLC/USDT": [ { "tier": 1.0, @@ -3586,820 +13528,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BTCSTUSDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 9.223372036854776e+18, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "9223372036854775807", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "STORJ/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "SNX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "1000XEC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "AUDIO/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "NEAR/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "XLM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, - "info": { - "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", - "notionalFloor": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, "info": { "bracket": "6", - "initialLeverage": "4", + "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6233035.0" - } - } - ], - "APE/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "30000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386950.0" } } ], - "IOTX/USDT": [ + "ROSE/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -4484,438 +13626,30 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "NEO/USDT": [ + "RSR/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "UNFI/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "SAND/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "DASH/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "KAVA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -5101,121 +13835,7 @@ } } ], - "APE/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "CTK/USDT": [ + "RVN/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -5300,394 +13920,216 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "LINK/USDT": [ + "SAND/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "SAND/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, "info": { "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", + "initialLeverage": "50", + "notionalCap": "50000", "notionalFloor": "0", - "maintMarginRatio": "0.0065", + "maintMarginRatio": "0.01", "cum": "0.0" } }, { "tier": 2.0, "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "minNotional": 50000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" + "initialLeverage": "20", + "notionalCap": "150000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "750.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 50000.0, + "minNotional": 150000.0, "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "25", + "initialLeverage": "10", "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" + "notionalFloor": "150000", + "maintMarginRatio": "0.05", + "cum": "4500.0" } }, { "tier": 4.0, "currency": "USDT", "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", + "initialLeverage": "5", + "notionalCap": "500000", "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" + "maintMarginRatio": "0.1", + "cum": "17000.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" + "initialLeverage": "4", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.125", + "cum": "29500.0" } }, { "tier": 6.0, "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "154500.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", "minNotional": 2000000.0, "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, "info": { - "bracket": "6", - "initialLeverage": "4", + "bracket": "7", + "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6233035.0" - } - } - ], - "CELR/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } } ], - "BNX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "RSR/USDT": [ + "SC/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -5772,118 +14214,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "ADA/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "100000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "500000", - "notionalFloor": "100000", - "maintMarginRatio": "0.05", - "cum": "2500.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.1", - "cum": "27500.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "4", - "initialLeverage": "3", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.15", - "cum": "77500.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.25", - "cum": "277500.0" - } - }, - { - "tier": 6.0, - "currency": "BUSD", - "minNotional": 5000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.5", - "cum": "1527500.0" - } - } - ], - "DGB/USDT": [ + "SFP/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -5968,13 +14312,13 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" @@ -6066,666 +14410,30 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "REN/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "LPT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "JASMY/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "TOMO/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "MTL/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "LTC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, - "info": { - "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", - "notionalFloor": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, "info": { "bracket": "6", - "initialLeverage": "4", + "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "6233035.0" + "cum": "386950.0" } } ], - "DODO/USDT": [ + "SNX/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -6800,3185 +14508,19 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "EGLD/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "KSM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BNB/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "100000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "500000", - "notionalFloor": "100000", - "maintMarginRatio": "0.05", - "cum": "2500.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.1", - "cum": "27500.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "4", - "initialLeverage": "3", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.15", - "cum": "77500.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 2000000.0, "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, "info": { - "bracket": "5", - "initialLeverage": "2", + "bracket": "6", + "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.25", - "cum": "277500.0" - } - }, - { - "tier": 6.0, - "currency": "BUSD", - "minNotional": 5000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.5", - "cum": "1527500.0" - } - } - ], - "ONT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "VET/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "IMX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "TRB/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "MANA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "FLOW/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "COTI/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "CHR/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BAKE/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "AVAX/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "GRT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "FLM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "GAL/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "MASK/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "EOS/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, - "info": { - "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", - "notionalFloor": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6233035.0" - } - } - ], - "OGN/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "SC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ETHUSDT_220624": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 375000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "375000", - "notionalFloor": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 375000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "2000000", - "notionalFloor": "375000", - "maintMarginRatio": "0.05", - "cum": "11250.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "4000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.1", - "cum": "111250.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "4", - "initialLeverage": "4", - "notionalCap": "10000000", - "notionalFloor": "4000000", - "maintMarginRatio": "0.125", - "cum": "211250.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "5", - "initialLeverage": "3", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.15", - "cum": "461250.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 40000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "40000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.25", - "cum": "2461250.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 40000000.0, - "maxNotional": 400000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "400000000", - "notionalFloor": "40000000", - "maintMarginRatio": "0.5", - "cum": "1.246125E7" - } - } - ], - "BAL/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "STMX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "DENT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "KNC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "SRM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ENJ/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "C98/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ZEN/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ATOM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "NEAR/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], "SOL/BUSD": [ { "tier": 1.0, @@ -10064,1812 +14606,20 @@ "tier": 6.0, "currency": "BUSD", "minNotional": 5000000.0, - "maxNotional": 30000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "8000000", "notionalFloor": "5000000", "maintMarginRatio": "0.5", "cum": "1527500.0" } } ], - "ENS/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BCH/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, - "info": { - "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", - "notionalFloor": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8035.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58035.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108035.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "9", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6233035.0" - } - } - ], - "ATA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "IOST/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "HBAR/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ZEC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "1000SHIB/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "TLM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ANT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ETH/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.004, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.004", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.005, - "maxLeverage": 25.0, - "info": { - "bracket": "2", - "initialLeverage": "25", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.005", - "cum": "25.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 20.0, - "info": { - "bracket": "3", - "initialLeverage": "20", - "notionalCap": "500000", - "notionalFloor": "100000", - "maintMarginRatio": "0.01", - "cum": "525.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 500000.0, - "maxNotional": 1500000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, - "info": { - "bracket": "4", - "initialLeverage": "10", - "notionalCap": "1500000", - "notionalFloor": "500000", - "maintMarginRatio": "0.025", - "cum": "8025.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1500000.0, - "maxNotional": 4000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 6.0, - "info": { - "bracket": "5", - "initialLeverage": "6", - "notionalCap": "4000000", - "notionalFloor": "1500000", - "maintMarginRatio": "0.05", - "cum": "45525.0" - } - }, - { - "tier": 6.0, - "currency": "BUSD", - "minNotional": 4000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "6", - "initialLeverage": "5", - "notionalCap": "10000000", - "notionalFloor": "4000000", - "maintMarginRatio": "0.1", - "cum": "245525.0" - } - }, - { - "tier": 7.0, - "currency": "BUSD", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "7", - "initialLeverage": "4", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.125", - "cum": "495525.0" - } - }, - { - "tier": 8.0, - "currency": "BUSD", - "minNotional": 20000000.0, - "maxNotional": 40000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "8", - "initialLeverage": "3", - "notionalCap": "40000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.15", - "cum": "995525.0" - } - }, - { - "tier": 9.0, - "currency": "BUSD", - "minNotional": 40000000.0, - "maxNotional": 150000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "9", - "initialLeverage": "2", - "notionalCap": "150000000", - "notionalFloor": "40000000", - "maintMarginRatio": "0.25", - "cum": "4995525.0" - } - }, - { - "tier": 10.0, - "currency": "BUSD", - "minNotional": 150000000.0, - "maxNotional": 500000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "10", - "initialLeverage": "1", - "notionalCap": "500000000", - "notionalFloor": "150000000", - "maintMarginRatio": "0.5", - "cum": "4.2495525E7" - } - } - ], - "GALA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "AAVE/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "2", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "500.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8000.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108000.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.1665, - "maxLeverage": 3.0, - "info": { - "bracket": "6", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.1665", - "cum": "315500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "7", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1150500.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "8", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6150500.0" - } - } - ], - "GTC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ALGO/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "ICP/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "LRC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "AVAX/USDT": [ + "SOL/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -11970,526 +14720,20 @@ "tier": 7.0, "currency": "USDT", "minNotional": 10000000.0, - "maxNotional": 50000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "50000000", + "notionalCap": "20000000", "notionalFloor": "10000000", "maintMarginRatio": "0.5", "cum": "3232000.0" } } ], - "ARPA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "CELO/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ROSE/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "MATIC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 750000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "750000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 750000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "750000", - "maintMarginRatio": "0.25", - "cum": "123250.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "373250.0" - } - } - ], - "1INCH/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.012, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.012", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "65.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "690.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5690.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11940.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 100000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "100000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386940.0" - } - } - ], - "MKR/USDT": [ + "SRM/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -12574,20 +14818,216 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "PEOPLE/USDT": [ + "STMX/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "STORJ/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "SUSHI/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -12672,13 +15112,111 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "SXP/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" @@ -12802,31 +15340,733 @@ "tier": 8.0, "currency": "USDT", "minNotional": 20000000.0, - "maxNotional": 50000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "notionalCap": "50000000", + "notionalCap": "30000000", "notionalFloor": "20000000", "maintMarginRatio": "0.5", "cum": "6150500.0" } } ], + "TLM/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "TLM/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "TOMO/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "TRB/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "TRX/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "TRX/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.0065, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.0065", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 22.0, + "info": { + "bracket": "2", + "initialLeverage": "22", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "35.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, + "info": { + "bracket": "3", + "initialLeverage": "20", + "notionalCap": "250000", + "notionalFloor": "50000", + "maintMarginRatio": "0.02", + "cum": "535.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.05", + "cum": "8035.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "58035.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "108035.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.15, + "maxLeverage": 3.0, + "info": { + "bracket": "7", + "initialLeverage": "3", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.15", + "cum": "233035.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "20000000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.25", + "cum": "1233035.0" + } + }, + { + "tier": 9.0, + "currency": "USDT", + "minNotional": 20000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "20000000", + "maintMarginRatio": "0.5", + "cum": "6233035.0" + } + } + ], + "UNFI/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], "UNI/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 50000.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", + "initialLeverage": "25", + "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -12835,215 +16075,85 @@ { "tier": 2.0, "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "500.0" + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "8000.0" + "cum": "700.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "58000.0" + "cum": "5700.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 2000000.0, + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, "info": { - "bracket": "5", - "initialLeverage": "4", + "bracket": "6", + "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108000.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.1665, - "maxLeverage": 3.0, - "info": { - "bracket": "6", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.1665", - "cum": "315500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "7", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1150500.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "8", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.5", - "cum": "6150500.0" - } - } - ], - "LINA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "AR/USDT": [ + "VET/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13128,248 +16238,102 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "RVN/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "FIL/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "2", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "500.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8000.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 2000000.0, "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, "info": { - "bracket": "5", - "initialLeverage": "4", + "bracket": "6", + "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108000.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.1665, - "maxLeverage": 3.0, - "info": { - "bracket": "6", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.1665", - "cum": "315500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "7", - "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1150500.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "8", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "6150500.0" + "cum": "386950.0" } } ], - "NKN/USDT": [ + "WAVES/BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "BUSD", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "BUSD", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "WAVES/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13454,20 +16418,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "KLAY/USDT": [ + "WOO/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13552,20 +16516,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "DEFI/USDT": [ + "XEM/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13650,216 +16614,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "COMP/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BTCDOM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "SOL/USDT": [ + "XLM/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13960,590 +16728,20 @@ "tier": 7.0, "currency": "USDT", "minNotional": 10000000.0, - "maxNotional": 50000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "50000000", + "notionalCap": "20000000", "notionalFloor": "10000000", "maintMarginRatio": "0.5", "cum": "3232000.0" } } ], - "BTC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.004, - "maxLeverage": 125.0, - "info": { - "bracket": "1", - "initialLeverage": "125", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.004", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.005, - "maxLeverage": 100.0, - "info": { - "bracket": "2", - "initialLeverage": "100", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.005", - "cum": "50.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "3", - "initialLeverage": "50", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.01", - "cum": "1300.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "4", - "initialLeverage": "20", - "notionalCap": "10000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.025", - "cum": "16300.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "5", - "initialLeverage": "10", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.05", - "cum": "266300.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "6", - "initialLeverage": "5", - "notionalCap": "50000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.1", - "cum": "1266300.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 50000000.0, - "maxNotional": 100000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "7", - "initialLeverage": "4", - "notionalCap": "100000000", - "notionalFloor": "50000000", - "maintMarginRatio": "0.125", - "cum": "2516300.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 100000000.0, - "maxNotional": 200000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "8", - "initialLeverage": "3", - "notionalCap": "200000000", - "notionalFloor": "100000000", - "maintMarginRatio": "0.15", - "cum": "5016300.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 200000000.0, - "maxNotional": 300000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "9", - "initialLeverage": "2", - "notionalCap": "300000000", - "notionalFloor": "200000000", - "maintMarginRatio": "0.25", - "cum": "2.50163E7" - } - }, - { - "tier": 10.0, - "currency": "USDT", - "minNotional": 300000000.0, - "maxNotional": 9.223372036854776e+18, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "10", - "initialLeverage": "1", - "notionalCap": "9223372036854775807", - "notionalFloor": "300000000", - "maintMarginRatio": "0.5", - "cum": "1.000163E8" - } - } - ], - "OMG/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.024, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.024", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "5.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "630.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5630.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11880.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "10000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386880.0" - } - } - ], - "ICX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BLZ/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "GMT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "FTM/USDT": [ + "XMR/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -14644,117 +16842,19 @@ "tier": 7.0, "currency": "USDT", "minNotional": 10000000.0, - "maxNotional": 50000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "50000000", + "notionalCap": "20000000", "notionalFloor": "10000000", "maintMarginRatio": "0.5", "cum": "3232000.0" } } ], - "BAND/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], "XRP/BUSD": [ { "tier": 1.0, @@ -14840,111 +16940,13 @@ "tier": 6.0, "currency": "BUSD", "minNotional": 5000000.0, - "maxNotional": 30000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.5", - "cum": "1527500.0" - } - } - ], - "DOGE/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "100000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "500000", - "notionalFloor": "100000", - "maintMarginRatio": "0.05", - "cum": "2500.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.1", - "cum": "27500.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "4", - "initialLeverage": "3", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.15", - "cum": "77500.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.25", - "cum": "277500.0" - } - }, - { - "tier": 6.0, - "currency": "BUSD", - "minNotional": 5000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "8000000", "notionalFloor": "5000000", "maintMarginRatio": "0.5", "cum": "1527500.0" @@ -15097,203 +17099,7 @@ } } ], - "FTT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "SXP/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "CRV/USDT": [ + "XTZ/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -15314,13 +17120,13 @@ "tier": 2.0, "currency": "USDT", "minNotional": 50000.0, - "maxNotional": 150000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "notionalCap": "150000", + "notionalCap": "250000", "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "750.0" @@ -15329,329 +17135,85 @@ { "tier": 3.0, "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "BEL/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "DOT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 75.0, - "info": { - "bracket": "1", - "initialLeverage": "75", - "notionalCap": "10000", - "notionalFloor": "0", - "maintMarginRatio": "0.0065", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "2", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "35.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "3", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { - "bracket": "4", + "bracket": "3", "initialLeverage": "10", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "8035.0" + "cum": "7000.0" } }, { - "tier": 5.0, + "tier": 4.0, "currency": "USDT", "minNotional": 1000000.0, "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { - "bracket": "5", + "bracket": "4", "initialLeverage": "5", "notionalCap": "2000000", "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "58035.0" + "cum": "57000.0" } }, { - "tier": 6.0, + "tier": 5.0, "currency": "USDT", "minNotional": 2000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { - "bracket": "6", + "bracket": "5", "initialLeverage": "4", "notionalCap": "5000000", "notionalFloor": "2000000", "maintMarginRatio": "0.125", - "cum": "108035.0" + "cum": "107000.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.25", + "cum": "732000.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "7", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.15", - "cum": "233035.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", "minNotional": 10000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "8", - "initialLeverage": "2", - "notionalCap": "50000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1233035.0" - } - }, - { - "tier": 9.0, - "currency": "USDT", - "minNotional": 50000000.0, - "maxNotional": 100000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "9", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "100000000", - "notionalFloor": "50000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "1.3733035E7" + "cum": "3232000.0" } } ], - "XEM/USDT": [ + "YFI/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -15736,102 +17298,20 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "GMT/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "ONE/USDT": [ + "ZEC/USDT": [ { "tier": 1.0, "currency": "USDT", @@ -15932,31 +17412,129 @@ "tier": 7.0, "currency": "USDT", "minNotional": 2000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "2000000", "maintMarginRatio": "0.5", "cum": "654500.0" } } ], + "ZEN/USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], "ZIL/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 50000.0, + "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", + "initialLeverage": "25", + "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -15965,649 +17543,95 @@ { "tier": 2.0, "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, + "minNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "2", "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", + "notionalCap": "25000", + "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "750.0" + "cum": "75.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, + "minNotional": 25000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", + "notionalCap": "100000", + "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "4500.0" + "cum": "700.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, + "minNotional": 100000.0, + "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", + "notionalCap": "250000", + "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "17000.0" + "cum": "5700.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 500000.0, + "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "maxLeverage": 2.0, "info": { "bracket": "5", - "initialLeverage": "4", + "initialLeverage": "2", "notionalCap": "1000000", - "notionalFloor": "500000", + "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "29500.0" + "cum": "11950.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.5", - "cum": "654500.0" - } - } - ], - "AXS/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "2", - "initialLeverage": "25", - "notionalCap": "250000", - "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "500.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "8000.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "58000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 2000000.0, "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, "info": { - "bracket": "5", - "initialLeverage": "4", + "bracket": "6", + "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "108000.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.1665, - "maxLeverage": 3.0, - "info": { - "bracket": "6", - "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.1665", - "cum": "315500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 15000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "7", - "initialLeverage": "2", - "notionalCap": "15000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.25", - "cum": "1150500.0" - } - }, - { - "tier": 8.0, - "currency": "USDT", - "minNotional": 15000000.0, - "maxNotional": 50000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "8", - "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "15000000", - "maintMarginRatio": "0.5", - "cum": "4900500.0" - } - } - ], - "DYDX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "50000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "250000", - "maintMarginRatio": "0.1", - "cum": "17000.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "29500.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 4000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "4000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "4000000", - "maintMarginRatio": "0.5", - "cum": "1154500.0" - } - } - ], - "OCEAN/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "CHZ/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.012, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.012", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "65.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "690.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5690.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11940.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386940.0" - } - } - ], - "ANKR/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.012, - "maxLeverage": 50.0, - "info": { - "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.012", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "65.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "690.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5690.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11940.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386940.0" - } - } - ], - "DUSK/USDT": [ + "ZRX/USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxLeverage": 50.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "50", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -16682,225 +17706,13 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BTCUSDT_220624": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 375000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "375000", - "notionalFloor": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 375000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "2000000", - "notionalFloor": "375000", - "maintMarginRatio": "0.05", - "cum": "11250.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "4000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.1", - "cum": "111250.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, - "info": { - "bracket": "4", - "initialLeverage": "4", - "notionalCap": "10000000", - "notionalFloor": "4000000", - "maintMarginRatio": "0.125", - "cum": "211250.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, - "maintenanceMarginRate": 0.15, - "maxLeverage": 3.0, - "info": { - "bracket": "5", - "initialLeverage": "3", - "notionalCap": "20000000", - "notionalFloor": "10000000", - "maintMarginRatio": "0.15", - "cum": "461250.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 40000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "40000000", - "notionalFloor": "20000000", - "maintMarginRatio": "0.25", - "cum": "2461250.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 40000000.0, - "maxNotional": 400000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "7", - "initialLeverage": "1", - "notionalCap": "400000000", - "notionalFloor": "40000000", - "maintMarginRatio": "0.5", - "cum": "1.246125E7" - } - } - ], - "CTSI/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386950.0" From 494e0529d2dcb70dba350ef5a8e5f7b57fa9396e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 10 Jul 2022 19:31:14 +0200 Subject: [PATCH 412/449] Update conftest for leverage tiers --- tests/conftest.py | 62 ++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 2e447c281..0cf32545f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3166,60 +3166,46 @@ def leverage_tiers(): "AAVE/USDT": [ { 'min': 0, - 'max': 50000, + 'max': 5000, 'mmr': 0.01, 'lev': 50, 'maintAmt': 0.0 }, { - 'min': 50000, - 'max': 250000, + 'min': 5000, + 'max': 25000, 'mmr': 0.02, 'lev': 25, - 'maintAmt': 500.0 + 'maintAmt': 75.0 + }, + { + 'min': 25000, + 'max': 100000, + 'mmr': 0.05, + 'lev': 10, + 'maintAmt': 700.0 + }, + { + 'min': 100000, + 'max': 250000, + 'mmr': 0.1, + 'lev': 5, + 'maintAmt': 5700.0 }, { 'min': 250000, 'max': 1000000, - 'mmr': 0.05, - 'lev': 10, - 'maintAmt': 8000.0 - }, - { - 'min': 1000000, - 'max': 2000000, - 'mmr': 0.1, - 'lev': 5, - 'maintAmt': 58000.0 - }, - { - 'min': 2000000, - 'max': 5000000, 'mmr': 0.125, - 'lev': 4, - 'maintAmt': 108000.0 - }, - { - 'min': 5000000, - 'max': 10000000, - 'mmr': 0.1665, - 'lev': 3, - 'maintAmt': 315500.0 + 'lev': 2, + 'maintAmt': 11950.0 }, { 'min': 10000000, - 'max': 20000000, - 'mmr': 0.25, - 'lev': 2, - 'maintAmt': 1150500.0 + 'max': 50000000, + 'mmr': 0.5, + 'lev': 1, + 'maintAmt': 386950.0 }, - { - "min": 20000000, - "max": 50000000, - "mmr": 0.5, - "lev": 1, - "maintAmt": 6150500.0 - } ], "ADA/BUSD": [ { From 9086176f7385e16db201e98112e4c2548189c815 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 03:01:47 +0000 Subject: [PATCH 413/449] Bump pytest-mock from 3.8.1 to 3.8.2 Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.8.1 to 3.8.2. - [Release notes](https://github.com/pytest-dev/pytest-mock/releases) - [Changelog](https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.8.1...v3.8.2) --- updated-dependencies: - dependency-name: pytest-mock dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 50cb98fa1..6bd107809 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -12,7 +12,7 @@ pre-commit==2.19.0 pytest==7.1.2 pytest-asyncio==0.18.3 pytest-cov==3.0.0 -pytest-mock==3.8.1 +pytest-mock==3.8.2 pytest-random-order==1.0.4 isort==5.10.1 # For datetime mocking From 5070a04a82d57576c722f13030fcd270bdc50d89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 03:01:50 +0000 Subject: [PATCH 414/449] Bump mkdocs-material from 8.3.8 to 8.3.9 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.3.8 to 8.3.9. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/8.3.8...8.3.9) --- updated-dependencies: - dependency-name: mkdocs-material dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index fe00705b9..66e83a397 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,5 +1,5 @@ mkdocs==1.3.0 -mkdocs-material==8.3.8 +mkdocs-material==8.3.9 mdx_truly_sane_lists==1.2 pymdown-extensions==9.5 jinja2==3.1.2 From b1d34dba9476b87f72869e48c9118bd7568409fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 03:02:12 +0000 Subject: [PATCH 415/449] Bump ccxt from 1.90.40 to 1.90.41 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.90.40 to 1.90.41. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg) - [Commits](https://github.com/ccxt/ccxt/compare/1.90.40...1.90.41) --- updated-dependencies: - dependency-name: ccxt dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2bce619d3..83f768e20 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.23.0 pandas==1.4.3 pandas-ta==0.3.14b -ccxt==1.90.40 +ccxt==1.90.41 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.2 aiohttp==3.8.1 From c98786a4f6752719b5ff0a6483fa01b800a5319a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 03:02:17 +0000 Subject: [PATCH 416/449] Bump jsonschema from 4.6.1 to 4.6.2 Bumps [jsonschema](https://github.com/python-jsonschema/jsonschema) from 4.6.1 to 4.6.2. - [Release notes](https://github.com/python-jsonschema/jsonschema/releases) - [Changelog](https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst) - [Commits](https://github.com/python-jsonschema/jsonschema/compare/v4.6.1...v4.6.2) --- updated-dependencies: - dependency-name: jsonschema dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2bce619d3..2400f7699 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ arrow==1.2.2 cachetools==4.2.2 requests==2.28.1 urllib3==1.26.9 -jsonschema==4.6.1 +jsonschema==4.6.2 TA-Lib==0.4.24 technical==1.3.0 tabulate==0.8.10 From 719fa6f8e1b4600d08247bb9d8f385d924dc6038 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 03:02:39 +0000 Subject: [PATCH 417/449] Bump orjson from 3.7.6 to 3.7.7 Bumps [orjson](https://github.com/ijl/orjson) from 3.7.6 to 3.7.7. - [Release notes](https://github.com/ijl/orjson/releases) - [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md) - [Commits](https://github.com/ijl/orjson/compare/3.7.6...3.7.7) --- updated-dependencies: - dependency-name: orjson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2bce619d3..fa3a3ee6a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,7 +28,7 @@ py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.6 # Properly format api responses -orjson==3.7.6 +orjson==3.7.7 # Notify systemd sdnotify==0.3.2 From fa158ba8de02ff45c9cea5bd5c26ac40d8a1dcb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 05:14:41 +0000 Subject: [PATCH 418/449] Bump pre-commit from 2.19.0 to 2.20.0 Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.19.0 to 2.20.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v2.19.0...v2.20.0) --- updated-dependencies: - dependency-name: pre-commit dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 6bd107809..f2f77c2ba 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,7 +8,7 @@ coveralls==3.3.1 flake8==4.0.1 flake8-tidy-imports==4.8.0 mypy==0.961 -pre-commit==2.19.0 +pre-commit==2.20.0 pytest==7.1.2 pytest-asyncio==0.18.3 pytest-cov==3.0.0 From 7b998378ced8638b1f8436fd5593e5f20a0499d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 05:15:37 +0000 Subject: [PATCH 419/449] Bump numpy from 1.23.0 to 1.23.1 Bumps [numpy](https://github.com/numpy/numpy) from 1.23.0 to 1.23.1. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v1.23.0...v1.23.1) --- updated-dependencies: - dependency-name: numpy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 868f27cd7..9910efd3a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy==1.23.0 +numpy==1.23.1 pandas==1.4.3 pandas-ta==0.3.14b From 7c6c2c4d6ed7adb1678d85e03ea8058ed6dd137a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 05:15:38 +0000 Subject: [PATCH 420/449] Bump cryptography from 37.0.2 to 37.0.4 Bumps [cryptography](https://github.com/pyca/cryptography) from 37.0.2 to 37.0.4. - [Release notes](https://github.com/pyca/cryptography/releases) - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/37.0.2...37.0.4) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 868f27cd7..cb3f577c2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ pandas-ta==0.3.14b ccxt==1.90.41 # Pin cryptography for now due to rust build errors with piwheels -cryptography==37.0.2 +cryptography==37.0.4 aiohttp==3.8.1 SQLAlchemy==1.4.39 python-telegram-bot==13.13 From c06b524b4eac96ec57f136809d61347377ab2e2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 05:16:14 +0000 Subject: [PATCH 421/449] Bump urllib3 from 1.26.9 to 1.26.10 Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.9 to 1.26.10. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/1.26.10/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.9...1.26.10) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 868f27cd7..4db3e5866 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ python-telegram-bot==13.13 arrow==1.2.2 cachetools==4.2.2 requests==2.28.1 -urllib3==1.26.9 +urllib3==1.26.10 jsonschema==4.6.2 TA-Lib==0.4.24 technical==1.3.0 From 0bb8c8feba97476dc40bfc2f5cab801e1dcccd9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 05:23:01 +0000 Subject: [PATCH 422/449] Bump python-rapidjson from 1.6 to 1.8 Bumps [python-rapidjson](https://github.com/python-rapidjson/python-rapidjson) from 1.6 to 1.8. - [Release notes](https://github.com/python-rapidjson/python-rapidjson/releases) - [Changelog](https://github.com/python-rapidjson/python-rapidjson/blob/master/CHANGES.rst) - [Commits](https://github.com/python-rapidjson/python-rapidjson/compare/v1.6...v1.8) --- updated-dependencies: - dependency-name: python-rapidjson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 459deadb6..1b730f2b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,7 +26,7 @@ joblib==1.1.0 py_find_1st==1.1.5 # Load ticker files 30% faster -python-rapidjson==1.6 +python-rapidjson==1.8 # Properly format api responses orjson==3.7.7 From 7d6b3d0e02158685a3c13c347aa897e325a371c9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 08:14:39 +0200 Subject: [PATCH 423/449] Update hyperopt param docs to be clear that non-conclusive parameters will be ignored --- docs/hyperopt.md | 3 ++- freqtrade/strategy/hyper.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 63c7a4413..f44a68037 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -271,7 +271,8 @@ The last one we call `trigger` and use it to decide which buy trigger we want to !!! Note "Parameter space assignment" Parameters must either be assigned to a variable named `buy_*` or `sell_*` - or contain `space='buy'` | `space='sell'` to be assigned to a space correctly. - If no parameter is available for a space, you'll receive the error that no space was found when running hyperopt. + If no parameter is available for a space, you'll receive the error that no space was found when running hyperopt. + Parameters with unclear space (e.g. `adx_period = IntParameter(4, 24, default=14)` - no explicit nor implicit space) will not be detected and will therefore be ignored. So let's write the buy strategy using these values: diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index cdcfc969e..47377f238 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -191,6 +191,7 @@ def detect_parameters( and attr.category is not None and attr.category != category): raise OperationalException( f'Inconclusive parameter name {attr_name}, category: {attr.category}.') + if (category == attr.category or (attr_name.startswith(category + '_') and attr.category is None)): yield attr_name, attr From 523d8a84a810535588452d49c8f4489c3066ef66 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 10:22:51 +0200 Subject: [PATCH 424/449] skip "supports market order" for now until CCXT fixes their assignemnt bugs. --- freqtrade/exchange/common.py | 2 +- freqtrade/exchange/exchange.py | 11 +++++++---- tests/exchange/test_exchange.py | 6 +++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index e5b6533c4..0046ba458 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -64,7 +64,6 @@ EXCHANGE_HAS_REQUIRED = [ 'fetchOrder', 'cancelOrder', 'createOrder', - # 'createLimitOrder', 'createMarketOrder', 'fetchBalance', # Public endpoints @@ -74,6 +73,7 @@ EXCHANGE_HAS_REQUIRED = [ EXCHANGE_HAS_OPTIONAL = [ # Private 'fetchMyTrades', # Trades for order - fee detection + # 'createLimitOrder', 'createMarketOrder', # Either OR for orders # 'setLeverage', # Margin/Futures trading # 'setMarginMode', # Margin/Futures trading # 'fetchFundingHistory', # Futures trading diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index cd13964c4..58d5ebb07 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -586,10 +586,13 @@ class Exchange: """ Checks if order-types configured in strategy/config are supported """ - if any(v == 'market' for k, v in order_types.items()): - if not self.exchange_has('createMarketOrder'): - raise OperationalException( - f'Exchange {self.name} does not support market orders.') + # TODO: Reenable once ccxt fixes createMarketOrder assignment - as well as + # Revert the change in test_validate_ordertypes. + + # if any(v == 'market' for k, v in order_types.items()): + # if not self.exchange_has('createMarketOrder'): + # raise OperationalException( + # f'Exchange {self.name} does not support market orders.') if (order_types.get("stoploss_on_exchange") and not self._ft_has.get("stoploss_on_exchange", False)): diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index acd48b3fd..69969e527 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1027,9 +1027,9 @@ def test_validate_ordertypes(default_conf, mocker): 'stoploss': 'market', 'stoploss_on_exchange': False } - with pytest.raises(OperationalException, - match=r'Exchange .* does not support market orders.'): - Exchange(default_conf) + # with pytest.raises(OperationalException, + # match=r'Exchange .* does not support market orders.'): + # Exchange(default_conf) default_conf['order_types'] = { 'entry': 'limit', From f8e35d876018e1a80918827f40d142a3a103f6f4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 10:30:05 +0200 Subject: [PATCH 425/449] Add TODO to disabled test --- tests/exchange/test_exchange.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 69969e527..f09d647ce 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1027,6 +1027,7 @@ def test_validate_ordertypes(default_conf, mocker): 'stoploss': 'market', 'stoploss_on_exchange': False } + # TODO: Revert once createMarketOrder is available again. # with pytest.raises(OperationalException, # match=r'Exchange .* does not support market orders.'): # Exchange(default_conf) From 6ac1aa15f582d8665936c0658c09f0ba308f68d0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 10:36:19 +0200 Subject: [PATCH 426/449] Reenable ccxt order checks --- freqtrade/exchange/exchange.py | 11 ++++------- tests/exchange/test_exchange.py | 7 +++---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 58d5ebb07..cd13964c4 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -586,13 +586,10 @@ class Exchange: """ Checks if order-types configured in strategy/config are supported """ - # TODO: Reenable once ccxt fixes createMarketOrder assignment - as well as - # Revert the change in test_validate_ordertypes. - - # if any(v == 'market' for k, v in order_types.items()): - # if not self.exchange_has('createMarketOrder'): - # raise OperationalException( - # f'Exchange {self.name} does not support market orders.') + if any(v == 'market' for k, v in order_types.items()): + if not self.exchange_has('createMarketOrder'): + raise OperationalException( + f'Exchange {self.name} does not support market orders.') if (order_types.get("stoploss_on_exchange") and not self._ft_has.get("stoploss_on_exchange", False)): diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index f09d647ce..acd48b3fd 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1027,10 +1027,9 @@ def test_validate_ordertypes(default_conf, mocker): 'stoploss': 'market', 'stoploss_on_exchange': False } - # TODO: Revert once createMarketOrder is available again. - # with pytest.raises(OperationalException, - # match=r'Exchange .* does not support market orders.'): - # Exchange(default_conf) + with pytest.raises(OperationalException, + match=r'Exchange .* does not support market orders.'): + Exchange(default_conf) default_conf['order_types'] = { 'entry': 'limit', From 64f89af69e8e88f4c24bf0a8dace2b740821287b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 10:43:21 +0200 Subject: [PATCH 427/449] Add Explicit test for "has" checks --- tests/exchange/test_ccxt_compat.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 50154bcaf..74106f28b 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -153,6 +153,25 @@ class TestCCXTExchange(): assert isinstance(markets[pair], dict) assert exchange.market_is_spot(markets[pair]) + def test_has_validations(self, exchange): + + exchange, exchangename = exchange + + exchange.validate_ordertypes({ + 'entry': 'limit', + 'exit': 'limit', + 'stoploss': 'limit', + }) + + if exchangename == 'gateio': + # gateio doesn't have market orders on spot + return + exchange.validate_ordertypes({ + 'entry': 'market', + 'exit': 'market', + 'stoploss': 'market', + }) + def test_load_markets_futures(self, exchange_futures): exchange, exchangename = exchange_futures if not exchange: From ec3179156c200da0649c1604ce7a1e29561d09d9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 11:48:24 +0200 Subject: [PATCH 428/449] Revert unwanted changes. --- .gitignore | 5 -- freqtrade/templates/sample_strategy.py | 27 ++++++-- .../templates/strategy_analysis_example.ipynb | 61 +++---------------- 3 files changed, 33 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index 5042dfb9b..97f77f779 100644 --- a/.gitignore +++ b/.gitignore @@ -105,8 +105,3 @@ target/ !config_examples/config_ftx.example.json !config_examples/config_full.example.json !config_examples/config_kraken.example.json -doc/doc-filelist.js -.gitignore -.gitignore -doc/doc-style.css -doc/doc-script.js diff --git a/freqtrade/templates/sample_strategy.py b/freqtrade/templates/sample_strategy.py index 1b49f82c9..1b375714a 100644 --- a/freqtrade/templates/sample_strategy.py +++ b/freqtrade/templates/sample_strategy.py @@ -178,10 +178,29 @@ class SampleStrategy(IStrategy): # RSI dataframe['rsi'] = ta.RSI(dataframe) - # Stochastic RSI - stoch_rsi = ta.STOCHRSI(dataframe) - dataframe['fastd_rsi'] = stoch_rsi['fastd'] - dataframe['fastk_rsi'] = stoch_rsi['fastk'] + # # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy) + # rsi = 0.1 * (dataframe['rsi'] - 50) + # dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) + + # # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy) + # dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) + + # # Stochastic Slow + # stoch = ta.STOCH(dataframe) + # dataframe['slowd'] = stoch['slowd'] + # dataframe['slowk'] = stoch['slowk'] + + # Stochastic Fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # # Stochastic RSI + # Please read https://github.com/freqtrade/freqtrade/issues/2961 before using this. + # STOCHRSI is NOT aligned with tradingview, which may result in non-expected results. + # stoch_rsi = ta.STOCHRSI(dataframe) + # dataframe['fastd_rsi'] = stoch_rsi['fastd'] + # dataframe['fastk_rsi'] = stoch_rsi['fastk'] # MACD macd = ta.MACD(dataframe) diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index 33182dbf0..93e4b83ae 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -19,27 +19,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "OperationalException", - "evalue": "Directory `/Users/surfer/Software/MMM/develop/freqtrade/freqtrade/templates/user_data` does not exist. Please use `freqtrade create-userdir` to create a user directory", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mOperationalException\u001b[0m Traceback (most recent call last)", - "Input \u001b[0;32mIn [2]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mfreqtrade\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mconfiguration\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m Configuration\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# Customize these according to your needs.\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \n\u001b[1;32m 6\u001b[0m \u001b[38;5;66;03m# Initialize empty configuration object\u001b[39;00m\n\u001b[0;32m----> 7\u001b[0m config \u001b[38;5;241m=\u001b[39m \u001b[43mConfiguration\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_files\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;66;03m# Optionally, use existing configuration file\u001b[39;00m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# config = Configuration.from_files([\"config.json\"])\u001b[39;00m\n\u001b[1;32m 10\u001b[0m \n\u001b[1;32m 11\u001b[0m \u001b[38;5;66;03m# Define some constants\u001b[39;00m\n\u001b[1;32m 12\u001b[0m config[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtimeframe\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m1m\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:60\u001b[0m, in \u001b[0;36mConfiguration.from_files\u001b[0;34m(files)\u001b[0m\n\u001b[1;32m 58\u001b[0m \u001b[38;5;66;03m# Keep this method as staticmethod, so it can be used from interactive environments\u001b[39;00m\n\u001b[1;32m 59\u001b[0m c \u001b[38;5;241m=\u001b[39m Configuration({\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mconfig\u001b[39m\u001b[38;5;124m'\u001b[39m: files}, RunMode\u001b[38;5;241m.\u001b[39mOTHER)\n\u001b[0;32m---> 60\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_config\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:42\u001b[0m, in \u001b[0;36mConfiguration.get_config\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 38\u001b[0m \u001b[38;5;124;03mReturn the config. Use this method to get the bot config\u001b[39;00m\n\u001b[1;32m 39\u001b[0m \u001b[38;5;124;03m:return: Dict: Bot config\u001b[39;00m\n\u001b[1;32m 40\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconfig \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 42\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconfig \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload_config\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 44\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconfig\n", - "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:92\u001b[0m, in \u001b[0;36mConfiguration.load_config\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 88\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_common_options(config)\n\u001b[1;32m 90\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_trading_options(config)\n\u001b[0;32m---> 92\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_process_optimize_options\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 94\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_plot_options(config)\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_data_options(config)\n", - "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:249\u001b[0m, in \u001b[0;36mConfiguration._process_optimize_options\u001b[0;34m(self, config)\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_args_to_config(config, argname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mfee\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 243\u001b[0m logstring\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mParameter --fee detected, \u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 244\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124msetting fee to: \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m ...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 246\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_args_to_config(config, argname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtimerange\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 247\u001b[0m logstring\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mParameter --timerange detected: \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m ...\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m--> 249\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_process_datadir_options\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 251\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_args_to_config(config, argname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mstrategy_list\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 252\u001b[0m logstring\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mUsing strategy list of \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m strategies\u001b[39m\u001b[38;5;124m'\u001b[39m, logfun\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mlen\u001b[39m)\n\u001b[1;32m 254\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_args_to_config(\n\u001b[1;32m 255\u001b[0m config,\n\u001b[1;32m 256\u001b[0m argname\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrecursive_strategy_search\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 257\u001b[0m logstring\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mRecursively searching for a strategy in the strategies folder.\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 258\u001b[0m )\n", - "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/configuration.py:180\u001b[0m, in \u001b[0;36mConfiguration._process_datadir_options\u001b[0;34m(self, config)\u001b[0m\n\u001b[1;32m 177\u001b[0m config\u001b[38;5;241m.\u001b[39mupdate({\u001b[38;5;124m'\u001b[39m\u001b[38;5;124muser_data_dir\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;28mstr\u001b[39m(Path\u001b[38;5;241m.\u001b[39mcwd() \u001b[38;5;241m/\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124muser_data\u001b[39m\u001b[38;5;124m'\u001b[39m)})\n\u001b[1;32m 179\u001b[0m \u001b[38;5;66;03m# reset to user_data_dir so this contains the absolute path.\u001b[39;00m\n\u001b[0;32m--> 180\u001b[0m config[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124muser_data_dir\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[43mcreate_userdata_dir\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43muser_data_dir\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreate_dir\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 181\u001b[0m logger\u001b[38;5;241m.\u001b[39minfo(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mUsing user-data directory: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m ...\u001b[39m\u001b[38;5;124m'\u001b[39m, config[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124muser_data_dir\u001b[39m\u001b[38;5;124m'\u001b[39m])\n\u001b[1;32m 183\u001b[0m config\u001b[38;5;241m.\u001b[39mupdate({\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdatadir\u001b[39m\u001b[38;5;124m'\u001b[39m: create_datadir(config, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39margs\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdatadir\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;28;01mNone\u001b[39;00m))})\n", - "File \u001b[0;32m~/Software/MMM/develop/freqtrade/freqtrade/configuration/directory_operations.py:61\u001b[0m, in \u001b[0;36mcreate_userdata_dir\u001b[0;34m(directory, create_dir)\u001b[0m\n\u001b[1;32m 59\u001b[0m logger\u001b[38;5;241m.\u001b[39minfo(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCreated user-data directory: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfolder\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 60\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m---> 61\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m OperationalException(\n\u001b[1;32m 62\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDirectory `\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfolder\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m` does not exist. \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 63\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mPlease use `freqtrade create-userdir` to create a user directory\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 65\u001b[0m \u001b[38;5;66;03m# Create required subdirectories\u001b[39;00m\n\u001b[1;32m 66\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m sub_dirs:\n", - "\u001b[0;31mOperationalException\u001b[0m: Directory `/Users/surfer/Software/MMM/develop/freqtrade/freqtrade/templates/user_data` does not exist. Please use `freqtrade create-userdir` to create a user directory" - ] - } - ], + "outputs": [], "source": [ "from pathlib import Path\n", "from freqtrade.configuration import Configuration\n", @@ -52,9 +34,9 @@ "# config = Configuration.from_files([\"config.json\"])\n", "\n", "# Define some constants\n", - "config[\"timeframe\"] = \"1m\"\n", + "config[\"timeframe\"] = \"5m\"\n", "# Name of the strategy class\n", - "config[\"strategy\"] = \"MMMOracle\"\n", + "config[\"strategy\"] = \"SampleStrategy\"\n", "# Location of the data\n", "data_location = Path(config['user_data_dir'], 'data', 'binance')\n", "# Pair to analyze - Only use one pair here\n", @@ -154,21 +136,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'config' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "Input \u001b[0;32mIn [3]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mfreqtrade\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdata\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mbtanalysis\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m load_backtest_data, load_backtest_stats\n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# if backtest_dir points to a directory, it'll automatically load the last backtest file.\u001b[39;00m\n\u001b[0;32m----> 4\u001b[0m backtest_dir \u001b[38;5;241m=\u001b[39m \u001b[43mconfig\u001b[49m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser_data_dir\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m/\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbacktest_results\u001b[39m\u001b[38;5;124m\"\u001b[39m\n", - "\u001b[0;31mNameError\u001b[0m: name 'config' is not defined" - ] - } - ], + "outputs": [], "source": [ "from freqtrade.data.btanalysis import load_backtest_data, load_backtest_stats\n", "\n", @@ -277,20 +247,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Series([], Name: exit_reason, dtype: int64)" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from freqtrade.data.btanalysis import load_trades_from_db\n", "\n", @@ -404,7 +363,7 @@ "metadata": { "file_extension": ".py", "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -418,7 +377,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.8.5" }, "mimetype": "text/x-python", "name": "python", From 8e8f026ea77a11259e93e1691a737b0c079f7f83 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 12:10:29 +0200 Subject: [PATCH 429/449] Telegram candle message should be configurable --- config_examples/config_full.example.json | 3 ++- docs/telegram-usage.md | 5 +++-- freqtrade/constants.py | 4 ++++ freqtrade/freqtradebot.py | 4 ++-- freqtrade/rpc/telegram.py | 23 +++++++++++++++-------- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/config_examples/config_full.example.json b/config_examples/config_full.example.json index 6382e1baf..e2e9a16fd 100644 --- a/config_examples/config_full.example.json +++ b/config_examples/config_full.example.json @@ -155,7 +155,8 @@ "entry_cancel": "on", "exit_cancel": "on", "protection_trigger": "off", - "protection_trigger_global": "on" + "protection_trigger_global": "on", + "show_candle": "off" }, "reload": true, "balance_dust_level": 0.01 diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 2145797b4..9853e15c6 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -97,7 +97,8 @@ Example configuration showing the different settings: "entry_fill": "off", "exit_fill": "off", "protection_trigger": "off", - "protection_trigger_global": "on" + "protection_trigger_global": "on", + "show_candle": "off" }, "reload": true, "balance_dust_level": 0.01 @@ -108,7 +109,7 @@ Example configuration showing the different settings: `exit` notifications are sent when the order is placed, while `exit_fill` notifications are sent when the order is filled on the exchange. `*_fill` notifications are off by default and must be explicitly enabled. `protection_trigger` notifications are sent when a protection triggers and `protection_trigger_global` notifications trigger when global protections are triggered. - +`show_candle` - show candle values as part of entry/exit messages. Only possible value is "ohlc". `balance_dust_level` will define what the `/balance` command takes as "dust" - Currencies with a balance below this will be shown. `reload` allows you to disable reload-buttons on selected messages. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 18dbea259..ce7c0ff83 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -313,6 +313,10 @@ CONF_SCHEMA = { 'type': 'string', 'enum': TELEGRAM_SETTING_OPTIONS, }, + 'show_candle': { + 'type': 'string', + 'enum': ['off', 'ohlc'], + }, } }, 'reload': {'type': 'boolean'}, diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 2d16dc9ff..fe8bcc89b 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -868,7 +868,7 @@ class FreqtradeBot(LoggingMixin): if analyzed_candle is not None: candle_columns = analyzed_candle[['date', 'open', 'high', 'low', 'close']] msg.update({ - 'analyzed_candle': candle_columns.to_json(date_unit='s', date_format='iso') + 'analyzed_candle': candle_columns.to_dict() }) # Send the message @@ -1567,7 +1567,7 @@ class FreqtradeBot(LoggingMixin): if analyzed_candle is not None: candle_columns = analyzed_candle[['date', 'open', 'high', 'low', 'close']] msg.update({ - 'analyzed_candle': candle_columns.to_json(date_unit='s', date_format='iso') + 'analyzed_candle': candle_columns.to_dict() }) # Send the message diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 16a851ce1..9ade8cb5f 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -243,6 +243,19 @@ class Telegram(RPCHandler): """ return f"{msg['exchange']}{' (dry)' if self._config['dry_run'] else ''}" + def _add_analyzed_candle(self, msg) -> str: + candle_val = self._config['telegram'].get( + 'notification_settings', {}).get('show_candle', 'off') + if candle_val != 'off' and msg.get('analyzed_candle'): + if candle_val == 'ohlc': + candle_json = msg['analyzed_candle'] + return ( + f"*Candle OHLC*: `{candle_json['open']}, {candle_json['high']}, " + f"{candle_json['low']}, {candle_json['close']}`\n" + ) + + return '' + def _format_entry_msg(self, msg: Dict[str, Any]) -> str: if self._rpc._fiat_converter: msg['stake_amount_fiat'] = self._rpc._fiat_converter.convert_amount( @@ -259,8 +272,7 @@ class Telegram(RPCHandler): f" {entry_side['entered'] if is_fill else entry_side['enter']} {msg['pair']}" f" (#{msg['trade_id']})\n" ) - if msg.get('analyzed_candle'): - message += f"*Analyzed Candle:* `{msg['analyzed_candle']}`\n" + message += self._add_analyzed_candle(msg) message += f"*Enter Tag:* `{msg['enter_tag']}`\n" if msg.get('enter_tag') else "" message += f"*Amount:* `{msg['amount']:.8f}`\n" if msg.get('leverage') and msg.get('leverage', 1.0) != 1.0: @@ -308,12 +320,7 @@ class Telegram(RPCHandler): message = ( f"{msg['emoji']} *{self._exchange_from_msg(msg)}:* " f"{'Exited' if is_fill else 'Exiting'} {msg['pair']} (#{msg['trade_id']})\n" - ) - if not is_fill and msg.get('analyzed_candle'): - message += ( - f"*Analyzed Candle:* `{msg['analyzed_candle']}`\n" - ) - message += ( + f"{self._add_analyzed_candle(msg)}" f"*{'Profit' if is_fill else 'Unrealized Profit'}:* " f"`{msg['profit_ratio']:.2%}{msg['profit_extra']}`\n" f"*Enter Tag:* `{msg['enter_tag']}`\n" From 9a3a2f9013003182b9b5fe014e9d6679138e9f2b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 13:55:32 +0200 Subject: [PATCH 430/449] Simplify adding candle to message --- freqtrade/freqtradebot.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index fe8bcc89b..bde9ea8aa 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -861,8 +861,15 @@ class FreqtradeBot(LoggingMixin): 'current_rate': current_rate, } + self._analyzed_candle_to_msg(trade.pair, msg) + + # Send the message + self.rpc.send_msg(msg) + + def _analyzed_candle_to_msg(self, pair: str, msg: Dict): + """Msg dict will be enhanced with analyzed_candle if possible.""" # display the candle analyzed in telegram - analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair, + analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(pair, self.strategy.timeframe) analyzed_candle = analyzed_df.iloc[-1] if len(analyzed_df) > 0 else None if analyzed_candle is not None: @@ -871,9 +878,6 @@ class FreqtradeBot(LoggingMixin): 'analyzed_candle': candle_columns.to_dict() }) - # Send the message - self.rpc.send_msg(msg) - def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str) -> None: """ Sends rpc notification when a entry order cancel occurred. @@ -1560,15 +1564,7 @@ class FreqtradeBot(LoggingMixin): 'fiat_currency': self.config['fiat_display_currency'], }) - # display the candle analyzed in telegram - analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair, - self.strategy.timeframe) - analyzed_candle = analyzed_df.iloc[-1] if len(analyzed_df) > 0 else None - if analyzed_candle is not None: - candle_columns = analyzed_candle[['date', 'open', 'high', 'low', 'close']] - msg.update({ - 'analyzed_candle': candle_columns.to_dict() - }) + self._analyzed_candle_to_msg(trade.pair, msg) # Send the message self.rpc.send_msg(msg) From f9d3775d4c36f1c45a137f5919ebef12f6703c1e Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 14:09:39 +0200 Subject: [PATCH 431/449] Move "candle" logic for message to telegram this avoids calling this method unless necessary --- freqtrade/freqtradebot.py | 16 ---------------- freqtrade/rpc/telegram.py | 21 ++++++++++++--------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index bde9ea8aa..469bfda7e 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -861,23 +861,9 @@ class FreqtradeBot(LoggingMixin): 'current_rate': current_rate, } - self._analyzed_candle_to_msg(trade.pair, msg) - # Send the message self.rpc.send_msg(msg) - def _analyzed_candle_to_msg(self, pair: str, msg: Dict): - """Msg dict will be enhanced with analyzed_candle if possible.""" - # display the candle analyzed in telegram - analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(pair, - self.strategy.timeframe) - analyzed_candle = analyzed_df.iloc[-1] if len(analyzed_df) > 0 else None - if analyzed_candle is not None: - candle_columns = analyzed_candle[['date', 'open', 'high', 'low', 'close']] - msg.update({ - 'analyzed_candle': candle_columns.to_dict() - }) - def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str) -> None: """ Sends rpc notification when a entry order cancel occurred. @@ -1564,8 +1550,6 @@ class FreqtradeBot(LoggingMixin): 'fiat_currency': self.config['fiat_display_currency'], }) - self._analyzed_candle_to_msg(trade.pair, msg) - # Send the message self.rpc.send_msg(msg) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 9ade8cb5f..2aff1d210 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -243,16 +243,19 @@ class Telegram(RPCHandler): """ return f"{msg['exchange']}{' (dry)' if self._config['dry_run'] else ''}" - def _add_analyzed_candle(self, msg) -> str: + def _add_analyzed_candle(self, pair: str) -> str: candle_val = self._config['telegram'].get( 'notification_settings', {}).get('show_candle', 'off') - if candle_val != 'off' and msg.get('analyzed_candle'): + if candle_val != 'off': if candle_val == 'ohlc': - candle_json = msg['analyzed_candle'] - return ( - f"*Candle OHLC*: `{candle_json['open']}, {candle_json['high']}, " - f"{candle_json['low']}, {candle_json['close']}`\n" - ) + analyzed_df, _ = self._rpc._freqtrade.dataprovider.get_analyzed_dataframe( + pair, self._config['timeframe']) + candle = analyzed_df.iloc[-1].squeeze() if len(analyzed_df) > 0 else None + if candle is not None: + return ( + f"*Candle OHLC*: `{candle['open']}, {candle['high']}, " + f"{candle['low']}, {candle['close']}`\n" + ) return '' @@ -272,7 +275,7 @@ class Telegram(RPCHandler): f" {entry_side['entered'] if is_fill else entry_side['enter']} {msg['pair']}" f" (#{msg['trade_id']})\n" ) - message += self._add_analyzed_candle(msg) + message += self._add_analyzed_candle(msg['pair']) message += f"*Enter Tag:* `{msg['enter_tag']}`\n" if msg.get('enter_tag') else "" message += f"*Amount:* `{msg['amount']:.8f}`\n" if msg.get('leverage') and msg.get('leverage', 1.0) != 1.0: @@ -320,7 +323,7 @@ class Telegram(RPCHandler): message = ( f"{msg['emoji']} *{self._exchange_from_msg(msg)}:* " f"{'Exited' if is_fill else 'Exiting'} {msg['pair']} (#{msg['trade_id']})\n" - f"{self._add_analyzed_candle(msg)}" + f"{self._add_analyzed_candle(msg['pair'])}" f"*{'Profit' if is_fill else 'Unrealized Profit'}:* " f"`{msg['profit_ratio']:.2%}{msg['profit_extra']}`\n" f"*Enter Tag:* `{msg['enter_tag']}`\n" From bf992fd9dfce74e916a961164436a8349df25aa1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 14:09:44 +0200 Subject: [PATCH 432/449] Add test for newly added functionality --- tests/rpc/test_rpc_telegram.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index e36d98083..91ee92fd7 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -12,6 +12,7 @@ from unittest.mock import ANY, MagicMock import arrow import pytest +from pandas import DataFrame from telegram import Chat, Message, ReplyKeyboardMarkup, Update from telegram.error import BadRequest, NetworkError, TelegramError @@ -1655,8 +1656,17 @@ def test_show_config_handle(default_conf, update, mocker) -> None: (RPCMessageType.ENTRY, 'Long', 'long_signal_01', 1.0), (RPCMessageType.ENTRY, 'Long', 'long_signal_01', 5.0), (RPCMessageType.ENTRY, 'Short', 'short_signal_01', 2.0)]) -def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type, - enter, enter_signal, leverage) -> None: +def test_send_msg_enter_notification(default_conf, mocker, caplog, message_type, + enter, enter_signal, leverage) -> None: + default_conf['telegram']['notification_settings']['show_candle'] = 'ohlc' + df = DataFrame({ + 'open': [1.1], + 'high': [2.2], + 'low': [1.0], + 'close': [1.5], + }) + mocker.patch('freqtrade.data.dataprovider.DataProvider.get_analyzed_dataframe', + return_value=(df, 1)) msg = { 'type': message_type, @@ -1674,6 +1684,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type, 'fiat_currency': 'USD', 'current_rate': 1.099e-05, 'amount': 1333.3333333333335, + 'analyzed_candle': {'open': 1.1, 'high': 2.2, 'low': 1.0, 'close': 1.5}, 'open_date': arrow.utcnow().shift(hours=-1) } telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) @@ -1683,6 +1694,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type, assert msg_mock.call_args[0][0] == ( f'\N{LARGE BLUE CIRCLE} *Binance (dry):* {enter} ETH/BTC (#1)\n' + '*Candle OHLC*: `1.1, 2.2, 1.0, 1.5`\n' f'*Enter Tag:* `{enter_signal}`\n' '*Amount:* `1333.33333333`\n' f'{leverage_text}' @@ -1710,7 +1722,8 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog, message_type, @pytest.mark.parametrize('message_type,enter_signal', [ (RPCMessageType.ENTRY_CANCEL, 'long_signal_01'), (RPCMessageType.ENTRY_CANCEL, 'short_signal_01')]) -def test_send_msg_buy_cancel_notification(default_conf, mocker, message_type, enter_signal) -> None: +def test_send_msg_enter_cancel_notification( + default_conf, mocker, message_type, enter_signal) -> None: telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) From b9ba94d644c4408059093e0cb0ada7fee1a4ac46 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 16:07:58 +0200 Subject: [PATCH 433/449] Bump ccxt to 1.90.47 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 115ae734e..2bb3b4b75 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.23.1 pandas==1.4.3 pandas-ta==0.3.14b -ccxt==1.90.41 +ccxt==1.90.47 # Pin cryptography for now due to rust build errors with piwheels cryptography==37.0.4 aiohttp==3.8.1 From 5c164efdb6845313eee57d849aff04f3b93eb93d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 11 Jul 2022 16:09:12 +0200 Subject: [PATCH 434/449] Also check for createLimitOrder as optionals --- freqtrade/exchange/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index 0046ba458..5765dc459 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -73,7 +73,7 @@ EXCHANGE_HAS_REQUIRED = [ EXCHANGE_HAS_OPTIONAL = [ # Private 'fetchMyTrades', # Trades for order - fee detection - # 'createLimitOrder', 'createMarketOrder', # Either OR for orders + 'createLimitOrder', 'createMarketOrder', # Either OR for orders # 'setLeverage', # Margin/Futures trading # 'setMarginMode', # Margin/Futures trading # 'fetchFundingHistory', # Futures trading From cdc58058d72aca1bf11cfd108f01f79226056277 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 14 Jul 2022 19:40:26 +0200 Subject: [PATCH 435/449] Add candletype to notebook example closes #7084, closes #7073 --- docs/strategy_analysis_example.md | 4 +++- freqtrade/templates/strategy_analysis_example.ipynb | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/strategy_analysis_example.md b/docs/strategy_analysis_example.md index ae0c6a6a3..fbfce37d1 100644 --- a/docs/strategy_analysis_example.md +++ b/docs/strategy_analysis_example.md @@ -31,11 +31,13 @@ pair = "BTC/USDT" ```python # Load data using values set above from freqtrade.data.history import load_pair_history +from freqtrade.enums import CandleType candles = load_pair_history(datadir=data_location, timeframe=config["timeframe"], pair=pair, data_format = "hdf5", + candle_type=CandleType.SPOT, ) # Confirm success @@ -93,7 +95,7 @@ from freqtrade.data.btanalysis import load_backtest_data, load_backtest_stats # if backtest_dir points to a directory, it'll automatically load the last backtest file. backtest_dir = config["user_data_dir"] / "backtest_results" -# backtest_dir can also point to a specific file +# backtest_dir can also point to a specific file # backtest_dir = config["user_data_dir"] / "backtest_results/backtest-result-2020-07-01_20-04-22.json" ``` diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index 93e4b83ae..a7430c225 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -51,11 +51,13 @@ "source": [ "# Load data using values set above\n", "from freqtrade.data.history import load_pair_history\n", + "from freqtrade.enums import CandleType\n", "\n", "candles = load_pair_history(datadir=data_location,\n", " timeframe=config[\"timeframe\"],\n", " pair=pair,\n", " data_format = \"hdf5\",\n", + " candle_type=CandleType.SPOT,\n", " )\n", "\n", "# Confirm success\n", From b657a4df2375aeebc9ad4f1e4c4eff995f7fd90a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 15 Jul 2022 18:55:30 +0200 Subject: [PATCH 436/449] Improve hyperopt docs part of #7088 --- docs/hyperopt.md | 24 ++++++++++++++++++++++-- docs/strategy-advanced.md | 2 ++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index f44a68037..55fe8f008 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -335,6 +335,7 @@ There are four parameter types each suited for different purposes. ## Optimizing an indicator parameter Assuming you have a simple strategy in mind - a EMA cross strategy (2 Moving averages crossing) - and you'd like to find the ideal parameters for this strategy. +By default, we assume a stoploss of 5% - and a take-profit (`minimal_roi`) of 10% - which means freqtrade will sell the trade once 10% profit has been reached. ``` python from pandas import DataFrame @@ -349,6 +350,9 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib class MyAwesomeStrategy(IStrategy): stoploss = -0.05 timeframe = '15m' + minimal_roi = { + "0": 0.10 + }, # Define the parameter spaces buy_ema_short = IntParameter(3, 50, default=5) buy_ema_long = IntParameter(15, 200, default=50) @@ -383,7 +387,7 @@ class MyAwesomeStrategy(IStrategy): return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - conditions = [] + conditions = [] conditions.append(qtpylib.crossed_above( dataframe[f'ema_long_{self.buy_ema_long.value}'], dataframe[f'ema_short_{self.buy_ema_short.value}'] )) @@ -404,7 +408,7 @@ Using `self.buy_ema_short.range` will return a range object containing all entri In this case (`IntParameter(3, 50, default=5)`), the loop would run for all numbers between 3 and 50 (`[3, 4, 5, ... 49, 50]`). By using this in a loop, hyperopt will generate 48 new columns (`['buy_ema_3', 'buy_ema_4', ... , 'buy_ema_50']`). -Hyperopt itself will then use the selected value to create the buy and sell signals +Hyperopt itself will then use the selected value to create the buy and sell signals. While this strategy is most likely too simple to provide consistent profit, it should serve as an example how optimize indicator parameters. @@ -868,6 +872,22 @@ To combat these, you have multiple options: * reduce the number of parallel processes (`-j `) * Increase the memory of your machine +## The objective has been evaluated at this point before. + +If you see `The objective has been evaluated at this point before.` - then this is a sign that your space has been exhausted, or is close to that. +Basically all points in your space have been hit (or a local minima has been hit) - and hyperopt does no longer find points in the multi-dimensional space it did not try yet. +Freqtrade tries to counter the "local minima" problem by using new, randomized points in this case. + +Example: + +``` python +buy_ema_short = IntParameter(5, 20, default=10, space="buy", optimize=True) +# This is the only parameter in the buy space +``` + +The `buy_ema_short` space has 15 possible values (`5, 6, ... 19, 20`). If you now run hyperopt for the buy space, hyperopt will only have 15 values to try before running out of options. +Your epochs should therefore be aligned to the possible values - or you should be ready to interrupt a run if you norice a lot of `The objective has been evaluated at this point before.` warnings. + ## Show details of Hyperopt results After you run Hyperopt for the desired amount of epochs, you can later list all results for analysis, select only best or profitable once, and show the details for any of the epochs previously evaluated. This can be done with the `hyperopt-list` and `hyperopt-show` sub-commands. The usage of these sub-commands is described in the [Utils](utils.md#list-hyperopt-results) chapter. diff --git a/docs/strategy-advanced.md b/docs/strategy-advanced.md index 374c675a2..a3115bfb2 100644 --- a/docs/strategy-advanced.md +++ b/docs/strategy-advanced.md @@ -224,3 +224,5 @@ for val in self.buy_ema_short.range: # Append columns to existing dataframe merged_frame = pd.concat(frames, axis=1) ``` + +Freqtrade does however also counter this by running `dataframe.copy()` on the dataframe right after the `populate_indicators()` method - so performance implications of this should be low to non-existant. From fada432f49611da259b720c58e0dfd8259936276 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 15 Jul 2022 19:48:12 +0200 Subject: [PATCH 437/449] Pin markdown docs dependency --- docs/requirements-docs.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 66e83a397..22d92c65d 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,3 +1,4 @@ +markdown==3.3.7 mkdocs==1.3.0 mkdocs-material==8.3.9 mdx_truly_sane_lists==1.2 From 1c7f60103db564fb5abf0ac0db83600e713c4586 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 15 Jul 2022 20:26:24 +0200 Subject: [PATCH 438/449] Don't use master for publish CI action --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4fe1ad853..7b077be04 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -351,7 +351,7 @@ jobs: python setup.py sdist bdist_wheel - name: Publish to PyPI (Test) - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@v1.5.0 if: (github.event_name == 'release') with: user: __token__ @@ -359,7 +359,7 @@ jobs: repository_url: https://test.pypi.org/legacy/ - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@v1.5.0 if: (github.event_name == 'release') with: user: __token__ From 29efe75a6fc307a7224017765134199bed7dc11e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 11:15:14 +0200 Subject: [PATCH 439/449] Update hyperoptable strategy to use V3 interface --- tests/rpc/test_rpc_apiserver.py | 1 + .../strategy/strats/hyperoptable_strategy.py | 4 +- .../strats/hyperoptable_strategy_v2.py | 54 +++++++++++++++++++ tests/strategy/test_interface.py | 2 +- tests/strategy/test_strategy_loading.py | 6 +-- 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 tests/strategy/strats/hyperoptable_strategy_v2.py diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index c0de54c6d..57c08f48e 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1398,6 +1398,7 @@ def test_api_strategies(botclient): assert rc.json() == {'strategies': [ 'HyperoptableStrategy', + 'HyperoptableStrategyV2', 'InformativeDecoratorTest', 'StrategyTestV2', 'StrategyTestV3', diff --git a/tests/strategy/strats/hyperoptable_strategy.py b/tests/strategy/strats/hyperoptable_strategy.py index 876b31b14..9850a5675 100644 --- a/tests/strategy/strats/hyperoptable_strategy.py +++ b/tests/strategy/strats/hyperoptable_strategy.py @@ -1,13 +1,13 @@ # pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement from pandas import DataFrame -from strategy_test_v2 import StrategyTestV2 +from strategy_test_v3 import StrategyTestV3 import freqtrade.vendor.qtpylib.indicators as qtpylib from freqtrade.strategy import BooleanParameter, DecimalParameter, IntParameter, RealParameter -class HyperoptableStrategy(StrategyTestV2): +class HyperoptableStrategy(StrategyTestV3): """ Default Strategy provided by freqtrade bot. Please do not modify this strategy, it's intended for internal use only. diff --git a/tests/strategy/strats/hyperoptable_strategy_v2.py b/tests/strategy/strats/hyperoptable_strategy_v2.py new file mode 100644 index 000000000..94a15b456 --- /dev/null +++ b/tests/strategy/strats/hyperoptable_strategy_v2.py @@ -0,0 +1,54 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement + +from strategy_test_v2 import StrategyTestV2 + +from freqtrade.strategy import BooleanParameter, DecimalParameter, IntParameter, RealParameter + + +class HyperoptableStrategyV2(StrategyTestV2): + """ + Default Strategy provided by freqtrade bot. + Please do not modify this strategy, it's intended for internal use only. + Please look at the SampleStrategy in the user_data/strategy directory + or strategy repository https://github.com/freqtrade/freqtrade-strategies + for samples and inspiration. + """ + + buy_params = { + 'buy_rsi': 35, + # Intentionally not specified, so "default" is tested + # 'buy_plusdi': 0.4 + } + + sell_params = { + 'sell_rsi': 74, + 'sell_minusdi': 0.4 + } + + buy_plusdi = RealParameter(low=0, high=1, default=0.5, space='buy') + sell_rsi = IntParameter(low=50, high=100, default=70, space='sell') + sell_minusdi = DecimalParameter(low=0, high=1, default=0.5001, decimals=3, space='sell', + load=False) + protection_enabled = BooleanParameter(default=True) + protection_cooldown_lookback = IntParameter([0, 50], default=30) + + @property + def protections(self): + prot = [] + if self.protection_enabled.value: + prot.append({ + "method": "CooldownPeriod", + "stop_duration_candles": self.protection_cooldown_lookback.value + }) + return prot + + bot_loop_started = False + + def bot_loop_start(self): + self.bot_loop_started = True + + def bot_start(self, **kwargs) -> None: + """ + Parameters can also be defined here ... + """ + self.buy_rsi = IntParameter([0, 50], default=30, space='buy') diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index dca87e724..f6996a7a2 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -916,7 +916,7 @@ def test_hyperopt_parameters(): def test_auto_hyperopt_interface(default_conf): - default_conf.update({'strategy': 'HyperoptableStrategy'}) + default_conf.update({'strategy': 'HyperoptableStrategyV2'}) PairLocks.timeframe = default_conf['timeframe'] strategy = StrategyResolver.load_strategy(default_conf) strategy.ft_bot_start() diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index 666ae2b05..bdfcf3211 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -34,7 +34,7 @@ def test_search_all_strategies_no_failed(): directory = Path(__file__).parent / "strats" strategies = StrategyResolver.search_all_objects(directory, enum_failed=False) assert isinstance(strategies, list) - assert len(strategies) == 6 + assert len(strategies) == 7 assert isinstance(strategies[0], dict) @@ -42,10 +42,10 @@ def test_search_all_strategies_with_failed(): directory = Path(__file__).parent / "strats" strategies = StrategyResolver.search_all_objects(directory, enum_failed=True) assert isinstance(strategies, list) - assert len(strategies) == 7 + assert len(strategies) == 8 # with enum_failed=True search_all_objects() shall find 2 good strategies # and 1 which fails to load - assert len([x for x in strategies if x['class'] is not None]) == 6 + assert len([x for x in strategies if x['class'] is not None]) == 7 assert len([x for x in strategies if x['class'] is None]) == 1 From 2e642593e5e737ab87c3097574a4cb8def66f448 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 11:23:37 +0200 Subject: [PATCH 440/449] Update formatting of hyperopt_conf fixture --- tests/optimize/conftest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/optimize/conftest.py b/tests/optimize/conftest.py index 8a9e0cbf0..9eb3a88cc 100644 --- a/tests/optimize/conftest.py +++ b/tests/optimize/conftest.py @@ -18,11 +18,11 @@ def hyperopt_conf(default_conf): 'runmode': RunMode.HYPEROPT, 'strategy': 'HyperoptableStrategy', 'hyperopt_loss': 'ShortTradeDurHyperOptLoss', - 'hyperopt_path': str(Path(__file__).parent / 'hyperopts'), - 'epochs': 1, - 'timerange': None, - 'spaces': ['default'], - 'hyperopt_jobs': 1, + 'hyperopt_path': str(Path(__file__).parent / 'hyperopts'), + 'epochs': 1, + 'timerange': None, + 'spaces': ['default'], + 'hyperopt_jobs': 1, 'hyperopt_min_trades': 1, }) return hyperconf From e53e53087491081b4b0f7e6f2f6c3afcd5ddefec Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 11:32:43 +0200 Subject: [PATCH 441/449] Add test showing broken inheritance hyperopt --- tests/optimize/test_hyperopt.py | 36 ++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 1ad8b33cf..fb5593ed2 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -855,7 +855,7 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None: 'strategy': 'HyperoptableStrategy', 'user_data_dir': Path(tmpdir), 'hyperopt_random_state': 42, - 'spaces': ['all'] + 'spaces': ['all'], }) hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.exchange.get_max_leverage = MagicMock(return_value=1.0) @@ -883,6 +883,40 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None: hyperopt.get_optimizer([], 2) +def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmpdir, fee) -> None: + # patch_exchange(mocker) + # TODO: This reaches out to the exchange! + mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) + (Path(tmpdir) / 'hyperopt_results').mkdir(parents=True) + # No hyperopt needed + hyperopt_conf.update({ + 'strategy': 'HyperoptableStrategy', + 'user_data_dir': Path(tmpdir), + 'hyperopt_random_state': 42, + 'spaces': ['all'], + # Enforce parallelity + 'epochs': 2, + 'hyperopt_jobs': 2, + 'fee': fee.return_value, + }) + hyperopt = Hyperopt(hyperopt_conf) + hyperopt.backtesting.exchange.get_max_leverage = lambda *x, **xx: 1.0 + assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto) + assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter) + assert hyperopt.backtesting.strategy.bot_loop_started is True + + assert hyperopt.backtesting.strategy.buy_rsi.in_space is True + assert hyperopt.backtesting.strategy.buy_rsi.value == 35 + assert hyperopt.backtesting.strategy.sell_rsi.value == 74 + assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30 + buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range + assert isinstance(buy_rsi_range, range) + # Range from 0 - 50 (inclusive) + assert len(list(buy_rsi_range)) == 51 + + hyperopt.start() + + def test_SKDecimal(): space = SKDecimal(1, 2, decimals=2) assert 1.5 in space From 40e2da10f35f7b2769df9278d050f912d2650a39 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 11:05:58 +0200 Subject: [PATCH 442/449] Add hypeorpt cloudpickle magic closes #7078 --- freqtrade/optimize/hyperopt.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 7c7493590..566412f29 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -6,6 +6,7 @@ This module contains the hyperopt logic import logging import random +import sys import warnings from datetime import datetime, timezone from math import ceil @@ -17,6 +18,7 @@ import rapidjson from colorama import Fore, Style from colorama import init as colorama_init from joblib import Parallel, cpu_count, delayed, dump, load, wrap_non_picklable_objects +from joblib.externals import cloudpickle from pandas import DataFrame from freqtrade.constants import DATETIME_PRINT_FORMAT, FTHYPT_FILEVERSION, LAST_BT_RESULT_FN @@ -87,6 +89,7 @@ class Hyperopt: self.backtesting._set_strategy(self.backtesting.strategylist[0]) self.custom_hyperopt.strategy = self.backtesting.strategy + self.hyperopt_pickle_magic(self.backtesting.strategy.__class__.__bases__) self.custom_hyperoptloss: IHyperOptLoss = HyperOptLossResolver.load_hyperoptloss( self.config) self.calculate_loss = self.custom_hyperoptloss.hyperopt_loss_function @@ -137,6 +140,17 @@ class Hyperopt: logger.info(f"Removing `{p}`.") p.unlink() + def hyperopt_pickle_magic(self, bases) -> None: + """ + Hyperopt magic to allow strategy inheritance across files. + For this to properly work, we need to register the module of the imported class + to pickle as value. + """ + for modules in bases: + if modules.__name__ != 'IStrategy': + cloudpickle.register_pickle_by_value(sys.modules[modules.__module__]) + self.hyperopt_pickle_magic(modules.__bases__) + def _get_params_dict(self, dimensions: List[Dimension], raw_params: List[Any]) -> Dict: # Ensure the number of dimensions match From 7c4dd4c48c7257f433669522ff1bd14be9d8133a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 15 Jul 2022 09:54:53 +0200 Subject: [PATCH 443/449] Support fee cost as string closes #7056 --- freqtrade/exchange/exchange.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index cd13964c4..f6b85436d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1646,7 +1646,7 @@ class Exchange: fee_curr = fee.get('currency') if fee_curr is None: return None - fee_cost = fee['cost'] + fee_cost = float(fee['cost']) if self._ft_has['fee_cost_in_contracts']: # Convert cost via "contracts" conversion fee_cost = self._contracts_to_amount(symbol, fee['cost']) @@ -1654,7 +1654,7 @@ class Exchange: # Calculate fee based on order details if fee_curr == self.get_pair_base_currency(symbol): # Base currency - divide by amount - return round(fee['cost'] / amount, 8) + return round(fee_cost / amount, 8) elif fee_curr == self.get_pair_quote_currency(symbol): # Quote currency - divide by cost return round(fee_cost / cost, 8) if cost else None @@ -1685,7 +1685,7 @@ class Exchange: :param amount: Amount of the order :return: Tuple with cost, currency, rate of the given fee dict """ - return (fee['cost'], + return (float(fee['cost']), fee['currency'], self.calculate_fee_rate( fee, From 7b8a5585dd6b2cb7cbfc550c30d2353af3869616 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 15 Jul 2022 14:35:49 +0200 Subject: [PATCH 444/449] Fetch 2ndary stoploss order once the order triggered. --- freqtrade/exchange/gateio.py | 14 +++++++++++++- tests/exchange/test_gateio.py | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index b9de212de..f46508022 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -97,11 +97,23 @@ class Gateio(Exchange): return trades def fetch_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: - return self.fetch_order( + order = self.fetch_order( order_id=order_id, pair=pair, params={'stop': True} ) + if self.trading_mode == TradingMode.FUTURES: + if order['status'] == 'closed': + # Places a real order - which we need to fetch explicitly. + new_orderid = order.get('info', {}).get('trade_id') + if new_orderid: + order1 = self.fetch_order(order_id=new_orderid, pair=pair, params=params) + order1['id_stop'] = order1['id'] + order1['id'] = order_id + order1['stopPrice'] = order.get('stopPrice') + + return order1 + return order def cancel_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: return self.cancel_order( diff --git a/tests/exchange/test_gateio.py b/tests/exchange/test_gateio.py index cbd4776fb..dabdbba65 100644 --- a/tests/exchange/test_gateio.py +++ b/tests/exchange/test_gateio.py @@ -53,6 +53,25 @@ def test_fetch_stoploss_order_gateio(default_conf, mocker): assert fetch_order_mock.call_args_list[0][1]['pair'] == 'ETH/BTC' assert fetch_order_mock.call_args_list[0][1]['params'] == {'stop': True} + default_conf['trading_mode'] = 'futures' + default_conf['margin_mode'] = 'isolated' + + exchange = get_patched_exchange(mocker, default_conf, id='gateio') + + exchange.fetch_order = MagicMock(return_value={ + 'status': 'closed', + 'id': '1234', + 'stopPrice': 5.62, + 'info': { + 'trade_id': '222555' + } + }) + + exchange.fetch_stoploss_order('1234', 'ETH/BTC') + assert exchange.fetch_order.call_count == 2 + assert exchange.fetch_order.call_args_list[0][1]['order_id'] == '1234' + assert exchange.fetch_order.call_args_list[1][1]['order_id'] == '222555' + def test_cancel_stoploss_order_gateio(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf, id='gateio') From 415780a4fe1c37785ebe26c398762f467ed5b570 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 11:58:38 +0200 Subject: [PATCH 445/449] gateio order cost is not in contracts closes #7081 --- freqtrade/exchange/exchange.py | 3 ++- freqtrade/exchange/gateio.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index f6b85436d..7ac45bcc9 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -79,6 +79,7 @@ class Exchange: "ccxt_futures_name": "swap", "fee_cost_in_contracts": False, # Fee cost needs contract conversion "needs_trading_fees": False, # use fetch_trading_fees to cache fees + "order_props_in_contracts": ['amount', 'cost', 'filled', 'remaining'], } _ft_has: Dict = {} _ft_has_futures: Dict = {} @@ -423,7 +424,7 @@ class Exchange: if 'symbol' in order and order['symbol'] is not None: contract_size = self._get_contract_size(order['symbol']) if contract_size != 1: - for prop in ['amount', 'cost', 'filled', 'remaining']: + for prop in self._ft_has.get('order_props_in_contracts', []): if prop in order and order[prop] is not None: order[prop] = order[prop] * contract_size return order diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index f46508022..c049ce4cc 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -34,6 +34,7 @@ class Gateio(Exchange): _ft_has_futures: Dict = { "needs_trading_fees": True, "fee_cost_in_contracts": False, # Set explicitly to false for clarity + "order_props_in_contracts": ['amount', 'filled', 'remaining'], } _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ From ed64e4299bb6b728513f3063a56e6fceda777e90 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 12:52:35 +0200 Subject: [PATCH 446/449] Stoploss orders should also be eligible to update closed fees --- freqtrade/exchange/gateio.py | 8 +++++++- freqtrade/freqtradebot.py | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index c049ce4cc..6df3425d2 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -1,12 +1,13 @@ """ Gate.io exchange subclass """ import logging from datetime import datetime -from typing import Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, TradingMode from freqtrade.exceptions import OperationalException from freqtrade.exchange import Exchange +from freqtrade.misc import safe_value_fallback2 logger = logging.getLogger(__name__) @@ -97,6 +98,11 @@ class Gateio(Exchange): } return trades + def get_order_id_conditional(self, order: Dict[str, Any]) -> str: + if self.trading_mode == TradingMode.FUTURES: + return safe_value_fallback2(order, order, 'id_stop', 'id') + return order['id'] + def fetch_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict: order = self.fetch_order( order_id=order_id, diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 469bfda7e..2007f9b4e 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -332,6 +332,8 @@ class FreqtradeBot(LoggingMixin): if not trade.is_open and not trade.fee_updated(trade.exit_side): # Get sell fee order = trade.select_order(trade.exit_side, False) + if not order: + order = trade.select_order('stoploss', False) if order: logger.info( f"Updating {trade.exit_side}-fee on trade {trade}" From d03dfb393497fe63b042ebd22d932a0bcabcbfec Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 13:12:50 +0200 Subject: [PATCH 447/449] Oder cost is real cost (including leverage) --- freqtrade/exchange/exchange.py | 2 +- tests/exchange/test_exchange.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 7ac45bcc9..43fbbe28b 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -822,7 +822,7 @@ class Exchange: 'price': rate, 'average': rate, 'amount': _amount, - 'cost': _amount * rate / leverage, + 'cost': _amount * rate, 'type': ordertype, 'side': side, 'filled': 0, diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index acd48b3fd..bf4f44440 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1135,7 +1135,7 @@ def test_create_dry_run_order(default_conf, mocker, side, exchange_name, leverag assert order["symbol"] == "ETH/BTC" assert order["amount"] == 1 assert order["leverage"] == leverage - assert order["cost"] == 1 * 200 / leverage + assert order["cost"] == 1 * 200 @pytest.mark.parametrize("side,startprice,endprice", [ From 357000c478a078a22d09345887ee9955d41b9abe Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 13:27:13 +0200 Subject: [PATCH 448/449] Extract exchange validation to separate method --- freqtrade/exchange/exchange.py | 28 +++++++++++++++------------- tests/conftest.py | 5 +---- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index cd13964c4..505d02e8c 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -175,23 +175,11 @@ class Exchange: logger.info(f'Using Exchange "{self.name}"') if validate: - # Check if timeframe is available - self.validate_timeframes(config.get('timeframe')) - # Initial markets load self._load_markets() - - # Check if all pairs are available - self.validate_stakecurrency(config['stake_currency']) - if not exchange_config.get('skip_pair_validation'): - self.validate_pairs(config['exchange']['pair_whitelist']) - self.validate_ordertypes(config.get('order_types', {})) - self.validate_order_time_in_force(config.get('order_time_in_force', {})) + self.validate_config(config) self.required_candle_call_count = self.validate_required_startup_candles( config.get('startup_candle_count', 0), config.get('timeframe', '')) - self.validate_trading_mode_and_margin_mode(self.trading_mode, self.margin_mode) - self.validate_pricing(config['exit_pricing']) - self.validate_pricing(config['entry_pricing']) # Converts the interval provided in minutes in config to seconds self.markets_refresh_interval: int = exchange_config.get( @@ -214,6 +202,20 @@ class Exchange: logger.info("Closing async ccxt session.") self.loop.run_until_complete(self._api_async.close()) + def validate_config(self, config): + # Check if timeframe is available + self.validate_timeframes(config.get('timeframe')) + + # Check if all pairs are available + self.validate_stakecurrency(config['stake_currency']) + if not config['exchange'].get('skip_pair_validation'): + self.validate_pairs(config['exchange']['pair_whitelist']) + self.validate_ordertypes(config.get('order_types', {})) + self.validate_order_time_in_force(config.get('order_time_in_force', {})) + self.validate_trading_mode_and_margin_mode(self.trading_mode, self.margin_mode) + self.validate_pricing(config['exit_pricing']) + self.validate_pricing(config['entry_pricing']) + def _init_ccxt(self, exchange_config: Dict[str, Any], ccxt_module: CcxtModuleType = ccxt, ccxt_kwargs: Dict = {}) -> ccxt.Exchange: """ diff --git a/tests/conftest.py b/tests/conftest.py index 0cf32545f..3158e9ede 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -112,11 +112,8 @@ def patch_exchange( mock_supported_modes=True ) -> None: mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock(return_value={})) - mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) + mocker.patch('freqtrade.exchange.Exchange.validate_config', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) - mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock()) - mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency', MagicMock()) - mocker.patch('freqtrade.exchange.Exchange.validate_pricing') mocker.patch('freqtrade.exchange.Exchange.id', PropertyMock(return_value=id)) mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value=id.title())) mocker.patch('freqtrade.exchange.Exchange.precisionMode', PropertyMock(return_value=2)) From bf07d8fe879ca592db74b1bf61bb59cd8441bee4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jul 2022 13:57:04 +0200 Subject: [PATCH 449/449] Update test to properly patch/mock exchange --- tests/optimize/test_hyperopt.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index fb5593ed2..0f615b7a3 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -1,7 +1,7 @@ # pragma pylint: disable=missing-docstring,W0212,C0103 from datetime import datetime, timedelta from pathlib import Path -from unittest.mock import ANY, MagicMock +from unittest.mock import ANY, MagicMock, PropertyMock import pandas as pd import pytest @@ -18,8 +18,8 @@ from freqtrade.optimize.hyperopt_tools import HyperoptTools from freqtrade.optimize.optimize_reports import generate_strategy_stats from freqtrade.optimize.space import SKDecimal from freqtrade.strategy import IntParameter -from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, log_has, log_has_re, patch_exchange, - patched_configuration_load_config_file) +from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, get_markets, log_has, log_has_re, + patch_exchange, patched_configuration_load_config_file) def generate_result_metrics(): @@ -884,9 +884,11 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None: def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmpdir, fee) -> None: - # patch_exchange(mocker) - # TODO: This reaches out to the exchange! + mocker.patch('freqtrade.exchange.Exchange.validate_config', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) + mocker.patch('freqtrade.exchange.Exchange._load_markets') + mocker.patch('freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=get_markets())) (Path(tmpdir) / 'hyperopt_results').mkdir(parents=True) # No hyperopt needed hyperopt_conf.update({ @@ -901,6 +903,9 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmpdir, }) hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.exchange.get_max_leverage = lambda *x, **xx: 1.0 + hyperopt.backtesting.exchange.get_min_pair_stake_amount = lambda *x, **xx: 1.0 + hyperopt.backtesting.exchange.get_max_pair_stake_amount = lambda *x, **xx: 100.0 + assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto) assert isinstance(hyperopt.backtesting.strategy.buy_rsi, IntParameter) assert hyperopt.backtesting.strategy.bot_loop_started is True