From a3dee9350f2a4c9f17491b402a4613c66cc1e3d0 Mon Sep 17 00:00:00 2001 From: Andy Lawless Date: Fri, 3 Mar 2023 20:37:05 +0000 Subject: [PATCH 01/63] Move bot_loop_start call to run on every candle --- 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 83b65d24b..ccb027317 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -205,7 +205,6 @@ 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): @@ -1159,6 +1158,7 @@ class Backtesting: while current_time <= end_date: open_trade_count_start = LocalTrade.bt_open_open_trade_count self.check_abort() + strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)() for i, pair in enumerate(data): row_index = indexes[pair] row = self.validate_row(data, pair, row_index, current_time) From b262f0b3742033df7688e5ffb1d3affede620090 Mon Sep 17 00:00:00 2001 From: Andy Lawless Date: Fri, 3 Mar 2023 20:46:43 +0000 Subject: [PATCH 02/63] Update docs re: bot_loop_start in backtest --- docs/bot-basics.md | 2 +- docs/strategy-callbacks.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/bot-basics.md b/docs/bot-basics.md index 925fc7862..1d5668eb3 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -57,10 +57,10 @@ This loop will be repeated again and again until the bot is stopped. * 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). * Loops per candle simulating entry and exit points. + * Calls `bot_loop_start()` strategy callback. * 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). diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 81366c66e..64b6bd551 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -51,7 +51,8 @@ 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). +A simple callback which is called once at the start of every bot throttling iteration in dry/live mode (roughly every 5 +seconds, unless configured differently) or once per candle in backtest/hyperopt mode. This can be used to perform calculations which are pair independent (apply to all pairs), loading of external data, etc. ``` python From e16db814fad1b55c168965027185b68a6f94b083 Mon Sep 17 00:00:00 2001 From: Joe Schr <8218910+TheJoeSchr@users.noreply.github.com> Date: Tue, 21 Mar 2023 17:52:14 +0100 Subject: [PATCH 03/63] featherdatahandler: implement trades_store/_trades_load --- freqtrade/data/history/featherdatahandler.py | 26 ++--- tests/data/test_datahandler.py | 108 +++++++++++++++---- tests/testdata/XRP_ETH-trades.feather | Bin 0 -> 374570 bytes 3 files changed, 102 insertions(+), 32 deletions(-) create mode 100644 tests/testdata/XRP_ETH-trades.feather diff --git a/freqtrade/data/history/featherdatahandler.py b/freqtrade/data/history/featherdatahandler.py index 22a6805e7..87c1d0886 100644 --- a/freqtrade/data/history/featherdatahandler.py +++ b/freqtrade/data/history/featherdatahandler.py @@ -4,8 +4,9 @@ from typing import Optional from pandas import DataFrame, read_feather, to_datetime from freqtrade.configuration import TimeRange -from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, TradeList +from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, TradeList, DEFAULT_TRADES_COLUMNS from freqtrade.enums import CandleType +from freqtrade.data.converter import trades_dict_to_list from .idatahandler import IDataHandler @@ -29,7 +30,8 @@ class FeatherDataHandler(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, timeframe, candle_type) self.create_dir_if_needed(filename) data.reset_index(drop=True).loc[:, self._columns].to_feather( @@ -92,12 +94,11 @@ class FeatherDataHandler(IDataHandler): :param data: List of Lists containing trade data, column sequence as in DEFAULT_TRADES_COLUMNS """ - # filename = self._pair_trades_filename(self._datadir, pair) + filename = self._pair_trades_filename(self._datadir, pair) + self.create_dir_if_needed(filename) - raise NotImplementedError() - # array = pa.array(data) - # array - # feather.write_feather(data, filename) + tradesdata = DataFrame(data, columns=DEFAULT_TRADES_COLUMNS) + tradesdata.to_feather(filename, compression_level=9, compression='lz4') def trades_append(self, pair: str, data: TradeList): """ @@ -116,14 +117,13 @@ class FeatherDataHandler(IDataHandler): :param timerange: Timerange to load trades for - currently not implemented :return: List of trades """ - raise NotImplementedError() - # filename = self._pair_trades_filename(self._datadir, pair) - # tradesdata = misc.file_load_json(filename) + filename = self._pair_trades_filename(self._datadir, pair) + if not filename.exists(): + return [] - # if not tradesdata: - # return [] + tradesdata = read_feather(filename) - # return tradesdata + return tradesdata.values.tolist() @classmethod def _get_file_extension(cls): diff --git a/tests/data/test_datahandler.py b/tests/data/test_datahandler.py index f673ede6e..2c5241367 100644 --- a/tests/data/test_datahandler.py +++ b/tests/data/test_datahandler.py @@ -20,25 +20,31 @@ from tests.conftest import log_has, log_has_re def test_datahandler_ohlcv_get_pairs(testdatadir): - pairs = JsonDataHandler.ohlcv_get_pairs(testdatadir, '5m', candle_type=CandleType.SPOT) + pairs = JsonDataHandler.ohlcv_get_pairs( + testdatadir, '5m', candle_type=CandleType.SPOT) # Convert to set to avoid failures due to sorting assert set(pairs) == {'UNITTEST/BTC', 'XLM/BTC', 'ETH/BTC', 'TRX/BTC', 'LTC/BTC', 'XMR/BTC', 'ZEC/BTC', 'ADA/BTC', 'ETC/BTC', 'NXT/BTC', 'DASH/BTC', 'XRP/ETH'} - pairs = JsonGzDataHandler.ohlcv_get_pairs(testdatadir, '8m', candle_type=CandleType.SPOT) + pairs = JsonGzDataHandler.ohlcv_get_pairs( + testdatadir, '8m', candle_type=CandleType.SPOT) assert set(pairs) == {'UNITTEST/BTC'} - pairs = HDF5DataHandler.ohlcv_get_pairs(testdatadir, '5m', candle_type=CandleType.SPOT) + pairs = HDF5DataHandler.ohlcv_get_pairs( + testdatadir, '5m', candle_type=CandleType.SPOT) assert set(pairs) == {'UNITTEST/BTC'} - pairs = JsonDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.MARK) + pairs = JsonDataHandler.ohlcv_get_pairs( + testdatadir, '1h', candle_type=CandleType.MARK) assert set(pairs) == {'UNITTEST/USDT:USDT', 'XRP/USDT:USDT'} - pairs = JsonGzDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.FUTURES) + pairs = JsonGzDataHandler.ohlcv_get_pairs( + testdatadir, '1h', candle_type=CandleType.FUTURES) assert set(pairs) == {'XRP/USDT:USDT'} - pairs = HDF5DataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.MARK) + pairs = HDF5DataHandler.ohlcv_get_pairs( + testdatadir, '1h', candle_type=CandleType.MARK) assert set(pairs) == {'UNITTEST/USDT:USDT'} @@ -79,7 +85,8 @@ def test_rebuild_pair_from_filename(input, expected): def test_datahandler_ohlcv_get_available_data(testdatadir): - paircombs = JsonDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT) + paircombs = JsonDataHandler.ohlcv_get_available_data( + testdatadir, TradingMode.SPOT) # Convert to set to avoid failures due to sorting assert set(paircombs) == { ('UNITTEST/BTC', '5m', CandleType.SPOT), @@ -101,7 +108,8 @@ def test_datahandler_ohlcv_get_available_data(testdatadir): ('NOPAIR/XXX', '4m', CandleType.SPOT), } - paircombs = JsonDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.FUTURES) + paircombs = JsonDataHandler.ohlcv_get_available_data( + testdatadir, TradingMode.FUTURES) # Convert to set to avoid failures due to sorting assert set(paircombs) == { ('UNITTEST/USDT:USDT', '1h', 'mark'), @@ -112,9 +120,11 @@ def test_datahandler_ohlcv_get_available_data(testdatadir): ('XRP/USDT:USDT', '8h', 'funding_rate'), } - paircombs = JsonGzDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT) + paircombs = JsonGzDataHandler.ohlcv_get_available_data( + testdatadir, TradingMode.SPOT) assert set(paircombs) == {('UNITTEST/BTC', '8m', CandleType.SPOT)} - paircombs = HDF5DataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT) + paircombs = HDF5DataHandler.ohlcv_get_available_data( + testdatadir, TradingMode.SPOT) assert set(paircombs) == {('UNITTEST/BTC', '5m', CandleType.SPOT)} @@ -252,7 +262,7 @@ def test_datahandler__check_empty_df(testdatadir, caplog): assert log_has_re(expected_text, caplog) -@pytest.mark.parametrize('datahandler', ['feather', 'parquet']) +@pytest.mark.parametrize('datahandler', ['parquet']) def test_datahandler_trades_not_supported(datahandler, testdatadir, ): dh = get_datahandler(testdatadir, datahandler) with pytest.raises(NotImplementedError): @@ -406,18 +416,21 @@ def test_hdf5datahandler_ohlcv_load_and_resave( assert not ohlcv[ohlcv['date'] < startdt].empty - timerange = TimeRange.parse_timerange(f"{startdt.replace('-', '')}-{enddt.replace('-', '')}") + timerange = TimeRange.parse_timerange( + f"{startdt.replace('-', '')}-{enddt.replace('-', '')}") # Call private function to ensure timerange is filtered in hdf5 ohlcv = dh._ohlcv_load(pair, timeframe, timerange, candle_type=candle_type) - ohlcv1 = dh1._ohlcv_load('UNITTEST/NEW', timeframe, timerange, candle_type=candle_type) + ohlcv1 = dh1._ohlcv_load('UNITTEST/NEW', timeframe, + timerange, candle_type=candle_type) assert len(ohlcv) == len(ohlcv1) assert ohlcv.equals(ohlcv1) assert ohlcv[ohlcv['date'] < startdt].empty assert ohlcv[ohlcv['date'] > enddt].empty # Try loading inexisting file - ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', timeframe, candle_type=candle_type) + ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', timeframe, + candle_type=candle_type) assert ohlcv.empty @@ -452,7 +465,8 @@ def test_generic_datahandler_ohlcv_load_and_resave( # Get data to test dh = get_datahandler(testdatadir, datahandler) - file = tmpdir2 / f"UNITTEST_NEW-{timeframe}{candle_append}.{dh._get_file_extension()}" + file = tmpdir2 / \ + f"UNITTEST_NEW-{timeframe}{candle_append}.{dh._get_file_extension()}" assert not file.is_file() dh1 = get_datahandler(tmpdir1, datahandler) @@ -461,11 +475,14 @@ def test_generic_datahandler_ohlcv_load_and_resave( assert not ohlcv[ohlcv['date'] < startdt].empty - timerange = TimeRange.parse_timerange(f"{startdt.replace('-', '')}-{enddt.replace('-', '')}") + timerange = TimeRange.parse_timerange( + f"{startdt.replace('-', '')}-{enddt.replace('-', '')}") - ohlcv = dhbase.ohlcv_load(pair, timeframe, timerange=timerange, candle_type=candle_type) + ohlcv = dhbase.ohlcv_load( + pair, timeframe, timerange=timerange, candle_type=candle_type) if datahandler == 'hdf5': - ohlcv1 = dh1._ohlcv_load('UNITTEST/NEW', timeframe, timerange, candle_type=candle_type) + ohlcv1 = dh1._ohlcv_load( + 'UNITTEST/NEW', timeframe, timerange, candle_type=candle_type) if candle_type == 'mark': ohlcv1['volume'] = 0.0 else: @@ -478,7 +495,8 @@ def test_generic_datahandler_ohlcv_load_and_resave( assert ohlcv[ohlcv['date'] > enddt].empty # Try loading inexisting file - ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', timeframe, candle_type=candle_type) + ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', timeframe, + candle_type=candle_type) assert ohlcv.empty @@ -496,6 +514,58 @@ def test_hdf5datahandler_ohlcv_purge(mocker, testdatadir): assert unlinkmock.call_count == 2 +def test_featherdatahandler_trades_load(testdatadir): + dh = get_datahandler(testdatadir, 'feather') + trades = dh.trades_load('XRP/ETH') + assert isinstance(trades, list) + assert trades[0][0] == 1570752011620 + assert trades[-1][-1] == 0.1986231 + + trades1 = dh.trades_load('UNITTEST/NONEXIST') + assert trades1 == [] + + +def test_featherdatahandler_trades_store(testdatadir, tmpdir): + tmpdir1 = Path(tmpdir) + dh = get_datahandler(testdatadir, 'feather') + trades = dh.trades_load('XRP/ETH') + + dh1 = get_datahandler(tmpdir1, 'feather') + dh1.trades_store('XRP/NEW', trades) + file = tmpdir1 / 'XRP_NEW-trades.feather' + assert file.is_file() + # Load trades back + trades_new = dh1.trades_load('XRP/NEW') + + assert len(trades_new) == len(trades) + assert trades[0][0] == trades_new[0][0] + assert trades[0][1] == trades_new[0][1] + # assert trades[0][2] == trades_new[0][2] # This is nan - so comparison does not make sense + assert trades[0][3] == trades_new[0][3] + assert trades[0][4] == trades_new[0][4] + assert trades[0][5] == trades_new[0][5] + assert trades[0][6] == trades_new[0][6] + assert trades[-1][0] == trades_new[-1][0] + assert trades[-1][1] == trades_new[-1][1] + # assert trades[-1][2] == trades_new[-1][2] # This is nan - so comparison does not make sense + assert trades[-1][3] == trades_new[-1][3] + assert trades[-1][4] == trades_new[-1][4] + assert trades[-1][5] == trades_new[-1][5] + assert trades[-1][6] == trades_new[-1][6] + + +def test_featherdatahandler_trades_purge(mocker, testdatadir): + mocker.patch.object(Path, "exists", MagicMock(return_value=False)) + unlinkmock = mocker.patch.object(Path, "unlink", MagicMock()) + dh = get_datahandler(testdatadir, 'feather') + assert not dh.trades_purge('UNITTEST/NONEXIST') + assert unlinkmock.call_count == 0 + + mocker.patch.object(Path, "exists", MagicMock(return_value=True)) + assert dh.trades_purge('UNITTEST/NONEXIST') + assert unlinkmock.call_count == 1 + + def test_gethandlerclass(): cl = get_datahandlerclass('json') assert cl == JsonDataHandler diff --git a/tests/testdata/XRP_ETH-trades.feather b/tests/testdata/XRP_ETH-trades.feather new file mode 100644 index 0000000000000000000000000000000000000000..68e1c8467193123cc540f7b794d14aa151a2168f GIT binary patch literal 374570 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π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 literal 0 HcmV?d00001 From 0128b63c1c44a339ac8b92ccac7322c6a1e885c9 Mon Sep 17 00:00:00 2001 From: Joe Schr <8218910+TheJoeSchr@users.noreply.github.com> Date: Tue, 21 Mar 2023 19:12:25 +0100 Subject: [PATCH 04/63] add 'feather' to AVAILABLE_DATAHANDLERS_TRADES --- freqtrade/constants.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 46e9b5cd4..ebb946221 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -36,9 +36,10 @@ AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList', 'ProducerPairList', ' 'AgeFilter', 'OffsetFilter', 'PerformanceFilter', 'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter', 'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter'] -AVAILABLE_PROTECTIONS = ['CooldownPeriod', 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard'] -AVAILABLE_DATAHANDLERS_TRADES = ['json', 'jsongz', 'hdf5'] -AVAILABLE_DATAHANDLERS = AVAILABLE_DATAHANDLERS_TRADES + ['feather', 'parquet'] +AVAILABLE_PROTECTIONS = ['CooldownPeriod', + 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard'] +AVAILABLE_DATAHANDLERS_TRADES = ['json', 'jsongz', 'hdf5', 'feather'] +AVAILABLE_DATAHANDLERS = AVAILABLE_DATAHANDLERS_TRADES + ['parquet'] BACKTEST_BREAKDOWNS = ['day', 'week', 'month'] BACKTEST_CACHE_AGE = ['none', 'day', 'week', 'month'] BACKTEST_CACHE_DEFAULT = 'day' From bdf19f1d6622272c4f607080eea347854e13ac02 Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Tue, 21 Mar 2023 22:44:56 +0100 Subject: [PATCH 05/63] Update freqai_interface.py --- freqtrade/freqai/freqai_interface.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 07c357de3..8e842b8f2 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -105,6 +105,10 @@ class IFreqaiModel(ABC): self.max_system_threads = max(int(psutil.cpu_count() * 2 - 2), 1) self.can_short = True # overridden in start() with strategy.can_short self.model: Any = None + if self.ft_params.get('principal_component_analysis', False) and self.continual_learning: + self.ft_params.update({'principal_component_analysis': False}) + logger.warning('User tried to use PCA with continual learning. Deactivating PCA.') + record_params(config, self.full_path) @@ -154,8 +158,7 @@ class IFreqaiModel(ABC): dk = self.start_backtesting(dataframe, metadata, self.dk, strategy) dataframe = dk.remove_features_from_df(dk.return_dataframe) else: - logger.info( - "Backtesting using historic predictions (live models)") + logger.info("Backtesting using historic predictions (live models)") dk = self.start_backtesting_from_historic_predictions( dataframe, metadata, self.dk) dataframe = dk.return_dataframe From 0ece73578c67c64bf83147bc87f9e36e6f502aae Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 20 Sep 2022 19:51:42 +0200 Subject: [PATCH 06/63] Add typedDict for RPC messages Currently not fully functional. --- freqtrade/freqtradebot.py | 10 ++-- freqtrade/rpc/api_server/webserver.py | 5 +- freqtrade/rpc/rpc.py | 3 +- freqtrade/rpc/rpc_manager.py | 5 +- freqtrade/rpc/rpc_types.py | 82 +++++++++++++++++++++++++++ freqtrade/rpc/telegram.py | 3 +- freqtrade/rpc/webhook.py | 5 +- 7 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 freqtrade/rpc/rpc_types.py diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 623d39c09..28dd1fae5 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -30,6 +30,7 @@ from freqtrade.plugins.protectionmanager import ProtectionManager from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.rpc import RPCManager from freqtrade.rpc.external_message_consumer import ExternalMessageConsumer +from freqtrade.rpc.rpc_types import RPCBuyMsg, RPCCancelMsg, RPCSellCancelMsg, RPCSellMsg from freqtrade.strategy.interface import IStrategy from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.util import FtPrecise @@ -957,7 +958,7 @@ class FreqtradeBot(LoggingMixin): current_rate = self.exchange.get_rate( trade.pair, side='entry', is_short=trade.is_short, refresh=False) - msg = { + msg: RPCBuyMsg = { 'trade_id': trade.id, 'type': msg_type, 'buy_tag': trade.enter_tag, @@ -989,7 +990,7 @@ class FreqtradeBot(LoggingMixin): current_rate = self.exchange.get_rate( trade.pair, side='entry', is_short=trade.is_short, refresh=False) - msg = { + msg: RPCCancelMsg = { 'trade_id': trade.id, 'type': RPCMessageType.ENTRY_CANCEL, 'buy_tag': trade.enter_tag, @@ -1001,6 +1002,7 @@ class FreqtradeBot(LoggingMixin): 'limit': trade.open_rate, 'order_type': order_type, 'stake_amount': trade.stake_amount, + 'open_rate': trade.open_rate, 'stake_currency': self.config['stake_currency'], 'fiat_currency': self.config.get('fiat_display_currency', None), 'amount': trade.amount, @@ -1666,7 +1668,7 @@ class FreqtradeBot(LoggingMixin): amount = trade.amount gain = "profit" if profit_ratio > 0 else "loss" - msg = { + msg: RPCSellMsg = { 'type': (RPCMessageType.EXIT_FILL if fill else RPCMessageType.EXIT), 'trade_id': trade.id, @@ -1722,7 +1724,7 @@ class FreqtradeBot(LoggingMixin): profit_ratio = trade.calc_profit_ratio(profit_rate) gain = "profit" if profit_ratio > 0 else "loss" - msg = { + msg: RPCSellCancelMsg = { 'type': RPCMessageType.EXIT_CANCEL, 'trade_id': trade.id, 'exchange': trade.exchange.capitalize(), diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py index b53662451..2413e5264 100644 --- a/freqtrade/rpc/api_server/webserver.py +++ b/freqtrade/rpc/api_server/webserver.py @@ -1,6 +1,6 @@ import logging from ipaddress import IPv4Address -from typing import Any, Dict, Optional +from typing import Any, Optional import orjson import uvicorn @@ -13,6 +13,7 @@ from freqtrade.exceptions import OperationalException from freqtrade.rpc.api_server.uvicorn_threaded import UvicornServer from freqtrade.rpc.api_server.ws.message_stream import MessageStream from freqtrade.rpc.rpc import RPC, RPCException, RPCHandler +from freqtrade.rpc.rpc_types import RPCSendMsg logger = logging.getLogger(__name__) @@ -108,7 +109,7 @@ class ApiServer(RPCHandler): cls._has_rpc = False cls._rpc = None - def send_msg(self, msg: Dict[str, Any]) -> None: + def send_msg(self, msg: RPCSendMsg) -> None: """ Publish the message to the message stream """ diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index c6a6f5cae..2b5eb107c 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -30,6 +30,7 @@ from freqtrade.persistence import Order, PairLocks, Trade from freqtrade.persistence.models import PairLock from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist from freqtrade.rpc.fiat_convert import CryptoToFiatConverter +from freqtrade.rpc.rpc_types import RPCSendMsg from freqtrade.wallets import PositionWallet, Wallet @@ -79,7 +80,7 @@ class RPCHandler: """ Cleanup pending module resources """ @abstractmethod - def send_msg(self, msg: Dict[str, str]) -> None: + def send_msg(self, msg: RPCSendMsg) -> None: """ Sends a message to all registered rpc modules """ diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index c4d4fa2dd..e4c925995 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -3,11 +3,12 @@ This module contains class to manage RPC communications (Telegram, API, ...) """ import logging from collections import deque -from typing import Any, Dict, List +from typing import List from freqtrade.constants import Config from freqtrade.enums import NO_ECHO_MESSAGES, RPCMessageType from freqtrade.rpc import RPC, RPCHandler +from freqtrade.rpc.rpc_types import RPCSendMsg logger = logging.getLogger(__name__) @@ -58,7 +59,7 @@ class RPCManager: mod.cleanup() del mod - def send_msg(self, msg: Dict[str, Any]) -> None: + def send_msg(self, msg: RPCSendMsg) -> None: """ Send given message to all registered rpc modules. A message consists of one or more key value pairs of strings. diff --git a/freqtrade/rpc/rpc_types.py b/freqtrade/rpc/rpc_types.py new file mode 100644 index 000000000..0fb5a6bfa --- /dev/null +++ b/freqtrade/rpc/rpc_types.py @@ -0,0 +1,82 @@ +from datetime import datetime +from typing import Optional, TypedDict, Union + +from freqtrade.enums import RPCMessageType + + +class RPCSendMsgBase(TypedDict): + type: RPCMessageType + + +class RPCStatusMsg(RPCSendMsgBase): + """Used for Status, Startup and Warning messages""" + status: str + + +class RPCProtectionMsg(RPCSendMsgBase): + id: int + pair: str + base_currency: Optional[str] + lock_time: str + lock_timestamp: int + lock_end_time: str + lock_end_timestamp: int + reason: str + side: str + active: bool + + +class RPCBuyMsg(RPCSendMsgBase): + trade_id: str + buy_tag: str + enter_tag: str + exchange: str + pair: str + leverage: float + direction: str + limit: float + open_rate: float + order_type: Optional[str] # TODO: why optional?? + stake_amount: float + stake_currency: str + fiat_currency: Optional[str] + amount: float + open_date: datetime + current_rate: float + sub_trade: bool + + +class RPCCancelMsg(RPCBuyMsg): + reason: str + + +class RPCSellMsg(RPCBuyMsg): + cumulative_profit: float + gain: str # Literal["profit", "loss"] + close_rate: float + profit_amount: float + profit_ratio: float + sell_reason: str + exit_reason: str + close_date: datetime + current_rate: Optional[float] + + +class RPCSellCancelMsg(RPCBuyMsg): + reason: str + gain: str # Literal["profit", "loss"] + profit_amount: float + profit_ratio: float + sell_reason: str + exit_reason: str + close_date: datetime + + +RPCSendMsg = Union[ + RPCStatusMsg, + RPCProtectionMsg, + RPCBuyMsg, + RPCCancelMsg, + RPCSellMsg, + RPCSellCancelMsg + ] diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 962c5e058..c1365702d 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -30,6 +30,7 @@ from freqtrade.exceptions import OperationalException from freqtrade.misc import chunks, plural, round_coin_value from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException, RPCHandler +from freqtrade.rpc.rpc_types import RPCSendMsg logger = logging.getLogger(__name__) @@ -429,7 +430,7 @@ class Telegram(RPCHandler): return None return message - def send_msg(self, msg: Dict[str, Any]) -> None: + def send_msg(self, msg: RPCSendMsg) -> None: """ Send a message to telegram channel """ default_noti = 'on' diff --git a/freqtrade/rpc/webhook.py b/freqtrade/rpc/webhook.py index 118ebed88..14b881126 100644 --- a/freqtrade/rpc/webhook.py +++ b/freqtrade/rpc/webhook.py @@ -10,6 +10,7 @@ from requests import RequestException, post from freqtrade.constants import Config from freqtrade.enums import RPCMessageType from freqtrade.rpc import RPC, RPCHandler +from freqtrade.rpc.rpc_types import RPCSendMsg logger = logging.getLogger(__name__) @@ -41,7 +42,7 @@ class Webhook(RPCHandler): """ pass - def _get_value_dict(self, msg: Dict[str, Any]) -> Optional[Dict[str, Any]]: + def _get_value_dict(self, msg: RPCSendMsg) -> Optional[Dict[str, Any]]: whconfig = self._config['webhook'] # Deprecated 2022.10 - only keep generic method. if msg['type'] in [RPCMessageType.ENTRY]: @@ -75,7 +76,7 @@ class Webhook(RPCHandler): return None return valuedict - def send_msg(self, msg: Dict[str, Any]) -> None: + def send_msg(self, msg: RPCSendMsg) -> None: """ Send a message to telegram channel """ try: From 70ad7b42b1b0492fe79f28ffc4ce855d318c8adc Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Mar 2023 19:23:05 +0100 Subject: [PATCH 07/63] Improve msg typing --- freqtrade/rpc/api_server/webserver.py | 2 +- freqtrade/rpc/rpc_types.py | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py index 2413e5264..8030e303b 100644 --- a/freqtrade/rpc/api_server/webserver.py +++ b/freqtrade/rpc/api_server/webserver.py @@ -1,6 +1,6 @@ import logging from ipaddress import IPv4Address -from typing import Any, Optional +from typing import Any, Dict, Optional import orjson import uvicorn diff --git a/freqtrade/rpc/rpc_types.py b/freqtrade/rpc/rpc_types.py index 0fb5a6bfa..bde985548 100644 --- a/freqtrade/rpc/rpc_types.py +++ b/freqtrade/rpc/rpc_types.py @@ -27,12 +27,12 @@ class RPCProtectionMsg(RPCSendMsgBase): class RPCBuyMsg(RPCSendMsgBase): - trade_id: str - buy_tag: str - enter_tag: str + trade_id: int + buy_tag: Optional[str] + enter_tag: Optional[str] exchange: str pair: str - leverage: float + leverage: Optional[float] direction: str limit: float open_rate: float @@ -42,7 +42,7 @@ class RPCBuyMsg(RPCSendMsgBase): fiat_currency: Optional[str] amount: float open_date: datetime - current_rate: float + current_rate: Optional[float] sub_trade: bool @@ -56,10 +56,11 @@ class RPCSellMsg(RPCBuyMsg): close_rate: float profit_amount: float profit_ratio: float - sell_reason: str - exit_reason: str + sell_reason: Optional[str] + exit_reason: Optional[str] close_date: datetime - current_rate: Optional[float] + # current_rate: Optional[float] + order_rate: Optional[float] class RPCSellCancelMsg(RPCBuyMsg): @@ -67,8 +68,8 @@ class RPCSellCancelMsg(RPCBuyMsg): gain: str # Literal["profit", "loss"] profit_amount: float profit_ratio: float - sell_reason: str - exit_reason: str + sell_reason: Optional[str] + exit_reason: Optional[str] close_date: datetime From 245ae99273dcc7ff591c37d830b1b8462b1efde6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Mar 2023 19:44:23 +0100 Subject: [PATCH 08/63] Further typing ... --- freqtrade/freqtradebot.py | 15 ++++++++++----- freqtrade/rpc/rpc_types.py | 17 +++++++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 28dd1fae5..7db9c1e30 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -30,7 +30,8 @@ from freqtrade.plugins.protectionmanager import ProtectionManager from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.rpc import RPCManager from freqtrade.rpc.external_message_consumer import ExternalMessageConsumer -from freqtrade.rpc.rpc_types import RPCBuyMsg, RPCCancelMsg, RPCSellCancelMsg, RPCSellMsg +from freqtrade.rpc.rpc_types import (RPCBuyMsg, RPCCancelMsg, RPCProtectionMsg, RPCSellCancelMsg, + RPCSellMsg) from freqtrade.strategy.interface import IStrategy from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.util import FtPrecise @@ -1853,14 +1854,18 @@ class FreqtradeBot(LoggingMixin): self.strategy.lock_pair(pair, datetime.now(timezone.utc), reason='Auto lock') prot_trig = self.protections.stop_per_pair(pair, side=side) if prot_trig: - msg = {'type': RPCMessageType.PROTECTION_TRIGGER, } - msg.update(prot_trig.to_json()) + msg: RPCProtectionMsg = { + 'type': RPCMessageType.PROTECTION_TRIGGER, + **prot_trig.to_json() + } self.rpc.send_msg(msg) prot_trig_glb = self.protections.global_stop(side=side) if prot_trig_glb: - msg = {'type': RPCMessageType.PROTECTION_TRIGGER_GLOBAL, } - msg.update(prot_trig_glb.to_json()) + msg = { + 'type': RPCMessageType.PROTECTION_TRIGGER_GLOBAL, + **prot_trig_glb.to_json() + } self.rpc.send_msg(msg) def apply_fee_conditional(self, trade: Trade, trade_base_currency: str, diff --git a/freqtrade/rpc/rpc_types.py b/freqtrade/rpc/rpc_types.py index bde985548..b81591954 100644 --- a/freqtrade/rpc/rpc_types.py +++ b/freqtrade/rpc/rpc_types.py @@ -1,19 +1,22 @@ from datetime import datetime -from typing import Optional, TypedDict, Union +from typing import List, Literal, Optional, TypedDict, Union from freqtrade.enums import RPCMessageType class RPCSendMsgBase(TypedDict): - type: RPCMessageType + pass + # ty1pe: Literal[RPCMessageType] class RPCStatusMsg(RPCSendMsgBase): """Used for Status, Startup and Warning messages""" + type: Literal[RPCMessageType.STATUS] status: str class RPCProtectionMsg(RPCSendMsgBase): + type: Literal[RPCMessageType.PROTECTION_TRIGGER, RPCMessageType.PROTECTION_TRIGGER_GLOBAL] id: int pair: str base_currency: Optional[str] @@ -26,7 +29,13 @@ class RPCProtectionMsg(RPCSendMsgBase): active: bool +class RPCWhitelistMsg(RPCSendMsgBase): + type: Literal[RPCMessageType.WHITELIST] + data: List[str] + + class RPCBuyMsg(RPCSendMsgBase): + type: Literal[RPCMessageType.ENTRY, RPCMessageType.ENTRY_FILL] trade_id: int buy_tag: Optional[str] enter_tag: Optional[str] @@ -47,10 +56,12 @@ class RPCBuyMsg(RPCSendMsgBase): class RPCCancelMsg(RPCBuyMsg): + type: Literal[RPCMessageType.ENTRY_CANCEL] reason: str class RPCSellMsg(RPCBuyMsg): + type: Literal[RPCMessageType.EXIT, RPCMessageType.EXIT_FILL] cumulative_profit: float gain: str # Literal["profit", "loss"] close_rate: float @@ -64,6 +75,7 @@ class RPCSellMsg(RPCBuyMsg): class RPCSellCancelMsg(RPCBuyMsg): + type: Literal[RPCMessageType.EXIT_CANCEL] reason: str gain: str # Literal["profit", "loss"] profit_amount: float @@ -76,6 +88,7 @@ class RPCSellCancelMsg(RPCBuyMsg): RPCSendMsg = Union[ RPCStatusMsg, RPCProtectionMsg, + RPCWhitelistMsg, RPCBuyMsg, RPCCancelMsg, RPCSellMsg, From 76d289f0cecb504c18e678cf06c93cbefab5ca0d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Mar 2023 20:35:01 +0100 Subject: [PATCH 09/63] Don't overwrite types --- freqtrade/rpc/rpc_types.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/freqtrade/rpc/rpc_types.py b/freqtrade/rpc/rpc_types.py index b81591954..a43cfd34e 100644 --- a/freqtrade/rpc/rpc_types.py +++ b/freqtrade/rpc/rpc_types.py @@ -34,8 +34,7 @@ class RPCWhitelistMsg(RPCSendMsgBase): data: List[str] -class RPCBuyMsg(RPCSendMsgBase): - type: Literal[RPCMessageType.ENTRY, RPCMessageType.ENTRY_FILL] +class __RPCBuyMsgBase(RPCSendMsgBase): trade_id: int buy_tag: Optional[str] enter_tag: Optional[str] @@ -55,12 +54,16 @@ class RPCBuyMsg(RPCSendMsgBase): sub_trade: bool -class RPCCancelMsg(RPCBuyMsg): +class RPCBuyMsg(__RPCBuyMsgBase): + type: Literal[RPCMessageType.ENTRY, RPCMessageType.ENTRY_FILL] + + +class RPCCancelMsg(__RPCBuyMsgBase): type: Literal[RPCMessageType.ENTRY_CANCEL] reason: str -class RPCSellMsg(RPCBuyMsg): +class RPCSellMsg(__RPCBuyMsgBase): type: Literal[RPCMessageType.EXIT, RPCMessageType.EXIT_FILL] cumulative_profit: float gain: str # Literal["profit", "loss"] @@ -74,7 +77,7 @@ class RPCSellMsg(RPCBuyMsg): order_rate: Optional[float] -class RPCSellCancelMsg(RPCBuyMsg): +class RPCSellCancelMsg(__RPCBuyMsgBase): type: Literal[RPCMessageType.EXIT_CANCEL] reason: str gain: str # Literal["profit", "loss"] From e8cffeeffd9972f97769406ffce6498875b089ba Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Mar 2023 20:36:29 +0100 Subject: [PATCH 10/63] Update RPCStatusMessage type --- freqtrade/rpc/rpc_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/rpc_types.py b/freqtrade/rpc/rpc_types.py index a43cfd34e..5ddaa0c17 100644 --- a/freqtrade/rpc/rpc_types.py +++ b/freqtrade/rpc/rpc_types.py @@ -11,7 +11,7 @@ class RPCSendMsgBase(TypedDict): class RPCStatusMsg(RPCSendMsgBase): """Used for Status, Startup and Warning messages""" - type: Literal[RPCMessageType.STATUS] + type: Literal[RPCMessageType.STATUS, RPCMessageType.STARTUP, RPCMessageType.WARNING] status: str From 8928d3616a81a45d8c7084150f67beded55337a7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Mar 2023 20:47:17 +0100 Subject: [PATCH 11/63] Improve msgtypes --- freqtrade/freqtradebot.py | 4 ++++ freqtrade/rpc/rpc_types.py | 8 ++++++++ freqtrade/rpc/telegram.py | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 7db9c1e30..3aa1075d8 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -973,6 +973,7 @@ class FreqtradeBot(LoggingMixin): 'order_type': order_type, 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], + 'base_currency': self.exchange.get_pair_base_currency(trade.pair), 'fiat_currency': self.config.get('fiat_display_currency', None), 'amount': order.safe_amount_after_fee if fill else (order.amount or trade.amount), 'open_date': trade.open_date or datetime.utcnow(), @@ -1005,6 +1006,7 @@ class FreqtradeBot(LoggingMixin): 'stake_amount': trade.stake_amount, 'open_rate': trade.open_rate, 'stake_currency': self.config['stake_currency'], + 'base_currency': self.exchange.get_pair_base_currency(trade.pair), 'fiat_currency': self.config.get('fiat_display_currency', None), 'amount': trade.amount, 'open_date': trade.open_date, @@ -1695,6 +1697,7 @@ class FreqtradeBot(LoggingMixin): 'close_date': trade.close_date or datetime.utcnow(), 'stake_amount': trade.stake_amount, 'stake_currency': self.config['stake_currency'], + 'base_currency': self.exchange.get_pair_base_currency(trade.pair), 'fiat_currency': self.config.get('fiat_display_currency'), 'sub_trade': sub_trade, 'cumulative_profit': trade.realized_profit, @@ -1747,6 +1750,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'], + 'base_currency': self.exchange.get_pair_base_currency(trade.pair), 'fiat_currency': self.config.get('fiat_display_currency', None), 'reason': reason, 'sub_trade': sub_trade, diff --git a/freqtrade/rpc/rpc_types.py b/freqtrade/rpc/rpc_types.py index 5ddaa0c17..5a3549aa7 100644 --- a/freqtrade/rpc/rpc_types.py +++ b/freqtrade/rpc/rpc_types.py @@ -15,6 +15,12 @@ class RPCStatusMsg(RPCSendMsgBase): status: str +class RPCStrategyMsg(RPCSendMsgBase): + """Used for Status, Startup and Warning messages""" + type: Literal[RPCMessageType.STRATEGY_MSG] + msg: str + + class RPCProtectionMsg(RPCSendMsgBase): type: Literal[RPCMessageType.PROTECTION_TRIGGER, RPCMessageType.PROTECTION_TRIGGER_GLOBAL] id: int @@ -40,6 +46,7 @@ class __RPCBuyMsgBase(RPCSendMsgBase): enter_tag: Optional[str] exchange: str pair: str + base_currency: str leverage: Optional[float] direction: str limit: float @@ -90,6 +97,7 @@ class RPCSellCancelMsg(__RPCBuyMsgBase): RPCSendMsg = Union[ RPCStatusMsg, + RPCStrategyMsg, RPCProtectionMsg, RPCWhitelistMsg, RPCBuyMsg, diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index c1365702d..6f34b7325 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -437,7 +437,7 @@ class Telegram(RPCHandler): msg_type = msg['type'] noti = '' - if msg_type == RPCMessageType.EXIT: + if msg['type'] == RPCMessageType.EXIT: sell_noti = self._config['telegram'] \ .get('notification_settings', {}).get(str(msg_type), {}) # For backward compatibility sell still can be string From ad58bac810bf5cfd2fbcd9556a192f0b1dc0d429 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Mar 2023 20:54:28 +0100 Subject: [PATCH 12/63] Type WS messagetypes --- freqtrade/data/dataprovider.py | 6 +++--- freqtrade/rpc/rpc_types.py | 25 +++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index 3991432a4..d05ee5db7 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -21,6 +21,7 @@ from freqtrade.exchange import Exchange, timeframe_to_seconds from freqtrade.exchange.types import OrderBook from freqtrade.misc import append_candles_to_dataframe from freqtrade.rpc import RPCManager +from freqtrade.rpc.rpc_types import RPCAnalyzedDFMsg from freqtrade.util import PeriodicCache @@ -118,8 +119,7 @@ class DataProvider: :param new_candle: This is a new candle """ if self.__rpc: - self.__rpc.send_msg( - { + msg: RPCAnalyzedDFMsg = { 'type': RPCMessageType.ANALYZED_DF, 'data': { 'key': pair_key, @@ -127,7 +127,7 @@ class DataProvider: 'la': datetime.now(timezone.utc) } } - ) + self.__rpc.send_msg(msg) if new_candle: self.__rpc.send_msg({ 'type': RPCMessageType.NEW_CANDLE, diff --git a/freqtrade/rpc/rpc_types.py b/freqtrade/rpc/rpc_types.py index 5a3549aa7..a290ee78c 100644 --- a/freqtrade/rpc/rpc_types.py +++ b/freqtrade/rpc/rpc_types.py @@ -1,6 +1,7 @@ from datetime import datetime -from typing import List, Literal, Optional, TypedDict, Union +from typing import Any, List, Literal, Optional, TypedDict, Union +from freqtrade.constants import PairWithTimeframe from freqtrade.enums import RPCMessageType @@ -95,6 +96,24 @@ class RPCSellCancelMsg(__RPCBuyMsgBase): close_date: datetime +class __AnalyzedDFData(TypedDict): + key: PairWithTimeframe + df: Any + la: datetime + + +class RPCAnalyzedDFMsg(RPCSendMsgBase): + """New Analyzed dataframe message""" + type: Literal[RPCMessageType.ANALYZED_DF] + data: __AnalyzedDFData + + +class RPCNewCandleMsg(RPCSendMsgBase): + """New candle ping message, issued once per new candle/pair""" + type: Literal[RPCMessageType.NEW_CANDLE] + data: PairWithTimeframe + + RPCSendMsg = Union[ RPCStatusMsg, RPCStrategyMsg, @@ -103,5 +122,7 @@ RPCSendMsg = Union[ RPCBuyMsg, RPCCancelMsg, RPCSellMsg, - RPCSellCancelMsg + RPCSellCancelMsg, + RPCAnalyzedDFMsg, + RPCNewCandleMsg ] From 281dd7785ebf190460bdf483f0839799bcf55d58 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Mar 2023 20:56:18 +0100 Subject: [PATCH 13/63] Fix some remaining type errors --- freqtrade/freqtradebot.py | 7 +++---- freqtrade/rpc/telegram.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3aa1075d8..1f7b4493c 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -948,7 +948,6 @@ class FreqtradeBot(LoggingMixin): """ Sends rpc notification when a entry order occurred. """ - msg_type = RPCMessageType.ENTRY_FILL if fill else RPCMessageType.ENTRY open_rate = order.safe_price if open_rate is None: @@ -961,7 +960,7 @@ class FreqtradeBot(LoggingMixin): msg: RPCBuyMsg = { 'trade_id': trade.id, - 'type': msg_type, + 'type': RPCMessageType.ENTRY_FILL if fill else RPCMessageType.ENTRY, 'buy_tag': trade.enter_tag, 'enter_tag': trade.enter_tag, 'exchange': trade.exchange.capitalize(), @@ -1860,7 +1859,7 @@ class FreqtradeBot(LoggingMixin): if prot_trig: msg: RPCProtectionMsg = { 'type': RPCMessageType.PROTECTION_TRIGGER, - **prot_trig.to_json() + **prot_trig.to_json() # type: ignore } self.rpc.send_msg(msg) @@ -1868,7 +1867,7 @@ class FreqtradeBot(LoggingMixin): if prot_trig_glb: msg = { 'type': RPCMessageType.PROTECTION_TRIGGER_GLOBAL, - **prot_trig_glb.to_json() + **prot_trig_glb.to_json() # type: ignore } self.rpc.send_msg(msg) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 6f34b7325..d79d8ea76 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -454,7 +454,7 @@ class Telegram(RPCHandler): # Notification disabled return - message = self.compose_message(deepcopy(msg), msg_type) + message = self.compose_message(deepcopy(msg), msg_type) # type: ignore if message: self._send_msg(message, disable_notification=(noti == 'silent')) From cbdd86d7775ac767b45c0ce4673cb192eeb30fad Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Mar 2023 21:05:10 +0100 Subject: [PATCH 14/63] Fix test failures due to additional field --- freqtrade/rpc/rpc_types.py | 4 ++-- tests/test_freqtradebot.py | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/rpc_types.py b/freqtrade/rpc/rpc_types.py index a290ee78c..3277a2d6e 100644 --- a/freqtrade/rpc/rpc_types.py +++ b/freqtrade/rpc/rpc_types.py @@ -96,7 +96,7 @@ class RPCSellCancelMsg(__RPCBuyMsgBase): close_date: datetime -class __AnalyzedDFData(TypedDict): +class _AnalyzedDFData(TypedDict): key: PairWithTimeframe df: Any la: datetime @@ -105,7 +105,7 @@ class __AnalyzedDFData(TypedDict): class RPCAnalyzedDFMsg(RPCSendMsgBase): """New Analyzed dataframe message""" type: Literal[RPCMessageType.ANALYZED_DF] - data: __AnalyzedDFData + data: _AnalyzedDFData class RPCNewCandleMsg(RPCSendMsgBase): diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index cea70ec48..da98fed94 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3326,6 +3326,7 @@ def test_execute_trade_exit_up(default_conf_usdt, ticker_usdt, fee, ticker_usdt_ 'profit_ratio': 0.00493809 if is_short else 0.09451372, 'stake_currency': 'USDT', 'fiat_currency': 'USD', + 'base_currency': 'ETH', 'sell_reason': ExitType.ROI.value, 'exit_reason': ExitType.ROI.value, 'open_date': ANY, @@ -3389,6 +3390,7 @@ def test_execute_trade_exit_down(default_conf_usdt, ticker_usdt, fee, ticker_usd 'profit_amount': -5.65990099 if is_short else -0.00075, 'profit_ratio': -0.0945681 if is_short else -1.247e-05, 'stake_currency': 'USDT', + 'base_currency': 'ETH', 'fiat_currency': 'USD', 'sell_reason': ExitType.STOP_LOSS.value, 'exit_reason': ExitType.STOP_LOSS.value, @@ -3474,6 +3476,7 @@ def test_execute_trade_exit_custom_exit_price( 'profit_amount': pytest.approx(profit_amount), 'profit_ratio': profit_ratio, 'stake_currency': 'USDT', + 'base_currency': 'ETH', 'fiat_currency': 'USD', 'sell_reason': 'foo', 'exit_reason': 'foo', @@ -3547,6 +3550,7 @@ def test_execute_trade_exit_down_stoploss_on_exchange_dry_run( 'profit_ratio': -0.00501253 if is_short else -0.01493766, 'stake_currency': 'USDT', 'fiat_currency': 'USD', + 'base_currency': 'ETH', 'sell_reason': ExitType.STOP_LOSS.value, 'exit_reason': ExitType.STOP_LOSS.value, 'open_date': ANY, @@ -3811,6 +3815,7 @@ def test_execute_trade_exit_market_order( 'profit_amount': pytest.approx(profit_amount), 'profit_ratio': profit_ratio, 'stake_currency': 'USDT', + 'base_currency': 'ETH', 'fiat_currency': 'USD', 'sell_reason': ExitType.ROI.value, 'exit_reason': ExitType.ROI.value, From c0a57d352f7f8058cb20c4b60b4b5779ca9b1a45 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Mar 2023 08:16:07 +0100 Subject: [PATCH 15/63] send base_currency with messages that need it. --- freqtrade/freqtradebot.py | 2 ++ freqtrade/rpc/rpc_manager.py | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 1f7b4493c..1f072571d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1859,6 +1859,7 @@ class FreqtradeBot(LoggingMixin): if prot_trig: msg: RPCProtectionMsg = { 'type': RPCMessageType.PROTECTION_TRIGGER, + 'base_currency': self.exchange.get_pair_base_currency(prot_trig.pair), **prot_trig.to_json() # type: ignore } self.rpc.send_msg(msg) @@ -1867,6 +1868,7 @@ class FreqtradeBot(LoggingMixin): if prot_trig_glb: msg = { 'type': RPCMessageType.PROTECTION_TRIGGER_GLOBAL, + 'base_currency': self.exchange.get_pair_base_currency(prot_trig_glb.pair), **prot_trig_glb.to_json() # type: ignore } self.rpc.send_msg(msg) diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index e4c925995..1972ad6e5 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -70,10 +70,6 @@ class RPCManager: """ if msg.get('type') not in NO_ECHO_MESSAGES: logger.info('Sending rpc message: %s', msg) - if 'pair' in msg: - msg.update({ - 'base_currency': self._rpc._freqtrade.exchange.get_pair_base_currency(msg['pair']) - }) for mod in self.registered_modules: logger.debug('Forwarding message to rpc.%s', mod.name) try: From 79a2de7a64a7a737bf6bdc593a187dd422453bb2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Mar 2023 08:31:35 +0100 Subject: [PATCH 16/63] Reduce impact of short outages --- tests/exchange/test_ccxt_compat.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 872cf5059..4a65b16d7 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -37,7 +37,7 @@ EXCHANGES = { 'stake_currency': 'USDT', 'use_ci_proxy': True, 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'futures': True, 'futures_pair': 'BTC/USDT:USDT', 'hasQuoteVolumeFutures': True, @@ -66,7 +66,7 @@ EXCHANGES = { 'pair': 'BTC/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'futures': False, 'sample_order': [{ "symbol": "SOLUSDT", @@ -91,7 +91,7 @@ EXCHANGES = { 'pair': 'BTC/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'leverage_tiers_public': False, 'leverage_in_spot_market': True, }, @@ -99,7 +99,7 @@ EXCHANGES = { 'pair': 'XRP/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'leverage_tiers_public': False, 'leverage_in_spot_market': True, 'sample_order': [ @@ -141,7 +141,7 @@ EXCHANGES = { 'pair': 'BTC/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'futures': True, 'futures_pair': 'BTC/USDT:USDT', 'hasQuoteVolumeFutures': True, @@ -215,7 +215,7 @@ EXCHANGES = { 'pair': 'BTC/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'futures': True, 'futures_pair': 'BTC/USDT:USDT', 'hasQuoteVolumeFutures': False, @@ -226,7 +226,7 @@ EXCHANGES = { 'pair': 'BTC/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'futures_pair': 'BTC/USDT:USDT', 'futures': True, 'leverage_tiers_public': True, @@ -253,14 +253,14 @@ EXCHANGES = { 'pair': 'ETH/BTC', 'stake_currency': 'BTC', 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'futures': False, }, 'bitvavo': { 'pair': 'BTC/EUR', 'stake_currency': 'EUR', 'hasQuoteVolume': True, - 'timeframe': '5m', + 'timeframe': '1h', 'leverage_tiers_public': False, 'leverage_in_spot_market': False, }, From 56170dba19b5d46fc5884e17d786b0f17fb0feda Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Mar 2023 08:44:35 +0100 Subject: [PATCH 17/63] use github to download guess instead of gnu.org gnu.org seems down rn (dns does no longer resolve), and doesn't have good uptime history --- build_helpers/install_ta-lib.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_helpers/install_ta-lib.sh b/build_helpers/install_ta-lib.sh index 079d578b4..005d9abca 100755 --- a/build_helpers/install_ta-lib.sh +++ b/build_helpers/install_ta-lib.sh @@ -8,8 +8,8 @@ if [ -n "$2" ] || [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then tar zxvf ta-lib-0.4.0-src.tar.gz cd ta-lib \ && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \ - && curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' -o config.guess \ - && curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' -o config.sub \ + && curl 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.guess' -o config.guess \ + && curl 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.sub' -o config.sub \ && ./configure --prefix=${INSTALL_LOC}/ \ && make if [ $? -ne 0 ]; then From cdd44a40058bd8bce80519d8f79007ff1034fb3a Mon Sep 17 00:00:00 2001 From: linquanisaac Date: Sat, 25 Mar 2023 17:19:58 +0800 Subject: [PATCH 18/63] docs(protections): fix typo --- docs/includes/protections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/includes/protections.md b/docs/includes/protections.md index e0ad8189f..12af081c0 100644 --- a/docs/includes/protections.md +++ b/docs/includes/protections.md @@ -149,7 +149,7 @@ The below example assumes a timeframe of 1 hour: * Locks each pair after selling for an additional 5 candles (`CooldownPeriod`), giving other pairs a chance to get filled. * Stops trading for 4 hours (`4 * 1h candles`) if the last 2 days (`48 * 1h candles`) had 20 trades, which caused a max-drawdown of more than 20%. (`MaxDrawdown`). * Stops trading if more than 4 stoploss occur for all pairs within a 1 day (`24 * 1h candles`) limit (`StoplossGuard`). -* Locks all pairs that had 4 Trades within the last 6 hours (`6 * 1h candles`) with a combined profit ratio of below 0.02 (<2%) (`LowProfitPairs`). +* Locks all pairs that had 2 Trades within the last 6 hours (`6 * 1h candles`) with a combined profit ratio of below 0.02 (<2%) (`LowProfitPairs`). * Locks all pairs for 2 candles that had a profit of below 0.01 (<1%) within the last 24h (`24 * 1h candles`), a minimum of 4 trades. ``` python From 9c6a49436bd17752a8c0921c801c642116658c95 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Mar 2023 11:42:19 +0100 Subject: [PATCH 19/63] Export amount/price precisions per trade --- freqtrade/persistence/trade_model.py | 3 + tests/persistence/test_persistence.py | 256 ++++++++++++++------------ tests/rpc/test_rpc.py | 3 + 3 files changed, 141 insertions(+), 121 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 27be0d726..54ff1313b 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -560,6 +560,9 @@ class LocalTrade(): 'trading_mode': self.trading_mode, 'funding_fees': self.funding_fees, 'open_order_id': self.open_order_id, + 'amount_precision': self.amount_precision, + 'price_precision': self.price_precision, + 'precision_mode': self.precision_mode, 'orders': orders, } diff --git a/tests/persistence/test_persistence.py b/tests/persistence/test_persistence.py index db882d56d..23ec6d4fb 100644 --- a/tests/persistence/test_persistence.py +++ b/tests/persistence/test_persistence.py @@ -1330,71 +1330,78 @@ def test_to_json(fee): open_rate=0.123, exchange='binance', enter_tag=None, - open_order_id='dry_run_buy_12345' + open_order_id='dry_run_buy_12345', + precision_mode=1, + amount_precision=8.0, + price_precision=7.0, ) result = trade.to_json() assert isinstance(result, dict) - assert result == {'trade_id': None, - 'pair': 'ADA/USDT', - 'base_currency': 'ADA', - 'quote_currency': 'USDT', - 'is_open': None, - 'open_date': trade.open_date.strftime(DATETIME_PRINT_FORMAT), - 'open_timestamp': int(trade.open_date.timestamp() * 1000), - 'open_order_id': 'dry_run_buy_12345', - 'close_date': None, - 'close_timestamp': None, - 'open_rate': 0.123, - 'open_rate_requested': None, - 'open_trade_value': 15.1668225, - 'fee_close': 0.0025, - 'fee_close_cost': None, - 'fee_close_currency': None, - 'fee_open': 0.0025, - 'fee_open_cost': None, - 'fee_open_currency': None, - 'close_rate': None, - 'close_rate_requested': None, - 'amount': 123.0, - 'amount_requested': 123.0, - 'stake_amount': 0.001, - 'max_stake_amount': None, - 'trade_duration': None, - 'trade_duration_s': None, - 'realized_profit': 0.0, - 'realized_profit_ratio': None, - 'close_profit': None, - 'close_profit_pct': None, - 'close_profit_abs': None, - 'profit_ratio': None, - 'profit_pct': None, - 'profit_abs': None, - 'exit_reason': None, - 'exit_order_status': None, - 'stop_loss_abs': None, - 'stop_loss_ratio': None, - 'stop_loss_pct': None, - 'stoploss_order_id': None, - 'stoploss_last_update': None, - 'stoploss_last_update_timestamp': None, - 'initial_stop_loss_abs': None, - 'initial_stop_loss_pct': None, - 'initial_stop_loss_ratio': None, - 'min_rate': None, - 'max_rate': None, - 'strategy': None, - 'enter_tag': None, - 'timeframe': None, - 'exchange': 'binance', - 'leverage': None, - 'interest_rate': None, - 'liquidation_price': None, - 'is_short': None, - 'trading_mode': None, - 'funding_fees': None, - 'orders': [], - } + assert result == { + 'trade_id': None, + 'pair': 'ADA/USDT', + 'base_currency': 'ADA', + 'quote_currency': 'USDT', + 'is_open': None, + 'open_date': trade.open_date.strftime(DATETIME_PRINT_FORMAT), + 'open_timestamp': int(trade.open_date.timestamp() * 1000), + 'open_order_id': 'dry_run_buy_12345', + 'close_date': None, + 'close_timestamp': None, + 'open_rate': 0.123, + 'open_rate_requested': None, + 'open_trade_value': 15.1668225, + 'fee_close': 0.0025, + 'fee_close_cost': None, + 'fee_close_currency': None, + 'fee_open': 0.0025, + 'fee_open_cost': None, + 'fee_open_currency': None, + 'close_rate': None, + 'close_rate_requested': None, + 'amount': 123.0, + 'amount_requested': 123.0, + 'stake_amount': 0.001, + 'max_stake_amount': None, + 'trade_duration': None, + 'trade_duration_s': None, + 'realized_profit': 0.0, + 'realized_profit_ratio': None, + 'close_profit': None, + 'close_profit_pct': None, + 'close_profit_abs': None, + 'profit_ratio': None, + 'profit_pct': None, + 'profit_abs': None, + 'exit_reason': None, + 'exit_order_status': None, + 'stop_loss_abs': None, + 'stop_loss_ratio': None, + 'stop_loss_pct': None, + 'stoploss_order_id': None, + 'stoploss_last_update': None, + 'stoploss_last_update_timestamp': None, + 'initial_stop_loss_abs': None, + 'initial_stop_loss_pct': None, + 'initial_stop_loss_ratio': None, + 'min_rate': None, + 'max_rate': None, + 'strategy': None, + 'enter_tag': None, + 'timeframe': None, + 'exchange': 'binance', + 'leverage': None, + 'interest_rate': None, + 'liquidation_price': None, + 'is_short': None, + 'trading_mode': None, + 'funding_fees': None, + 'amount_precision': 8.0, + 'price_precision': 7.0, + 'precision_mode': 1, + 'orders': [], + } # Simulate dry_run entries trade = Trade( @@ -1410,70 +1417,77 @@ def test_to_json(fee): close_rate=0.125, enter_tag='buys_signal_001', exchange='binance', + precision_mode=2, + amount_precision=7.0, + price_precision=8.0, ) result = trade.to_json() assert isinstance(result, dict) - assert result == {'trade_id': None, - 'pair': 'XRP/BTC', - 'base_currency': 'XRP', - 'quote_currency': 'BTC', - 'open_date': trade.open_date.strftime(DATETIME_PRINT_FORMAT), - 'open_timestamp': int(trade.open_date.timestamp() * 1000), - 'close_date': trade.close_date.strftime(DATETIME_PRINT_FORMAT), - 'close_timestamp': int(trade.close_date.timestamp() * 1000), - 'open_rate': 0.123, - 'close_rate': 0.125, - 'amount': 100.0, - 'amount_requested': 101.0, - 'stake_amount': 0.001, - 'max_stake_amount': None, - 'trade_duration': 60, - 'trade_duration_s': 3600, - 'stop_loss_abs': None, - 'stop_loss_pct': None, - 'stop_loss_ratio': None, - 'stoploss_order_id': None, - 'stoploss_last_update': None, - 'stoploss_last_update_timestamp': None, - 'initial_stop_loss_abs': None, - 'initial_stop_loss_pct': None, - 'initial_stop_loss_ratio': None, - 'realized_profit': 0.0, - 'realized_profit_ratio': None, - 'close_profit': None, - 'close_profit_pct': None, - 'close_profit_abs': None, - 'profit_ratio': None, - 'profit_pct': None, - 'profit_abs': None, - 'close_rate_requested': None, - 'fee_close': 0.0025, - 'fee_close_cost': None, - 'fee_close_currency': None, - 'fee_open': 0.0025, - 'fee_open_cost': None, - 'fee_open_currency': None, - 'is_open': None, - 'max_rate': None, - 'min_rate': None, - 'open_order_id': None, - 'open_rate_requested': None, - 'open_trade_value': 12.33075, - 'exit_reason': None, - 'exit_order_status': None, - 'strategy': None, - 'enter_tag': 'buys_signal_001', - 'timeframe': None, - 'exchange': 'binance', - 'leverage': None, - 'interest_rate': None, - 'liquidation_price': None, - 'is_short': None, - 'trading_mode': None, - 'funding_fees': None, - 'orders': [], - } + assert result == { + 'trade_id': None, + 'pair': 'XRP/BTC', + 'base_currency': 'XRP', + 'quote_currency': 'BTC', + 'open_date': trade.open_date.strftime(DATETIME_PRINT_FORMAT), + 'open_timestamp': int(trade.open_date.timestamp() * 1000), + 'close_date': trade.close_date.strftime(DATETIME_PRINT_FORMAT), + 'close_timestamp': int(trade.close_date.timestamp() * 1000), + 'open_rate': 0.123, + 'close_rate': 0.125, + 'amount': 100.0, + 'amount_requested': 101.0, + 'stake_amount': 0.001, + 'max_stake_amount': None, + 'trade_duration': 60, + 'trade_duration_s': 3600, + 'stop_loss_abs': None, + 'stop_loss_pct': None, + 'stop_loss_ratio': None, + 'stoploss_order_id': None, + 'stoploss_last_update': None, + 'stoploss_last_update_timestamp': None, + 'initial_stop_loss_abs': None, + 'initial_stop_loss_pct': None, + 'initial_stop_loss_ratio': None, + 'realized_profit': 0.0, + 'realized_profit_ratio': None, + 'close_profit': None, + 'close_profit_pct': None, + 'close_profit_abs': None, + 'profit_ratio': None, + 'profit_pct': None, + 'profit_abs': None, + 'close_rate_requested': None, + 'fee_close': 0.0025, + 'fee_close_cost': None, + 'fee_close_currency': None, + 'fee_open': 0.0025, + 'fee_open_cost': None, + 'fee_open_currency': None, + 'is_open': None, + 'max_rate': None, + 'min_rate': None, + 'open_order_id': None, + 'open_rate_requested': None, + 'open_trade_value': 12.33075, + 'exit_reason': None, + 'exit_order_status': None, + 'strategy': None, + 'enter_tag': 'buys_signal_001', + 'timeframe': None, + 'exchange': 'binance', + 'leverage': None, + 'interest_rate': None, + 'liquidation_price': None, + 'is_short': None, + 'trading_mode': None, + 'funding_fees': None, + 'amount_precision': 7.0, + 'price_precision': 8.0, + 'precision_mode': 2, + 'orders': [], + } def test_stoploss_reinitialization(default_conf, fee): diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 4e2dc94ae..ff08a0564 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -88,6 +88,9 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'is_short': False, 'funding_fees': 0.0, 'trading_mode': TradingMode.SPOT, + 'amount_precision': 8.0, + 'price_precision': 8.0, + 'precision_mode': 2, 'orders': [{ 'amount': 91.07468123, 'average': 1.098e-05, 'safe_price': 1.098e-05, 'cost': 0.0009999999999054, 'filled': 91.07468123, 'ft_order_side': 'buy', From f7c1ee6d3e1aa9f40ba5329d70cbe3e291c77581 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Mar 2023 11:55:47 +0100 Subject: [PATCH 20/63] add precision values to api schema --- freqtrade/rpc/api_server/api_schemas.py | 4 ++++ tests/rpc/test_rpc_apiserver.py | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 18621ccbd..7497b27f1 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -276,6 +276,10 @@ class TradeSchema(BaseModel): funding_fees: Optional[float] trading_mode: Optional[TradingMode] + amount_precision: Optional[float] + price_precision: Optional[float] + precision_mode: Optional[int] + class OpenTradeSchema(TradeSchema): stoploss_current_dist: Optional[float] diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 97319b78b..bf9d6cc3b 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1066,6 +1066,9 @@ def test_api_status(botclient, mocker, ticker, fee, markets, is_short, 'liquidation_price': None, 'funding_fees': None, 'trading_mode': ANY, + 'amount_precision': None, + 'price_precision': None, + 'precision_mode': None, 'orders': [ANY], } @@ -1271,6 +1274,9 @@ def test_api_force_entry(botclient, mocker, fee, endpoint): 'liquidation_price': None, 'funding_fees': None, 'trading_mode': 'spot', + 'amount_precision': None, + 'price_precision': None, + 'precision_mode': None, 'orders': [], } From 68154a1f52c002944132242a089de29f27b0196e Mon Sep 17 00:00:00 2001 From: robcaulk Date: Sat, 25 Mar 2023 11:57:52 +0100 Subject: [PATCH 21/63] document why users cant arbitrarily change parameter spaces... --- docs/freqai-running.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/freqai-running.md b/docs/freqai-running.md index 1eaee1bf2..f3ccc546f 100644 --- a/docs/freqai-running.md +++ b/docs/freqai-running.md @@ -128,6 +128,9 @@ The FreqAI specific parameter `label_period_candles` defines the offset (number You can choose to adopt a continual learning scheme by setting `"continual_learning": true` in the config. By enabling `continual_learning`, after training an initial model from scratch, subsequent trainings will start from the final model state of the preceding training. This gives the new model a "memory" of the previous state. By default, this is set to `False` which means that all new models are trained from scratch, without input from previous models. +???+ danger "Continual learning enforces a constant parameter space" + Since `continual_learning` means that the model parameter space *cannot* change between trainings, `principal_component_analysis` is automatically disabled when `continual_learning` is enabled. Hint: PCA changes the parameter space and the number of features, learn more about PCA [here](freqai-feature-engineering.md#data-dimensionality-reduction-with-principal-component-analysis). + ## Hyperopt You can hyperopt using the same command as for [typical Freqtrade hyperopt](hyperopt.md): From d9c8b322ce45c88abeb23ffc63ad815e10c72e74 Mon Sep 17 00:00:00 2001 From: Robert Caulk Date: Sat, 25 Mar 2023 13:37:07 +0100 Subject: [PATCH 22/63] Update freqai_interface.py --- freqtrade/freqai/freqai_interface.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 8e842b8f2..b657bd811 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -109,7 +109,6 @@ class IFreqaiModel(ABC): self.ft_params.update({'principal_component_analysis': False}) logger.warning('User tried to use PCA with continual learning. Deactivating PCA.') - record_params(config, self.full_path) def __getstate__(self): From 486d8a48a05befc9dee60da922f319b51aebc651 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Mar 2023 19:36:28 +0100 Subject: [PATCH 23/63] Fix docs (buffer_train_data_candles is an integer, not a boolean) closes #8384 --- docs/freqai-parameter-table.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai-parameter-table.md b/docs/freqai-parameter-table.md index f67ea8541..9822a895a 100644 --- a/docs/freqai-parameter-table.md +++ b/docs/freqai-parameter-table.md @@ -46,7 +46,7 @@ Mandatory parameters are marked as **Required** and have to be set in one of the | `outlier_protection_percentage` | Enable to prevent outlier detection methods from discarding too much data. If more than `outlier_protection_percentage` % of points are detected as outliers by the SVM or DBSCAN, FreqAI will log a warning message and ignore outlier detection, i.e., the original dataset will be kept intact. If the outlier protection is triggered, no predictions will be made based on the training dataset.
**Datatype:** Float.
Default: `30`. | `reverse_train_test_order` | Split the feature dataset (see below) and use the latest data split for training and test on historical split of the data. This allows the model to be trained up to the most recent data point, while avoiding overfitting. However, you should be careful to understand the unorthodox nature of this parameter before employing it.
**Datatype:** Boolean.
Default: `False` (no reversal). | `shuffle_after_split` | Split the data into train and test sets, and then shuffle both sets individually.
**Datatype:** Boolean.
Default: `False`. -| `buffer_train_data_candles` | Cut `buffer_train_data_candles` off the beginning and end of the training data *after* the indicators were populated. The main example use is when predicting maxima and minima, the argrelextrema function cannot know the maxima/minima at the edges of the timerange. To improve model accuracy, it is best to compute argrelextrema on the full timerange and then use this function to cut off the edges (buffer) by the kernel. In another case, if the targets are set to a shifted price movement, this buffer is unnecessary because the shifted candles at the end of the timerange will be NaN and FreqAI will automatically cut those off of the training dataset.
**Datatype:** Boolean.
Default: `False`. +| `buffer_train_data_candles` | Cut `buffer_train_data_candles` off the beginning and end of the training data *after* the indicators were populated. The main example use is when predicting maxima and minima, the argrelextrema function cannot know the maxima/minima at the edges of the timerange. To improve model accuracy, it is best to compute argrelextrema on the full timerange and then use this function to cut off the edges (buffer) by the kernel. In another case, if the targets are set to a shifted price movement, this buffer is unnecessary because the shifted candles at the end of the timerange will be NaN and FreqAI will automatically cut those off of the training dataset.
**Datatype:** Integer.
Default: `0`. ### Data split parameters From 298f5685ee3f3c902243efe0e953fb83076bffa6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Mar 2023 20:06:21 +0100 Subject: [PATCH 24/63] Reuse existing "cancel_stoploss" call --- freqtrade/freqtradebot.py | 12 ++++-------- tests/test_freqtradebot.py | 16 +++++++++------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 623d39c09..4482f37bf 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -854,7 +854,8 @@ class FreqtradeBot(LoggingMixin): # Reset stoploss order id. trade.stoploss_order_id = None except InvalidOrderException: - logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}") + logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id} " + f"for pair {trade.pair}") return trade def get_valid_enter_price_and_stake( @@ -1239,13 +1240,8 @@ class FreqtradeBot(LoggingMixin): # cancelling the current stoploss on exchange first logger.info(f"Cancelling current stoploss on exchange for pair {trade.pair} " f"(orderid:{order['id']}) in order to add another one ...") - try: - co = self.exchange.cancel_stoploss_order_with_result(order['id'], trade.pair, - trade.amount) - trade.update_order(co) - except InvalidOrderException: - logger.exception(f"Could not cancel stoploss order {order['id']} " - f"for pair {trade.pair}") + + self.cancel_stoploss_on_exchange(trade) # Create new stoploss order if not self.create_stoploss_order(trade=trade, stop_price=stoploss_norm): diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index cea70ec48..ff10cd2f0 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1440,11 +1440,11 @@ def test_handle_stoploss_on_exchange_trailing( trade.is_short = is_short trade.is_open = True trade.open_order_id = None - trade.stoploss_order_id = 100 + trade.stoploss_order_id = '100' trade.stoploss_last_update = arrow.utcnow().shift(minutes=-20).datetime stoploss_order_hanging = MagicMock(return_value={ - 'id': 100, + 'id': '100', 'status': 'open', 'type': 'stop_loss_limit', 'price': hang_price, @@ -1483,13 +1483,14 @@ def test_handle_stoploss_on_exchange_trailing( assert freqtrade.handle_trade(trade) is False assert trade.stop_loss == stop_price[1] + trade.stoploss_order_id = '100' # setting stoploss_on_exchange_interval to 0 seconds freqtrade.strategy.order_types['stoploss_on_exchange_interval'] = 0 assert freqtrade.handle_stoploss_on_exchange(trade) is False - cancel_order_mock.assert_called_once_with(100, 'ETH/USDT') + cancel_order_mock.assert_called_once_with('100', 'ETH/USDT') stoploss_order_mock.assert_called_once_with( amount=pytest.approx(amt), pair='ETH/USDT', @@ -1673,11 +1674,11 @@ def test_handle_stoploss_on_exchange_custom_stop( trade.is_short = is_short trade.is_open = True trade.open_order_id = None - trade.stoploss_order_id = 100 + trade.stoploss_order_id = '100' trade.stoploss_last_update = arrow.utcnow().shift(minutes=-601).datetime stoploss_order_hanging = MagicMock(return_value={ - 'id': 100, + 'id': '100', 'status': 'open', 'type': 'stop_loss_limit', 'price': 3, @@ -1706,6 +1707,7 @@ def test_handle_stoploss_on_exchange_custom_stop( stoploss_order_mock = MagicMock(return_value={'id': 'so1'}) mocker.patch(f'{EXMS}.cancel_stoploss_order', cancel_order_mock) mocker.patch(f'{EXMS}.create_stoploss', stoploss_order_mock) + trade.stoploss_order_id = '100' # stoploss should not be updated as the interval is 60 seconds assert freqtrade.handle_trade(trade) is False @@ -1722,7 +1724,7 @@ def test_handle_stoploss_on_exchange_custom_stop( assert freqtrade.handle_stoploss_on_exchange(trade) is False - cancel_order_mock.assert_called_once_with(100, 'ETH/USDT') + cancel_order_mock.assert_called_once_with('100', 'ETH/USDT') # Long uses modified ask - offset, short modified bid + offset stoploss_order_mock.assert_called_once_with( amount=pytest.approx(trade.amount), @@ -3588,7 +3590,7 @@ def test_execute_trade_exit_sloe_cancel_exception( freqtrade.execute_trade_exit(trade=trade, limit=1234, exit_check=ExitCheckTuple(exit_type=ExitType.STOP_LOSS)) assert create_order_mock.call_count == 2 - assert log_has('Could not cancel stoploss order abcd', caplog) + assert log_has('Could not cancel stoploss order abcd for pair ETH/USDT', caplog) @pytest.mark.parametrize("is_short", [False, True]) From ee205ddc862ee0105e570deed47b728272d21521 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Mar 2023 20:26:56 +0100 Subject: [PATCH 25/63] Improve trade.from_json when stops are used --- freqtrade/persistence/trade_model.py | 6 ++++-- tests/persistence/test_trade_fromjson.py | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 54ff1313b..17117d436 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -1663,8 +1663,10 @@ class Trade(ModelBase, LocalTrade): stop_loss=data["stop_loss_abs"], stop_loss_pct=data["stop_loss_ratio"], stoploss_order_id=data["stoploss_order_id"], - stoploss_last_update=(datetime.fromtimestamp(data["stoploss_last_update"] // 1000, - tz=timezone.utc) if data["stoploss_last_update"] else None), + stoploss_last_update=( + datetime.fromtimestamp(data["stoploss_last_update_timestamp"] // 1000, + tz=timezone.utc) + if data["stoploss_last_update_timestamp"] else None), initial_stop_loss=data["initial_stop_loss_abs"], initial_stop_loss_pct=data["initial_stop_loss_ratio"], min_rate=data["min_rate"], diff --git a/tests/persistence/test_trade_fromjson.py b/tests/persistence/test_trade_fromjson.py index 529008e02..22053463d 100644 --- a/tests/persistence/test_trade_fromjson.py +++ b/tests/persistence/test_trade_fromjson.py @@ -50,8 +50,8 @@ def test_trade_fromjson(): "stop_loss_ratio": -0.216, "stop_loss_pct": -21.6, "stoploss_order_id": null, - "stoploss_last_update": null, - "stoploss_last_update_timestamp": null, + "stoploss_last_update": "2022-10-18 09:13:42", + "stoploss_last_update_timestamp": 1666077222000, "initial_stop_loss_abs": 0.1981, "initial_stop_loss_ratio": -0.216, "initial_stop_loss_pct": -21.6, From 86aef7cf9da6eec4c4bdb621bba33c7a38d7eeb5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 11:21:18 +0200 Subject: [PATCH 26/63] Add current_time to bot_loop_start callbak --- docs/strategy-callbacks.md | 3 ++- freqtrade/freqtradebot.py | 3 ++- freqtrade/optimize/backtesting.py | 3 ++- freqtrade/plot/plotting.py | 3 ++- freqtrade/strategy/interface.py | 3 ++- .../strategy_subtemplates/strategy_methods_advanced.j2 | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 64b6bd551..bdc809a22 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -62,11 +62,12 @@ class AwesomeStrategy(IStrategy): # ... populate_* methods - def bot_loop_start(self, **kwargs) -> None: + def bot_loop_start(self, current_time: datetime, **kwargs) -> None: """ Called at the start of the bot iteration (one loop). Might be used to perform pair-independent tasks (e.g. gather some remote resource for comparison) + :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. """ if self.config['runmode'].value in ('live', 'dry_run'): diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index cec7176f6..21d23e49b 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -212,7 +212,8 @@ class FreqtradeBot(LoggingMixin): self.dataprovider.refresh(self.pairlists.create_pair_list(self.active_pair_whitelist), self.strategy.gather_informative_pairs()) - strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)() + strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)( + current_time=datetime.now(timezone.utc)) self.strategy.analyze(self.active_pair_whitelist) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index ccb027317..699e3c3cb 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -1158,7 +1158,8 @@ class Backtesting: while current_time <= end_date: open_trade_count_start = LocalTrade.bt_open_open_trade_count self.check_abort() - strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)() + strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)( + current_time=current_time) for i, pair in enumerate(data): row_index = indexes[pair] row = self.validate_row(data, pair, row_index, current_time) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 1b2ee44da..e415c4911 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -1,4 +1,5 @@ import logging +from datetime import datetime, timezone from pathlib import Path from typing import Dict, List, Optional @@ -635,7 +636,7 @@ def load_and_plot_trades(config: Config): exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config) IStrategy.dp = DataProvider(config, exchange) strategy.ft_bot_start() - strategy.bot_loop_start() + strategy.bot_loop_start(datetime.now(timezone.utc)) plot_elements = init_plotscript(config, list(exchange.markets), strategy.startup_candle_count) timerange = plot_elements['timerange'] trades = plot_elements['trades'] diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 96b2ac8ce..6d4a3036f 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -251,11 +251,12 @@ class IStrategy(ABC, HyperStrategyMixin): """ pass - def bot_loop_start(self, **kwargs) -> None: + def bot_loop_start(self, current_time: datetime, **kwargs) -> None: """ Called at the start of the bot iteration (one loop). Might be used to perform pair-independent tasks (e.g. gather some remote resource for comparison) + :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. """ pass diff --git a/freqtrade/templates/strategy_subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/strategy_subtemplates/strategy_methods_advanced.j2 index 488ca2fd7..bfbb20ec1 100644 --- a/freqtrade/templates/strategy_subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/strategy_subtemplates/strategy_methods_advanced.j2 @@ -1,5 +1,5 @@ -def bot_loop_start(self, **kwargs) -> None: +def bot_loop_start(self, current_time: datetime, **kwargs) -> None: """ Called at the start of the bot iteration (one loop). Might be used to perform pair-independent tasks @@ -8,6 +8,7 @@ def bot_loop_start(self, **kwargs) -> None: For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/ When not implemented by a strategy, this simply does nothing. + :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. """ pass From 7cdcd97c266662be3e0be79e9e8f39b4e8e81d7f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 11:30:44 +0200 Subject: [PATCH 27/63] Update tests for new logic. --- tests/optimize/test_backtesting.py | 6 ++++-- tests/optimize/test_hyperopt.py | 9 ++++++--- tests/strategy/strats/hyperoptable_strategy.py | 2 ++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 8dee45b6d..9dbda51b0 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -344,7 +344,7 @@ def test_backtest_abort(default_conf, mocker, testdatadir) -> None: assert backtesting.progress.progress == 0 -def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: +def test_backtesting_start(default_conf, mocker, caplog) -> None: def get_timerange(input1): return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59) @@ -367,6 +367,7 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: backtesting = Backtesting(default_conf) backtesting._set_strategy(backtesting.strategylist[0]) backtesting.strategy.bot_loop_start = MagicMock() + backtesting.strategy.bot_start = MagicMock() backtesting.start() # check the logs, that will contain the backtest result exists = [ @@ -376,7 +377,8 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: for line in exists: assert log_has(line, caplog) assert backtesting.strategy.dp._pairlists is not None - assert backtesting.strategy.bot_loop_start.call_count == 1 + assert backtesting.strategy.bot_start.call_count == 1 + assert backtesting.strategy.bot_loop_start.call_count == 0 assert sbs.call_count == 1 assert sbc.call_count == 1 diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 998798580..786720030 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -872,7 +872,8 @@ 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.bot_started is True + assert hyperopt.backtesting.strategy.bot_loop_started is False assert hyperopt.backtesting.strategy.buy_rsi.in_space is True assert hyperopt.backtesting.strategy.buy_rsi.value == 35 @@ -922,7 +923,8 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmpdir, 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.bot_started is True + assert hyperopt.backtesting.strategy.bot_loop_started is False assert hyperopt.backtesting.strategy.buy_rsi.in_space is True assert hyperopt.backtesting.strategy.buy_rsi.value == 35 @@ -959,7 +961,8 @@ def test_in_strategy_auto_hyperopt_per_epoch(mocker, hyperopt_conf, tmpdir, fee) 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.bot_loop_started is False + assert hyperopt.backtesting.strategy.bot_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 eadbc533f..d05e8ead2 100644 --- a/tests/strategy/strats/hyperoptable_strategy.py +++ b/tests/strategy/strats/hyperoptable_strategy.py @@ -50,6 +50,7 @@ class HyperoptableStrategy(StrategyTestV3): return prot bot_loop_started = False + bot_started = False def bot_loop_start(self): self.bot_loop_started = True @@ -58,6 +59,7 @@ class HyperoptableStrategy(StrategyTestV3): """ Parameters can also be defined here ... """ + self.bot_started = True self.buy_rsi = IntParameter([0, 50], default=30, space='buy') def informative_pairs(self): From 16057da6cc5f7c418df8c521a7d6dc11f1271267 Mon Sep 17 00:00:00 2001 From: escanoro <128816061+escanoro@users.noreply.github.com> Date: Sun, 26 Mar 2023 14:09:41 +0200 Subject: [PATCH 28/63] typo: above should be below --- docs/freqai-reinforcement-learning.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/freqai-reinforcement-learning.md b/docs/freqai-reinforcement-learning.md index ed6a41825..f5679a4ba 100644 --- a/docs/freqai-reinforcement-learning.md +++ b/docs/freqai-reinforcement-learning.md @@ -55,7 +55,7 @@ where `ReinforcementLearner` will use the templated `ReinforcementLearner` from dataframe["&-action"] = 0 ``` -Most of the function remains the same as for typical Regressors, however, the function above shows how the strategy must pass the raw price data to the agent so that it has access to raw OHLCV in the training environment: +Most of the function remains the same as for typical Regressors, however, the function below shows how the strategy must pass the raw price data to the agent so that it has access to raw OHLCV in the training environment: ```python def feature_engineering_standard(self, dataframe, **kwargs): From 444d18aa39cd7d143a152fa7d17ac79be3726a19 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 14:30:29 +0200 Subject: [PATCH 29/63] Revert binance PO fix, since ccxt has fixed this bug. --- freqtrade/exchange/binance.py | 21 --------------------- tests/exchange/test_binance.py | 4 ++-- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index a89c02631..7ac496f62 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -7,7 +7,6 @@ from typing import Dict, List, Optional, Tuple import arrow import ccxt -from freqtrade.constants import BuySell from freqtrade.enums import CandleType, MarginMode, PriceType, TradingMode from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange @@ -49,26 +48,6 @@ class Binance(Exchange): (TradingMode.FUTURES, MarginMode.ISOLATED) ] - def _get_params( - self, - side: BuySell, - ordertype: str, - leverage: float, - reduceOnly: bool, - time_in_force: str = 'GTC', - ) -> Dict: - params = super()._get_params(side, ordertype, leverage, reduceOnly, time_in_force) - if ( - time_in_force == 'PO' - and ordertype != 'market' - and self.trading_mode == TradingMode.SPOT - # Only spot can do post only orders - ): - params.pop('timeInForce') - params['postOnly'] = True - - return params - def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Tickers: tickers = super().get_tickers(symbols=symbols, cached=cached) if self.trading_mode == TradingMode.FUTURES: diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index 273860e15..fda33b859 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -15,8 +15,8 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers ('buy', 'limit', 'gtc', {'timeInForce': 'GTC'}), ('buy', 'limit', 'IOC', {'timeInForce': 'IOC'}), ('buy', 'market', 'IOC', {}), - ('buy', 'limit', 'PO', {'postOnly': True}), - ('sell', 'limit', 'PO', {'postOnly': True}), + ('buy', 'limit', 'PO', {'timeInForce': 'PO'}), + ('sell', 'limit', 'PO', {'timeInForce': 'PO'}), ('sell', 'market', 'PO', {}), ]) def test__get_params_binance(default_conf, mocker, side, type, time_in_force, expected): From fb1541bdf632c5c9b6f8e96907fbd1986ff0bff7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 15:46:20 +0200 Subject: [PATCH 30/63] Explicitly close loop in async tests --- freqtrade/exchange/exchange.py | 2 ++ tests/exchange/test_exchange.py | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 104eaa221..92eb4b58a 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -205,6 +205,8 @@ class Exchange: and self._api_async.session): logger.debug("Closing async ccxt session.") self.loop.run_until_complete(self._api_async.close()) + if self.loop and not self.loop.is_closed(): + self.loop.close() def validate_config(self, config): # Check if timeframe is available diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 586f023b4..5350f4e3e 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -113,18 +113,21 @@ async def async_ccxt_exception(mocker, default_conf, api_mock, fun, mock_ccxt_fu exchange = get_patched_exchange(mocker, default_conf, api_mock) await getattr(exchange, fun)(**kwargs) assert api_mock.__dict__[mock_ccxt_fun].call_count == retries + exchange.close() with pytest.raises(TemporaryError): api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError("DeadBeef")) exchange = get_patched_exchange(mocker, default_conf, api_mock) await getattr(exchange, fun)(**kwargs) assert api_mock.__dict__[mock_ccxt_fun].call_count == retries + exchange.close() with pytest.raises(OperationalException): api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.BaseError("DeadBeef")) exchange = get_patched_exchange(mocker, default_conf, api_mock) await getattr(exchange, fun)(**kwargs) assert api_mock.__dict__[mock_ccxt_fun].call_count == 1 + exchange.close() def test_init(default_conf, mocker, caplog): @@ -2248,7 +2251,6 @@ def test_refresh_latest_ohlcv_cache(mocker, default_conf, candle_type, time_mach assert res[pair2].at[0, 'open'] -@pytest.mark.asyncio @pytest.mark.parametrize("exchange_name", EXCHANGES) async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_name): ohlcv = [ @@ -2277,7 +2279,7 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_ assert res[3] == ohlcv assert exchange._api_async.fetch_ohlcv.call_count == 1 assert not log_has(f"Using cached candle (OHLCV) data for {pair} ...", caplog) - + exchange.close() # exchange = Exchange(default_conf) await async_ccxt_exception(mocker, default_conf, MagicMock(), "_async_get_candle_history", "fetch_ohlcv", @@ -2292,15 +2294,17 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_ await exchange._async_get_candle_history(pair, "5m", CandleType.SPOT, (arrow.utcnow().int_timestamp - 2000) * 1000) + exchange.close() + with pytest.raises(OperationalException, match=r'Exchange.* does not support fetching ' r'historical candle \(OHLCV\) data\..*'): api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.NotSupported("Not supported")) exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) await exchange._async_get_candle_history(pair, "5m", CandleType.SPOT, (arrow.utcnow().int_timestamp - 2000) * 1000) + exchange.close() -@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() @@ -2341,9 +2345,9 @@ async def test__async_kucoin_get_candle_history(default_conf, mocker, caplog): # Expect the "returned exception" message 12 times (4 retries * 3 (loop)) assert num_log_has_re(msg, caplog) == 12 assert num_log_has_re(msg2, caplog) == 9 + exchange.close() -@pytest.mark.asyncio async def test__async_get_candle_history_empty(default_conf, mocker, caplog): """ Test empty exchange result """ ohlcv = [] @@ -2363,6 +2367,7 @@ async def test__async_get_candle_history_empty(default_conf, mocker, caplog): assert res[2] == CandleType.SPOT assert res[3] == ohlcv assert exchange._api_async.fetch_ohlcv.call_count == 1 + exchange.close() def test_refresh_latest_ohlcv_inv_result(default_conf, mocker, caplog): @@ -2757,7 +2762,6 @@ async def test___async_get_candle_history_sort(default_conf, mocker, exchange_na assert res_ohlcv[9][5] == 2.31452783 -@pytest.mark.asyncio @pytest.mark.parametrize("exchange_name", EXCHANGES) async def test__async_fetch_trades(default_conf, mocker, caplog, exchange_name, fetch_trades_result): @@ -2785,8 +2789,8 @@ async def test__async_fetch_trades(default_conf, mocker, caplog, exchange_name, assert exchange._api_async.fetch_trades.call_args[1]['limit'] == 1000 assert exchange._api_async.fetch_trades.call_args[1]['params'] == {'from': '123'} assert log_has_re(f"Fetching trades for pair {pair}, params: .*", caplog) + exchange.close() - exchange = Exchange(default_conf) await async_ccxt_exception(mocker, default_conf, MagicMock(), "_async_fetch_trades", "fetch_trades", pair='ABCD/BTC', since=None) @@ -2796,15 +2800,16 @@ async def test__async_fetch_trades(default_conf, mocker, caplog, exchange_name, api_mock.fetch_trades = MagicMock(side_effect=ccxt.BaseError("Unknown error")) exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) await exchange._async_fetch_trades(pair, since=(arrow.utcnow().int_timestamp - 2000) * 1000) + exchange.close() with pytest.raises(OperationalException, match=r'Exchange.* does not support fetching ' r'historical trade data\..*'): api_mock.fetch_trades = MagicMock(side_effect=ccxt.NotSupported("Not supported")) exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) await exchange._async_fetch_trades(pair, since=(arrow.utcnow().int_timestamp - 2000) * 1000) + exchange.close() -@pytest.mark.asyncio @pytest.mark.parametrize("exchange_name", EXCHANGES) async def test__async_fetch_trades_contract_size(default_conf, mocker, caplog, exchange_name, fetch_trades_result): @@ -2839,6 +2844,7 @@ async def test__async_fetch_trades_contract_size(default_conf, mocker, caplog, e pair = 'ETH/USDT:USDT' res = await exchange._async_fetch_trades(pair, since=None, params=None) assert res[0][5] == 300 + exchange.close() @pytest.mark.asyncio @@ -4807,7 +4813,6 @@ def test_load_leverage_tiers(mocker, default_conf, leverage_tiers, exchange_name ) -@pytest.mark.asyncio @pytest.mark.parametrize('exchange_name', EXCHANGES) async def test_get_market_leverage_tiers(mocker, default_conf, exchange_name): default_conf['exchange']['name'] = exchange_name From b09fb5826f9404bd60963736307b6efa3649461f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 16:17:10 +0200 Subject: [PATCH 31/63] don't use "can_short" in backtesting to determine application of leverage --- freqtrade/optimize/backtesting.py | 2 +- tests/optimize/test_backtest_detail.py | 4 +++- tests/optimize/test_backtesting_adjust_position.py | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 702b4fb85..cd77c75a5 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -739,7 +739,7 @@ class Backtesting: proposed_leverage=1.0, max_leverage=max_leverage, side=direction, entry_tag=entry_tag, - ) if self._can_short else 1.0 + ) 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/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 2cb42c003..dd9e42971 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -5,7 +5,7 @@ from unittest.mock import MagicMock import pytest from freqtrade.data.history import get_timerange -from freqtrade.enums import ExitType +from freqtrade.enums import ExitType, TradingMode from freqtrade.optimize.backtesting import Backtesting from freqtrade.persistence.trade_model import LocalTrade from tests.conftest import EXMS, patch_exchange @@ -925,11 +925,13 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=0.00001) mocker.patch(f"{EXMS}.get_max_pair_stake_amount", return_value=float('inf')) mocker.patch(f"{EXMS}.get_max_leverage", return_value=100) + mocker.patch(f"{EXMS}.calculate_funding_fees", return_value=0) patch_exchange(mocker) frame = _build_backtest_dataframe(data.data) backtesting = Backtesting(default_conf) # TODO: Should we initialize this properly?? backtesting._can_short = True + backtesting.trading_mode = TradingMode.MARGIN backtesting._set_strategy(backtesting.strategylist[0]) backtesting.required_startup = 0 backtesting.strategy.advise_entry = lambda a, m: frame diff --git a/tests/optimize/test_backtesting_adjust_position.py b/tests/optimize/test_backtesting_adjust_position.py index 9fc726bd1..0d57ff89a 100644 --- a/tests/optimize/test_backtesting_adjust_position.py +++ b/tests/optimize/test_backtesting_adjust_position.py @@ -10,7 +10,7 @@ from arrow import Arrow from freqtrade.configuration import TimeRange from freqtrade.data import history from freqtrade.data.history import get_timerange -from freqtrade.enums import ExitType +from freqtrade.enums import ExitType, TradingMode from freqtrade.optimize.backtesting import Backtesting from tests.conftest import EXMS, patch_exchange @@ -108,9 +108,10 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker, levera default_conf.update({ "stake_amount": 100.0, "dry_run_wallet": 1000.0, - "strategy": "StrategyTestV3" + "strategy": "StrategyTestV3", }) backtesting = Backtesting(default_conf) + backtesting.trading_mode = TradingMode.FUTURES backtesting._can_short = True backtesting._set_strategy(backtesting.strategylist[0]) pair = 'XRP/USDT' From c14ac8a205e53bf8f6ecbb16292efae96101331b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 16:46:41 +0200 Subject: [PATCH 32/63] Properly handle non-replaced first entry orders --- freqtrade/optimize/backtesting.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index cd77c75a5..31e133515 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -1029,6 +1029,9 @@ class Backtesting: requested_stake=( order.safe_remaining * order.ft_price / trade.leverage), direction='short' if trade.is_short else 'long') + # Delete trade if no successful entries happened (if placing the new order failed) + if trade.open_order_id is None and trade.nr_of_successful_entries == 0 : + return True self.replaced_entry_orders += 1 else: # assumption: there can't be multiple open entry orders at any given time From 1c9abd9e3579097bb6c3c323e2d765afe551f351 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 17:27:52 +0200 Subject: [PATCH 33/63] Properly respect can_short flag in backtesting closes #8387 --- freqtrade/optimize/backtesting.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 31e133515..a701b04e4 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -203,6 +203,8 @@ 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 + # Update can_short flag + self._can_short = self.trading_mode != TradingMode.SPOT and strategy.can_short self.strategy.ft_bot_start() From 80a27bc0db800d336b036411cccda7df97000a84 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 18:18:52 +0200 Subject: [PATCH 34/63] Fix random uvicorn error --- freqtrade/optimize/backtesting.py | 2 +- tests/rpc/test_rpc_apiserver.py | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index a701b04e4..c7b2a0d3c 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -1032,7 +1032,7 @@ class Backtesting: order.safe_remaining * order.ft_price / trade.leverage), direction='short' if trade.is_short else 'long') # Delete trade if no successful entries happened (if placing the new order failed) - if trade.open_order_id is None and trade.nr_of_successful_entries == 0 : + if trade.open_order_id is None and trade.nr_of_successful_entries == 0: return True self.replaced_entry_orders += 1 else: diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index bf9d6cc3b..31075e514 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1,6 +1,7 @@ """ Unit test file for rpc/api_server.py """ +import asyncio import logging import time from datetime import datetime, timedelta, timezone @@ -299,10 +300,6 @@ def test_api_UvicornServer(mocker): s = UvicornServer(uvicorn.Config(MagicMock(), port=8080, host='127.0.0.1')) assert thread_mock.call_count == 0 - s.install_signal_handlers() - # Original implementation starts a thread - make sure that's not the case - assert thread_mock.call_count == 0 - # Fake started to avoid sleeping forever s.started = True s.run_in_thread() @@ -318,10 +315,6 @@ def test_api_UvicornServer_run(mocker): s = UvicornServer(uvicorn.Config(MagicMock(), port=8080, host='127.0.0.1')) assert serve_mock.call_count == 0 - s.install_signal_handlers() - # Original implementation starts a thread - make sure that's not the case - assert serve_mock.call_count == 0 - # Fake started to avoid sleeping forever s.started = True s.run() @@ -331,13 +324,10 @@ def test_api_UvicornServer_run(mocker): def test_api_UvicornServer_run_no_uvloop(mocker, import_fails): serve_mock = mocker.patch('freqtrade.rpc.api_server.uvicorn_threaded.UvicornServer.serve', get_mock_coro(None)) + asyncio.set_event_loop(asyncio.new_event_loop()) s = UvicornServer(uvicorn.Config(MagicMock(), port=8080, host='127.0.0.1')) assert serve_mock.call_count == 0 - s.install_signal_handlers() - # Original implementation starts a thread - make sure that's not the case - assert serve_mock.call_count == 0 - # Fake started to avoid sleeping forever s.started = True s.run() From 72284317c2cfefe6b22558b169a328016c426e17 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Mar 2023 18:21:21 +0200 Subject: [PATCH 35/63] Fix failing backtest test --- tests/optimize/test_backtest_detail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index dd9e42971..158dd04dc 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -930,9 +930,9 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) frame = _build_backtest_dataframe(data.data) backtesting = Backtesting(default_conf) # TODO: Should we initialize this properly?? - backtesting._can_short = True backtesting.trading_mode = TradingMode.MARGIN backtesting._set_strategy(backtesting.strategylist[0]) + backtesting._can_short = True backtesting.required_startup = 0 backtesting.strategy.advise_entry = lambda a, m: frame backtesting.strategy.advise_exit = lambda a, m: frame From 2f8f60373e6331c6ad0519e70816b1af3ad8f057 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 03:56:49 +0000 Subject: [PATCH 36/63] Bump ccxt from 3.0.23 to 3.0.36 Bumps [ccxt](https://github.com/ccxt/ccxt) from 3.0.23 to 3.0.36. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/CHANGELOG.md) - [Commits](https://github.com/ccxt/ccxt/compare/3.0.23...3.0.36) --- 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 ad34883ae..7e7463d9f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.24.2 pandas==1.5.3 pandas-ta==0.3.14b -ccxt==3.0.23 +ccxt==3.0.36 cryptography==39.0.2 aiohttp==3.8.4 SQLAlchemy==2.0.7 From 1b3d9efedd9a9c4a2bc367cd3fd1d4d2734c8848 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 03:56:55 +0000 Subject: [PATCH 37/63] Bump types-requests from 2.28.11.15 to 2.28.11.16 Bumps [types-requests](https://github.com/python/typeshed) from 2.28.11.15 to 2.28.11.16. - [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 8312e2820..a9458b51d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -27,6 +27,6 @@ nbconvert==7.2.10 # mypy types types-cachetools==5.3.0.4 types-filelock==3.2.7 -types-requests==2.28.11.15 +types-requests==2.28.11.16 types-tabulate==0.9.0.1 types-python-dateutil==2.8.19.10 From 75c31cc8cc966af3964e419f8cea0ba42a32a720 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 03:57:14 +0000 Subject: [PATCH 38/63] Bump ruff from 0.0.257 to 0.0.259 Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.257 to 0.0.259. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.257...v0.0.259) --- updated-dependencies: - dependency-name: ruff 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 8312e2820..02d384889 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ -r docs/requirements-docs.txt coveralls==3.3.1 -ruff==0.0.257 +ruff==0.0.259 mypy==1.1.1 pre-commit==3.2.0 pytest==7.2.2 From b72f61080b98abfa8933686f42c59c8131ce097c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 03:57:46 +0000 Subject: [PATCH 39/63] Bump orjson from 3.8.7 to 3.8.8 Bumps [orjson](https://github.com/ijl/orjson) from 3.8.7 to 3.8.8. - [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.8.7...3.8.8) --- 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 ad34883ae..80fc1f776 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.10 # Properly format api responses -orjson==3.8.7 +orjson==3.8.8 # Notify systemd sdnotify==0.3.2 From d13ea71a58744eb2bf4e2ae39bd5bc3763cf19e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 03:57:55 +0000 Subject: [PATCH 40/63] Bump mkdocs-material from 9.1.3 to 9.1.4 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.1.3 to 9.1.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/9.1.3...9.1.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 110373844..7f4215aef 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,6 +1,6 @@ markdown==3.3.7 mkdocs==1.4.2 -mkdocs-material==9.1.3 +mkdocs-material==9.1.4 mdx_truly_sane_lists==1.3 pymdown-extensions==9.10 jinja2==3.1.2 From 8955e091750cf805f5e01b3ec56ebb6c42d2f1cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 03:58:00 +0000 Subject: [PATCH 41/63] Bump filelock from 3.10.0 to 3.10.6 Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.10.0 to 3.10.6. - [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.10.0...3.10.6) --- 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 4d86da2b6..2c7c27d98 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -5,5 +5,5 @@ scipy==1.10.1 scikit-learn==1.1.3 scikit-optimize==0.9.0 -filelock==3.10.0 +filelock==3.10.6 progressbar2==4.2.0 From 7e11bce4f44a8272832095ea21b6306346f6010f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 03:58:02 +0000 Subject: [PATCH 42/63] Bump pypa/gh-action-pypi-publish from 1.8.1 to 1.8.3 Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.1 to 1.8.3. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.8.1...v1.8.3) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .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 904387fb2..5c80bc141 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -425,7 +425,7 @@ jobs: python setup.py sdist bdist_wheel - name: Publish to PyPI (Test) - uses: pypa/gh-action-pypi-publish@v1.8.1 + uses: pypa/gh-action-pypi-publish@v1.8.3 if: (github.event_name == 'release') with: user: __token__ @@ -433,7 +433,7 @@ jobs: repository_url: https://test.pypi.org/legacy/ - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@v1.8.1 + uses: pypa/gh-action-pypi-publish@v1.8.3 if: (github.event_name == 'release') with: user: __token__ From 8845f765db7e217e6810184cb7efe3b3415f741d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Mar 2023 06:25:11 +0200 Subject: [PATCH 43/63] pre-commit - bump requests --- .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 ca3da8e90..4784055a9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: additional_dependencies: - types-cachetools==5.3.0.4 - types-filelock==3.2.7 - - types-requests==2.28.11.15 + - types-requests==2.28.11.16 - types-tabulate==0.9.0.1 - types-python-dateutil==2.8.19.10 - SQLAlchemy==2.0.7 From 4891174a71730db31aeef08e431d890ceb2afea1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Mar 2023 06:44:36 +0200 Subject: [PATCH 44/63] list-data should sort pairs also in timerange mode --- freqtrade/commands/data_commands.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index 1e74e1036..bcef1c252 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -204,11 +204,14 @@ def start_list_data(args: Dict[str, Any]) -> None: pair, timeframe, candle_type, *dhc.ohlcv_data_min_max(pair, timeframe, candle_type) ) for pair, timeframe, candle_type in paircombs] + print(tabulate([ (pair, timeframe, candle_type, start.strftime(DATETIME_PRINT_FORMAT), end.strftime(DATETIME_PRINT_FORMAT)) - for pair, timeframe, candle_type, start, end in paircombs1 + for pair, timeframe, candle_type, start, end in sorted( + paircombs1, + key=lambda x: (x[0], timeframe_to_minutes(x[1]), x[2])) ], headers=("Pair", "Timeframe", "Type", 'From', 'To'), tablefmt='psql', stralign='right')) From 1743ad7946ddc6e1c6a550e0716094ab246d1ff5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 05:14:04 +0000 Subject: [PATCH 45/63] Bump pre-commit from 3.2.0 to 3.2.1 Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.2.0 to 3.2.1. - [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/v3.2.0...v3.2.1) --- updated-dependencies: - dependency-name: pre-commit 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 02d384889..afb8d0bf4 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -9,7 +9,7 @@ coveralls==3.3.1 ruff==0.0.259 mypy==1.1.1 -pre-commit==3.2.0 +pre-commit==3.2.1 pytest==7.2.2 pytest-asyncio==0.21.0 pytest-cov==4.0.0 From bc0816aa66d4acb41d7b98c04529421a55e32faa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 05:15:59 +0000 Subject: [PATCH 46/63] Bump cryptography from 39.0.2 to 40.0.1 Bumps [cryptography](https://github.com/pyca/cryptography) from 39.0.2 to 40.0.1. - [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/39.0.2...40.0.1) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7e7463d9f..b32ed2808 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ pandas==1.5.3 pandas-ta==0.3.14b ccxt==3.0.36 -cryptography==39.0.2 +cryptography==40.0.1 aiohttp==3.8.4 SQLAlchemy==2.0.7 python-telegram-bot==13.15 From 90669e0ba9ecb1387d32d759a1372bb89d0fe901 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 07:49:56 +0000 Subject: [PATCH 47/63] Bump ccxt from 3.0.36 to 3.0.37 Bumps [ccxt](https://github.com/ccxt/ccxt) from 3.0.36 to 3.0.37. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/CHANGELOG.md) - [Commits](https://github.com/ccxt/ccxt/compare/3.0.36...3.0.37) --- 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 7d25fa5a1..809925488 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.24.2 pandas==1.5.3 pandas-ta==0.3.14b -ccxt==3.0.36 +ccxt==3.0.37 cryptography==40.0.1 aiohttp==3.8.4 SQLAlchemy==2.0.7 From 4f4dfa2a59a03acf3e877727fb0bfe6c7ae8af0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 07:50:06 +0000 Subject: [PATCH 48/63] Bump pydantic from 1.10.6 to 1.10.7 Bumps [pydantic](https://github.com/pydantic/pydantic) from 1.10.6 to 1.10.7. - [Release notes](https://github.com/pydantic/pydantic/releases) - [Changelog](https://github.com/pydantic/pydantic/blob/v1.10.7/HISTORY.md) - [Commits](https://github.com/pydantic/pydantic/compare/v1.10.6...v1.10.7) --- updated-dependencies: - dependency-name: pydantic 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 7d25fa5a1..00b8dc390 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,7 +35,7 @@ sdnotify==0.3.2 # API Server fastapi==0.95.0 -pydantic==1.10.6 +pydantic==1.10.7 uvicorn==0.21.1 pyjwt==2.6.0 aiofiles==23.1.0 From e35c85000e0ee872960157c1a887468d44b4f60b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Mar 2023 20:19:23 +0200 Subject: [PATCH 49/63] Excude raspberry from catboost installs closes #8404 --- requirements-freqai.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-freqai.txt b/requirements-freqai.txt index bc0be85e5..e6eae667c 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -5,7 +5,7 @@ # Required for freqai scikit-learn==1.1.3 joblib==1.2.0 -catboost==1.1.1; platform_machine != 'aarch64' and python_version < '3.11' +catboost==1.1.1; platform_machine != 'aarch64' and 'arm' not in platform_machine and python_version < '3.11' lightgbm==3.3.5 xgboost==1.7.4 tensorboard==2.12.0 From 3928051baf6faa162dd865f6b4f2ce7281944ade Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Mar 2023 20:35:19 +0200 Subject: [PATCH 50/63] Revert unneeded formatting changes --- freqtrade/data/history/featherdatahandler.py | 3 +- tests/data/test_datahandler.py | 54 +++++++------------- 2 files changed, 19 insertions(+), 38 deletions(-) diff --git a/freqtrade/data/history/featherdatahandler.py b/freqtrade/data/history/featherdatahandler.py index 87c1d0886..4e016080c 100644 --- a/freqtrade/data/history/featherdatahandler.py +++ b/freqtrade/data/history/featherdatahandler.py @@ -30,8 +30,7 @@ class FeatherDataHandler(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, timeframe, candle_type) self.create_dir_if_needed(filename) data.reset_index(drop=True).loc[:, self._columns].to_feather( diff --git a/tests/data/test_datahandler.py b/tests/data/test_datahandler.py index 2c5241367..f19b15455 100644 --- a/tests/data/test_datahandler.py +++ b/tests/data/test_datahandler.py @@ -20,31 +20,25 @@ from tests.conftest import log_has, log_has_re def test_datahandler_ohlcv_get_pairs(testdatadir): - pairs = JsonDataHandler.ohlcv_get_pairs( - testdatadir, '5m', candle_type=CandleType.SPOT) + pairs = JsonDataHandler.ohlcv_get_pairs(testdatadir, '5m', candle_type=CandleType.SPOT) # Convert to set to avoid failures due to sorting assert set(pairs) == {'UNITTEST/BTC', 'XLM/BTC', 'ETH/BTC', 'TRX/BTC', 'LTC/BTC', 'XMR/BTC', 'ZEC/BTC', 'ADA/BTC', 'ETC/BTC', 'NXT/BTC', 'DASH/BTC', 'XRP/ETH'} - pairs = JsonGzDataHandler.ohlcv_get_pairs( - testdatadir, '8m', candle_type=CandleType.SPOT) + pairs = JsonGzDataHandler.ohlcv_get_pairs(testdatadir, '8m', candle_type=CandleType.SPOT) assert set(pairs) == {'UNITTEST/BTC'} - pairs = HDF5DataHandler.ohlcv_get_pairs( - testdatadir, '5m', candle_type=CandleType.SPOT) + pairs = HDF5DataHandler.ohlcv_get_pairs(testdatadir, '5m', candle_type=CandleType.SPOT) assert set(pairs) == {'UNITTEST/BTC'} - pairs = JsonDataHandler.ohlcv_get_pairs( - testdatadir, '1h', candle_type=CandleType.MARK) + pairs = JsonDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.MARK) assert set(pairs) == {'UNITTEST/USDT:USDT', 'XRP/USDT:USDT'} - pairs = JsonGzDataHandler.ohlcv_get_pairs( - testdatadir, '1h', candle_type=CandleType.FUTURES) + pairs = JsonGzDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.FUTURES) assert set(pairs) == {'XRP/USDT:USDT'} - pairs = HDF5DataHandler.ohlcv_get_pairs( - testdatadir, '1h', candle_type=CandleType.MARK) + pairs = HDF5DataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.MARK) assert set(pairs) == {'UNITTEST/USDT:USDT'} @@ -85,8 +79,7 @@ def test_rebuild_pair_from_filename(input, expected): def test_datahandler_ohlcv_get_available_data(testdatadir): - paircombs = JsonDataHandler.ohlcv_get_available_data( - testdatadir, TradingMode.SPOT) + paircombs = JsonDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT) # Convert to set to avoid failures due to sorting assert set(paircombs) == { ('UNITTEST/BTC', '5m', CandleType.SPOT), @@ -108,8 +101,7 @@ def test_datahandler_ohlcv_get_available_data(testdatadir): ('NOPAIR/XXX', '4m', CandleType.SPOT), } - paircombs = JsonDataHandler.ohlcv_get_available_data( - testdatadir, TradingMode.FUTURES) + paircombs = JsonDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.FUTURES) # Convert to set to avoid failures due to sorting assert set(paircombs) == { ('UNITTEST/USDT:USDT', '1h', 'mark'), @@ -120,11 +112,9 @@ def test_datahandler_ohlcv_get_available_data(testdatadir): ('XRP/USDT:USDT', '8h', 'funding_rate'), } - paircombs = JsonGzDataHandler.ohlcv_get_available_data( - testdatadir, TradingMode.SPOT) + paircombs = JsonGzDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT) assert set(paircombs) == {('UNITTEST/BTC', '8m', CandleType.SPOT)} - paircombs = HDF5DataHandler.ohlcv_get_available_data( - testdatadir, TradingMode.SPOT) + paircombs = HDF5DataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT) assert set(paircombs) == {('UNITTEST/BTC', '5m', CandleType.SPOT)} @@ -416,21 +406,18 @@ def test_hdf5datahandler_ohlcv_load_and_resave( assert not ohlcv[ohlcv['date'] < startdt].empty - timerange = TimeRange.parse_timerange( - f"{startdt.replace('-', '')}-{enddt.replace('-', '')}") + timerange = TimeRange.parse_timerange(f"{startdt.replace('-', '')}-{enddt.replace('-', '')}") # Call private function to ensure timerange is filtered in hdf5 ohlcv = dh._ohlcv_load(pair, timeframe, timerange, candle_type=candle_type) - ohlcv1 = dh1._ohlcv_load('UNITTEST/NEW', timeframe, - timerange, candle_type=candle_type) + ohlcv1 = dh1._ohlcv_load('UNITTEST/NEW', timeframe, timerange, candle_type=candle_type) assert len(ohlcv) == len(ohlcv1) assert ohlcv.equals(ohlcv1) assert ohlcv[ohlcv['date'] < startdt].empty assert ohlcv[ohlcv['date'] > enddt].empty # Try loading inexisting file - ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', timeframe, - candle_type=candle_type) + ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', timeframe, candle_type=candle_type) assert ohlcv.empty @@ -465,8 +452,7 @@ def test_generic_datahandler_ohlcv_load_and_resave( # Get data to test dh = get_datahandler(testdatadir, datahandler) - file = tmpdir2 / \ - f"UNITTEST_NEW-{timeframe}{candle_append}.{dh._get_file_extension()}" + file = tmpdir2 / f"UNITTEST_NEW-{timeframe}{candle_append}.{dh._get_file_extension()}" assert not file.is_file() dh1 = get_datahandler(tmpdir1, datahandler) @@ -475,14 +461,11 @@ def test_generic_datahandler_ohlcv_load_and_resave( assert not ohlcv[ohlcv['date'] < startdt].empty - timerange = TimeRange.parse_timerange( - f"{startdt.replace('-', '')}-{enddt.replace('-', '')}") + timerange = TimeRange.parse_timerange(f"{startdt.replace('-', '')}-{enddt.replace('-', '')}") - ohlcv = dhbase.ohlcv_load( - pair, timeframe, timerange=timerange, candle_type=candle_type) + ohlcv = dhbase.ohlcv_load(pair, timeframe, timerange=timerange, candle_type=candle_type) if datahandler == 'hdf5': - ohlcv1 = dh1._ohlcv_load( - 'UNITTEST/NEW', timeframe, timerange, candle_type=candle_type) + ohlcv1 = dh1._ohlcv_load('UNITTEST/NEW', timeframe, timerange, candle_type=candle_type) if candle_type == 'mark': ohlcv1['volume'] = 0.0 else: @@ -495,8 +478,7 @@ def test_generic_datahandler_ohlcv_load_and_resave( assert ohlcv[ohlcv['date'] > enddt].empty # Try loading inexisting file - ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', timeframe, - candle_type=candle_type) + ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', timeframe, candle_type=candle_type) assert ohlcv.empty From ed0e7ead312e5ba0a678bddb5669ef75949d8f99 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Mar 2023 20:36:05 +0200 Subject: [PATCH 51/63] Fix wrong import --- freqtrade/data/history/featherdatahandler.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/data/history/featherdatahandler.py b/freqtrade/data/history/featherdatahandler.py index 4e016080c..bb387fc84 100644 --- a/freqtrade/data/history/featherdatahandler.py +++ b/freqtrade/data/history/featherdatahandler.py @@ -4,9 +4,8 @@ from typing import Optional from pandas import DataFrame, read_feather, to_datetime from freqtrade.configuration import TimeRange -from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, TradeList, DEFAULT_TRADES_COLUMNS +from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, DEFAULT_TRADES_COLUMNS, TradeList from freqtrade.enums import CandleType -from freqtrade.data.converter import trades_dict_to_list from .idatahandler import IDataHandler From cde432fef05c19218d0ce8883c732e36d7178eb9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 23 Mar 2023 18:15:54 +0100 Subject: [PATCH 52/63] Enable gate market orders closes #8368 --- freqtrade/exchange/gate.py | 8 -------- tests/exchange/test_gate.py | 33 --------------------------------- 2 files changed, 41 deletions(-) diff --git a/freqtrade/exchange/gate.py b/freqtrade/exchange/gate.py index bf6d5b59c..f0c1053a6 100644 --- a/freqtrade/exchange/gate.py +++ b/freqtrade/exchange/gate.py @@ -50,14 +50,6 @@ class Gate(Exchange): (TradingMode.FUTURES, MarginMode.ISOLATED) ] - def validate_ordertypes(self, order_types: Dict) -> None: - - if self.trading_mode != TradingMode.FUTURES: - if any(v == 'market' for k, v in order_types.items()): - raise OperationalException( - f'Exchange {self.name} does not support market orders.') - super().validate_stop_ordertypes(order_types) - def _get_params( self, side: BuySell, diff --git a/tests/exchange/test_gate.py b/tests/exchange/test_gate.py index db7591a40..3cb5a9a3e 100644 --- a/tests/exchange/test_gate.py +++ b/tests/exchange/test_gate.py @@ -4,42 +4,9 @@ from unittest.mock import MagicMock import pytest from freqtrade.enums import MarginMode, TradingMode -from freqtrade.exceptions import OperationalException -from freqtrade.exchange import Gate -from freqtrade.resolvers.exchange_resolver import ExchangeResolver from tests.conftest import EXMS, get_patched_exchange -def test_validate_order_types_gate(default_conf, mocker): - default_conf['exchange']['name'] = 'gate' - mocker.patch(f'{EXMS}._init_ccxt') - mocker.patch(f'{EXMS}._load_markets', return_value={}) - mocker.patch(f'{EXMS}.validate_pairs') - mocker.patch(f'{EXMS}.validate_timeframes') - mocker.patch(f'{EXMS}.validate_stakecurrency') - mocker.patch(f'{EXMS}.validate_pricing') - mocker.patch(f'{EXMS}.name', 'Gate') - exch = ExchangeResolver.load_exchange('gate', default_conf, True) - assert isinstance(exch, Gate) - - default_conf['order_types'] = { - 'entry': 'market', - 'exit': 'limit', - 'stoploss': 'market', - 'stoploss_on_exchange': False - } - - with pytest.raises(OperationalException, - match=r'Exchange .* does not support market orders.'): - ExchangeResolver.load_exchange('gate', default_conf, True) - - # market-orders supported on futures markets. - default_conf['trading_mode'] = 'futures' - default_conf['margin_mode'] = 'isolated' - ex = ExchangeResolver.load_exchange('gate', default_conf, True) - assert ex - - @pytest.mark.usefixtures("init_persistence") def test_fetch_stoploss_order_gate(default_conf, mocker): exchange = get_patched_exchange(mocker, default_conf, id='gate') From 19b78fbc22856160d8f2d436ce6af7be8dbb61fd Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Mar 2023 06:55:55 +0200 Subject: [PATCH 53/63] Override ccxt's marketOrderRequiresPrice settings for gate --- freqtrade/exchange/exchange.py | 12 ++++++++++-- freqtrade/exchange/gate.py | 3 ++- tests/exchange/test_exchange.py | 20 ++++++++++++++++---- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 92eb4b58a..bbe9585ae 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -80,6 +80,8 @@ class Exchange: "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'], + # Override createMarketBuyOrderRequiresPrice where ccxt has it wrong + "marketOrderRequiresPrice": False, } _ft_has: Dict = {} _ft_has_futures: Dict = {} @@ -1040,6 +1042,13 @@ class Exchange: params.update({'reduceOnly': True}) return params + def _order_needs_price(self, ordertype: str) -> bool: + return ( + ordertype != 'market' + or self._api.options.get("createMarketBuyOrderRequiresPrice", False) + or self._ft_has.get('marketOrderRequiresPrice', False) + ) + def create_order( self, *, @@ -1062,8 +1071,7 @@ class Exchange: try: # Set the precision for amount and price(rate) as accepted by the exchange amount = self.amount_to_precision(pair, self._amount_to_contracts(pair, amount)) - needs_price = (ordertype != 'market' - or self._api.options.get("createMarketBuyOrderRequiresPrice", False)) + needs_price = self._order_needs_price(ordertype) rate_for_order = self.price_to_precision(pair, rate) if needs_price else None if not reduceOnly: diff --git a/freqtrade/exchange/gate.py b/freqtrade/exchange/gate.py index f0c1053a6..2ac135fc1 100644 --- a/freqtrade/exchange/gate.py +++ b/freqtrade/exchange/gate.py @@ -5,7 +5,6 @@ from typing import Any, Dict, List, Optional, Tuple from freqtrade.constants import BuySell from freqtrade.enums import MarginMode, PriceType, TradingMode -from freqtrade.exceptions import OperationalException from freqtrade.exchange import Exchange from freqtrade.misc import safe_value_fallback2 @@ -28,10 +27,12 @@ class Gate(Exchange): "order_time_in_force": ['GTC', 'IOC'], "stoploss_order_types": {"limit": "limit"}, "stoploss_on_exchange": True, + "marketOrderRequiresPrice": True, } _ft_has_futures: Dict = { "needs_trading_fees": True, + "marketOrderRequiresPrice": False, "tickers_have_bid_ask": False, "fee_cost_in_contracts": False, # Set explicitly to false for clarity "order_props_in_contracts": ['amount', 'filled', 'remaining'], diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 5350f4e3e..e08815e61 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1439,7 +1439,10 @@ def test_buy_prod(default_conf, mocker, exchange_name): assert api_mock.create_order.call_args[0][1] == order_type assert api_mock.create_order.call_args[0][2] == 'buy' assert api_mock.create_order.call_args[0][3] == 1 - assert api_mock.create_order.call_args[0][4] is None + if exchange._order_needs_price(order_type): + assert api_mock.create_order.call_args[0][4] == 200 + else: + assert api_mock.create_order.call_args[0][4] is None api_mock.create_order.reset_mock() order_type = 'limit' @@ -1544,7 +1547,10 @@ def test_buy_considers_time_in_force(default_conf, mocker, exchange_name): assert api_mock.create_order.call_args[0][1] == order_type assert api_mock.create_order.call_args[0][2] == 'buy' assert api_mock.create_order.call_args[0][3] == 1 - assert api_mock.create_order.call_args[0][4] is None + if exchange._order_needs_price(order_type): + assert api_mock.create_order.call_args[0][4] == 200 + else: + assert api_mock.create_order.call_args[0][4] is None # Market orders should not send timeInForce!! assert "timeInForce" not in api_mock.create_order.call_args[0][5] @@ -1588,7 +1594,10 @@ def test_sell_prod(default_conf, mocker, exchange_name): assert api_mock.create_order.call_args[0][1] == order_type assert api_mock.create_order.call_args[0][2] == 'sell' assert api_mock.create_order.call_args[0][3] == 1 - assert api_mock.create_order.call_args[0][4] is None + if exchange._order_needs_price(order_type): + assert api_mock.create_order.call_args[0][4] == 200 + else: + assert api_mock.create_order.call_args[0][4] is None api_mock.create_order.reset_mock() order_type = 'limit' @@ -1682,7 +1691,10 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name): assert api_mock.create_order.call_args[0][1] == order_type assert api_mock.create_order.call_args[0][2] == 'sell' assert api_mock.create_order.call_args[0][3] == 1 - assert api_mock.create_order.call_args[0][4] is None + if exchange._order_needs_price(order_type): + assert api_mock.create_order.call_args[0][4] == 200 + else: + assert api_mock.create_order.call_args[0][4] is None # Market orders should not send timeInForce!! assert "timeInForce" not in api_mock.create_order.call_args[0][5] From 2860e817bd24400acf1ec4d92ac2b115552a1896 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Mar 2023 07:05:37 +0200 Subject: [PATCH 54/63] Update cached binance leverage Tiers --- .../exchange/binance_leverage_tiers.json | 3262 ++++++++++------- 1 file changed, 1953 insertions(+), 1309 deletions(-) diff --git a/freqtrade/exchange/binance_leverage_tiers.json b/freqtrade/exchange/binance_leverage_tiers.json index 07fdcb5a4..597db27ff 100644 --- a/freqtrade/exchange/binance_leverage_tiers.json +++ b/freqtrade/exchange/binance_leverage_tiers.json @@ -999,15 +999,15 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "maintMarginRatio": "0.006", + "cum": "5.0" } }, { @@ -1023,7 +1023,7 @@ "notionalCap": "50000", "notionalFloor": "10000", "maintMarginRatio": "0.01", - "cum": "42.5" + "cum": "45.0" } }, { @@ -1039,7 +1039,7 @@ "notionalCap": "250000", "notionalFloor": "50000", "maintMarginRatio": "0.02", - "cum": "542.5" + "cum": "545.0" } }, { @@ -1055,77 +1055,77 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "8042.5" + "cum": "8045.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "58042.5" + "cum": "58045.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.125", - "cum": "108042.5" + "cum": "183045.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.15, "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.15", - "cum": "233042.5" + "cum": "433045.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "1233042.5" + "cum": "2433045.0" } }, { "tier": 10.0, "currency": "USDT", - "minNotional": 20000000.0, + "minNotional": 30000000.0, "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, @@ -1133,9 +1133,9 @@ "bracket": "10", "initialLeverage": "1", "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "30000000", "maintMarginRatio": "0.5", - "cum": "6233042.5" + "cum": "9933045.0" } } ], @@ -1274,13 +1274,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 200000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "notionalCap": "200000", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -1289,65 +1289,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "200000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "10650.0" + "cum": "30650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "23150.0" + "cum": "70650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "6000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.25", - "cum": "148150.0" + "cum": "320650.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 5000000.0, + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "3000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "898150.0" + "cum": "1820650.0" } } ], @@ -2304,10 +2304,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -2320,10 +2320,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -2334,13 +2334,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -2349,49 +2349,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "30650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "70650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "1820650.0" } } ], @@ -2546,13 +2562,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 300000.0, + "maxNotional": 900000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "3", "initialLeverage": "20", - "notionalCap": "300000", + "notionalCap": "900000", "notionalFloor": "25000", "maintMarginRatio": "0.02", "cum": "150.0" @@ -2561,39 +2577,39 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 1200000.0, + "minNotional": 900000.0, + "maxNotional": 1800000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "notionalCap": "1200000", - "notionalFloor": "300000", + "notionalCap": "1800000", + "notionalFloor": "900000", "maintMarginRatio": "0.05", - "cum": "9150.0" + "cum": "27150.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 1200000.0, - "maxNotional": 3000000.0, + "minNotional": 1800000.0, + "maxNotional": 4800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "notionalCap": "3000000", - "notionalFloor": "1200000", + "notionalCap": "4800000", + "notionalFloor": "1800000", "maintMarginRatio": "0.1", - "cum": "69150.0" + "cum": "117150.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 3000000.0, + "minNotional": 4800000.0, "maxNotional": 6000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, @@ -2601,9 +2617,9 @@ "bracket": "6", "initialLeverage": "4", "notionalCap": "6000000", - "notionalFloor": "3000000", + "notionalFloor": "4800000", "maintMarginRatio": "0.125", - "cum": "144150.0" + "cum": "237150.0" } }, { @@ -2619,7 +2635,7 @@ "notionalCap": "18000000", "notionalFloor": "6000000", "maintMarginRatio": "0.25", - "cum": "894150.0" + "cum": "987150.0" } }, { @@ -2635,7 +2651,7 @@ "notionalCap": "30000000", "notionalFloor": "18000000", "maintMarginRatio": "0.5", - "cum": "5394150.0" + "cum": "5487150.0" } } ], @@ -2737,6 +2753,136 @@ } } ], + "ARB/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.006, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.006", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "2", + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "5000", + "maintMarginRatio": "0.01", + "cum": "20.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 50000.0, + "maxNotional": 400000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "3", + "initialLeverage": "20", + "notionalCap": "400000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "770.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 400000.0, + "maxNotional": 800000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "800000", + "notionalFloor": "400000", + "maintMarginRatio": "0.05", + "cum": "10770.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 800000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "800000", + "maintMarginRatio": "0.1", + "cum": "50770.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": "100770.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 12000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "12000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.25", + "cum": "725770.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 12000000.0, + "maxNotional": 20000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "8", + "initialLeverage": "1", + "notionalCap": "20000000", + "notionalFloor": "12000000", + "maintMarginRatio": "0.5", + "cum": "3725770.0" + } + } + ], "ARPA/USDT:USDT": [ { "tier": 1.0, @@ -2760,10 +2906,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 15.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "15", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -2774,13 +2920,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -2789,49 +2935,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "30650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "70650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "1820650.0" } } ], @@ -3639,14 +3801,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.0065, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.006, + "maxLeverage": 50.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "50", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.0065", + "maintMarginRatio": "0.006", "cum": "0.0" } }, @@ -3655,14 +3817,14 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 25000.0, - "maintenanceMarginRate": 0.0075, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.007, + "maxLeverage": 30.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "30", "notionalCap": "25000", "notionalFloor": "5000", - "maintMarginRatio": "0.0075", + "maintMarginRatio": "0.007", "cum": "5.0" } }, @@ -3670,70 +3832,70 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 50000.0, + "maxNotional": 400000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 18.0, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "18", - "notionalCap": "50000", + "initialLeverage": "25", + "notionalCap": "400000", "notionalFloor": "25000", "maintMarginRatio": "0.01", - "cum": "67.5" + "cum": "80.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, + "minNotional": 400000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 15.0, + "maxLeverage": 20.0, "info": { "bracket": "4", - "initialLeverage": "15", - "notionalCap": "250000", - "notionalFloor": "50000", + "initialLeverage": "20", + "notionalCap": "600000", + "notionalFloor": "400000", "maintMarginRatio": "0.02", - "cum": "567.5" + "cum": "4080.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 600000.0, + "maxNotional": 1200000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", + "notionalCap": "1200000", + "notionalFloor": "600000", "maintMarginRatio": "0.05", - "cum": "8067.5" + "cum": "22080.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 1200000.0, + "maxNotional": 3200000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "3200000", + "notionalFloor": "1200000", "maintMarginRatio": "0.1", - "cum": "58067.5" + "cum": "82080.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, + "minNotional": 3200000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, @@ -3741,9 +3903,9 @@ "bracket": "7", "initialLeverage": "4", "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalFloor": "3200000", "maintMarginRatio": "0.125", - "cum": "108067.5" + "cum": "162080.0" } }, { @@ -3751,15 +3913,15 @@ "currency": "USDT", "minNotional": 5000000.0, "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.1665, + "maintenanceMarginRate": 0.15, "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", "notionalCap": "10000000", "notionalFloor": "5000000", - "maintMarginRatio": "0.1665", - "cum": "315567.5" + "maintMarginRatio": "0.15", + "cum": "287080.0" } }, { @@ -3775,7 +3937,7 @@ "notionalCap": "15000000", "notionalFloor": "10000000", "maintMarginRatio": "0.25", - "cum": "1150567.5" + "cum": "1287080.0" } }, { @@ -3791,7 +3953,7 @@ "notionalCap": "20000000", "notionalFloor": "15000000", "maintMarginRatio": "0.5", - "cum": "4900567.5" + "cum": "5037080.0" } } ], @@ -4763,15 +4925,15 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "maintMarginRatio": "0.006", + "cum": "5.0" } }, { @@ -4787,7 +4949,7 @@ "notionalCap": "50000", "notionalFloor": "10000", "maintMarginRatio": "0.01", - "cum": "42.5" + "cum": "45.0" } }, { @@ -4803,7 +4965,7 @@ "notionalCap": "250000", "notionalFloor": "50000", "maintMarginRatio": "0.02", - "cum": "542.5" + "cum": "545.0" } }, { @@ -4819,77 +4981,77 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "8042.5" + "cum": "8045.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "58042.5" + "cum": "58045.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.125", - "cum": "108042.5" + "cum": "183045.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.15, "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.15", - "cum": "233042.5" + "cum": "433045.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "1233042.5" + "cum": "2433045.0" } }, { "tier": 10.0, "currency": "USDT", - "minNotional": 20000000.0, + "minNotional": 30000000.0, "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, @@ -4897,9 +5059,9 @@ "bracket": "10", "initialLeverage": "1", "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "30000000", "maintMarginRatio": "0.5", - "cum": "6233042.5" + "cum": "9933045.0" } } ], @@ -5439,6 +5601,120 @@ } } ], + "BTC/USDT:USDT-230630": [ + { + "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" + } + } + ], "BTCDOM/USDT:USDT": [ { "tier": 1.0, @@ -5936,10 +6212,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -5952,10 +6228,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -5966,13 +6242,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -5981,49 +6257,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "30650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "70650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "1820650.0" } } ], @@ -6980,10 +7272,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -6996,10 +7288,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -7010,13 +7302,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 300000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "300000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -7025,33 +7317,33 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 300000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "800000", + "notionalFloor": "300000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "15650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, + "minNotional": 800000.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": "800000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "35650.0" } }, { @@ -7059,15 +7351,31 @@ "currency": "USDT", "minNotional": 1000000.0, "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "3000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "160650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 3000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "5000000", + "notionalFloor": "3000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "910650.0" } } ], @@ -7160,10 +7468,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -7176,10 +7484,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -7192,10 +7500,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "8", + "initialLeverage": "6", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -7222,13 +7530,13 @@ "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, - "maxNotional": 1000000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "notionalCap": "1000000", + "notionalCap": "500000", "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11900.0" @@ -7237,17 +7545,17 @@ { "tier": 6.0, "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "199400.0" } } ], @@ -7340,10 +7648,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -7356,10 +7664,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -7370,13 +7678,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -7385,49 +7693,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "30650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "70650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "1820650.0" } } ], @@ -7634,10 +7958,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 15.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "15", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -7650,10 +7974,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -7664,13 +7988,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 200000.0, + "maxNotional": 300000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "200000", + "initialLeverage": "10", + "notionalCap": "300000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -7679,49 +8003,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, + "minNotional": 300000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "200000", + "notionalCap": "800000", + "notionalFloor": "300000", "maintMarginRatio": "0.1", - "cum": "10650.0" + "cum": "15650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 500000.0, + "minNotional": 800000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", + "initialLeverage": "4", "notionalCap": "1000000", - "notionalFloor": "500000", + "notionalFloor": "800000", "maintMarginRatio": "0.125", - "cum": "23150.0" + "cum": "35650.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "3000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "160650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 3000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalFloor": "3000000", "maintMarginRatio": "0.5", - "cum": "398150.0" + "cum": "910650.0" } } ], @@ -8025,14 +8365,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.0065", + "maintMarginRatio": "0.006", "cum": "0.0" } }, @@ -8041,14 +8381,14 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 25000.0, - "maintenanceMarginRate": 0.0075, + "maintenanceMarginRate": 0.007, "maxLeverage": 40.0, "info": { "bracket": "2", "initialLeverage": "40", "notionalCap": "25000", "notionalFloor": "5000", - "maintMarginRatio": "0.0075", + "maintMarginRatio": "0.007", "cum": "5.0" } }, @@ -8056,112 +8396,112 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 50000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "50000", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.01", - "cum": "67.5" + "cum": "80.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 900000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "250000", - "notionalFloor": "50000", + "notionalCap": "900000", + "notionalFloor": "600000", "maintMarginRatio": "0.025", - "cum": "817.5" + "cum": "9080.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 900000.0, + "maxNotional": 1800000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", + "notionalCap": "1800000", + "notionalFloor": "900000", "maintMarginRatio": "0.05", - "cum": "7067.5" + "cum": "31580.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 1800000.0, + "maxNotional": 4800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "4800000", + "notionalFloor": "1800000", "maintMarginRatio": "0.1", - "cum": "57067.5" + "cum": "121580.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 4800000.0, + "maxNotional": 6000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "6000000", + "notionalFloor": "4800000", "maintMarginRatio": "0.125", - "cum": "107067.5" + "cum": "241580.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 6000000.0, + "maxNotional": 18000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "18000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.25", - "cum": "732067.5" + "cum": "991580.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 18000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "18000000", "maintMarginRatio": "0.5", - "cum": "3232067.5" + "cum": "5491580.0" } } ], @@ -8706,13 +9046,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "notionalCap": "100000", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" @@ -8721,49 +9061,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "30700.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "70700.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 50000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320700.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "1820700.0" } } ], @@ -9017,15 +9373,15 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "maintMarginRatio": "0.006", + "cum": "5.0" } }, { @@ -9041,7 +9397,7 @@ "notionalCap": "50000", "notionalFloor": "10000", "maintMarginRatio": "0.01", - "cum": "42.5" + "cum": "45.0" } }, { @@ -9057,7 +9413,7 @@ "notionalCap": "250000", "notionalFloor": "50000", "maintMarginRatio": "0.02", - "cum": "542.5" + "cum": "545.0" } }, { @@ -9073,77 +9429,77 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "8042.5" + "cum": "8045.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "58042.5" + "cum": "58045.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.125", - "cum": "108042.5" + "cum": "183045.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.15, "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.15", - "cum": "233042.5" + "cum": "433045.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "1233042.5" + "cum": "2433045.0" } }, { "tier": 10.0, "currency": "USDT", - "minNotional": 20000000.0, + "minNotional": 30000000.0, "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, @@ -9151,9 +9507,9 @@ "bracket": "10", "initialLeverage": "1", "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "30000000", "maintMarginRatio": "0.5", - "cum": "6233042.5" + "cum": "9933045.0" } } ], @@ -9277,15 +9633,15 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "maintMarginRatio": "0.006", + "cum": "5.0" } }, { @@ -9301,7 +9657,7 @@ "notionalCap": "50000", "notionalFloor": "10000", "maintMarginRatio": "0.01", - "cum": "42.5" + "cum": "45.0" } }, { @@ -9317,7 +9673,7 @@ "notionalCap": "250000", "notionalFloor": "50000", "maintMarginRatio": "0.02", - "cum": "542.5" + "cum": "545.0" } }, { @@ -9333,77 +9689,77 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "8042.5" + "cum": "8045.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "58042.5" + "cum": "58045.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.125", - "cum": "108042.5" + "cum": "183045.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.15, "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.15", - "cum": "233042.5" + "cum": "433045.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "1233042.5" + "cum": "2433045.0" } }, { "tier": 10.0, "currency": "USDT", - "minNotional": 20000000.0, + "minNotional": 30000000.0, "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, @@ -9411,9 +9767,9 @@ "bracket": "10", "initialLeverage": "1", "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "30000000", "maintMarginRatio": "0.5", - "cum": "6233042.5" + "cum": "9933045.0" } } ], @@ -9855,6 +10211,120 @@ } } ], + "ETH/USDT:USDT-230630": [ + { + "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" + } + } + ], "FET/USDT:USDT": [ { "tier": 1.0, @@ -11036,10 +11506,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -11052,10 +11522,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -11068,10 +11538,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "8", + "initialLeverage": "6", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -11098,13 +11568,13 @@ "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, - "maxNotional": 1000000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "notionalCap": "1000000", + "notionalCap": "500000", "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11900.0" @@ -11113,17 +11583,17 @@ { "tier": 6.0, "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "199400.0" } } ], @@ -11329,14 +11799,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "1", "initialLeverage": "50", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.0065", + "maintMarginRatio": "0.006", "cum": "0.0" } }, @@ -11353,103 +11823,103 @@ "notionalCap": "50000", "notionalFloor": "5000", "maintMarginRatio": "0.01", - "cum": "17.5" + "cum": "20.0" } }, { "tier": 3.0, "currency": "USDT", "minNotional": 50000.0, - "maxNotional": 200000.0, + "maxNotional": 900000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "3", "initialLeverage": "20", - "notionalCap": "200000", + "notionalCap": "900000", "notionalFloor": "50000", "maintMarginRatio": "0.025", - "cum": "767.5" + "cum": "770.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, + "minNotional": 900000.0, + "maxNotional": 1800000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "notionalCap": "400000", - "notionalFloor": "200000", + "notionalCap": "1800000", + "notionalFloor": "900000", "maintMarginRatio": "0.05", - "cum": "5767.5" + "cum": "23270.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 1000000.0, + "minNotional": 1800000.0, + "maxNotional": 4800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "notionalCap": "1000000", - "notionalFloor": "400000", + "notionalCap": "4800000", + "notionalFloor": "1800000", "maintMarginRatio": "0.1", - "cum": "25767.5" + "cum": "113270.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 4800000.0, + "maxNotional": 6000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "6000000", + "notionalFloor": "4800000", "maintMarginRatio": "0.125", - "cum": "50767.5" + "cum": "233270.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 6000000.0, + "minNotional": 6000000.0, + "maxNotional": 18000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "notionalCap": "6000000", - "notionalFloor": "5000000", + "notionalCap": "18000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.25", - "cum": "675767.5" + "cum": "983270.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 10000000.0, + "minNotional": 18000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "notionalCap": "10000000", - "notionalFloor": "6000000", + "notionalCap": "30000000", + "notionalFloor": "18000000", "maintMarginRatio": "0.5", - "cum": "2175767.5" + "cum": "5483270.0" } } ], @@ -11672,10 +12142,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -11688,10 +12158,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 15.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "15", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -11702,13 +12172,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 480000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "notionalCap": "100000", + "notionalCap": "480000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -11717,49 +12187,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 480000.0, + "maxNotional": 1280000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1280000", + "notionalFloor": "480000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "24650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1280000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "1600000", + "notionalFloor": "1280000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "56650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 1600000.0, + "maxNotional": 4800000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "4800000", + "notionalFloor": "1600000", + "maintMarginRatio": "0.25", + "cum": "256650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 4800000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "4800000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "1456650.0" } } ], @@ -12194,10 +12680,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 15.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "15", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -12210,10 +12696,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -12224,13 +12710,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 120000.0, + "maxNotional": 300000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "120000", + "initialLeverage": "6", + "notionalCap": "300000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -12239,49 +12725,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 120000.0, - "maxNotional": 300000.0, + "minNotional": 300000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "300000", - "notionalFloor": "120000", + "notionalCap": "800000", + "notionalFloor": "300000", "maintMarginRatio": "0.1", - "cum": "6650.0" + "cum": "15650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 300000.0, + "minNotional": 800000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", + "initialLeverage": "4", "notionalCap": "1000000", - "notionalFloor": "300000", + "notionalFloor": "800000", "maintMarginRatio": "0.125", - "cum": "14150.0" + "cum": "35650.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "160650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "2000000", + "notionalFloor": "1500000", "maintMarginRatio": "0.5", - "cum": "389150.0" + "cum": "535650.0" } } ], @@ -12481,104 +12983,6 @@ } } ], - "ICP/BUSD:BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "25.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, - "info": { - "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "650.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "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": "5650.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "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": "11900.0" - } - }, - { - "tier": 6.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386900.0" - } - } - ], "ICP/USDT:USDT": [ { "tier": 1.0, @@ -12586,10 +12990,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -12602,10 +13006,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -12616,13 +13020,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" @@ -12631,49 +13035,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "30700.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "70700.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320700.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "1820700.0" } } ], @@ -12775,105 +13195,7 @@ } } ], - "IMX/USDT:USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "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": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "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": 8.0, - "info": { - "bracket": "3", - "initialLeverage": "8", - "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" - } - } - ], - "INJ/USDT:USDT": [ + "ID/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -12896,10 +13218,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 15.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "15", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -12910,13 +13232,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 200000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "200000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -12925,33 +13247,33 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 200000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "500000", + "notionalFloor": "200000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "10650.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": "11900.0" + "cum": "23150.0" } }, { @@ -12959,15 +13281,259 @@ "currency": "USDT", "minNotional": 1000000.0, "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "3000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "148150.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 3000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "5000000", + "notionalFloor": "3000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "898150.0" + } + } + ], + "IMX/USDT: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": 600000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "600000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 1600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "1600000", + "notionalFloor": "600000", + "maintMarginRatio": "0.1", + "cum": "30700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1600000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", + "maintMarginRatio": "0.125", + "cum": "70700.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320700.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.5", + "cum": "1820700.0" + } + } + ], + "INJ/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.02", + "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": "25.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "600000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "650.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 1600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "1600000", + "notionalFloor": "600000", + "maintMarginRatio": "0.1", + "cum": "30650.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1600000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", + "maintMarginRatio": "0.125", + "cum": "70650.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "7", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.5", + "cum": "1820650.0" } } ], @@ -14136,10 +14702,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -14152,10 +14718,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -14166,13 +14732,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 900000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "900000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -14181,49 +14747,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 900000.0, + "maxNotional": 2400000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "2400000", + "notionalFloor": "900000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "45650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 2400000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "3000000", + "notionalFloor": "2400000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "105650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 3000000.0, + "maxNotional": 9000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "9000000", + "notionalFloor": "3000000", + "maintMarginRatio": "0.25", + "cum": "480650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 9000000.0, + "maxNotional": 15000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "15000000", + "notionalFloor": "9000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "2730650.0" } } ], @@ -14363,15 +14945,15 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "maintMarginRatio": "0.006", + "cum": "5.0" } }, { @@ -14387,7 +14969,7 @@ "notionalCap": "50000", "notionalFloor": "10000", "maintMarginRatio": "0.01", - "cum": "42.5" + "cum": "45.0" } }, { @@ -14403,7 +14985,7 @@ "notionalCap": "250000", "notionalFloor": "50000", "maintMarginRatio": "0.02", - "cum": "542.5" + "cum": "545.0" } }, { @@ -14419,77 +15001,77 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "8042.5" + "cum": "8045.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "58042.5" + "cum": "58045.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.125", - "cum": "108042.5" + "cum": "183045.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.15, "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.15", - "cum": "233042.5" + "cum": "433045.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "1233042.5" + "cum": "2433045.0" } }, { "tier": 10.0, "currency": "USDT", - "minNotional": 20000000.0, + "minNotional": 30000000.0, "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, @@ -14497,9 +15079,9 @@ "bracket": "10", "initialLeverage": "1", "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "30000000", "maintMarginRatio": "0.5", - "cum": "6233042.5" + "cum": "9933045.0" } } ], @@ -15031,15 +15613,15 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "maintMarginRatio": "0.006", + "cum": "5.0" } }, { @@ -15055,7 +15637,7 @@ "notionalCap": "50000", "notionalFloor": "10000", "maintMarginRatio": "0.01", - "cum": "42.5" + "cum": "45.0" } }, { @@ -15071,7 +15653,7 @@ "notionalCap": "250000", "notionalFloor": "50000", "maintMarginRatio": "0.02", - "cum": "542.5" + "cum": "545.0" } }, { @@ -15087,77 +15669,77 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "8042.5" + "cum": "8045.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "58042.5" + "cum": "58045.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.125", - "cum": "108042.5" + "cum": "183045.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.15, "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.15", - "cum": "233042.5" + "cum": "433045.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "1233042.5" + "cum": "2433045.0" } }, { "tier": 10.0, "currency": "USDT", - "minNotional": 20000000.0, + "minNotional": 30000000.0, "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, @@ -15165,107 +15747,9 @@ "bracket": "10", "initialLeverage": "1", "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "30000000", "maintMarginRatio": "0.5", - "cum": "6233042.5" - } - } - ], - "LUNA2/BUSD:BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.02", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "25.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, - "info": { - "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "650.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "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": "5650.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "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": "11900.0" - } - }, - { - "tier": 6.0, - "currency": "BUSD", - "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": "386900.0" + "cum": "9933045.0" } } ], @@ -15617,14 +16101,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "50", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.02", + "maintMarginRatio": "0.01", "cum": "0.0" } }, @@ -15633,95 +16117,111 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "25000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "25.0" + "maintMarginRatio": "0.02", + "cum": "50.0" } }, { "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 600000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxNotional": 900000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "600000", + "initialLeverage": "20", + "notionalCap": "900000", "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "650.0" + "maintMarginRatio": "0.025", + "cum": "175.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 1600000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 900000.0, + "maxNotional": 1800000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "1600000", - "notionalFloor": "600000", - "maintMarginRatio": "0.1", - "cum": "30650.0" + "initialLeverage": "10", + "notionalCap": "1800000", + "notionalFloor": "900000", + "maintMarginRatio": "0.05", + "cum": "22675.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 1600000.0, - "maxNotional": 3000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 1800000.0, + "maxNotional": 4800000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "5", - "initialLeverage": "4", - "notionalCap": "3000000", - "notionalFloor": "1600000", - "maintMarginRatio": "0.125", - "cum": "70650.0" + "initialLeverage": "5", + "notionalCap": "4800000", + "notionalFloor": "1800000", + "maintMarginRatio": "0.1", + "cum": "112675.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 3000000.0, + "minNotional": 4800000.0, "maxNotional": 6000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "6", - "initialLeverage": "2", + "initialLeverage": "4", "notionalCap": "6000000", - "notionalFloor": "3000000", - "maintMarginRatio": "0.25", - "cum": "445650.0" + "notionalFloor": "4800000", + "maintMarginRatio": "0.125", + "cum": "232675.0" } }, { "tier": 7.0, "currency": "USDT", "minNotional": 6000000.0, - "maxNotional": 10000000.0, + "maxNotional": 18000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "18000000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.25", + "cum": "982675.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 18000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "7", + "bracket": "8", "initialLeverage": "1", - "notionalCap": "10000000", - "notionalFloor": "6000000", + "notionalCap": "30000000", + "notionalFloor": "18000000", "maintMarginRatio": "0.5", - "cum": "1945650.0" + "cum": "5482675.0" } } ], @@ -15876,13 +16376,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 50000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "50000", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.01", "cum": "80.0" @@ -15891,97 +16391,97 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 400000.0, + "minNotional": 600000.0, + "maxNotional": 900000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "400000", - "notionalFloor": "50000", + "notionalCap": "900000", + "notionalFloor": "600000", "maintMarginRatio": "0.025", - "cum": "830.0" + "cum": "9080.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 800000.0, + "minNotional": 900000.0, + "maxNotional": 1800000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "800000", - "notionalFloor": "400000", + "notionalCap": "1800000", + "notionalFloor": "900000", "maintMarginRatio": "0.05", - "cum": "10830.0" + "cum": "31580.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 2000000.0, + "minNotional": 1800000.0, + "maxNotional": 4800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "800000", + "notionalCap": "4800000", + "notionalFloor": "1800000", "maintMarginRatio": "0.1", - "cum": "50830.0" + "cum": "121580.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 4800000.0, + "maxNotional": 6000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "6000000", + "notionalFloor": "4800000", "maintMarginRatio": "0.125", - "cum": "100830.0" + "cum": "241580.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 12000000.0, + "minNotional": 6000000.0, + "maxNotional": 18000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "12000000", - "notionalFloor": "5000000", + "notionalCap": "18000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.25", - "cum": "725830.0" + "cum": "991580.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 12000000.0, - "maxNotional": 20000000.0, + "minNotional": 18000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "12000000", + "notionalCap": "30000000", + "notionalFloor": "18000000", "maintMarginRatio": "0.5", - "cum": "3725830.0" + "cum": "5491580.0" } } ], @@ -16105,14 +16605,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.006, + "maxLeverage": 50.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "50", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.006", "cum": "0.0" } }, @@ -16121,79 +16621,111 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "25000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" + "maintMarginRatio": "0.01", + "cum": "20.0" } }, { "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxNotional": 450000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", + "initialLeverage": "20", + "notionalCap": "450000", "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" + "maintMarginRatio": "0.025", + "cum": "395.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 450000.0, + "maxNotional": 900000.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": "900000", + "notionalFloor": "450000", + "maintMarginRatio": "0.05", + "cum": "11645.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "minNotional": 900000.0, + "maxNotional": 2400000.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": "2400000", + "notionalFloor": "900000", + "maintMarginRatio": "0.1", + "cum": "56645.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 2400000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "3000000", + "notionalFloor": "2400000", + "maintMarginRatio": "0.125", + "cum": "116645.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 3000000.0, + "maxNotional": 9000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "9000000", + "notionalFloor": "3000000", + "maintMarginRatio": "0.25", + "cum": "491645.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 9000000.0, + "maxNotional": 15000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "8", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "15000000", + "notionalFloor": "9000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "2741645.0" } } ], @@ -16204,10 +16736,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -16220,10 +16752,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -16234,13 +16766,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -16249,49 +16781,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "30650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "70650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "1820650.0" } } ], @@ -16968,13 +17516,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 900000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 8.0, "info": { "bracket": "3", "initialLeverage": "8", - "notionalCap": "100000", + "notionalCap": "900000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -16983,49 +17531,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 900000.0, + "maxNotional": 2400000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "2400000", + "notionalFloor": "900000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "45650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 2400000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "3000000", + "notionalFloor": "2400000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "105650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 3000000.0, + "maxNotional": 9000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "9000000", + "notionalFloor": "3000000", + "maintMarginRatio": "0.25", + "cum": "480650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 9000000.0, + "maxNotional": 15000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "15000000", + "notionalFloor": "9000000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "2730650.0" } } ], @@ -17164,13 +17728,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "notionalCap": "100000", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" @@ -17179,49 +17743,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "30700.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "70700.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320700.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "1820700.0" } } ], @@ -18208,13 +18788,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 200000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "3", "initialLeverage": "10", - "notionalCap": "200000", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -18223,65 +18803,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "200000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "10650.0" + "cum": "30650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "23150.0" + "cum": "70650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "6000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.25", - "cum": "148150.0" + "cum": "320650.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 5000000.0, + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "3000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "898150.0" + "cum": "1820650.0" } } ], @@ -18290,80 +18870,112 @@ "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.03, - "maxLeverage": 20.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", + "initialLeverage": "25", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.03", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "500.0" + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "25.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 25000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5500.0" + "initialLeverage": "10", + "notionalCap": "600000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "650.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11750.0" + "initialLeverage": "5", + "notionalCap": "1600000", + "notionalFloor": "600000", + "maintMarginRatio": "0.1", + "cum": "30650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "5", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", + "maintMarginRatio": "0.125", + "cum": "70650.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386750.0" + "cum": "1820650.0" } } ], @@ -19678,10 +20290,10 @@ "minNotional": 50000.0, "maxNotional": 150000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "150000", "notionalFloor": "50000", "maintMarginRatio": "0.02", @@ -19692,13 +20304,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 150000.0, - "maxNotional": 250000.0, + "maxNotional": 900000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 15.0, + "maxLeverage": 20.0, "info": { "bracket": "3", - "initialLeverage": "15", - "notionalCap": "250000", + "initialLeverage": "20", + "notionalCap": "900000", "notionalFloor": "150000", "maintMarginRatio": "0.025", "cum": "1250.0" @@ -19707,81 +20319,81 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 900000.0, + "maxNotional": 1800000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "250000", + "notionalCap": "1800000", + "notionalFloor": "900000", "maintMarginRatio": "0.05", - "cum": "7500.0" + "cum": "23750.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 1800000.0, + "maxNotional": 4800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "4800000", + "notionalFloor": "1800000", "maintMarginRatio": "0.1", - "cum": "57500.0" + "cum": "113750.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 4800000.0, + "maxNotional": 6000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "6000000", + "notionalFloor": "4800000", "maintMarginRatio": "0.125", - "cum": "107500.0" + "cum": "233750.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 6000000.0, + "maxNotional": 18000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "18000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.25", - "cum": "732500.0" + "cum": "983750.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 18000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "18000000", "maintMarginRatio": "0.5", - "cum": "3232500.0" + "cum": "5483750.0" } } ], @@ -20200,10 +20812,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -20216,10 +20828,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -20232,10 +20844,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "8", + "initialLeverage": "6", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -20278,13 +20890,13 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "3000000", + "notionalCap": "1500000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386900.0" @@ -20526,10 +21138,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -20542,10 +21154,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -20556,13 +21168,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "600000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "700.0" @@ -20571,49 +21183,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 600000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1600000", + "notionalFloor": "600000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "30700.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "70700.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 2000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "320700.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "1820700.0" } } ], @@ -21146,10 +21774,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maxLeverage": 25.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -21162,10 +21790,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxLeverage": 20.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -21176,13 +21804,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, + "maxNotional": 480000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "maxLeverage": 10.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", + "initialLeverage": "10", + "notionalCap": "480000", "notionalFloor": "25000", "maintMarginRatio": "0.05", "cum": "650.0" @@ -21191,49 +21819,65 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, + "minNotional": 480000.0, + "maxNotional": 1280000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", + "notionalCap": "1280000", + "notionalFloor": "480000", "maintMarginRatio": "0.1", - "cum": "5650.0" + "cum": "24650.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, + "minNotional": 1280000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "maxLeverage": 4.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", + "initialLeverage": "4", + "notionalCap": "1600000", + "notionalFloor": "1280000", "maintMarginRatio": "0.125", - "cum": "11900.0" + "cum": "56650.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 1600000.0, + "maxNotional": 4800000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "6", + "initialLeverage": "2", + "notionalCap": "4800000", + "notionalFloor": "1600000", + "maintMarginRatio": "0.25", + "cum": "256650.0" + } + }, + { + "tier": 7.0, + "currency": "USDT", + "minNotional": 4800000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "7", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "4800000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "1456650.0" } } ], @@ -21942,13 +22586,13 @@ "tier": 3.0, "currency": "USDT", "minNotional": 50000.0, - "maxNotional": 400000.0, + "maxNotional": 900000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "3", "initialLeverage": "20", - "notionalCap": "400000", + "notionalCap": "900000", "notionalFloor": "50000", "maintMarginRatio": "0.025", "cum": "770.0" @@ -21957,81 +22601,81 @@ { "tier": 4.0, "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 800000.0, + "minNotional": 900000.0, + "maxNotional": 1800000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "notionalCap": "800000", - "notionalFloor": "400000", + "notionalCap": "1800000", + "notionalFloor": "900000", "maintMarginRatio": "0.05", - "cum": "10770.0" + "cum": "23270.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 2000000.0, + "minNotional": 1800000.0, + "maxNotional": 4800000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "800000", + "notionalCap": "4800000", + "notionalFloor": "1800000", "maintMarginRatio": "0.1", - "cum": "50770.0" + "cum": "113270.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 4800000.0, + "maxNotional": 6000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "6000000", + "notionalFloor": "4800000", "maintMarginRatio": "0.125", - "cum": "100770.0" + "cum": "233270.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 12000000.0, + "minNotional": 6000000.0, + "maxNotional": 18000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "notionalCap": "12000000", - "notionalFloor": "5000000", + "notionalCap": "18000000", + "notionalFloor": "6000000", "maintMarginRatio": "0.25", - "cum": "725770.0" + "cum": "983270.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 12000000.0, - "maxNotional": 20000000.0, + "minNotional": 18000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "12000000", + "notionalCap": "30000000", + "notionalFloor": "18000000", "maintMarginRatio": "0.5", - "cum": "3725770.0" + "cum": "5483270.0" } } ], @@ -22364,13 +23008,13 @@ "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, - "maxNotional": 1000000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "notionalCap": "1000000", + "notionalCap": "500000", "notionalFloor": "250000", "maintMarginRatio": "0.125", "cum": "11900.0" @@ -22379,17 +23023,17 @@ { "tier": 6.0, "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.5", - "cum": "386900.0" + "cum": "199400.0" } } ], @@ -23067,15 +23711,15 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, + "maintenanceMarginRate": 0.006, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "maintMarginRatio": "0.006", + "cum": "5.0" } }, { @@ -23091,7 +23735,7 @@ "notionalCap": "50000", "notionalFloor": "10000", "maintMarginRatio": "0.01", - "cum": "42.5" + "cum": "45.0" } }, { @@ -23107,7 +23751,7 @@ "notionalCap": "250000", "notionalFloor": "50000", "maintMarginRatio": "0.02", - "cum": "542.5" + "cum": "545.0" } }, { @@ -23123,77 +23767,77 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.05", - "cum": "8042.5" + "cum": "8045.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "58042.5" + "cum": "58045.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.125", - "cum": "108042.5" + "cum": "183045.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.15, "maxLeverage": 3.0, "info": { "bracket": "8", "initialLeverage": "3", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.15", - "cum": "233042.5" + "cum": "433045.0" } }, { "tier": 9.0, "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "1233042.5" + "cum": "2433045.0" } }, { "tier": 10.0, "currency": "USDT", - "minNotional": 20000000.0, + "minNotional": 30000000.0, "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, @@ -23201,9 +23845,9 @@ "bracket": "10", "initialLeverage": "1", "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalFloor": "30000000", "maintMarginRatio": "0.5", - "cum": "6233042.5" + "cum": "9933045.0" } } ], From 736c396d98422f533c0a920e4f225327b43313b1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Mar 2023 16:09:46 +0200 Subject: [PATCH 55/63] Use correct amount for stoploss test --- tests/test_freqtradebot.py | 60 +++++++++++++++++++++++++++++--------- tests/test_integration.py | 2 +- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index bf3cc6ab8..adb581252 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1395,7 +1395,7 @@ def test_handle_stoploss_on_exchange_trailing( # When trailing stoploss is set enter_order = limit_order[entry_side(is_short)] exit_order = limit_order[exit_side(is_short)] - stoploss = MagicMock(return_value={'id': 13434334}) + stoploss = MagicMock(return_value={'id': 13434334, 'status': 'open'}) patch_RPCManager(mocker) mocker.patch.multiple( EXMS, @@ -1442,6 +1442,16 @@ def test_handle_stoploss_on_exchange_trailing( trade.open_order_id = None trade.stoploss_order_id = '100' trade.stoploss_last_update = arrow.utcnow().shift(minutes=-20).datetime + trade.orders.append( + Order( + ft_order_side='stoploss', + ft_pair=trade.pair, + ft_is_open=True, + ft_amount=trade.amount, + ft_price=trade.stop_loss, + order_id='100', + ) + ) stoploss_order_hanging = MagicMock(return_value={ 'id': '100', @@ -1471,7 +1481,7 @@ def test_handle_stoploss_on_exchange_trailing( ) cancel_order_mock = MagicMock() - stoploss_order_mock = MagicMock(return_value={'id': 'so1'}) + stoploss_order_mock = MagicMock(return_value={'id': 'so1', 'status': 'open'}) mocker.patch(f'{EXMS}.cancel_stoploss_order', cancel_order_mock) mocker.patch(f'{EXMS}.create_stoploss', stoploss_order_mock) @@ -1520,7 +1530,7 @@ def test_handle_stoploss_on_exchange_trailing_error( enter_order = limit_order[entry_side(is_short)] exit_order = limit_order[exit_side(is_short)] # When trailing stoploss is set - stoploss = MagicMock(return_value={'id': 13434334}) + stoploss = MagicMock(return_value={'id': '13434334', 'status': 'open'}) patch_exchange(mocker) mocker.patch.multiple( @@ -1629,7 +1639,7 @@ def test_handle_stoploss_on_exchange_custom_stop( enter_order = limit_order[entry_side(is_short)] exit_order = limit_order[exit_side(is_short)] # When trailing stoploss is set - stoploss = MagicMock(return_value={'id': 13434334}) + stoploss = MagicMock(return_value={'id': 13434334, 'status': 'open'}) patch_RPCManager(mocker) mocker.patch.multiple( EXMS, @@ -1676,6 +1686,16 @@ def test_handle_stoploss_on_exchange_custom_stop( trade.open_order_id = None trade.stoploss_order_id = '100' trade.stoploss_last_update = arrow.utcnow().shift(minutes=-601).datetime + trade.orders.append( + Order( + ft_order_side='stoploss', + ft_pair=trade.pair, + ft_is_open=True, + ft_amount=trade.amount, + ft_price=trade.stop_loss, + order_id='100', + ) + ) stoploss_order_hanging = MagicMock(return_value={ 'id': '100', @@ -1704,7 +1724,7 @@ def test_handle_stoploss_on_exchange_custom_stop( ) cancel_order_mock = MagicMock() - stoploss_order_mock = MagicMock(return_value={'id': 'so1'}) + stoploss_order_mock = MagicMock(return_value={'id': 'so1', 'status': 'open'}) mocker.patch(f'{EXMS}.cancel_stoploss_order', cancel_order_mock) mocker.patch(f'{EXMS}.create_stoploss', stoploss_order_mock) trade.stoploss_order_id = '100' @@ -1753,7 +1773,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_orde exit_order = limit_order['sell'] # When trailing stoploss is set - stoploss = MagicMock(return_value={'id': 13434334}) + stoploss = MagicMock(return_value={'id': '13434334', 'status': 'open'}) patch_RPCManager(mocker) patch_exchange(mocker) patch_edge(mocker) @@ -1802,11 +1822,21 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_orde trade = Trade.session.scalars(select(Trade)).first() trade.is_open = True trade.open_order_id = None - trade.stoploss_order_id = 100 - trade.stoploss_last_update = arrow.utcnow() + trade.stoploss_order_id = '100' + trade.stoploss_last_update = arrow.utcnow().datetime + trade.orders.append( + Order( + ft_order_side='stoploss', + ft_pair=trade.pair, + ft_is_open=True, + ft_amount=trade.amount, + ft_price=trade.stop_loss, + order_id='100', + ) + ) stoploss_order_hanging = MagicMock(return_value={ - 'id': 100, + 'id': '100', 'status': 'open', 'type': 'stop_loss_limit', 'price': 3, @@ -1853,7 +1883,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, limit_orde # stoploss should be set to 1% as trailing is on assert trade.stop_loss == 4.4 * 0.99 - cancel_order_mock.assert_called_once_with(100, 'NEO/BTC') + cancel_order_mock.assert_called_once_with('100', 'NEO/BTC') stoploss_order_mock.assert_called_once_with( amount=pytest.approx(11.41438356), pair='NEO/BTC', @@ -3606,10 +3636,12 @@ def test_execute_trade_exit_with_stoploss_on_exchange( patch_exchange(mocker) stoploss = MagicMock(return_value={ 'id': 123, + 'status': 'open', 'info': { 'foo': 'bar' } }) + mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_order_fee') cancel_order = MagicMock(return_value=True) mocker.patch.multiple( @@ -3707,12 +3739,12 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit( "lastTradeTimestamp": None, "symbol": "BTC/USDT", "type": "stop_loss_limit", - "side": "sell", + "side": "buy" if is_short else "sell", "price": 1.08801, - "amount": 90.99181074, - "cost": 99.0000000032274, + "amount": trade.amount, + "cost": 1.08801 * trade.amount, "average": 1.08801, - "filled": 90.99181074, + "filled": trade.amount, "remaining": 0.0, "status": "closed", "fee": None, diff --git a/tests/test_integration.py b/tests/test_integration.py index 5cbedd818..af8473514 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -35,7 +35,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, "type": "stop_loss_limit", "side": "sell", "price": 1.08801, - "amount": 90.99181074, + "amount": 91.07468123, "cost": 0.0, "average": 0.0, "filled": 0.0, From f0b5f95fd651cb642b68fb6b0614de7fc60e7470 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Mar 2023 18:10:26 +0200 Subject: [PATCH 56/63] Remove missleading comment --- tests/test_integration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index af8473514..66aa7b4ee 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -93,7 +93,7 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, wallets_mock.reset_mock() trades = Trade.session.scalars(select(Trade)).all() - # Make sure stoploss-order is open and trade is bought (since we mock update_trade_state) + # Make sure stoploss-order is open and trade is bought for trade in trades: stoploss_order_closed['id'] = '3' oobj = Order.parse_from_ccxt_object(stoploss_order_closed, trade.pair, 'stoploss') From 411e21f430a51d3f36236bd71f81889356a0a701 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Mar 2023 18:13:26 +0200 Subject: [PATCH 57/63] Improve stop test --- tests/test_freqtradebot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index adb581252..2033a5518 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1149,10 +1149,12 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ canceled_stoploss_order = MagicMock(return_value={'status': 'canceled'}) mocker.patch(f'{EXMS}.fetch_stoploss_order', canceled_stoploss_order) stoploss.reset_mock() + amount_before = trade.amount assert freqtrade.handle_stoploss_on_exchange(trade) is False assert stoploss.call_count == 1 assert trade.stoploss_order_id == "13434334" + assert trade.amount == amount_before # Fourth case: when stoploss is set and it is hit # should unset stoploss_order_id and return true From 513df4515b85519df66a2f990389885cb9ae2df4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Mar 2023 19:19:55 +0200 Subject: [PATCH 58/63] Improve stoploss tests --- tests/test_freqtradebot.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 2033a5518..7b89bfb9b 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1060,9 +1060,19 @@ def test_execute_entry_min_leverage(mocker, default_conf_usdt, fee, limit_order, @pytest.mark.parametrize("is_short", [False, True]) -def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_short) -> None: +def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_short, fee) -> None: patch_RPCManager(mocker) patch_exchange(mocker) + mocker.patch.multiple( + EXMS, + fetch_ticker=MagicMock(return_value={ + 'bid': 1.9, + 'ask': 2.2, + 'last': 1.9 + }), + create_order=MagicMock(return_value=limit_order[entry_side(is_short)]), + get_fee=fee, + ) order = limit_order[entry_side(is_short)] mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) mocker.patch(f'{EXMS}.fetch_order', return_value=order) @@ -1074,8 +1084,10 @@ def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_sho freqtrade = FreqtradeBot(default_conf_usdt) freqtrade.strategy.order_types['stoploss_on_exchange'] = True - # TODO: should not be magicmock - trade = MagicMock() + patch_get_signal(freqtrade, enter_short=is_short, enter_long=not is_short) + + freqtrade.enter_positions() + trade = Trade.session.scalars(select(Trade)).first() trade.is_short = is_short trade.open_order_id = None trade.stoploss_order_id = None @@ -1227,7 +1239,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ 'amount': enter_order['amount'], 'info': {'stopPrice': 22}, }]) - trade.stoploss_order_id = 100 + trade.stoploss_order_id = "100" trade.is_open = True trade.stoploss_last_update = arrow.utcnow().shift(hours=-1).datetime trade.stop_loss = 24 @@ -1275,7 +1287,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog, freqtrade.enter_positions() trade = Trade.session.scalars(select(Trade)).first() - trade.is_short = is_short + assert trade.is_short == is_short trade.is_open = True trade.open_order_id = None trade.stoploss_order_id = 100 From 6282b42741543f5df494a43ad06c412953e16328 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Mar 2023 19:38:43 +0200 Subject: [PATCH 59/63] Remove further Magicmock trade --- tests/test_freqtradebot.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 7b89bfb9b..bbe23fa9e 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1103,7 +1103,8 @@ def test_add_stoploss_on_exchange(mocker, default_conf_usdt, limit_order, is_sho @pytest.mark.parametrize("is_short", [False, True]) def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_short, limit_order) -> None: - stoploss = MagicMock(return_value={'id': 13434334}) + stop_order_dict = {'id': "13434334"} + stoploss = MagicMock(return_value=stop_order_dict) enter_order = limit_order[entry_side(is_short)] exit_order = limit_order[exit_side(is_short)] patch_RPCManager(mocker) @@ -1128,8 +1129,9 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ # First case: when stoploss is not yet set but the order is open # should get the stoploss order id immediately # and should return false as no trade actually happened - # TODO: should not be magicmock - trade = MagicMock() + + freqtrade.enter_positions() + trade = Trade.session.scalars(select(Trade)).first() trade.is_short = is_short trade.is_open = True trade.open_order_id = None @@ -1141,31 +1143,34 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ # Second case: when stoploss is set but it is not yet hit # should do nothing and return false + stop_order_dict.update({'id': "102"}) trade.is_open = True trade.open_order_id = None - trade.stoploss_order_id = "100" + trade.stoploss_order_id = "102" hanging_stoploss_order = MagicMock(return_value={'status': 'open'}) mocker.patch(f'{EXMS}.fetch_stoploss_order', hanging_stoploss_order) assert freqtrade.handle_stoploss_on_exchange(trade) is False - assert trade.stoploss_order_id == "100" + assert trade.stoploss_order_id == "102" # Third case: when stoploss was set but it was canceled for some reason # should set a stoploss immediately and return False caplog.clear() trade.is_open = True trade.open_order_id = None - trade.stoploss_order_id = "100" + trade.stoploss_order_id = "103" canceled_stoploss_order = MagicMock(return_value={'status': 'canceled'}) mocker.patch(f'{EXMS}.fetch_stoploss_order', canceled_stoploss_order) stoploss.reset_mock() amount_before = trade.amount + stop_order_dict.update({'id': "103_1"}) + assert freqtrade.handle_stoploss_on_exchange(trade) is False assert stoploss.call_count == 1 - assert trade.stoploss_order_id == "13434334" + assert trade.stoploss_order_id == "103_1" assert trade.amount == amount_before # Fourth case: when stoploss is set and it is hit @@ -1173,14 +1178,16 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ # as a trade actually happened caplog.clear() freqtrade.enter_positions() + stop_order_dict.update({'id': "104"}) + trade = Trade.session.scalars(select(Trade)).first() trade.is_short = is_short trade.is_open = True trade.open_order_id = None - trade.stoploss_order_id = "100" + trade.stoploss_order_id = "104" trade.orders.append(Order( ft_order_side='stoploss', - order_id='100', + order_id='104', ft_pair=trade.pair, ft_is_open=True, ft_amount=trade.amount, @@ -1189,7 +1196,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ assert trade stoploss_order_hit = MagicMock(return_value={ - 'id': "100", + 'id': "104", 'status': 'closed', 'type': 'stop_loss_limit', 'price': 3, @@ -1211,7 +1218,8 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ # Fifth case: fetch_order returns InvalidOrder # It should try to add stoploss order - trade.stoploss_order_id = 100 + stop_order_dict.update({'id': "105"}) + trade.stoploss_order_id = "105" stoploss.reset_mock() mocker.patch(f'{EXMS}.fetch_stoploss_order', side_effect=InvalidOrderException()) mocker.patch(f'{EXMS}.create_stoploss', stoploss) @@ -1231,7 +1239,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ # Seventh case: emergency exit triggered # Trailing stop should not act anymore stoploss_order_cancelled = MagicMock(side_effect=[{ - 'id': "100", + 'id': "107", 'status': 'canceled', 'type': 'stop_loss_limit', 'price': 3, @@ -1239,13 +1247,14 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ 'amount': enter_order['amount'], 'info': {'stopPrice': 22}, }]) - trade.stoploss_order_id = "100" + trade.stoploss_order_id = "107" trade.is_open = True trade.stoploss_last_update = arrow.utcnow().shift(hours=-1).datetime trade.stop_loss = 24 freqtrade.config['trailing_stop'] = True stoploss = MagicMock(side_effect=InvalidOrderException()) + Trade.commit() mocker.patch(f'{EXMS}.cancel_stoploss_order_with_result', side_effect=InvalidOrderException()) mocker.patch(f'{EXMS}.fetch_stoploss_order', stoploss_order_cancelled) From eb96490c999f3617bfc6949f1fa440f692f765bb Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Mar 2023 20:27:31 +0200 Subject: [PATCH 60/63] Improve some more stoploss tests --- tests/test_freqtradebot.py | 42 +++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index bbe23fa9e..01aa730cb 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1147,6 +1147,17 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ trade.is_open = True trade.open_order_id = None trade.stoploss_order_id = "102" + trade.orders.append( + Order( + ft_order_side='stoploss', + ft_pair=trade.pair, + ft_is_open=True, + ft_amount=trade.amount, + ft_price=trade.stop_loss, + order_id='102', + status='open', + ) + ) hanging_stoploss_order = MagicMock(return_value={'status': 'open'}) mocker.patch(f'{EXMS}.fetch_stoploss_order', hanging_stoploss_order) @@ -1159,9 +1170,9 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ caplog.clear() trade.is_open = True trade.open_order_id = None - trade.stoploss_order_id = "103" + trade.stoploss_order_id = "102" - canceled_stoploss_order = MagicMock(return_value={'status': 'canceled'}) + canceled_stoploss_order = MagicMock(return_value={'id': '103_1', 'status': 'canceled'}) mocker.patch(f'{EXMS}.fetch_stoploss_order', canceled_stoploss_order) stoploss.reset_mock() amount_before = trade.amount @@ -1245,12 +1256,26 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ 'price': 3, 'average': 2, 'amount': enter_order['amount'], + 'filled': 0, + 'remaining': enter_order['amount'], 'info': {'stopPrice': 22}, }]) trade.stoploss_order_id = "107" trade.is_open = True trade.stoploss_last_update = arrow.utcnow().shift(hours=-1).datetime trade.stop_loss = 24 + trade.exit_reason = None + trade.orders.append( + Order( + ft_order_side='stoploss', + ft_pair=trade.pair, + ft_is_open=True, + ft_amount=trade.amount, + ft_price=trade.stop_loss, + order_id='107', + status='open', + ) + ) freqtrade.config['trailing_stop'] = True stoploss = MagicMock(side_effect=InvalidOrderException()) @@ -1299,7 +1324,18 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf_usdt, fee, caplog, assert trade.is_short == is_short trade.is_open = True trade.open_order_id = None - trade.stoploss_order_id = 100 + trade.stoploss_order_id = "100" + trade.orders.append( + Order( + ft_order_side='stoploss', + ft_pair=trade.pair, + ft_is_open=True, + ft_amount=trade.amount, + ft_price=trade.stop_loss, + order_id='100', + status='open', + ) + ) assert trade assert freqtrade.handle_stoploss_on_exchange(trade) is False From a64252492804cb6c254a4d4f09f03a7e1ed02d48 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Mar 2023 06:47:34 +0200 Subject: [PATCH 61/63] Improve integration test correctness --- tests/test_integration.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index 66aa7b4ee..9fb9fd8b3 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -49,8 +49,9 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, stoploss_order_closed['filled'] = stoploss_order_closed['amount'] # Sell first trade based on stoploss, keep 2nd and 3rd trade open + stop_orders = [stoploss_order_closed, stoploss_order_open, stoploss_order_open] stoploss_order_mock = MagicMock( - side_effect=[stoploss_order_closed, stoploss_order_open, stoploss_order_open]) + side_effect=stop_orders) # Sell 3rd trade (not called for the first trade) should_sell_mock = MagicMock(side_effect=[ [], @@ -94,12 +95,13 @@ def test_may_execute_exit_stoploss_on_exchange_multi(default_conf, ticker, fee, trades = Trade.session.scalars(select(Trade)).all() # Make sure stoploss-order is open and trade is bought - for trade in trades: - stoploss_order_closed['id'] = '3' - oobj = Order.parse_from_ccxt_object(stoploss_order_closed, trade.pair, 'stoploss') + for idx, trade in enumerate(trades): + stop_order = stop_orders[idx] + stop_order['id'] = f"stop{idx}" + oobj = Order.parse_from_ccxt_object(stop_order, trade.pair, 'stoploss') trade.orders.append(oobj) - trade.stoploss_order_id = '3' + trade.stoploss_order_id = f"stop{idx}" trade.open_order_id = None n = freqtrade.exit_positions(trades) From 8a49d620687d3c367cec1efbec6d4e5ab41c8137 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Mar 2023 06:49:11 +0200 Subject: [PATCH 62/63] Don't update liquidation price for closed trades --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 42db121e9..9746ac3d8 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1811,7 +1811,7 @@ class FreqtradeBot(LoggingMixin): # TODO: should shorting/leverage be supported by Edge, # then this will need to be fixed. trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss, initial=True) - if order.get('side') == trade.entry_side or trade.amount > 0: + if order.get('side') == trade.entry_side or (trade.amount > 0 and trade.is_open): # Must also run for partial exits # TODO: Margin will need to use interest_rate as well. # interest_rate = self.exchange.get_interest_rate() From fa7c29fe9f03483e02ac752617062b7b1c0b3963 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Mar 2023 20:43:23 +0200 Subject: [PATCH 63/63] Update producer docs to reflect proper datatype closes #8419 --- docs/producer-consumer.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/producer-consumer.md b/docs/producer-consumer.md index 88e34d0d6..c52279f26 100644 --- a/docs/producer-consumer.md +++ b/docs/producer-consumer.md @@ -42,14 +42,14 @@ Enable subscribing to an instance by adding the `external_message_consumer` sect | `producers` | **Required.** List of producers
**Datatype:** Array. | `producers.name` | **Required.** Name of this producer. This name must be used in calls to `get_producer_pairs()` and `get_producer_df()` if more than one producer is used.
**Datatype:** string | `producers.host` | **Required.** The hostname or IP address from your producer.
**Datatype:** string -| `producers.port` | **Required.** The port matching the above host.
**Datatype:** string +| `producers.port` | **Required.** The port matching the above host.
*Defaults to `8080`.*
**Datatype:** Integer | `producers.secure` | **Optional.** Use ssl in websockets connection. Default False.
**Datatype:** string | `producers.ws_token` | **Required.** `ws_token` as configured on the producer.
**Datatype:** string | | **Optional settings** | `wait_timeout` | Timeout until we ping again if no message is received.
*Defaults to `300`.*
**Datatype:** Integer - in seconds. -| `wait_timeout` | Ping timeout
*Defaults to `10`.*
**Datatype:** Integer - in seconds. +| `ping_timeout` | Ping timeout
*Defaults to `10`.*
**Datatype:** Integer - in seconds. | `sleep_time` | Sleep time before retrying to connect.
*Defaults to `10`.*
**Datatype:** Integer - in seconds. -| `remove_entry_exit_signals` | Remove signal columns from the dataframe (set them to 0) on dataframe receipt.
*Defaults to `10`.*
**Datatype:** Integer - in seconds. +| `remove_entry_exit_signals` | Remove signal columns from the dataframe (set them to 0) on dataframe receipt.
*Defaults to `False`.*
**Datatype:** Boolean. | `message_size_limit` | Size limit per message
*Defaults to `8`.*
**Datatype:** Integer - Megabytes. Instead of (or as well as) calculating indicators in `populate_indicators()` the follower instance listens on the connection to a producer instance's messages (or multiple producer instances in advanced configurations) and requests the producer's most recently analyzed dataframes for each pair in the active whitelist.