diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 608565fdc..63a0b7468 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -360,6 +360,8 @@ jobs: pip install -e . - name: Tests incl. ccxt compatibility tests + env: + CI_WEB_PROXY: http://152.67.78.211:13128 run: | pytest --random-order --cov=freqtrade --cov-config=.coveragerc --longrun diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 306e4bbda..d50506650 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,33 +2,33 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pycqa/flake8 - rev: "4.0.1" + rev: "6.0.0" hooks: - id: flake8 # stages: [push] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v0.942" + rev: "v0.991" hooks: - id: mypy exclude: build_helpers additional_dependencies: - - types-cachetools==5.2.1 + - types-cachetools==5.3.0.0 - types-filelock==3.2.7 - - types-requests==2.28.11.7 + - types-requests==2.28.11.8 - types-tabulate==0.9.0.0 - - types-python-dateutil==2.8.19.5 + - types-python-dateutil==2.8.19.6 # stages: [push] - repo: https://github.com/pycqa/isort - rev: "5.10.1" + rev: "5.12.0" hooks: - id: isort name: isort (python) # stages: [push] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.4.0 + rev: v4.4.0 hooks: - id: end-of-file-fixer exclude: | diff --git a/README.md b/README.md index 2ab62793d..c8bc50dac 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Please read the [exchange specific notes](docs/exchanges.md) to learn about even - [X] [Binance](https://www.binance.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) - [X] [OKX](https://okx.com/) +- [X] [Bybit](https://bybit.com/) Please make sure to read the [exchange specific notes](docs/exchanges.md), as well as the [trading with leverage](docs/leverage.md) documentation before diving in. @@ -164,6 +165,10 @@ first. If it hasn't been reported, please ensure you follow the template guide so that the team can assist you as quickly as possible. +For every [issue](https://github.com/freqtrade/freqtrade/issues/new/choose) created, kindly follow up and mark satisfaction or reminder to close issue when equilibrium ground is reached. + +--Maintain github's [community policy](https://docs.github.com/en/site-policy/github-terms/github-community-code-of-conduct)-- + ### [Feature Requests](https://github.com/freqtrade/freqtrade/labels/enhancement) Have you a great idea to improve the bot you want to share? Please, diff --git a/build_helpers/TA_Lib-0.4.25-cp311-cp311-win_amd64.whl b/build_helpers/TA_Lib-0.4.25-cp311-cp311-win_amd64.whl new file mode 100644 index 000000000..4d55d18c8 Binary files /dev/null and b/build_helpers/TA_Lib-0.4.25-cp311-cp311-win_amd64.whl differ diff --git a/build_helpers/install_windows.ps1 b/build_helpers/install_windows.ps1 index 461726a03..36606cc3a 100644 --- a/build_helpers/install_windows.ps1 +++ b/build_helpers/install_windows.ps1 @@ -14,5 +14,8 @@ if ($pyv -eq '3.9') { if ($pyv -eq '3.10') { pip install build_helpers\TA_Lib-0.4.25-cp310-cp310-win_amd64.whl } +if ($pyv -eq '3.11') { + pip install build_helpers\TA_Lib-0.4.25-cp311-cp311-win_amd64.whl +} pip install -r requirements-dev.txt pip install -e . diff --git a/build_helpers/publish_docker_arm64.sh b/build_helpers/publish_docker_arm64.sh index 071eb0fa2..f3cedff2e 100755 --- a/build_helpers/publish_docker_arm64.sh +++ b/build_helpers/publish_docker_arm64.sh @@ -70,20 +70,21 @@ docker push ${CACHE_IMAGE}:$TAG_ARM # Otherwise installation might fail. echo "create manifests" -docker manifest create --amend ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG} +docker manifest create ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} docker manifest push -p ${IMAGE_NAME}:${TAG} -docker manifest create ${IMAGE_NAME}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM} ${CACHE_IMAGE}:${TAG_PLOT} +docker manifest create ${IMAGE_NAME}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM} docker manifest push -p ${IMAGE_NAME}:${TAG_PLOT} -docker manifest create ${IMAGE_NAME}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI_ARM} ${CACHE_IMAGE}:${TAG_FREQAI} +docker manifest create ${IMAGE_NAME}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI_ARM} docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI} -docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM} ${CACHE_IMAGE}:${TAG_FREQAI_RL} +docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM} docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI_RL} # Tag as latest for develop builds if [ "${TAG}" = "develop" ]; then + echo 'Tagging image as latest' docker manifest create ${IMAGE_NAME}:latest ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG} docker manifest push -p ${IMAGE_NAME}:latest fi diff --git a/build_helpers/publish_docker_multi.sh b/build_helpers/publish_docker_multi.sh index a608c1282..3e5e61564 100755 --- a/build_helpers/publish_docker_multi.sh +++ b/build_helpers/publish_docker_multi.sh @@ -26,7 +26,10 @@ if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then --cache-to=type=registry,ref=${CACHE_TAG} \ -f docker/Dockerfile.armhf \ --platform ${PI_PLATFORM} \ - -t ${IMAGE_NAME}:${TAG_PI} --push . + -t ${IMAGE_NAME}:${TAG_PI} \ + --push \ + --provenance=false \ + . else echo "event ${GITHUB_EVENT_NAME}: building with cache" # Build regular image @@ -35,12 +38,16 @@ else # Pull last build to avoid rebuilding the whole image # docker pull --platform ${PI_PLATFORM} ${IMAGE_NAME}:${TAG} + # disable provenance due to https://github.com/docker/buildx/issues/1509 docker buildx build \ --cache-from=type=registry,ref=${CACHE_TAG} \ --cache-to=type=registry,ref=${CACHE_TAG} \ -f docker/Dockerfile.armhf \ --platform ${PI_PLATFORM} \ - -t ${IMAGE_NAME}:${TAG_PI} --push . + -t ${IMAGE_NAME}:${TAG_PI} \ + --push \ + --provenance=false \ + . fi if [ $? -ne 0 ]; then @@ -68,12 +75,10 @@ fi docker images -docker push ${CACHE_IMAGE} +docker push ${CACHE_IMAGE}:$TAG docker push ${CACHE_IMAGE}:$TAG_PLOT docker push ${CACHE_IMAGE}:$TAG_FREQAI docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL -docker push ${CACHE_IMAGE}:$TAG - docker images diff --git a/build_helpers/pyarrow-10.0.0-cp39-cp39-linux_armv7l.whl b/build_helpers/pyarrow-11.0.0-cp39-cp39-linux_armv7l.whl similarity index 62% rename from build_helpers/pyarrow-10.0.0-cp39-cp39-linux_armv7l.whl rename to build_helpers/pyarrow-11.0.0-cp39-cp39-linux_armv7l.whl index a6c879cf5..a7ad80bdf 100644 Binary files a/build_helpers/pyarrow-10.0.0-cp39-cp39-linux_armv7l.whl and b/build_helpers/pyarrow-11.0.0-cp39-cp39-linux_armv7l.whl differ diff --git a/config_examples/config_binance.example.json b/config_examples/config_binance.example.json index 3e99bd114..7968bdedc 100644 --- a/config_examples/config_binance.example.json +++ b/config_examples/config_binance.example.json @@ -59,20 +59,6 @@ "pairlists": [ {"method": "StaticPairList"} ], - "edge": { - "enabled": false, - "process_throttle_secs": 3600, - "calculate_since_number_of_days": 7, - "allowed_risk": 0.01, - "stoploss_range_min": -0.01, - "stoploss_range_max": -0.1, - "stoploss_range_step": -0.01, - "minimum_winrate": 0.60, - "minimum_expectancy": 0.20, - "min_trade_number": 10, - "max_trade_duration_minute": 1440, - "remove_pumps": false - }, "telegram": { "enabled": false, "token": "your_telegram_token", diff --git a/config_examples/config_bittrex.example.json b/config_examples/config_bittrex.example.json index a0a5071dd..3be5ba092 100644 --- a/config_examples/config_bittrex.example.json +++ b/config_examples/config_bittrex.example.json @@ -56,20 +56,6 @@ "pairlists": [ {"method": "StaticPairList"} ], - "edge": { - "enabled": false, - "process_throttle_secs": 3600, - "calculate_since_number_of_days": 7, - "allowed_risk": 0.01, - "stoploss_range_min": -0.01, - "stoploss_range_max": -0.1, - "stoploss_range_step": -0.01, - "minimum_winrate": 0.60, - "minimum_expectancy": 0.20, - "min_trade_number": 10, - "max_trade_duration_minute": 1440, - "remove_pumps": false - }, "telegram": { "enabled": false, "token": "your_telegram_token", diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json index dfd54b3d9..645c30227 100644 --- a/config_examples/config_freqai.example.json +++ b/config_examples/config_freqai.example.json @@ -21,8 +21,8 @@ "ccxt_config": {}, "ccxt_async_config": {}, "pair_whitelist": [ - "1INCH/USDT", - "ALGO/USDT" + "1INCH/USDT:USDT", + "ALGO/USDT:USDT" ], "pair_blacklist": [] }, @@ -60,8 +60,8 @@ "1h" ], "include_corr_pairlist": [ - "BTC/USDT", - "ETH/USDT" + "BTC/USDT:USDT", + "ETH/USDT:USDT" ], "label_period_candles": 20, "include_shifted_candles": 2, diff --git a/config_examples/config_full.example.json b/config_examples/config_full.example.json index b60957b58..64e5b76ea 100644 --- a/config_examples/config_full.example.json +++ b/config_examples/config_full.example.json @@ -60,6 +60,7 @@ "force_entry": "market", "stoploss": "market", "stoploss_on_exchange": false, + "stoploss_price_type": "last", "stoploss_on_exchange_interval": 60, "stoploss_on_exchange_limit_ratio": 0.99 }, diff --git a/config_examples/config_kraken.example.json b/config_examples/config_kraken.example.json index c55dea6ba..420047627 100644 --- a/config_examples/config_kraken.example.json +++ b/config_examples/config_kraken.example.json @@ -64,20 +64,6 @@ "pairlists": [ {"method": "StaticPairList"} ], - "edge": { - "enabled": false, - "process_throttle_secs": 3600, - "calculate_since_number_of_days": 7, - "allowed_risk": 0.01, - "stoploss_range_min": -0.01, - "stoploss_range_max": -0.1, - "stoploss_range_step": -0.01, - "minimum_winrate": 0.60, - "minimum_expectancy": 0.20, - "min_trade_number": 10, - "max_trade_duration_minute": 1440, - "remove_pumps": false - }, "telegram": { "enabled": false, "token": "your_telegram_token", diff --git a/docs/advanced-backtesting.md b/docs/advanced-backtesting.md index ae3eb2e4e..be9099df8 100644 --- a/docs/advanced-backtesting.md +++ b/docs/advanced-backtesting.md @@ -32,7 +32,7 @@ To analyze the entry/exit tags, we now need to use the `freqtrade backtesting-an with `--analysis-groups` option provided with space-separated arguments (default `0 1 2`): ``` bash -freqtrade backtesting-analysis -c --analysis-groups 0 1 2 3 4 +freqtrade backtesting-analysis -c --analysis-groups 0 1 2 3 4 5 ``` This command will read from the last backtesting results. The `--analysis-groups` option is @@ -43,6 +43,7 @@ ranging from the simplest (0) to the most detailed per pair, per buy and per sel * 2: profit summaries grouped by enter_tag and exit_tag * 3: profit summaries grouped by pair and enter_tag * 4: profit summaries grouped by pair, enter_ and exit_tag (this can get quite large) +* 5: profit summaries grouped by exit_tag More options are available by running with the `-h` option. diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index 0dace9985..ff0521f4f 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -75,7 +75,7 @@ This function needs to return a floating point number (`float`). Smaller numbers ## Overriding pre-defined spaces -To override a pre-defined space (`roi_space`, `generate_roi_table`, `stoploss_space`, `trailing_space`), define a nested class called Hyperopt and define the required spaces as follows: +To override a pre-defined space (`roi_space`, `generate_roi_table`, `stoploss_space`, `trailing_space`, `max_open_trades_space`), define a nested class called Hyperopt and define the required spaces as follows: ```python from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal @@ -123,6 +123,12 @@ class MyAwesomeStrategy(IStrategy): Categorical([True, False], name='trailing_only_offset_is_reached'), ] + + # Define a custom max_open_trades space + def max_open_trades_space(self) -> List[Dimension]: + return [ + Integer(-1, 10, name='max_open_trades'), + ] ``` !!! Note diff --git a/docs/bot-basics.md b/docs/bot-basics.md index 3df926371..925fc7862 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -75,3 +75,7 @@ This loop will be repeated again and again until the bot is stopped. !!! Note Both Backtesting and Hyperopt include exchange default Fees in the calculation. Custom fees can be passed to backtesting / hyperopt by specifying the `--fee` argument. + +!!! Warning "Callback call frequency" + Backtesting will call each callback at max. once per candle (`--timeframe-detail` modifies this behavior to once per detailed candle). + Most callbacks will be called once per iteration in live (usually every ~5s) - which can cause backtesting mismatches. diff --git a/docs/configuration.md b/docs/configuration.md index 83b23425c..8a1aeb40e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -11,7 +11,7 @@ Per default, the bot loads the configuration from the `config.json` file, locate You can specify a different configuration file used by the bot with the `-c/--config` command-line option. -If you used the [Quick start](installation.md/#quick-start) method for installing +If you used the [Quick start](docker_quickstart.md#docker-quick-start) method for installing the bot, the installation script should have already created the default configuration file (`config.json`) for you. If the default configuration file is not created we recommend to use `freqtrade new-config --config config.json` to generate a basic configuration file. @@ -134,7 +134,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | Parameter | Description | |------------|-------------| -| `max_open_trades` | **Required.** Number of open trades your bot is allowed to have. Only one open trade per pair is possible, so the length of your pairlist is another limitation that can apply. If -1 then it is ignored (i.e. potentially unlimited open trades, limited by the pairlist). [More information below](#configuring-amount-per-trade).
**Datatype:** Positive integer or -1. +| `max_open_trades` | **Required.** Number of open trades your bot is allowed to have. Only one open trade per pair is possible, so the length of your pairlist is another limitation that can apply. If -1 then it is ignored (i.e. potentially unlimited open trades, limited by the pairlist). [More information below](#configuring-amount-per-trade). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** Positive integer or -1. | `stake_currency` | **Required.** Crypto-currency used for trading.
**Datatype:** String | `stake_amount` | **Required.** Amount of crypto-currency your bot will use for each trade. Set it to `"unlimited"` to allow the bot to use all available balance. [More information below](#configuring-amount-per-trade).
**Datatype:** Positive float or `"unlimited"`. | `tradable_balance_ratio` | Ratio of the total account balance the bot is allowed to trade. [More information below](#configuring-amount-per-trade).
*Defaults to `0.99` 99%).*
**Datatype:** Positive float between `0.1` and `1.0`. @@ -263,6 +263,7 @@ Values set in the configuration file always overwrite values set in the strategy * `minimal_roi` * `timeframe` * `stoploss` +* `max_open_trades` * `trailing_stop` * `trailing_stop_positive` * `trailing_stop_positive_offset` @@ -665,7 +666,7 @@ You should also make sure to read the [Exchanges](exchanges.md) section of the d ### Using proxy with Freqtrade To use a proxy with freqtrade, export your proxy settings using the variables `"HTTP_PROXY"` and `"HTTPS_PROXY"` set to the appropriate values. -This will have the proxy settings applied to everything (telegram, coingecko, ...) except exchange requests. +This will have the proxy settings applied to everything (telegram, coingecko, ...) **except** for exchange requests. ``` bash export HTTP_PROXY="http://addr:port" @@ -681,11 +682,12 @@ To use a proxy for exchange connections - you will have to define the proxies as { "exchange": { "ccxt_config": { - "aiohttp_proxy": "http://addr:port", - "proxies": { - "http": "http://addr:port", - "https": "http://addr:port" - }, + "aiohttp_proxy": "http://addr:port", + "proxies": { + "http": "http://addr:port", + "https": "http://addr:port" + }, + } } } ``` diff --git a/docs/exchanges.md b/docs/exchanges.md index 7070fc690..997d012e1 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -75,6 +75,25 @@ Binance has been split into 2, and users must use the correct ccxt exchange ID f * [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance`. * [binance.us](https://www.binance.us/) - US based users. Use exchange id: `binanceus`. +### Binance RSA keys + +Freqtrade supports binance RSA API keys. + +We recommend to use them as environment variable. + +``` bash +export FREQTRADE__EXCHANGE__SECRET="$(cat ./rsa_binance.private)" +``` + +They can however also be configured via configuration file. Since json doesn't support multi-line strings, you'll have to replace all newlines with `\n` to have a valid json file. + +``` json +// ... + "key": "", + "secret": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBABACAFQA<...>s8KX8=\n-----END PRIVATE KEY-----" +// ... +``` + ### Binance Futures Binance has specific (unfortunately complex) [Futures Trading Quantitative Rules](https://www.binance.com/en/support/faq/4f462ebe6ff445d4a170be7d9e897272) which need to be followed, and which prohibit a too low stake-amount (among others) for too many orders. @@ -224,8 +243,8 @@ OKX requires a passphrase for each api key, you will therefore need to add this OKX only provides 100 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode. !!! Warning "Futures" - OKX Futures has the concept of "position mode" - which can be Net or long/short (hedge mode). - Freqtrade supports both modes (we recommend to use net mode) - but changing the mode mid-trading is not supported and will lead to exceptions and failures to place trades. + OKX Futures has the concept of "position mode" - which can be "Buy/Sell" or long/short (hedge mode). + Freqtrade supports both modes (we recommend to use Buy/Sell mode) - but changing the mode mid-trading is not supported and will lead to exceptions and failures to place trades. OKX also only provides MARK candles for the past ~3 months. Backtesting futures prior to that date will therefore lead to slight deviations, as funding-fees cannot be calculated correctly without this data. ## Gate.io @@ -236,6 +255,18 @@ OKX requires a passphrase for each api key, you will therefore need to add this Gate.io allows the use of `POINT` to pay for fees. As this is not a tradable currency (no regular market available), automatic fee calculations will fail (and default to a fee of 0). The configuration parameter `exchange.unknown_fee_rate` can be used to specify the exchange rate between Point and the stake currency. Obviously, changing the stake-currency will also require changes to this value. +## Bybit + +Futures trading on bybit is currently supported for USDT markets, and will use isolated futures mode. +Users with unified accounts (there's no way back) can create a Sub-account which will start as "non-unified", and can therefore use isolated futures. +On startup, freqtrade will set the position mode to "One-way Mode" for the whole (sub)account. This avoids making this call over and over again (slowing down bot operations), but means that changes to this setting may result in exceptions and errors. + +As bybit doesn't provide funding rate history, the dry-run calculation is used for live trades as well. + +!!! Tip "Stoploss on Exchange" + Bybit (futures only) supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange. + On futures, Bybit supports both `stop-limit` as well as `stop-market` orders. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use. + ## All exchanges Should you experience constant errors with Nonce (like `InvalidNonce`), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys. diff --git a/docs/freqai-configuration.md b/docs/freqai-configuration.md index 10f5838c9..9d89800be 100644 --- a/docs/freqai-configuration.md +++ b/docs/freqai-configuration.md @@ -43,116 +43,113 @@ The FreqAI strategy requires including the following lines of code in the standa def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # the model will return all labels created by user in `populate_any_indicators` + # the model will return all labels created by user in `set_freqai_labels()` # (& appended targets), an indication of whether or not the prediction should be accepted, # the target mean/std values for each of the labels created by user in - # `populate_any_indicators()` for each training period. + # `feature_engineering_*` for each training period. dataframe = self.freqai.start(dataframe, metadata, self) return dataframe - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe, period, **kwargs): """ - Function designed to automatically generate, name and merge features - from user indicated timeframes in the configuration file. User controls the indicators - passed to the training/prediction by prepending indicators with `'%-' + pair ` - (see convention below). I.e. user should not prepend any supporting metrics - (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the - model. - :param pair: pair to be used as informative - :param df: strategy dataframe which will receive merges from informatives - :param tf: timeframe of the dataframe which will modify the feature names - :param informative: the dataframe associated with the informative pair + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and + `include_corr_pairs`. In other words, a single feature defined in this function + will automatically expand to a total of + `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` * + `include_corr_pairs` numbers of features added to the model. + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + :param period: period of the indicator - usage example: + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) """ - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) + dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period) + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: - t = int(t) - informative[f"%-{pair}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{pair}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{pair}adx-period_{t}"] = ta.ADX(informative, window=t) + return dataframe - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + def feature_engineering_expand_basic(self, dataframe, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. + In other words, a single feature defined in this function + will automatically expand to a total of + `include_timeframes` * `include_shifted_candles` * `include_corr_pairs` + numbers of features added to the model. - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + Features defined here will *not* be automatically duplicated on user defined + `indicator_periods_candles` - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: + All features must be prepended with `%` to be recognized by FreqAI internals. - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 + :param df: strategy dataframe which will receive the features + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200) + """ + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] + return dataframe + + def feature_engineering_standard(self, dataframe, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This optional function will be called once with the dataframe of the base timeframe. + This is the final function to be called, which means that the dataframe entering this + function will contain all the features and columns created by all other + freqai_feature_engineering_* functions. + + This function is a good place to do custom exotic feature extractions (e.g. tsfresh). + This function is a good place for any feature that should not be auto-expanded upon + (e.g. day of the week). + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + """ + dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + dataframe["%-hour_of_day"] = (dataframe["date"].dt.hour + 1) / 25 + return dataframe + + def set_freqai_targets(self, dataframe, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + :param df: strategy dataframe which will receive the targets + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 ) - - return df - - ``` -Notice how the `populate_any_indicators()` is where [features](freqai-feature-engineering.md#feature-engineering) and labels/targets are added. A full example strategy is available in `templates/FreqaiExampleStrategy.py`. - -Notice also the location of the labels under `if set_generalized_indicators:` at the bottom of the example. This is where single features and labels/targets should be added to the feature set to avoid duplication of them from various configuration parameters that multiply the feature set, such as `include_timeframes`. +Notice how the `feature_engineering_*()` is where [features](freqai-feature-engineering.md#feature-engineering) are added. Meanwhile `set_freqai_targets()` adds the labels/targets. A full example strategy is available in `templates/FreqaiExampleStrategy.py`. !!! Note The `self.freqai.start()` function cannot be called outside the `populate_indicators()`. !!! Note - Features **must** be defined in `populate_any_indicators()`. Defining FreqAI features in `populate_indicators()` - will cause the algorithm to fail in live/dry mode. In order to add generalized features that are not associated with a specific pair or timeframe, the following structure inside `populate_any_indicators()` should be used - (as exemplified in `freqtrade/templates/FreqaiExampleStrategy.py`): - - ```python - def populate_any_indicators(self, pair, df, tf, informative=None, set_generalized_indicators=False): - - ... - - # Add generalized indicators here (because in live, it will call only this function to populate - # indicators for retraining). Notice how we ensure not to add them multiple times by associating - # these generalized indicators to the basepair/timeframe - if set_generalized_indicators: - df['%-day_of_week'] = (df["date"].dt.dayofweek + 1) / 7 - df['%-hour_of_day'] = (df['date'].dt.hour + 1) / 25 - - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) - ``` - - Please see the example script located in `freqtrade/templates/FreqaiExampleStrategy.py` for a full example of `populate_any_indicators()`. + Features **must** be defined in `feature_engineering_*()`. Defining FreqAI features in `populate_indicators()` + will cause the algorithm to fail in live/dry mode. In order to add generalized features that are not associated with a specific pair or timeframe, you should use `feature_engineering_standard()` + (as exemplified in `freqtrade/templates/FreqaiExampleStrategy.py`). ## Important dataframe key patterns @@ -160,11 +157,11 @@ Below are the values you can expect to include/use inside a typical strategy dat | DataFrame Key | Description | |------------|-------------| -| `df['&*']` | Any dataframe column prepended with `&` in `populate_any_indicators()` is treated as a training target (label) inside FreqAI (typically following the naming convention `&-s*`). For example, to predict the close price 40 candles into the future, you would set `df['&-s_close'] = df['close'].shift(-self.freqai_info["feature_parameters"]["label_period_candles"])` with `"label_period_candles": 40` in the config. FreqAI makes the predictions and gives them back under the same key (`df['&-s_close']`) to be used in `populate_entry/exit_trend()`.
**Datatype:** Depends on the output of the model. +| `df['&*']` | Any dataframe column prepended with `&` in `set_freqai_targets()` is treated as a training target (label) inside FreqAI (typically following the naming convention `&-s*`). For example, to predict the close price 40 candles into the future, you would set `df['&-s_close'] = df['close'].shift(-self.freqai_info["feature_parameters"]["label_period_candles"])` with `"label_period_candles": 40` in the config. FreqAI makes the predictions and gives them back under the same key (`df['&-s_close']`) to be used in `populate_entry/exit_trend()`.
**Datatype:** Depends on the output of the model. | `df['&*_std/mean']` | Standard deviation and mean values of the defined labels during training (or live tracking with `fit_live_predictions_candles`). Commonly used to understand the rarity of a prediction (use the z-score as shown in `templates/FreqaiExampleStrategy.py` and explained [here](#creating-a-dynamic-target-threshold) to evaluate how often a particular prediction was observed during training or historically with `fit_live_predictions_candles`).
**Datatype:** Float. | `df['do_predict']` | Indication of an outlier data point. The return value is integer between -2 and 2, which lets you know if the prediction is trustworthy or not. `do_predict==1` means that the prediction is trustworthy. If the Dissimilarity Index (DI, see details [here](freqai-feature-engineering.md#identifying-outliers-with-the-dissimilarity-index-di)) of the input data point is above the threshold defined in the config, FreqAI will subtract 1 from `do_predict`, resulting in `do_predict==0`. If `use_SVM_to_remove_outliers()` is active, the Support Vector Machine (SVM, see details [here](freqai-feature-engineering.md#identifying-outliers-using-a-support-vector-machine-svm)) may also detect outliers in training and prediction data. In this case, the SVM will also subtract 1 from `do_predict`. If the input data point was considered an outlier by the SVM but not by the DI, or vice versa, the result will be `do_predict==0`. If both the DI and the SVM considers the input data point to be an outlier, the result will be `do_predict==-1`. As with the SVM, if `use_DBSCAN_to_remove_outliers` is active, DBSCAN (see details [here](freqai-feature-engineering.md#identifying-outliers-with-dbscan)) may also detect outliers and subtract 1 from `do_predict`. Hence, if both the SVM and DBSCAN are active and identify a datapoint that was above the DI threshold as an outlier, the result will be `do_predict==-2`. A particular case is when `do_predict == 2`, which means that the model has expired due to exceeding `expired_hours`.
**Datatype:** Integer between -2 and 2. | `df['DI_values']` | Dissimilarity Index (DI) values are proxies for the level of confidence FreqAI has in the prediction. A lower DI means the prediction is close to the training data, i.e., higher prediction confidence. See details about the DI [here](freqai-feature-engineering.md#identifying-outliers-with-the-dissimilarity-index-di).
**Datatype:** Float. -| `df['%*']` | Any dataframe column prepended with `%` in `populate_any_indicators()` is treated as a training feature. For example, you can include the RSI in the training feature set (similar to in `templates/FreqaiExampleStrategy.py`) by setting `df['%-rsi']`. See more details on how this is done [here](freqai-feature-engineering.md).
**Note:** Since the number of features prepended with `%` can multiply very quickly (10s of thousands of features are easily engineered using the multiplictative functionality of, e.g., `include_shifted_candles` and `include_timeframes` as described in the [parameter table](freqai-parameter-table.md)), these features are removed from the dataframe that is returned from FreqAI to the strategy. To keep a particular type of feature for plotting purposes, you would prepend it with `%%`.
**Datatype:** Depends on the output of the model. +| `df['%*']` | Any dataframe column prepended with `%` in `feature_engineering_*()` is treated as a training feature. For example, you can include the RSI in the training feature set (similar to in `templates/FreqaiExampleStrategy.py`) by setting `df['%-rsi']`. See more details on how this is done [here](freqai-feature-engineering.md).
**Note:** Since the number of features prepended with `%` can multiply very quickly (10s of thousands of features are easily engineered using the multiplictative functionality of, e.g., `include_shifted_candles` and `include_timeframes` as described in the [parameter table](freqai-parameter-table.md)), these features are removed from the dataframe that is returned from FreqAI to the strategy. To keep a particular type of feature for plotting purposes, you would prepend it with `%%`.
**Datatype:** Depends on the output of the model. ## Setting the `startup_candle_count` diff --git a/docs/freqai-feature-engineering.md b/docs/freqai-feature-engineering.md index 3462955cc..8940aed4a 100644 --- a/docs/freqai-feature-engineering.md +++ b/docs/freqai-feature-engineering.md @@ -2,96 +2,150 @@ ## Defining the features -Low level feature engineering is performed in the user strategy within a function called `populate_any_indicators()`. That function sets the `base features` such as, `RSI`, `MFI`, `EMA`, `SMA`, time of day, volume, etc. The `base features` can be custom indicators or they can be imported from any technical-analysis library that you can find. One important syntax rule is that all `base features` string names are prepended with `%-{pair}`, while labels/targets are prepended with `&`. +Low level feature engineering is performed in the user strategy within a set of functions called `feature_engineering_*`. These function set the `base features` such as, `RSI`, `MFI`, `EMA`, `SMA`, time of day, volume, etc. The `base features` can be custom indicators or they can be imported from any technical-analysis library that you can find. FreqAI is equipped with a set of functions to simplify rapid large-scale feature engineering: -!!! Note - Adding the full pair string, e.g. XYZ/USD, in the feature name enables improved performance for dataframe caching on the backend. If you decide *not* to add the full pair string in the feature string, FreqAI will operate in a reduced performance mode. +| Function | Description | +|---------------|-------------| +| `feature_engineering__expand_all()` | This optional function will automatically expand the defined features on the config defined `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. +| `feature_engineering__expand_basic()` | This optional function will automatically expand the defined features on the config defined `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. Note: this function does *not* expand across `include_periods_candles`. +| `feature_engineering_standard()` | This optional function will be called once with the dataframe of the base timeframe. This is the final function to be called, which means that the dataframe entering this function will contain all the features and columns from the base asset created by the other `feature_engineering_expand` functions. This function is a good place to do custom exotic feature extractions (e.g. tsfresh). This function is also a good place for any feature that should not be auto-expanded upon (e.g. day of the week). +| `set_freqai_targets()` | Required function to set the targets for the model. All targets must be prepended with `&` to be recognized by the FreqAI internals. Meanwhile, high level feature engineering is handled within `"feature_parameters":{}` in the FreqAI config. Within this file, it is possible to decide large scale feature expansions on top of the `base_features` such as "including correlated pairs" or "including informative timeframes" or even "including recent candles." -It is advisable to start from the template `populate_any_indicators()` in the source provided example strategy (found in `templates/FreqaiExampleStrategy.py`) to ensure that the feature definitions are following the correct conventions. Here is an example of how to set the indicators and labels in the strategy: +It is advisable to start from the template `feature_engineering_*` functions in the source provided example strategy (found in `templates/FreqaiExampleStrategy.py`) to ensure that the feature definitions are following the correct conventions. Here is an example of how to set the indicators and labels in the strategy: ```python - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe, period, metadata, **kwargs): """ - Function designed to automatically generate, name, and merge features - from user-indicated timeframes in the configuration file. The user controls the indicators - passed to the training/prediction by prepending indicators with `'%-' + pair ` - (see convention below). I.e., the user should not prepend any supporting metrics - (e.g., bb_lowerband below) with % unless they explicitly want to pass that metric to the - model. - :param pair: pair to be used as informative - :param df: strategy dataframe which will receive merges from informatives - :param tf: timeframe of the dataframe which will modify the feature names - :param informative: the dataframe associated with the informative pair + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and + `include_corr_pairs`. In other words, a single feature defined in this function + will automatically expand to a total of + `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` * + `include_corr_pairs` numbers of features added to the model. + + All features must be prepended with `%` to be recognized by FreqAI internals. + + Access metadata such as the current pair/timeframe/period with: + + `metadata["pair"]` `metadata["tf"]` `metadata["period"]` + + :param df: strategy dataframe which will receive the features + :param period: period of the indicator - usage example: + :param metadata: metadata of current pair + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) """ - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) + dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period) + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: - t = int(t) - informative[f"%-{pair}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{pair}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{pair}adx-period_{t}"] = ta.ADX(informative, window=t) + bollinger = qtpylib.bollinger_bands( + qtpylib.typical_price(dataframe), window=period, stds=2.2 + ) + dataframe["bb_lowerband-period"] = bollinger["lower"] + dataframe["bb_middleband-period"] = bollinger["mid"] + dataframe["bb_upperband-period"] = bollinger["upper"] - bollinger = qtpylib.bollinger_bands( - qtpylib.typical_price(informative), window=t, stds=2.2 + dataframe["%-bb_width-period"] = ( + dataframe["bb_upperband-period"] + - dataframe["bb_lowerband-period"] + ) / dataframe["bb_middleband-period"] + dataframe["%-close-bb_lower-period"] = ( + dataframe["close"] / dataframe["bb_lowerband-period"] + ) + + dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) + + dataframe["%-relative_volume-period"] = ( + dataframe["volume"] / dataframe["volume"].rolling(period).mean() + ) + + return dataframe + + def feature_engineering_expand_basic(self, dataframe, metadata, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. + In other words, a single feature defined in this function + will automatically expand to a total of + `include_timeframes` * `include_shifted_candles` * `include_corr_pairs` + numbers of features added to the model. + + Features defined here will *not* be automatically duplicated on user defined + `indicator_periods_candles` + + Access metadata such as the current pair/timeframe with: + + `metadata["pair"]` `metadata["tf"]` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + :param metadata: metadata of current pair + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200) + """ + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] + return dataframe + + def feature_engineering_standard(self, dataframe, metadata, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This optional function will be called once with the dataframe of the base timeframe. + This is the final function to be called, which means that the dataframe entering this + function will contain all the features and columns created by all other + freqai_feature_engineering_* functions. + + This function is a good place to do custom exotic feature extractions (e.g. tsfresh). + This function is a good place for any feature that should not be auto-expanded upon + (e.g. day of the week). + + Access metadata such as the current pair with: + + `metadata["pair"]` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + :param metadata: metadata of current pair + usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + """ + dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + dataframe["%-hour_of_day"] = (dataframe["date"].dt.hour + 1) / 25 + return dataframe + + def set_freqai_targets(self, dataframe, metadata, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + Access metadata such as the current pair with: + + `metadata["pair"]` + + :param df: strategy dataframe which will receive the targets + :param metadata: metadata of current pair + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 ) - informative[f"{pair}bb_lowerband-period_{t}"] = bollinger["lower"] - informative[f"{pair}bb_middleband-period_{t}"] = bollinger["mid"] - informative[f"{pair}bb_upperband-period_{t}"] = bollinger["upper"] - - informative[f"%-{pair}bb_width-period_{t}"] = ( - informative[f"{pair}bb_upperband-period_{t}"] - - informative[f"{pair}bb_lowerband-period_{t}"] - ) / informative[f"{pair}bb_middleband-period_{t}"] - informative[f"%-{pair}close-bb_lower-period_{t}"] = ( - informative["close"] / informative[f"{pair}bb_lowerband-period_{t}"] - ) - - informative[f"%-{pair}relative_volume-period_{t}"] = ( - informative["volume"] / informative["volume"].rolling(t).mean() - ) - - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) - - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) - - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 - - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) - - return df + + return dataframe ``` In the presented example, the user does not wish to pass the `bb_lowerband` as a feature to the model, @@ -118,15 +172,28 @@ After having defined the `base features`, the next step is to expand upon them u } ``` -The `include_timeframes` in the config above are the timeframes (`tf`) of each call to `populate_any_indicators()` in the strategy. In the presented case, the user is asking for the `5m`, `15m`, and `4h` timeframes of the `rsi`, `mfi`, `roc`, and `bb_width` to be included in the feature set. +The `include_timeframes` in the config above are the timeframes (`tf`) of each call to `feature_engineering_expand_*()` in the strategy. In the presented case, the user is asking for the `5m`, `15m`, and `4h` timeframes of the `rsi`, `mfi`, `roc`, and `bb_width` to be included in the feature set. -You can ask for each of the defined features to be included also for informative pairs using the `include_corr_pairlist`. This means that the feature set will include all the features from `populate_any_indicators` on all the `include_timeframes` for each of the correlated pairs defined in the config (`ETH/USD`, `LINK/USD`, and `BNB/USD` in the presented example). +You can ask for each of the defined features to be included also for informative pairs using the `include_corr_pairlist`. This means that the feature set will include all the features from `feature_engineering_expand_*()` on all the `include_timeframes` for each of the correlated pairs defined in the config (`ETH/USD`, `LINK/USD`, and `BNB/USD` in the presented example). `include_shifted_candles` indicates the number of previous candles to include in the feature set. For example, `include_shifted_candles: 2` tells FreqAI to include the past 2 candles for each of the features in the feature set. -In total, the number of features the user of the presented example strat has created is: length of `include_timeframes` * no. features in `populate_any_indicators()` * length of `include_corr_pairlist` * no. `include_shifted_candles` * length of `indicator_periods_candles` +In total, the number of features the user of the presented example strat has created is: length of `include_timeframes` * no. features in `feature_engineering_expand_*()` * length of `include_corr_pairlist` * no. `include_shifted_candles` * length of `indicator_periods_candles` $= 3 * 3 * 3 * 2 * 2 = 108$. + + ### Gain finer control over `feature_engineering_*` functions with `metadata` + + All `feature_engineering_*` and `set_freqai_targets()` functions are passed a `metadata` dictionary which contains information about the `pair`, `tf` (timeframe), and `period` that FreqAI is automating for feature building. As such, a user can use `metadata` inside `feature_engineering_*` functions as criteria for blocking/reserving features for certain timeframes, periods, pairs etc. + + ```py +def feature_engineering_expand_all(self, dataframe, period, metadata, **kwargs): + if metadata["tf"] == "1h": + dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) +``` + +This will block `ta.ROC()` from being added to any timeframes other than `"1h"`. + ### Returning additional info from training Important metrics can be returned to the strategy at the end of each model training by assigning them to `dk.data['extra_returns_per_train']['my_new_value'] = XYZ` inside the custom prediction model class. @@ -167,7 +234,7 @@ This will perform PCA on the features and reduce their dimensionality so that th ## Inlier metric -The `inlier_metric` is a metric aimed at quantifying how similar a the features of a data point are to the most recent historic data points. +The `inlier_metric` is a metric aimed at quantifying how similar the features of a data point are to the most recent historical data points. You define the lookback window by setting `inlier_metric_window` and FreqAI computes the distance between the present time point and each of the previous `inlier_metric_window` lookback points. A Weibull function is fit to each of the lookback distributions and its cumulative distribution function (CDF) is used to produce a quantile for each lookback point. The `inlier_metric` is then computed for each time point as the average of the corresponding lookback quantiles. The figure below explains the concept for an `inlier_metric_window` of 5. diff --git a/docs/freqai-parameter-table.md b/docs/freqai-parameter-table.md index 72ee1e6b3..43a066fb8 100644 --- a/docs/freqai-parameter-table.md +++ b/docs/freqai-parameter-table.md @@ -18,7 +18,6 @@ Mandatory parameters are marked as **Required** and have to be set in one of the | `purge_old_models` | Delete all unused models during live runs (not relevant to backtesting). If set to false (not default), dry/live runs will accumulate all unused models to disk. If
**Datatype:** Boolean.
Default: `True`. | `save_backtest_models` | Save models to disk when running backtesting. Backtesting operates most efficiently by saving the prediction data and reusing them directly for subsequent runs (when you wish to tune entry/exit parameters). Saving backtesting models to disk also allows to use the same model files for starting a dry/live instance with the same model `identifier`.
**Datatype:** Boolean.
Default: `False` (no models are saved). | `fit_live_predictions_candles` | Number of historical candles to use for computing target (label) statistics from prediction data, instead of from the training dataset (more information can be found [here](freqai-configuration.md#creating-a-dynamic-target-threshold)).
**Datatype:** Positive integer. -| `follow_mode` | Use a `follower` that will look for models associated with a specific `identifier` and load those for inferencing. A `follower` will **not** train new models.
**Datatype:** Boolean.
Default: `False`. | `continual_learning` | Use the final state of the most recently trained model as starting point for the new model, allowing for incremental learning (more information can be found [here](freqai-running.md#continual-learning)).
**Datatype:** Boolean.
Default: `False`. | `write_metrics_to_disk` | Collect train timings, inference timings and cpu usage in json file.
**Datatype:** Boolean.
Default: `False` | `data_kitchen_thread_count` |
Designate the number of threads you want to use for data processing (outlier methods, normalization, etc.). This has no impact on the number of threads used for training. If user does not set it (default), FreqAI will use max number of threads - 2 (leaving 1 physical core available for Freqtrade bot and FreqUI)
**Datatype:** Positive integer. @@ -29,12 +28,12 @@ Mandatory parameters are marked as **Required** and have to be set in one of the |------------|-------------| | | **Feature parameters within the `freqai.feature_parameters` sub dictionary** | `feature_parameters` | A dictionary containing the parameters used to engineer the feature set. Details and examples are shown [here](freqai-feature-engineering.md).
**Datatype:** Dictionary. -| `include_timeframes` | A list of timeframes that all indicators in `populate_any_indicators` will be created for. The list is added as features to the base indicators dataset.
**Datatype:** List of timeframes (strings). -| `include_corr_pairlist` | A list of correlated coins that FreqAI will add as additional features to all `pair_whitelist` coins. All indicators set in `populate_any_indicators` during feature engineering (see details [here](freqai-feature-engineering.md)) will be created for each correlated coin. The correlated coins features are added to the base indicators dataset.
**Datatype:** List of assets (strings). -| `label_period_candles` | Number of candles into the future that the labels are created for. This is used in `populate_any_indicators` (see `templates/FreqaiExampleStrategy.py` for detailed usage). You can create custom labels and choose whether to make use of this parameter or not.
**Datatype:** Positive integer. +| `include_timeframes` | A list of timeframes that all indicators in `feature_engineering_expand_*()` will be created for. The list is added as features to the base indicators dataset.
**Datatype:** List of timeframes (strings). +| `include_corr_pairlist` | A list of correlated coins that FreqAI will add as additional features to all `pair_whitelist` coins. All indicators set in `feature_engineering_expand_*()` during feature engineering (see details [here](freqai-feature-engineering.md)) will be created for each correlated coin. The correlated coins features are added to the base indicators dataset.
**Datatype:** List of assets (strings). +| `label_period_candles` | Number of candles into the future that the labels are created for. This is used in `feature_engineering_expand_all()` (see `templates/FreqaiExampleStrategy.py` for detailed usage). You can create custom labels and choose whether to make use of this parameter or not.
**Datatype:** Positive integer. | `include_shifted_candles` | Add features from previous candles to subsequent candles with the intent of adding historical information. If used, FreqAI will duplicate and shift all features from the `include_shifted_candles` previous candles so that the information is available for the subsequent candle.
**Datatype:** Positive integer. | `weight_factor` | Weight training data points according to their recency (see details [here](freqai-feature-engineering.md#weighting-features-for-temporal-importance)).
**Datatype:** Positive float (typically < 1). -| `indicator_max_period_candles` | **No longer used (#7325)**. Replaced by `startup_candle_count` which is set in the [strategy](freqai-configuration.md#building-a-freqai-strategy). `startup_candle_count` is timeframe independent and defines the maximum *period* used in `populate_any_indicators()` for indicator creation. FreqAI uses this parameter together with the maximum timeframe in `include_time_frames` to calculate how many data points to download such that the first data point does not include a NaN.
**Datatype:** Positive integer. +| `indicator_max_period_candles` | **No longer used (#7325)**. Replaced by `startup_candle_count` which is set in the [strategy](freqai-configuration.md#building-a-freqai-strategy). `startup_candle_count` is timeframe independent and defines the maximum *period* used in `feature_engineering_*()` for indicator creation. FreqAI uses this parameter together with the maximum timeframe in `include_time_frames` to calculate how many data points to download such that the first data point does not include a NaN.
**Datatype:** Positive integer. | `indicator_periods_candles` | Time periods to calculate indicators for. The indicators are added to the base indicator dataset.
**Datatype:** List of positive integers. | `principal_component_analysis` | Automatically reduce the dimensionality of the data set using Principal Component Analysis. See details about how it works [here](#reducing-data-dimensionality-with-principal-component-analysis)
**Datatype:** Boolean.
Default: `False`. | `plot_feature_importances` | Create a feature importance plot for each model for the top/bottom `plot_feature_importances` number of features. Plot is stored in `user_data/models//sub-train-_.html`.
**Datatype:** Integer.
Default: `0`. diff --git a/docs/freqai-reinforcement-learning.md b/docs/freqai-reinforcement-learning.md index 22772c2ec..7e4110b0b 100644 --- a/docs/freqai-reinforcement-learning.md +++ b/docs/freqai-reinforcement-learning.md @@ -34,65 +34,36 @@ Setting up and running a Reinforcement Learning model is the same as running a R freqtrade trade --freqaimodel ReinforcementLearner --strategy MyRLStrategy --config config.json ``` -where `ReinforcementLearner` will use the templated `ReinforcementLearner` from `freqai/prediction_models/ReinforcementLearner` (or a custom user defined one located in `user_data/freqaimodels`). The strategy, on the other hand, follows the same base [feature engineering](freqai-feature-engineering.md) with `populate_any_indicators` as a typical Regressor: +where `ReinforcementLearner` will use the templated `ReinforcementLearner` from `freqai/prediction_models/ReinforcementLearner` (or a custom user defined one located in `user_data/freqaimodels`). The strategy, on the other hand, follows the same base [feature engineering](freqai-feature-engineering.md) with `feature_engineering_*` as a typical Regressor. The difference lies in the creation of the targets, Reinforcement Learning doesn't require them. However, FreqAI requires a default (neutral) value to be set in the action column: ```python - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def set_freqai_targets(self, dataframe, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + More details about feature engineering available: - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + https://www.freqtrade.io/en/latest/freqai-feature-engineering - t = int(t) - informative[f"%-{pair}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{pair}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{pair}adx-period_{t}"] = ta.ADX(informative, window=t) - - # The following raw price values are necessary for RL models - informative[f"%-{pair}raw_close"] = informative["close"] - informative[f"%-{pair}raw_open"] = informative["open"] - informative[f"%-{pair}raw_high"] = informative["high"] - informative[f"%-{pair}raw_low"] = informative["low"] - - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) - - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) - - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - - # For RL, there are no direct targets to set. This is filler (neutral) - # until the agent sends an action. - df["&-action"] = 0 - - return df + :param df: strategy dataframe which will receive the targets + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + # For RL, there are no direct targets to set. This is filler (neutral) + # until the agent sends an action. + 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: ```python + def feature_engineering_standard(self, dataframe, **kwargs): # The following features are necessary for RL models - informative[f"%-{pair}raw_close"] = informative["close"] - informative[f"%-{pair}raw_open"] = informative["open"] - informative[f"%-{pair}raw_high"] = informative["high"] - informative[f"%-{pair}raw_low"] = informative["low"] + dataframe[f"%-raw_close"] = dataframe["close"] + dataframe[f"%-raw_open"] = dataframe["open"] + dataframe[f"%-raw_high"] = dataframe["high"] + dataframe[f"%-raw_low"] = dataframe["low"] ``` Finally, there is no explicit "label" to make - instead it is necessary to assign the `&-action` column which will contain the agent's actions when accessed in `populate_entry/exit_trends()`. In the present example, the neutral action to 0. This value should align with the environment used. FreqAI provides two environments, both use 0 as the neutral action. @@ -204,10 +175,20 @@ As you begin to modify the strategy and the prediction model, you will quickly r pnl = self.get_unrealized_profit() factor = 100 - # reward agent for entering trades - if action in (Actions.Long_enter.value, Actions.Short_enter.value) \ - and self._position == Positions.Neutral: - return 25 + + # you can use feature values from dataframe + rsi_now = self.raw_features[f"%-rsi-period-10_shift-1_{self.pair}_" + f"{self.config['timeframe']}"].iloc[self._current_tick] + + # reward agent for entering trades + if (action in (Actions.Long_enter.value, Actions.Short_enter.value) + and self._position == Positions.Neutral): + if rsi_now < 40: + factor = 40 / rsi_now + else: + factor = 1 + return 25 * factor + # discourage agent from not entering trades if action == Actions.Neutral.value and self._position == Positions.Neutral: return -1 @@ -272,7 +253,6 @@ FreqAI also provides a built in episodic summary logger called `self.tensorboard !!! Note The `self.tensorboard_log()` function is designed for tracking incremented objects only i.e. events, actions inside the training environment. If the event of interest is a float, the float can be passed as the second argument e.g. `self.tensorboard_log("float_metric1", 0.23)` would add 0.23 to `float_metric`. In this case you can also disable incrementing using `inc=False` parameter. - ### Choosing a base environment FreqAI provides three base environments, `Base3ActionRLEnvironment`, `Base4ActionEnvironment` and `Base5ActionEnvironment`. As the names imply, the environments are customized for agents that can select from 3, 4 or 5 actions. The `Base3ActionEnvironment` is the simplest, the agent can select from hold, long, or short. This environment can also be used for long-only bots (it automatically follows the `can_short` flag from the strategy), where long is the enter condition and short is the exit condition. Meanwhile, in the `Base4ActionEnvironment`, the agent can enter long, enter short, hold neutral, or exit position. Finally, in the `Base5ActionEnvironment`, the agent has the same actions as Base4, but instead of a single exit action, it separates exit long and exit short. The main changes stemming from the environment selection include: diff --git a/docs/freqai-running.md b/docs/freqai-running.md index b046e7bb8..7127d21cc 100644 --- a/docs/freqai-running.md +++ b/docs/freqai-running.md @@ -67,6 +67,10 @@ Backtesting mode requires [downloading the necessary data](#downloading-data-to- *want* to retrain a new model with the same config file, you should simply change the `identifier`. This way, you can return to using any model you wish by simply specifying the `identifier`. +!!! Note + Backtesting calls `set_freqai_targets()` one time for each backtest window (where the number of windows is the full backtest timerange divided by the `backtest_period_days` parameter). Doing this means that the targets simulate dry/live behavior without look ahead bias. However, the definition of the features in `feature_engineering_*()` is performed once on the entire backtest timerange. This means that you should be sure that features do look-ahead into the future. + More details about look-ahead bias can be found in [Common Mistakes](strategy-customization.md#common-mistakes-when-developing-strategies). + --- ### Saving prediction data @@ -135,7 +139,7 @@ freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy FreqaiExampleSt `hyperopt` requires you to have the data pre-downloaded in the same fashion as if you were doing [backtesting](#backtesting). In addition, you must consider some restrictions when trying to hyperopt FreqAI strategies: - The `--analyze-per-epoch` hyperopt parameter is not compatible with FreqAI. -- It's not possible to hyperopt indicators in the `populate_any_indicators()` function. This means that you cannot optimize model parameters using hyperopt. Apart from this exception, it is possible to optimize all other [spaces](hyperopt.md#running-hyperopt-with-smaller-search-space). +- It's not possible to hyperopt indicators in the `feature_engineering_*()` and `set_freqai_targets()` functions. This means that you cannot optimize model parameters using hyperopt. Apart from this exception, it is possible to optimize all other [spaces](hyperopt.md#running-hyperopt-with-smaller-search-space). - The backtesting instructions also apply to hyperopt. The best method for combining hyperopt and FreqAI is to focus on hyperopting entry/exit thresholds/criteria. You need to focus on hyperopting parameters that are not used in your features. For example, you should not try to hyperopt rolling window lengths in the feature creation, or any part of the FreqAI config which changes predictions. In order to efficiently hyperopt the FreqAI strategy, FreqAI stores predictions as dataframes and reuses them. Hence the requirement to hyperopt entry/exit thresholds/criteria only. @@ -161,20 +165,3 @@ tensorboard --logdir user_data/models/unique-id where `unique-id` is the `identifier` set in the `freqai` configuration file. This command must be run in a separate shell if you wish to view the output in your browser at 127.0.0.1:6060 (6060 is the default port used by Tensorboard). ![tensorboard](assets/tensorboard.jpg) - -## Setting up a follower - -You can indicate to the bot that it should not train models, but instead should look for models trained by a leader with a specific `identifier` by defining: - -```json - "freqai": { - "enabled": true, - "follow_mode": true, - "identifier": "example", - "feature_parameters": { - // leader bots feature_parameters inserted here - }, - } -``` - -In this example, the user has a leader bot with the `"identifier": "example"`. The leader bot is already running or is launched simultaneously with the follower. The follower will load models created by the leader and inference them to obtain predictions instead of training its own models. The user will also need to duplicate the `feature_parameters` parameters from from the leaders freqai configuration file into the freqai section of the followers config. diff --git a/docs/hyperopt.md b/docs/hyperopt.md index e72b850ca..19bffd742 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -50,7 +50,7 @@ usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--eps] [--dmmp] [--enable-protections] [--dry-run-wallet DRY_RUN_WALLET] [--timeframe-detail TIMEFRAME_DETAIL] [-e INT] - [--spaces {all,buy,sell,roi,stoploss,trailing,protection,default} [{all,buy,sell,roi,stoploss,trailing,protection,default} ...]] + [--spaces {all,buy,sell,roi,stoploss,trailing,protection,trades,default} [{all,buy,sell,roi,stoploss,trailing,protection,trades,default} ...]] [--print-all] [--no-color] [--print-json] [-j JOBS] [--random-state INT] [--min-trades INT] [--hyperopt-loss NAME] [--disable-param-export] @@ -96,7 +96,7 @@ optional arguments: Specify detail timeframe for backtesting (`1m`, `5m`, `30m`, `1h`, `1d`). -e INT, --epochs INT Specify number of epochs (default: 100). - --spaces {all,buy,sell,roi,stoploss,trailing,protection,default} [{all,buy,sell,roi,stoploss,trailing,protection,default} ...] + --spaces {all,buy,sell,roi,stoploss,trailing,protection,trades,default} [{all,buy,sell,roi,stoploss,trailing,protection,trades,default} ...] Specify which parameters to hyperopt. Space-separated list. --print-all Print all results, not only the best ones. @@ -180,6 +180,7 @@ Rarely you may also need to create a [nested class](advanced-hyperopt.md#overrid * `generate_roi_table` - for custom ROI optimization (if you need the ranges for the values in the ROI table that differ from default or the number of entries (steps) in the ROI table which differs from the default 4 steps) * `stoploss_space` - for custom stoploss optimization (if you need the range for the stoploss parameter in the optimization hyperspace that differs from default) * `trailing_space` - for custom trailing stop optimization (if you need the ranges for the trailing stop parameters in the optimization hyperspace that differ from default) +* `max_open_trades_space` - for custom max_open_trades optimization (if you need the ranges for the max_open_trades parameter in the optimization hyperspace that differ from default) !!! Tip "Quickly optimize ROI, stoploss and trailing stoploss" You can quickly optimize the spaces `roi`, `stoploss` and `trailing` without changing anything in your strategy. @@ -643,6 +644,7 @@ Legal values are: * `roi`: just optimize the minimal profit table for your strategy * `stoploss`: search for the best stoploss value * `trailing`: search for the best trailing stop values +* `trades`: search for the best max open trades values * `protection`: search for the best protection parameters (read the [protections section](#optimizing-protections) on how to properly define these) * `default`: `all` except `trailing` and `protection` * space-separated list of any of the above values for example `--spaces roi stoploss` @@ -916,5 +918,5 @@ Once the optimized strategy has been implemented into your strategy, you should To achieve same the results (number of trades, their durations, profit, etc.) as during Hyperopt, please use the same configuration and parameters (timerange, timeframe, ...) used for hyperopt `--dmmp`/`--disable-max-market-positions` and `--eps`/`--enable-position-stacking` for Backtesting. Should results not match, please double-check to make sure you transferred all conditions correctly. -Pay special care to the stoploss (and trailing stoploss) parameters, as these are often set in configuration files, which override changes to the strategy. -You should also carefully review the log of your backtest to ensure that there were no parameters inadvertently set by the configuration (like `stoploss` or `trailing_stop`). +Pay special care to the stoploss, max_open_trades and trailing stoploss parameters, as these are often set in configuration files, which override changes to the strategy. +You should also carefully review the log of your backtest to ensure that there were no parameters inadvertently set by the configuration (like `stoploss`, `max_open_trades` or `trailing_stop`). diff --git a/docs/index.md b/docs/index.md index 40b9e98ad..c24d1f36b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -52,6 +52,7 @@ Please read the [exchange specific notes](exchanges.md) to learn about eventual, - [X] [Binance](https://www.binance.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) - [X] [OKX](https://okx.com/) +- [X] [Bybit](https://bybit.com/) Please make sure to read the [exchange specific notes](exchanges.md), as well as the [trading with leverage](leverage.md) documentation before diving in. diff --git a/docs/installation.md b/docs/installation.md index 9dd14274a..1c0aed7ba 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -30,6 +30,12 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito !!! Warning "Up-to-date clock" The clock on the system running the bot must be accurate, synchronized to a NTP server frequently enough to avoid problems with communication to the exchanges. +!!! Error "Running setup.py install for gym did not run successfully." + If you get an error related with gym we suggest you to downgrade setuptools it to version 65.5.0 you can do it with the following command: + ```bash + pip install setuptools==65.5.0 + ``` + ------ ## Requirements diff --git a/docs/leverage.md b/docs/leverage.md index 0a265277e..deaa65896 100644 --- a/docs/leverage.md +++ b/docs/leverage.md @@ -67,8 +67,6 @@ You will also have to pick a "margin mode" (explanation below) - with freqtrade Freqtrade follows the [ccxt naming conventions for futures](https://docs.ccxt.com/en/latest/manual.html?#perpetual-swap-perpetual-future). A futures pair will therefore have the naming of `base/quote:settle` (e.g. `ETH/USDT:USDT`). -Binance is currently still an exception to this naming scheme, where pairs are named `ETH/USDT` also for futures markets, but will be aligned as soon as CCXT is ready. - ### Margin mode On top of `trading_mode` - you will also have to configure your `margin_mode`. diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index fd4f66d71..0e3bf898f 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==8.5.11 +mkdocs-material==9.0.11 mdx_truly_sane_lists==1.3 -pymdown-extensions==9.9 +pymdown-extensions==9.9.2 jinja2==3.1.2 diff --git a/docs/rest-api.md b/docs/rest-api.md index 62ad586dd..5f604ef43 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -163,7 +163,7 @@ python3 scripts/rest_client.py --config rest_config.json [optional par | `strategy ` | Get specific Strategy content. **Alpha** | `available_pairs` | List available backtest data. **Alpha** | `version` | Show version. -| `sysinfo` | Show informations about the system load. +| `sysinfo` | Show information about the system load. | `health` | Show bot health (last bot loop). !!! Warning "Alpha status" @@ -192,6 +192,11 @@ blacklist :param add: List of coins to add (example: "BNB/BTC") +cancel_open_order + Cancel open order for trade. + + :param trade_id: Cancels open orders for this trade. + count Return the amount of open trades. @@ -274,7 +279,6 @@ reload_config Reload configuration. show_config - Returns part of the configuration, relevant for trading operations. start @@ -320,6 +324,7 @@ version whitelist Show the current whitelist. + ``` ### Message WebSocket diff --git a/docs/stoploss.md b/docs/stoploss.md index 20e53d8f5..7af717955 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -24,7 +24,7 @@ These modes can be configured with these values: ``` !!! Note - Stoploss on exchange is only supported for Binance (stop-loss-limit), Huobi (stop-limit), Kraken (stop-loss-market, stop-loss-limit), Gateio (stop-limit), and Kucoin (stop-limit and stop-market) as of now. + Stoploss on exchange is only supported for Binance (stop-loss-limit), Huobi (stop-limit), Kraken (stop-loss-market, stop-loss-limit), Gate (stop-limit), and Kucoin (stop-limit and stop-market) as of now. Do not set too low/tight stoploss value if using stop loss on exchange! If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work. @@ -52,6 +52,18 @@ The bot cannot do these every 5 seconds (at each iteration), otherwise it would So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute). This same logic will reapply a stoploss order on the exchange should you cancel it accidentally. +### stoploss_price_type + +!!! Warning "Only applies to futures" + `stoploss_price_type` only applies to futures markets (on exchanges where it's available). + Freqtrade will perform a validation of this setting on startup, failing to start if an invalid setting for your exchange has been selected. + Supported price types are gonna differs between each exchanges. Please check with your exchange on which price types it supports. + +Stoploss on exchange on futures markets can trigger on different price types. +The naming for these prices in exchange terminology often varies, but is usually something around "last" (or "contract price" ), "mark" and "index". + +Acceptable values for this setting are `"last"`, `"mark"` and `"index"` - which freqtrade will transfer automatically to the corresponding API type, and place the [stoploss on exchange](#stoploss_on_exchange-and-stoploss_on_exchange_limit_ratio) order correspondingly. + ### force_exit `force_exit` is an optional value, which defaults to the same value as `exit` and is used when sending a `/forceexit` command from Telegram or from the Rest API. diff --git a/docs/strategy-advanced.md b/docs/strategy-advanced.md index f55cda5e2..cbb71e810 100644 --- a/docs/strategy-advanced.md +++ b/docs/strategy-advanced.md @@ -80,7 +80,7 @@ class AwesomeStrategy(IStrategy): ## Enter Tag When your strategy has multiple buy signals, you can name the signal that triggered. -Then you can access you buy signal on `custom_exit` +Then you can access your buy signal on `custom_exit` ```python def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 19bd26a04..81366c66e 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -659,6 +659,7 @@ Position adjustments will always be applied in the direction of the trade, so a !!! Warning "Backtesting" During backtesting this callback is called for each candle in `timeframe` or `timeframe_detail`, so run-time performance will be affected. + This can also cause deviating results between live and backtesting, since backtesting can adjust the trade only once per candle, whereas live could adjust the trade multiple times per candle. ``` python from freqtrade.persistence import Trade @@ -827,7 +828,7 @@ class AwesomeStrategy(IStrategy): """ # Limit orders to use and follow SMA200 as price target for the first 10 minutes since entry trigger for BTC/USDT pair. - if pair == 'BTC/USDT' and entry_tag == 'long_sma200' and side == 'long' and (current_time - timedelta(minutes=10) > trade.open_date_utc: + if pair == 'BTC/USDT' and entry_tag == 'long_sma200' and side == 'long' and (current_time - timedelta(minutes=10)) > trade.open_date_utc: # just cancel the order if it has been filled more than half of the amount if order.filled > order.remaining: return None diff --git a/docs/strategy_analysis_example.md b/docs/strategy_analysis_example.md index e3d2870e2..06dd33bc2 100644 --- a/docs/strategy_analysis_example.md +++ b/docs/strategy_analysis_example.md @@ -80,6 +80,7 @@ from freqtrade.resolvers import StrategyResolver from freqtrade.data.dataprovider import DataProvider strategy = StrategyResolver.load_strategy(config) strategy.dp = DataProvider(config, None, None) +strategy.ft_bot_start() # Generate buy/sell signals using strategy df = strategy.analyze_ticker(candles, {'pair': pair}) diff --git a/docs/strategy_migration.md b/docs/strategy_migration.md index f93efd067..22e3d2c22 100644 --- a/docs/strategy_migration.md +++ b/docs/strategy_migration.md @@ -477,3 +477,254 @@ after: "ignore_buying_expired_candle_after": 120 } ``` + +## FreqAI strategy + +The `populate_any_indicators()` method has been split into `feature_engineering_expand_all()`, `feature_engineering_expand_basic()`, `feature_engineering_standard()` and`set_freqai_targets()`. + +For each new function, the pair (and timeframe where necessary) will be automatically added to the column. +As such, the definition of features becomes much simpler with the new logic. + +For a full explanation of each method, please go to the corresponding [freqAI documentation page](freqai-feature-engineering.md#defining-the-features) + +``` python linenums="1" hl_lines="12-37 39-42 63-65 67-75" + +def populate_any_indicators( + self, pair, df, tf, informative=None, set_generalized_indicators=False + ): + + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) + + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + + t = int(t) + informative[f"%-{pair}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{pair}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{pair}adx-period_{t}"] = ta.ADX(informative, timeperiod=t) + informative[f"%-{pair}sma-period_{t}"] = ta.SMA(informative, timeperiod=t) + informative[f"%-{pair}ema-period_{t}"] = ta.EMA(informative, timeperiod=t) + + bollinger = qtpylib.bollinger_bands( + qtpylib.typical_price(informative), window=t, stds=2.2 + ) + informative[f"{pair}bb_lowerband-period_{t}"] = bollinger["lower"] + informative[f"{pair}bb_middleband-period_{t}"] = bollinger["mid"] + informative[f"{pair}bb_upperband-period_{t}"] = bollinger["upper"] + + informative[f"%-{pair}bb_width-period_{t}"] = ( + informative[f"{pair}bb_upperband-period_{t}"] + - informative[f"{pair}bb_lowerband-period_{t}"] + ) / informative[f"{pair}bb_middleband-period_{t}"] + informative[f"%-{pair}close-bb_lower-period_{t}"] = ( + informative["close"] / informative[f"{pair}bb_lowerband-period_{t}"] + ) + + informative[f"%-{pair}roc-period_{t}"] = ta.ROC(informative, timeperiod=t) + + informative[f"%-{pair}relative_volume-period_{t}"] = ( + informative["volume"] / informative["volume"].rolling(t).mean() + ) # (1) + + informative[f"%-{pair}pct-change"] = informative["close"].pct_change() + informative[f"%-{pair}raw_volume"] = informative["volume"] + informative[f"%-{pair}raw_price"] = informative["close"] + # (2) + + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pd.concat((informative, informative_shift), axis=1) + + df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + df = df.drop(columns=skip_columns) + + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 + df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + # (3) + + # user adds targets here by prepending them with &- (see convention below) + df["&-s_close"] = ( + df["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / df["close"] + - 1 + ) # (4) + + return df +``` + +1. Features - Move to `feature_engineering_expand_all` +2. Basic features, not expanded across `include_periods_candles` - move to`feature_engineering_expand_basic()`. +3. Standard features which should not be expanded - move to `feature_engineering_standard()`. +4. Targets - Move this part to `set_freqai_targets()`. + +### freqai - feature engineering expand all + +Features will now expand automatically. As such, the expansion loops, as well as the `{pair}` / `{timeframe}` parts will need to be removed. + +``` python linenums="1" + def feature_engineering_expand_all(self, dataframe, period, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and + `include_corr_pairs`. In other words, a single feature defined in this function + will automatically expand to a total of + `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` * + `include_corr_pairs` numbers of features added to the model. + + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details on how these config defined parameters accelerate feature engineering + in the documentation at: + + https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters + + https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features + + :param df: strategy dataframe which will receive the features + :param period: period of the indicator - usage example: + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) + """ + + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) + dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period) + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) + + bollinger = qtpylib.bollinger_bands( + qtpylib.typical_price(dataframe), window=period, stds=2.2 + ) + dataframe["bb_lowerband-period"] = bollinger["lower"] + dataframe["bb_middleband-period"] = bollinger["mid"] + dataframe["bb_upperband-period"] = bollinger["upper"] + + dataframe["%-bb_width-period"] = ( + dataframe["bb_upperband-period"] + - dataframe["bb_lowerband-period"] + ) / dataframe["bb_middleband-period"] + dataframe["%-close-bb_lower-period"] = ( + dataframe["close"] / dataframe["bb_lowerband-period"] + ) + + dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) + + dataframe["%-relative_volume-period"] = ( + dataframe["volume"] / dataframe["volume"].rolling(period).mean() + ) + + return dataframe + +``` + +### Freqai - feature engineering basic + +Basic features. Make sure to remove the `{pair}` part from your features. + +``` python linenums="1" + def feature_engineering_expand_basic(self, dataframe, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. + In other words, a single feature defined in this function + will automatically expand to a total of + `include_timeframes` * `include_shifted_candles` * `include_corr_pairs` + numbers of features added to the model. + + Features defined here will *not* be automatically duplicated on user defined + `indicator_periods_candles` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details on how these config defined parameters accelerate feature engineering + in the documentation at: + + https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters + + https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features + + :param df: strategy dataframe which will receive the features + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200) + """ + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] + return dataframe +``` + +### FreqAI - feature engineering standard + +``` python linenums="1" + def feature_engineering_standard(self, dataframe, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This optional function will be called once with the dataframe of the base timeframe. + This is the final function to be called, which means that the dataframe entering this + function will contain all the features and columns created by all other + freqai_feature_engineering_* functions. + + This function is a good place to do custom exotic feature extractions (e.g. tsfresh). + This function is a good place for any feature that should not be auto-expanded upon + (e.g. day of the week). + + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param df: strategy dataframe which will receive the features + usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + """ + dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek + dataframe["%-hour_of_day"] = dataframe["date"].dt.hour + return dataframe +``` + +### FreqAI - set Targets + +Targets now get their own, dedicated method. + +``` python linenums="1" + def set_freqai_targets(self, dataframe, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param df: strategy dataframe which will receive the targets + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 + ) + + return dataframe +``` diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index db4a309d0..4626944c5 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -162,26 +162,33 @@ official commands. You can ask at any moment for help with `/help`. | Command | Description | |----------|-------------| +| **System commands** | `/start` | Starts the trader | `/stop` | Stops the trader | `/stopbuy | /stopentry` | Stops the trader from opening new trades. Gracefully closes open trades according to their rules. | `/reload_config` | Reloads the configuration file | `/show_config` | Shows part of the current configuration with relevant settings to operation | `/logs [limit]` | Show last log messages. +| `/help` | Show help message +| `/version` | Show version +| **Status** | | `/status` | Lists all open trades | `/status ` | Lists one or more specific trade. Separate multiple with a blank space. | `/status table` | List all open trades in a table format. Pending buy orders are marked with an asterisk (*) Pending sell orders are marked with a double asterisk (**) | `/trades [limit]` | List all recently closed trades in a table format. -| `/delete ` | Delete a specific trade from the Database. Tries to close open orders. Requires manual handling of this trade on the exchange. | `/count` | Displays number of trades used and available | `/locks` | Show currently locked pairs. | `/unlock ` | Remove the lock for this pair (or for this lock id). -| `/profit []` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default) +| **Modify Trade states** | | `/forceexit | /fx ` | Instantly exits the given trade (Ignoring `minimum_roi`). | `/forceexit all | /fx all` | Instantly exits all open trades (Ignoring `minimum_roi`). | `/fx` | alias for `/forceexit` | `/forcelong [rate]` | Instantly buys the given pair. Rate is optional and only applies to limit orders. (`force_entry_enable` must be set to True) | `/forceshort [rate]` | Instantly shorts the given pair. Rate is optional and only applies to limit orders. This will only work on non-spot markets. (`force_entry_enable` must be set to True) +| `/delete ` | Delete a specific trade from the Database. Tries to close open orders. Requires manual handling of this trade on the exchange. +| `/cancel_open_order | /coo ` | Cancel an open order for a trade. +| **Metrics** | +| `/profit []` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default) | `/performance` | Show performance of each finished trade grouped by pair | `/balance` | Show account balance per currency | `/daily ` | Shows profit or loss per day, over the last n days (n defaults to 7) @@ -193,8 +200,7 @@ official commands. You can ask at any moment for help with `/help`. | `/whitelist [sorted] [baseonly]` | Show the current whitelist. Optionally display in alphabetical order and/or with just the base currency of each pairing. | `/blacklist [pair]` | Show the current blacklist, or adds a pair to the blacklist. | `/edge` | Show validated pairs by Edge if it is enabled. -| `/help` | Show help message -| `/version` | Show version + ## Telegram commands in action diff --git a/environment.yml b/environment.yml index 5298b2baa..5b039e7f7 100644 --- a/environment.yml +++ b/environment.yml @@ -12,7 +12,7 @@ dependencies: - py-find-1st - aiohttp - SQLAlchemy - - python-telegram-bot + - python-telegram-bot<20.0.0 - arrow - cachetools - requests diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index 5430cd2d0..db339bea3 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -1,19 +1,20 @@ """ Freqtrade bot """ -__version__ = '2023.1.dev' +__version__ = '2023.2.dev' if 'dev' in __version__: + from pathlib import Path try: import subprocess + freqtrade_basedir = Path(__file__).parent __version__ = __version__ + '-' + subprocess.check_output( ['git', 'log', '--format="%h"', '-n 1'], - stderr=subprocess.DEVNULL).decode("utf-8").rstrip().strip('"') + stderr=subprocess.DEVNULL, cwd=freqtrade_basedir).decode("utf-8").rstrip().strip('"') except Exception: # pragma: no cover # git not available, ignore try: # Try Fallback to freqtrade_commit file (created by CI while building docker image) - from pathlib import Path versionfile = Path('./freqtrade_commit') if versionfile.is_file(): __version__ = f"docker-{__version__}-{versionfile.read_text()[:8]}" diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index f95a08ba5..63bb5c211 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -108,7 +108,7 @@ def ask_user_config() -> Dict[str, Any]: "binance", "binanceus", "bittrex", - "gateio", + "gate", "huobi", "kraken", "kucoin", @@ -123,7 +123,7 @@ def ask_user_config() -> Dict[str, Any]: "message": "Do you want to trade Perpetual Swaps (perpetual futures)?", "default": False, "filter": lambda val: 'futures' if val else 'spot', - "when": lambda x: x["exchange_name"] in ['binance', 'gateio', 'okx'], + "when": lambda x: x["exchange_name"] in ['binance', 'gate', 'okx'], }, { "type": "autocomplete", diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 91ac16365..f1474ec69 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -251,7 +251,8 @@ AVAILABLE_CLI_OPTIONS = { "spaces": Arg( '--spaces', help='Specify which parameters to hyperopt. Space-separated list.', - choices=['all', 'buy', 'sell', 'roi', 'stoploss', 'trailing', 'protection', 'default'], + choices=['all', 'buy', 'sell', 'roi', 'stoploss', + 'trailing', 'protection', 'trades', 'default'], nargs='+', default='default', ), @@ -632,10 +633,11 @@ AVAILABLE_CLI_OPTIONS = { "1: by enter_tag, " "2: by enter_tag and exit_tag, " "3: by pair and enter_tag, " - "4: by pair, enter_ and exit_tag (this can get quite large)"), + "4: by pair, enter_ and exit_tag (this can get quite large), " + "5: by exit_tag"), nargs='+', default=['0', '1', '2'], - choices=['0', '1', '2', '3', '4'], + choices=['0', '1', '2', '3', '4', '5'], ), "enter_reason_list": Arg( "--enter-reason-list", diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index 360387aa6..2cd736b3e 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -14,6 +14,7 @@ from freqtrade.exceptions import OperationalException from freqtrade.exchange import market_is_active, timeframe_to_minutes from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist, expand_pairlist from freqtrade.resolvers import ExchangeResolver +from freqtrade.util.binance_mig import migrate_binance_futures_data logger = logging.getLogger(__name__) @@ -86,6 +87,7 @@ def start_download_data(args: Dict[str, Any]) -> None: "Please use `--dl-trades` instead for this exchange " "(will unfortunately take a long time)." ) + migrate_binance_futures_data(config) pairs_not_available = refresh_backtest_ohlcv_data( exchange, pairs=expanded_pairs, timeframes=config['timeframes'], datadir=config['datadir'], timerange=timerange, @@ -145,6 +147,7 @@ def start_convert_data(args: Dict[str, Any], ohlcv: bool = True) -> None: """ config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) if ohlcv: + migrate_binance_futures_data(config) candle_types = [CandleType.from_string(ct) for ct in config.get('candle_types', ['spot'])] for candle_type in candle_types: convert_ohlcv_format(config, diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 664610f33..862976eb1 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -28,7 +28,7 @@ class Configuration: Reuse this class for the bot, backtesting, hyperopt and every script that required configuration """ - def __init__(self, args: Dict[str, Any], runmode: RunMode = None) -> None: + def __init__(self, args: Dict[str, Any], runmode: Optional[RunMode] = None) -> None: self.args = args self.config: Optional[Config] = None self.runmode = runmode diff --git a/freqtrade/configuration/environment_vars.py b/freqtrade/configuration/environment_vars.py index 473758fe1..d59d4bd23 100644 --- a/freqtrade/configuration/environment_vars.py +++ b/freqtrade/configuration/environment_vars.py @@ -32,7 +32,7 @@ def flat_vars_to_nested_dict(env_dict: Dict[str, Any], prefix: str) -> Dict[str, :param prefix: Prefix to consider (usually FREQTRADE__) :return: Nested dict based on available and relevant variables. """ - no_convert = ['CHAT_ID'] + no_convert = ['CHAT_ID', 'PASSWORD'] relevant_vars: Dict[str, Any] = {} for env_var, val in sorted(env_dict.items()): diff --git a/freqtrade/configuration/load_config.py b/freqtrade/configuration/load_config.py index 6d0321ba0..a1a77815a 100644 --- a/freqtrade/configuration/load_config.py +++ b/freqtrade/configuration/load_config.py @@ -6,7 +6,7 @@ import re import sys from copy import deepcopy from pathlib import Path -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional import rapidjson @@ -75,7 +75,8 @@ def load_config_file(path: str) -> Dict[str, Any]: return config -def load_from_files(files: List[str], base_path: Path = None, level: int = 0) -> Dict[str, Any]: +def load_from_files( + files: List[str], base_path: Optional[Path] = None, level: int = 0) -> Dict[str, Any]: """ Recursively load configuration files if specified. Sub-files are assumed to be relative to the initial config. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 397367216..08048c3e7 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -5,7 +5,7 @@ bot constants """ from typing import Any, Dict, List, Literal, Tuple -from freqtrade.enums import CandleType, RPCMessageType +from freqtrade.enums import CandleType, PriceType, RPCMessageType DEFAULT_CONFIG = 'config.json' @@ -25,6 +25,7 @@ PRICING_SIDES = ['ask', 'bid', 'same', 'other'] ORDERTYPE_POSSIBILITIES = ['limit', 'market'] _ORDERTIF_POSSIBILITIES = ['GTC', 'FOK', 'IOC', 'PO'] ORDERTIF_POSSIBILITIES = _ORDERTIF_POSSIBILITIES + [t.lower() for t in _ORDERTIF_POSSIBILITIES] +STOPLOSS_PRICE_TYPES = [p for p in PriceType] HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss', 'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily', 'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily', @@ -229,6 +230,7 @@ CONF_SCHEMA = { 'default': 'market'}, 'stoploss': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, 'stoploss_on_exchange': {'type': 'boolean'}, + 'stoploss_price_type': {'type': 'string', 'enum': STOPLOSS_PRICE_TYPES}, 'stoploss_on_exchange_interval': {'type': 'number'}, 'stoploss_on_exchange_limit_ratio': {'type': 'number', 'minimum': 0.0, 'maximum': 1.0} @@ -636,7 +638,6 @@ SCHEMA_TRADE_REQUIRED = [ SCHEMA_BACKTEST_REQUIRED = [ 'exchange', - 'max_open_trades', 'stake_currency', 'stake_amount', 'dry_run_wallet', @@ -646,6 +647,7 @@ SCHEMA_BACKTEST_REQUIRED = [ SCHEMA_BACKTEST_REQUIRED_FINAL = SCHEMA_BACKTEST_REQUIRED + [ 'stoploss', 'minimal_roi', + 'max_open_trades' ] SCHEMA_MINIMAL_REQUIRED = [ @@ -681,3 +683,4 @@ MakerTaker = Literal['maker', 'taker'] BidAsk = Literal['bid', 'ask'] Config = Dict[str, Any] +IntOrInf = float diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 3102683b2..c682436c7 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -10,7 +10,7 @@ from typing import Any, Dict, List, Optional, Union import numpy as np import pandas as pd -from freqtrade.constants import LAST_BT_RESULT_FN +from freqtrade.constants import LAST_BT_RESULT_FN, IntOrInf from freqtrade.exceptions import OperationalException from freqtrade.misc import json_load from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename @@ -90,7 +90,8 @@ def get_latest_hyperopt_filename(directory: Union[Path, str]) -> str: return 'hyperopt_results.pickle' -def get_latest_hyperopt_file(directory: Union[Path, str], predef_filename: str = None) -> Path: +def get_latest_hyperopt_file( + directory: Union[Path, str], predef_filename: Optional[str] = None) -> Path: """ Get latest hyperopt export based on '.last_result.json'. :param directory: Directory to search for last result @@ -193,7 +194,7 @@ def get_backtest_resultlist(dirname: Path): def find_existing_backtest_stats(dirname: Union[Path, str], run_ids: Dict[str, str], - min_backtest_date: datetime = None) -> Dict[str, Any]: + min_backtest_date: Optional[datetime] = None) -> Dict[str, Any]: """ Find existing backtest stats that match specified run IDs and load them. :param dirname: pathlib.Path object, or string pointing to the file. @@ -332,7 +333,7 @@ def analyze_trade_parallelism(results: pd.DataFrame, timeframe: str) -> pd.DataF def evaluate_result_multi(results: pd.DataFrame, timeframe: str, - max_open_trades: int) -> pd.DataFrame: + max_open_trades: IntOrInf) -> pd.DataFrame: """ Find overlapping trades by expanding each trade once per period it was open and then counting overlaps diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index df4a4c898..60a058952 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -9,7 +9,7 @@ from collections import deque from datetime import datetime, timezone from typing import Any, Dict, List, Optional, Tuple -from pandas import DataFrame, to_timedelta +from pandas import DataFrame, Timedelta, Timestamp, to_timedelta from freqtrade.configuration import TimeRange from freqtrade.constants import (FULL_DATAFRAME_THRESHOLD, Config, ListPairsWithTimeframes, @@ -206,9 +206,11 @@ class DataProvider: existing_df, _ = self.__producer_pairs_df[producer_name][pair_key] # CHECK FOR MISSING CANDLES - timeframe_delta = to_timedelta(timeframe) # Convert the timeframe to a timedelta for pandas - local_last = existing_df.iloc[-1]['date'] # We want the last date from our copy - incoming_first = dataframe.iloc[0]['date'] # We want the first date from the incoming + # Convert the timeframe to a timedelta for pandas + timeframe_delta: Timedelta = to_timedelta(timeframe) + local_last: Timestamp = existing_df.iloc[-1]['date'] # We want the last date from our copy + # We want the first date from the incoming + incoming_first: Timestamp = dataframe.iloc[0]['date'] # Remove existing candles that are newer than the incoming first candle existing_df1 = existing_df[existing_df['date'] < incoming_first] @@ -221,7 +223,7 @@ class DataProvider: # we missed some candles between our data and the incoming # so return False and candle_difference. if candle_difference > 1: - return (False, candle_difference) + return (False, int(candle_difference)) if existing_df1.empty: appended_df = dataframe else: @@ -281,7 +283,7 @@ class DataProvider: def historic_ohlcv( self, pair: str, - timeframe: str = None, + timeframe: Optional[str] = None, candle_type: str = '' ) -> DataFrame: """ @@ -333,7 +335,7 @@ class DataProvider: def get_pair_dataframe( self, pair: str, - timeframe: str = None, + timeframe: Optional[str] = None, candle_type: str = '' ) -> DataFrame: """ @@ -415,7 +417,7 @@ class DataProvider: def refresh(self, pairlist: ListPairsWithTimeframes, - helping_pairs: ListPairsWithTimeframes = None) -> None: + helping_pairs: Optional[ListPairsWithTimeframes] = None) -> None: """ Refresh data, called with each cycle """ @@ -439,7 +441,7 @@ class DataProvider: def ohlcv( self, pair: str, - timeframe: str = None, + timeframe: Optional[str] = None, copy: bool = True, candle_type: str = '' ) -> DataFrame: diff --git a/freqtrade/data/entryexitanalysis.py b/freqtrade/data/entryexitanalysis.py index baa1cca3a..b2679bcea 100755 --- a/freqtrade/data/entryexitanalysis.py +++ b/freqtrade/data/entryexitanalysis.py @@ -141,6 +141,12 @@ def _do_group_table_output(bigdf, glist): # 4: profit summaries grouped by pair, enter_ and exit_tag (this can get quite large) if g == "4": group_mask = ['pair', 'enter_reason', 'exit_reason'] + + # 5: profit summaries grouped by exit_tag + if g == "5": + group_mask = ['exit_reason'] + sortcols = ['exit_reason'] + if group_mask: new = bigdf.groupby(group_mask).agg(agg_mask).reset_index() new.columns = group_mask + agg_cols diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index 9a206baa4..b567b58bf 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -28,8 +28,8 @@ def load_pair_history(pair: str, fill_up_missing: bool = True, drop_incomplete: bool = False, startup_candles: int = 0, - data_format: str = None, - data_handler: IDataHandler = None, + data_format: Optional[str] = None, + data_handler: Optional[IDataHandler] = None, candle_type: CandleType = CandleType.SPOT ) -> DataFrame: """ @@ -69,7 +69,7 @@ def load_data(datadir: Path, fail_without_data: bool = False, data_format: str = 'json', candle_type: CandleType = CandleType.SPOT, - user_futures_funding_rate: int = None, + user_futures_funding_rate: Optional[int] = None, ) -> Dict[str, DataFrame]: """ Load ohlcv history data for a list of pairs. @@ -116,7 +116,7 @@ def refresh_data(*, datadir: Path, timeframe: str, pairs: List[str], exchange: Exchange, - data_format: str = None, + data_format: Optional[str] = None, timerange: Optional[TimeRange] = None, candle_type: CandleType, ) -> None: @@ -189,7 +189,7 @@ def _download_pair_history(pair: str, *, timeframe: str = '5m', process: str = '', new_pairs_days: int = 30, - data_handler: IDataHandler = None, + data_handler: Optional[IDataHandler] = None, timerange: Optional[TimeRange] = None, candle_type: CandleType, erase: bool = False, @@ -272,7 +272,7 @@ def refresh_backtest_ohlcv_data(exchange: Exchange, pairs: List[str], timeframes datadir: Path, trading_mode: str, timerange: Optional[TimeRange] = None, new_pairs_days: int = 30, erase: bool = False, - data_format: str = None, + data_format: Optional[str] = None, prepend: bool = False, ) -> List[str]: """ diff --git a/freqtrade/data/history/idatahandler.py b/freqtrade/data/history/idatahandler.py index 57441b4be..6637663ff 100644 --- a/freqtrade/data/history/idatahandler.py +++ b/freqtrade/data/history/idatahandler.py @@ -308,7 +308,7 @@ class IDataHandler(ABC): timerange=timerange_startup, candle_type=candle_type ) - if self._check_empty_df(pairdf, pair, timeframe, candle_type, warn_no_data, True): + if self._check_empty_df(pairdf, pair, timeframe, candle_type, warn_no_data): return pairdf else: enddate = pairdf.iloc[-1]['date'] @@ -316,7 +316,7 @@ class IDataHandler(ABC): if timerange_startup: self._validate_pairdata(pair, pairdf, timeframe, candle_type, timerange_startup) pairdf = trim_dataframe(pairdf, timerange_startup) - if self._check_empty_df(pairdf, pair, timeframe, candle_type, warn_no_data): + if self._check_empty_df(pairdf, pair, timeframe, candle_type, warn_no_data, True): return pairdf # incomplete candles should only be dropped if we didn't trim the end beforehand. @@ -374,6 +374,21 @@ class IDataHandler(ABC): logger.warning(f"{pair}, {candle_type}, {timeframe}, " f"data ends at {pairdata.iloc[-1]['date']:%Y-%m-%d %H:%M:%S}") + def rename_futures_data( + self, pair: str, new_pair: str, timeframe: str, candle_type: CandleType): + """ + Temporary method to migrate data from old naming to new naming (BTC/USDT -> BTC/USDT:USDT) + Only used for binance to support the binance futures naming unification. + """ + + file_old = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) + file_new = self._pair_data_filename(self._datadir, new_pair, timeframe, candle_type) + # print(file_old, file_new) + if file_new.exists(): + logger.warning(f"{file_new} exists already, can't migrate {pair}.") + return + file_old.rename(file_new) + def get_datahandlerclass(datatype: str) -> Type[IDataHandler]: """ @@ -403,8 +418,8 @@ def get_datahandlerclass(datatype: str) -> Type[IDataHandler]: raise ValueError(f"No datahandler for datatype {datatype} available.") -def get_datahandler(datadir: Path, data_format: str = None, - data_handler: IDataHandler = None) -> IDataHandler: +def get_datahandler(datadir: Path, data_format: Optional[str] = None, + data_handler: Optional[IDataHandler] = None) -> IDataHandler: """ :param datadir: Folder to save data :param data_format: dataformat to use diff --git a/freqtrade/data/metrics.py b/freqtrade/data/metrics.py index 1d2757f8f..138903b57 100644 --- a/freqtrade/data/metrics.py +++ b/freqtrade/data/metrics.py @@ -197,7 +197,7 @@ def calculate_cagr(days_passed: int, starting_balance: float, final_balance: flo def calculate_expectancy(trades: pd.DataFrame) -> float: """ Calculate expectancy - :param trades: DataFrame containing trades (requires columns close_date and profit_ratio) + :param trades: DataFrame containing trades (requires columns close_date and profit_abs) :return: expectancy """ if len(trades) == 0: diff --git a/freqtrade/enums/__init__.py b/freqtrade/enums/__init__.py index eb70a2894..8ef53e12d 100644 --- a/freqtrade/enums/__init__.py +++ b/freqtrade/enums/__init__.py @@ -6,6 +6,7 @@ from freqtrade.enums.exittype import ExitType from freqtrade.enums.hyperoptstate import HyperoptState from freqtrade.enums.marginmode import MarginMode from freqtrade.enums.ordertypevalue import OrderTypeValues +from freqtrade.enums.pricetype import PriceType from freqtrade.enums.rpcmessagetype import NO_ECHO_MESSAGES, RPCMessageType, RPCRequestType from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode from freqtrade.enums.signaltype import SignalDirection, SignalTagType, SignalType diff --git a/freqtrade/enums/pricetype.py b/freqtrade/enums/pricetype.py new file mode 100644 index 000000000..bf0922b9f --- /dev/null +++ b/freqtrade/enums/pricetype.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class PriceType(str, Enum): + """Enum to distinguish possible trigger prices for stoplosses""" + LAST = "last" + MARK = "mark" + INDEX = "index" diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 973ed499b..b815fb3ee 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -17,7 +17,7 @@ from freqtrade.exchange.exchange_utils import (amount_to_contract_precision, amo timeframe_to_next_date, timeframe_to_prev_date, timeframe_to_seconds, validate_exchange, validate_exchanges) -from freqtrade.exchange.gateio import Gateio +from freqtrade.exchange.gate import Gate from freqtrade.exchange.hitbtc import Hitbtc from freqtrade.exchange.huobi import Huobi from freqtrade.exchange.kraken import Kraken diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 7462e4f81..740d6e8a0 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -7,11 +7,11 @@ from typing import Dict, List, Optional, Tuple import arrow import ccxt -from freqtrade.enums import CandleType, MarginMode, TradingMode +from freqtrade.enums import CandleType, MarginMode, PriceType, TradingMode from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange from freqtrade.exchange.common import retrier -from freqtrade.exchange.types import Tickers +from freqtrade.exchange.types import OHLCVResponse, Tickers from freqtrade.misc import deep_merge_dicts, json_load @@ -28,11 +28,16 @@ class Binance(Exchange): "trades_pagination": "id", "trades_pagination_arg": "fromId", "l2_limit_range": [5, 10, 20, 50, 100, 500, 1000], - "ccxt_futures_name": "future" } _ft_has_futures: Dict = { "stoploss_order_types": {"limit": "stop", "market": "stop_market"}, "tickers_have_price": False, + "floor_leverage": True, + "stop_price_type_field": "workingType", + "stop_price_type_value_mapping": { + PriceType.LAST: "CONTRACT_PRICE", + PriceType.MARK: "MARK_PRICE", + }, } _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ @@ -78,33 +83,9 @@ class Binance(Exchange): raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: raise TemporaryError( - f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e - except ccxt.BaseError as e: - raise OperationalException(e) from e + f'Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}' + ) from e - @retrier - def _set_leverage( - self, - leverage: float, - pair: Optional[str] = None, - trading_mode: Optional[TradingMode] = None - ): - """ - Set's the leverage before making a trade, in order to not - have the same leverage on every trade - """ - trading_mode = trading_mode or self.trading_mode - - if self._config['dry_run'] or trading_mode != TradingMode.FUTURES: - return - - try: - self._api.set_leverage(symbol=pair, leverage=round(leverage)) - except ccxt.DDoSProtection as e: - raise DDosProtection(e) from e - except (ccxt.NetworkError, ccxt.ExchangeError) as e: - raise TemporaryError( - f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e except ccxt.BaseError as e: raise OperationalException(e) from e @@ -112,7 +93,7 @@ class Binance(Exchange): since_ms: int, candle_type: CandleType, is_new_pair: bool = False, raise_: bool = False, until_ms: Optional[int] = None - ) -> Tuple[str, str, str, List]: + ) -> OHLCVResponse: """ Overwrite to introduce "fast new pair" functionality by detecting the pair's listing date Does not work for other exchanges, which don't return the earliest data when called with "0" @@ -150,6 +131,7 @@ class Binance(Exchange): is_short: bool, amount: float, stake_amount: float, + leverage: float, wallet_balance: float, # Or margin balance mm_ex_1: float = 0.0, # (Binance) Cross only upnl_ex_1: float = 0.0, # (Binance) Cross only @@ -159,11 +141,12 @@ class Binance(Exchange): MARGIN: https://www.binance.com/en/support/faq/f6b010588e55413aa58b7d63ee0125ed PERPETUAL: https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93 - :param exchange_name: + :param pair: Pair to calculate liquidation price for :param open_rate: Entry price of position :param is_short: True if the trade is a short, false otherwise :param amount: Absolute value of position size incl. leverage (in base currency) :param stake_amount: Stake amount - Collateral in settle currency. + :param leverage: Leverage used for this position. :param trading_mode: SPOT, MARGIN, FUTURES, etc. :param margin_mode: Either ISOLATED or CROSS :param wallet_balance: Amount of margin_mode in the wallet being used to trade diff --git a/freqtrade/exchange/binance_leverage_tiers.json b/freqtrade/exchange/binance_leverage_tiers.json index 09bf0a4dc..908088cda 100644 --- a/freqtrade/exchange/binance_leverage_tiers.json +++ b/freqtrade/exchange/binance_leverage_tiers.json @@ -1,97 +1,113 @@ { - "1000LUNC/BUSD": [ + "1000LUNC/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "1000LUNC/USDT": [ + "1000LUNC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -104,10 +120,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -120,10 +136,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -179,89 +195,105 @@ } } ], - "1000SHIB/BUSD": [ + "1000SHIB/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "1000SHIB/USDT": [ + "1000SHIB/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -375,20 +407,20 @@ } } ], - "1000XEC/USDT": [ + "1000XEC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -405,7 +437,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -421,7 +453,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -437,7 +469,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -453,7 +485,7 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { @@ -469,11 +501,11 @@ "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "1INCH/USDT": [ + "1INCH/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -571,17 +603,17 @@ } } ], - "AAVE/USDT": [ + "AAVE/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -594,10 +626,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -610,10 +642,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -669,7 +701,7 @@ } } ], - "ADA/BUSD": [ + "ADA/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", @@ -767,7 +799,7 @@ } } ], - "ADA/USDT": [ + "ADA/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -913,105 +945,7 @@ } } ], - "ALGO/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ALICE/USDT": [ + "ALGO/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -1109,20 +1043,118 @@ } } ], - "ALPHA/USDT": [ + "ALICE/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", + "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "ALPHA/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 21.0, + "info": { + "bracket": "1", + "initialLeverage": "21", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -1139,7 +1171,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -1155,7 +1187,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -1171,7 +1203,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -1187,191 +1219,223 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "AMB/BUSD": [ + "AMB/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 8.0, "info": { "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", + "initialLeverage": "8", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 7.0, "info": { "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "initialLeverage": "7", + "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": 6.0, + "info": { + "bracket": "3", + "initialLeverage": "6", + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "1500000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "ANC/BUSD": [ + "ANC/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 8.0, "info": { "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", + "initialLeverage": "8", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 7.0, "info": { "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "initialLeverage": "7", + "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": 6.0, + "info": { + "bracket": "3", + "initialLeverage": "6", + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "1500000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "ANKR/USDT": [ + "ANKR/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -1469,20 +1533,20 @@ } } ], - "ANT/USDT": [ + "ANT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -1499,7 +1563,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -1515,7 +1579,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -1531,7 +1595,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -1547,13 +1611,111 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "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" + } + } + ], + "APE/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, @@ -1563,93 +1725,11 @@ "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "APE/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 8000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "8000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "APE/USDT": [ + "APE/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -1763,20 +1843,20 @@ } } ], - "API3/USDT": [ + "API3/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -1793,7 +1873,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -1809,7 +1889,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -1825,7 +1905,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -1841,13 +1921,111 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "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" + } + } + ], + "APT/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, @@ -1857,93 +2035,11 @@ "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "APT/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "APT/USDT": [ + "APT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -2057,105 +2153,7 @@ } } ], - "AR/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 8000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "8000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ARPA/USDT": [ + "AR/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -2253,7 +2251,203 @@ } } ], - "ATA/USDT": [ + "ARPA/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "ATA/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "ATOM/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -2351,58 +2545,58 @@ } } ], - "ATOM/USDT": [ + "AUCTION/BUSD:BUSD": [ { "tier": 1.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 8.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "8", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 7.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "7", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { "tier": 3.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "6", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { "tier": 4.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 100000.0, "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, @@ -2413,12 +2607,12 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { "tier": 5.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, @@ -2429,122 +2623,40 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, - "currency": "USDT", + "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "1500000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "AUCTION/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "AUDIO/USDT": [ + "AUDIO/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -2561,7 +2673,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -2577,7 +2689,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -2593,7 +2705,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -2609,13 +2721,111 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "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" + } + } + ], + "AVAX/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, @@ -2625,93 +2835,11 @@ "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "AVAX/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "AVAX/USDT": [ + "AVAX/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -2825,7 +2953,7 @@ } } ], - "AXS/USDT": [ + "AXS/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -2955,20 +3083,20 @@ } } ], - "BAKE/USDT": [ + "BAKE/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -2985,7 +3113,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -3001,7 +3129,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -3017,7 +3145,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -3033,27 +3161,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "BAL/USDT": [ + "BAL/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -3151,89 +3279,105 @@ } } ], - "BAND/USDT": [ + "BAND/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "25.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": "650.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", "minNotional": 100000.0, "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { - "bracket": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "USDT", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "BAT/USDT": [ + "BAT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -3331,7 +3475,7 @@ } } ], - "BCH/USDT": [ + "BCH/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -3477,20 +3621,20 @@ } } ], - "BEL/USDT": [ + "BEL/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -3507,7 +3651,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -3523,7 +3667,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -3539,7 +3683,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -3555,27 +3699,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 8000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "8000000", + "notionalCap": "2000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "BLUEBIRD/USDT": [ + "BLUEBIRD/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -3673,20 +3817,20 @@ } } ], - "BLZ/USDT": [ + "BLZ/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -3703,7 +3847,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -3719,7 +3863,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -3735,7 +3879,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -3751,27 +3895,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "2000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "BNB/BUSD": [ + "BNB/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", @@ -3869,7 +4013,7 @@ } } ], - "BNB/USDT": [ + "BNB/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -4015,121 +4159,105 @@ } } ], - "BNX/USDT": [ + "BNX/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 8.0, "info": { "bracket": "1", - "initialLeverage": "25", - "notionalCap": "50000", + "initialLeverage": "8", + "notionalCap": "25000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.025", "cum": "0.0" } }, { "tier": 2.0, "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "minNotional": 25000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 6.0, "info": { "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "750.0" + "initialLeverage": "6", + "notionalCap": "250000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.05", - "cum": "4500.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", "minNotional": 250000.0, "maxNotional": 500000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { - "bracket": "4", + "bracket": "3", "initialLeverage": "5", "notionalCap": "500000", "notionalFloor": "250000", "maintMarginRatio": "0.1", - "cum": "17000.0" + "cum": "13125.0" } }, { - "tier": 5.0, + "tier": 4.0, "currency": "USDT", "minNotional": 500000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { - "bracket": "5", + "bracket": "4", "initialLeverage": "4", "notionalCap": "1000000", "notionalFloor": "500000", "maintMarginRatio": "0.125", - "cum": "29500.0" + "cum": "25625.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.25", + "cum": "150625.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, + "minNotional": 1500000.0, "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, - "info": { - "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "154500.0" - } - }, - { - "tier": 7.0, - "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "7", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "8000000", - "notionalFloor": "2000000", + "notionalCap": "2000000", + "notionalFloor": "1500000", "maintMarginRatio": "0.5", - "cum": "654500.0" + "cum": "525625.0" } } ], - "BTC/BUSD": [ + "BTC/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", @@ -4291,7 +4419,7 @@ } } ], - "BTC/USDT": [ + "BTC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -4453,203 +4581,7 @@ } } ], - "BTCDOM/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": 3000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BTCSTUSDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 9.223372036854776e+18, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "9223372036854775807", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "BTCUSDT_221230": [ + "BTC/USDT:USDT-230331": [ { "tier": 1.0, "currency": "USDT", @@ -4763,7 +4695,203 @@ } } ], - "BTS/USDT": [ + "BTCDOM/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": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BTCST/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": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 9.223372036854776e+18, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "9223372036854775807", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "BTS/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -4861,118 +4989,20 @@ } } ], - "C98/USDT": [ + "C98/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": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "CELO/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -4989,7 +5019,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -5005,7 +5035,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -5021,7 +5051,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -5037,40 +5067,236 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "CELR/USDT": [ + "CELO/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", + "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "CELR/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "CHR/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 21.0, + "info": { + "bracket": "1", + "initialLeverage": "21", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -5087,7 +5313,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -5103,7 +5329,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -5119,7 +5345,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -5135,125 +5361,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "CHR/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "CHZ/USDT": [ + "CHZ/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -5351,7 +5479,7 @@ } } ], - "COMP/USDT": [ + "COMP/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -5449,20 +5577,20 @@ } } ], - "COTI/USDT": [ + "COTI/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 21.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "21", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -5479,7 +5607,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -5495,7 +5623,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -5511,7 +5639,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -5527,27 +5655,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "CRV/USDT": [ + "CRV/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -5661,118 +5789,20 @@ } } ], - "CTK/USDT": [ + "CTK/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": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "CTSI/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -5789,7 +5819,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -5805,7 +5835,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -5821,7 +5851,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -5837,7 +5867,7 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { @@ -5853,24 +5883,24 @@ "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "CVC/USDT": [ + "CTSI/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -5887,7 +5917,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -5903,7 +5933,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -5919,7 +5949,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -5935,7 +5965,367 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "CVC/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 10.0, + "info": { + "bracket": "1", + "initialLeverage": "10", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 8.0, + "info": { + "bracket": "2", + "initialLeverage": "8", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "CVX/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" + } + } + ], + "CVX/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.025", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "625.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "3", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5625.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "4", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11875.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386875.0" + } + } + ], + "DAR/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 10.0, + "info": { + "bracket": "1", + "initialLeverage": "10", + "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": 8.0, + "info": { + "bracket": "2", + "initialLeverage": "8", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 6.0, + "info": { + "bracket": "3", + "initialLeverage": "6", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "650.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": "5650.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": "11900.0" } }, { @@ -5951,273 +6341,11 @@ "notionalCap": "2000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "CVX/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "CVX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "DAR/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": 3000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "DASH/USDT": [ + "DASH/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -6315,7 +6443,7 @@ } } ], - "DEFI/USDT": [ + "DEFI/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -6413,20 +6541,20 @@ } } ], - "DENT/USDT": [ + "DENT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -6436,14 +6564,14 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 8.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "8", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -6452,14 +6580,14 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "6", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -6475,7 +6603,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -6491,7 +6619,7 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { @@ -6507,24 +6635,24 @@ "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "DGB/USDT": [ + "DGB/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -6541,7 +6669,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -6557,7 +6685,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -6573,7 +6701,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -6589,7 +6717,7 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { @@ -6605,93 +6733,109 @@ "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "DODO/BUSD": [ + "DODO/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "DOGE/BUSD": [ + "DOGE/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", @@ -6789,7 +6933,7 @@ } } ], - "DOGE/USDT": [ + "DOGE/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -6903,89 +7047,105 @@ } } ], - "DOT/BUSD": [ + "DOT/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 30000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "30000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "DOT/USDT": [ + "DOT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -7131,20 +7291,20 @@ } } ], - "DUSK/USDT": [ + "DUSK/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -7161,7 +7321,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -7177,7 +7337,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -7193,7 +7353,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -7209,7 +7369,7 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { @@ -7225,24 +7385,24 @@ "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "DYDX/USDT": [ + "DYDX/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "50000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -7252,14 +7412,14 @@ "minNotional": 50000.0, "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "150000", "notionalFloor": "50000", "maintMarginRatio": "0.025", - "cum": "750.0" + "cum": "250.0" } }, { @@ -7268,14 +7428,14 @@ "minNotional": 150000.0, "maxNotional": 250000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "250000", "notionalFloor": "150000", "maintMarginRatio": "0.05", - "cum": "4500.0" + "cum": "4000.0" } }, { @@ -7291,7 +7451,7 @@ "notionalCap": "500000", "notionalFloor": "250000", "maintMarginRatio": "0.1", - "cum": "17000.0" + "cum": "16500.0" } }, { @@ -7307,7 +7467,7 @@ "notionalCap": "1000000", "notionalFloor": "500000", "maintMarginRatio": "0.125", - "cum": "29500.0" + "cum": "29000.0" } }, { @@ -7323,27 +7483,27 @@ "notionalCap": "4000000", "notionalFloor": "1000000", "maintMarginRatio": "0.25", - "cum": "154500.0" + "cum": "154000.0" } }, { "tier": 7.0, "currency": "USDT", "minNotional": 4000000.0, - "maxNotional": 8000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "8000000", + "notionalCap": "5000000", "notionalFloor": "4000000", "maintMarginRatio": "0.5", - "cum": "1154500.0" + "cum": "1154000.0" } } ], - "EGLD/USDT": [ + "EGLD/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -7441,7 +7601,7 @@ } } ], - "ENJ/USDT": [ + "ENJ/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -7555,17 +7715,17 @@ } } ], - "ENS/USDT": [ + "ENS/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -7578,10 +7738,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -7594,10 +7754,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -7653,7 +7813,7 @@ } } ], - "EOS/USDT": [ + "EOS/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -7799,89 +7959,105 @@ } } ], - "ETC/BUSD": [ + "ETC/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "ETC/USDT": [ + "ETC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -8027,7 +8203,7 @@ } } ], - "ETH/BUSD": [ + "ETH/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", @@ -8189,7 +8365,7 @@ } } ], - "ETH/USDT": [ + "ETH/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -8351,7 +8527,7 @@ } } ], - "ETHUSDT_221230": [ + "ETH/USDT:USDT-230331": [ { "tier": 1.0, "currency": "USDT", @@ -8465,89 +8641,105 @@ } } ], - "FIL/BUSD": [ + "FIL/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "FIL/USDT": [ + "FIL/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -8677,20 +8869,20 @@ } } ], - "FLM/USDT": [ + "FLM/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -8707,7 +8899,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -8723,7 +8915,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -8739,7 +8931,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -8755,27 +8947,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 10000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "10000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "FLOW/USDT": [ + "FLOW/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -8873,20 +9065,20 @@ } } ], - "FOOTBALL/USDT": [ + "FOOTBALL/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -8903,7 +9095,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -8919,7 +9111,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -8935,7 +9127,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -8951,7 +9143,7 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { @@ -8967,93 +9159,109 @@ "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "FTM/BUSD": [ + "FTM/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "FTM/USDT": [ + "FTM/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -9167,7 +9375,7 @@ } } ], - "FTT/BUSD": [ + "FTT/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", @@ -9265,7 +9473,7 @@ } } ], - "FTT/USDT": [ + "FTT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -9347,99 +9555,311 @@ } } ], - "GAL/BUSD": [ + "GAL/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "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" + } + } + ], + "GAL/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "GALA/BUSD:BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 11.0, + "info": { + "bracket": "1", + "initialLeverage": "11", + "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": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "GAL/USDT": [ + "GALA/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 20.0, + "maxLeverage": 11.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "11", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -9510,186 +9930,6 @@ "cum": "11950.0" } }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "GALA/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "GALA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, { "tier": 6.0, "currency": "USDT", @@ -9707,89 +9947,105 @@ } } ], - "GMT/BUSD": [ + "GMT/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 8000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "8000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "GMT/USDT": [ + "GMT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -9903,7 +10159,7 @@ } } ], - "GRT/USDT": [ + "GRT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -10001,20 +10257,20 @@ } } ], - "GTC/USDT": [ + "GTC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -10031,7 +10287,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -10047,7 +10303,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -10063,7 +10319,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -10079,579 +10335,7 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "HBAR/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "HNT/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" - } - } - ], - "HOT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ICP/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "ICP/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "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": 30000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "ICX/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" + "cum": "11900.0" } }, { @@ -10667,11 +10351,599 @@ "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", + "cum": "386900.0" + } + } + ], + "HBAR/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": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", "cum": "386950.0" } } ], - "IMX/USDT": [ + "HNT/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 11.0, + "info": { + "bracket": "1", + "initialLeverage": "11", + "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": 10.0, + "info": { + "bracket": "2", + "initialLeverage": "10", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "HOT/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": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "650.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": "5650.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": "11900.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": "386900.0" + } + } + ], + "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, + "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": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "ICX/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "IMX/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -10769,7 +11041,203 @@ } } ], - "INJ/USDT": [ + "INJ/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "IOST/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "IOTA/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -10867,203 +11335,7 @@ } } ], - "IOST/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "IOTA/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "IOTX/USDT": [ + "IOTX/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -11161,20 +11433,20 @@ } } ], - "JASMY/USDT": [ + "JASMY/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -11184,14 +11456,14 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -11200,14 +11472,14 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -11223,7 +11495,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -11239,27 +11511,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "KAVA/USDT": [ + "KAVA/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -11357,7 +11629,7 @@ } } ], - "KLAY/USDT": [ + "KLAY/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -11439,7 +11711,7 @@ } } ], - "KNC/USDT": [ + "KNC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -11537,7 +11809,7 @@ } } ], - "KSM/USDT": [ + "KSM/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -11635,99 +11907,115 @@ } } ], - "LDO/BUSD": [ + "LDO/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 11.0, "info": { "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", + "initialLeverage": "11", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "LDO/USDT": [ + "LDO/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 20.0, + "maxLeverage": 11.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "11", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -11815,102 +12103,118 @@ } } ], - "LEVER/BUSD": [ + "LEVER/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.023, + "maxLeverage": 8.0, "info": { "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", + "initialLeverage": "8", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.023", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 7.0, "info": { "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "initialLeverage": "7", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "10.0" } }, { "tier": 3.0, "currency": "BUSD", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 6.0, + "info": { + "bracket": "3", + "initialLeverage": "6", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "635.0" + } + }, + { + "tier": 4.0, + "currency": "BUSD", "minNotional": 100000.0, "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { - "bracket": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5635.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11885.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "2000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386885.0" } } ], - "LINA/USDT": [ + "LINA/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -11927,7 +12231,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -11943,7 +12247,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -11959,7 +12263,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -11975,13 +12279,111 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "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" + } + } + ], + "LINK/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, @@ -11991,93 +12393,11 @@ "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "LINK/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "LINK/USDT": [ + "LINK/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -12223,7 +12543,7 @@ } } ], - "LIT/USDT": [ + "LIT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -12305,7 +12625,7 @@ } } ], - "LPT/USDT": [ + "LPT/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -12403,17 +12723,17 @@ } } ], - "LRC/USDT": [ + "LRC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -12426,10 +12746,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -12442,10 +12762,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -12501,89 +12821,105 @@ } } ], - "LTC/BUSD": [ + "LTC/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "LTC/USDT": [ + "LTC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -12729,99 +13065,115 @@ } } ], - "LUNA2/BUSD": [ + "LUNA2/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, - "maxNotional": 8000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", - "notionalCap": "8000000", + "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "LUNA2/USDT": [ + "LUNA2/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.015, - "maxLeverage": 25.0, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.015", @@ -12834,10 +13186,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -12850,10 +13202,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -12909,7 +13261,7 @@ } } ], - "MANA/USDT": [ + "MANA/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13023,7 +13375,7 @@ } } ], - "MASK/USDT": [ + "MASK/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13105,89 +13457,105 @@ } } ], - "MATIC/BUSD": [ + "MATIC/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "MATIC/USDT": [ + "MATIC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13301,7 +13669,7 @@ } } ], - "MKR/USDT": [ + "MKR/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13399,20 +13767,20 @@ } } ], - "MTL/USDT": [ + "MTL/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -13422,14 +13790,14 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -13438,14 +13806,14 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -13461,7 +13829,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -13477,13 +13845,111 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "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" + } + } + ], + "NEAR/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, @@ -13493,93 +13959,11 @@ "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "NEAR/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "NEAR/USDT": [ + "NEAR/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13693,7 +14077,7 @@ } } ], - "NEO/USDT": [ + "NEO/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -13791,20 +14175,20 @@ } } ], - "NKN/USDT": [ + "NKN/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -13821,7 +14205,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -13837,7 +14221,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -13853,7 +14237,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -13869,301 +14253,7 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "OCEAN/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "OGN/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" - } - } - ], - "OMG/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" + "cum": "11900.0" } }, { @@ -14179,1165 +14269,21 @@ "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "ONE/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" - } - } - ], - "ONT/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "OP/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 8000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "8000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "PEOPLE/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "PHB/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "QNT/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" - } - } - ], - "QTUM/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "RAY/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "REEF/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "REN/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": 1500000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "1500000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "RLC/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "ROSE/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" - } - } - ], - "RSR/USDT": [ + "OCEAN/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maxLeverage": 21.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "21", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -15412,33 +14358,33 @@ "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", "cum": "386900.0" } } ], - "RUNE/USDT": [ + "OGN/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -15448,14 +14394,14 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -15464,14 +14410,14 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -15487,7 +14433,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -15503,27 +14449,125 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "RVN/USDT": [ + "OMG/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "ONE/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -15621,26 +14665,908 @@ } } ], - "SAND/BUSD": [ + "ONT/USDT:USDT": [ { "tier": 1.0, - "currency": "BUSD", + "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": "1", + "bracket": "2", "initialLeverage": "20", "notionalCap": "25000", - "notionalFloor": "0", + "notionalFloor": "5000", "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "OP/USDT: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": 8000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "8000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "PEOPLE/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "PHB/BUSD:BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 11.0, + "info": { + "bracket": "1", + "initialLeverage": "11", + "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" + } + } + ], + "QNT/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" + } + } + ], + "QTUM/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": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "RAY/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "1", + "initialLeverage": "25", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "2", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "75.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "REEF/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "REN/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 10.0, + "info": { + "bracket": "1", + "initialLeverage": "10", + "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": 8.0, + "info": { + "bracket": "2", + "initialLeverage": "8", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 6.0, + "info": { + "bracket": "3", + "initialLeverage": "6", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "1500000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386900.0" + } + } + ], + "RLC/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.03, + "maxLeverage": 20.0, + "info": { + "bracket": "1", + "initialLeverage": "20", + "notionalCap": "25000", + "notionalFloor": "0", + "maintMarginRatio": "0.03", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDT", "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, @@ -15651,12 +15577,12 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "625.0" + "cum": "500.0" } }, { "tier": 3.0, - "currency": "BUSD", + "currency": "USDT", "minNotional": 100000.0, "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, @@ -15667,12 +15593,12 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5500.0" } }, { "tier": 4.0, - "currency": "BUSD", + "currency": "USDT", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, @@ -15683,27 +15609,517 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11750.0" } }, { "tier": 5.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "5", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386750.0" + } + } + ], + "ROSE/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" + } + } + ], + "RSR/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.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": "386900.0" + } + } + ], + "RUNE/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": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "3", + "initialLeverage": "10", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "700.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 250000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "4", + "initialLeverage": "5", + "notionalCap": "250000", + "notionalFloor": "100000", + "maintMarginRatio": "0.1", + "cum": "5700.0" + } + }, + { + "tier": 5.0, + "currency": "USDT", + "minNotional": 250000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 2.0, + "info": { + "bracket": "5", + "initialLeverage": "2", + "notionalCap": "1000000", + "notionalFloor": "250000", + "maintMarginRatio": "0.125", + "cum": "11950.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "6", + "initialLeverage": "1", + "notionalCap": "5000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.5", + "cum": "386950.0" + } + } + ], + "RVN/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" + } + } + ], + "SAND/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": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "SAND/USDT": [ + "SAND/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -15817,7 +16233,7 @@ } } ], - "SC/USDT": [ + "SC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -15915,99 +16331,213 @@ } } ], - "SFP/USDT": [ + "SFP/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, - "maxNotional": 15000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 8.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "8", - "notionalCap": "15000", + "initialLeverage": "20", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "USDT", - "minNotional": 15000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 7.0, + "minNotional": 5000.0, + "maxNotional": 15000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "7", - "notionalCap": "100000", - "notionalFloor": "15000", - "maintMarginRatio": "0.05", - "cum": "375.0" + "initialLeverage": "10", + "notionalCap": "15000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "25.0" } }, { "tier": 3.0, "currency": "USDT", + "minNotional": 15000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 8.0, + "info": { + "bracket": "3", + "initialLeverage": "8", + "notionalCap": "100000", + "notionalFloor": "15000", + "maintMarginRatio": "0.05", + "cum": "400.0" + } + }, + { + "tier": 4.0, + "currency": "USDT", "minNotional": 100000.0, "maxNotional": 250000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { - "bracket": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5375.0" + "cum": "5400.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "USDT", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11625.0" + "cum": "11650.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386625.0" + "cum": "386650.0" } } ], - "SKL/USDT": [ + "SKL/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "SNX/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -16020,10 +16550,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -16036,10 +16566,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -16095,115 +16625,17 @@ } } ], - "SNX/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "SOL/BUSD": [ + "SOL/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 11.0, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "11", + "initialLeverage": "20", "notionalCap": "100000", "notionalFloor": "0", "maintMarginRatio": "0.025", @@ -16291,17 +16723,17 @@ } } ], - "SOL/USDT": [ + "SOL/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 150000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 12.0, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "12", + "initialLeverage": "20", "notionalCap": "150000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -16314,10 +16746,10 @@ "minNotional": 150000.0, "maxNotional": 250000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 11.0, + "maxLeverage": 15.0, "info": { "bracket": "2", - "initialLeverage": "11", + "initialLeverage": "15", "notionalCap": "250000", "notionalFloor": "150000", "maintMarginRatio": "0.025", @@ -16405,20 +16837,20 @@ } } ], - "SPELL/USDT": [ + "SPELL/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -16435,7 +16867,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -16451,7 +16883,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -16467,7 +16899,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -16483,27 +16915,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "SRM/USDT": [ + "SRM/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -16585,20 +17017,20 @@ } } ], - "STG/USDT": [ + "STG/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -16615,7 +17047,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -16631,7 +17063,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -16647,7 +17079,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -16663,105 +17095,7 @@ "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" - } - } - ], - "STMX/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" + "cum": "11900.0" } }, { @@ -16777,11 +17111,109 @@ "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "STORJ/USDT": [ + "STMX/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "STORJ/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -16879,7 +17311,105 @@ } } ], - "SUSHI/USDT": [ + "SUSHI/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" + } + } + ], + "SXP/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -16977,105 +17507,7 @@ } } ], - "SXP/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "THETA/USDT": [ + "THETA/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -17205,89 +17637,105 @@ } } ], - "TLM/BUSD": [ + "TLM/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", - "notionalCap": "25000", + "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "0.0" } }, { "tier": 2.0, "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, + "minNotional": 5000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.025, "maxLeverage": 10.0, "info": { "bracket": "2", "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" + "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": "3", + "bracket": "4", "initialLeverage": "5", "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5625.0" + "cum": "5650.0" } }, { - "tier": 4.0, + "tier": 5.0, "currency": "BUSD", "minNotional": 250000.0, "maxNotional": 1000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 2.0, "info": { - "bracket": "4", + "bracket": "5", "initialLeverage": "2", "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11875.0" + "cum": "11900.0" } }, { - "tier": 5.0, + "tier": 6.0, "currency": "BUSD", "minNotional": 1000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "5", + "bracket": "6", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386875.0" + "cum": "386900.0" } } ], - "TLM/USDT": [ + "TLM/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -17385,20 +17833,20 @@ } } ], - "TOMO/USDT": [ + "TOMO/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -17415,7 +17863,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -17431,7 +17879,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -17447,7 +17895,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -17463,40 +17911,40 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "TRB/USDT": [ + "TRB/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -17513,7 +17961,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -17529,7 +17977,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -17545,7 +17993,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -17561,13 +18009,111 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "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" + } + } + ], + "TRX/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, @@ -17577,103 +18123,21 @@ "notionalCap": "5000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "TRX/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "TRX/USDT": [ + "TRX/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 10000.0, "maintenanceMarginRate": 0.0065, - "maxLeverage": 50.0, + "maxLeverage": 30.0, "info": { "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "30", "notionalCap": "10000", "notionalFloor": "0", "maintMarginRatio": "0.0065", @@ -17809,576 +18273,20 @@ } } ], - "UNFI/USDT": [ + "UNFI/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": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "UNI/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "UNI/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "VET/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "WAVES/BUSD": [ - { - "tier": 1.0, - "currency": "BUSD", - "minNotional": 0.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "1", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "0", - "maintMarginRatio": "0.025", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "BUSD", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "2", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "625.0" - } - }, - { - "tier": 3.0, - "currency": "BUSD", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "3", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5625.0" - } - }, - { - "tier": 4.0, - "currency": "BUSD", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "4", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11875.0" - } - }, - { - "tier": 5.0, - "currency": "BUSD", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "5", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386875.0" - } - } - ], - "WAVES/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, - "info": { - "bracket": "1", - "initialLeverage": "25", - "notionalCap": "5000", - "notionalFloor": "0", - "maintMarginRatio": "0.01", - "cum": "0.0" - } - }, - { - "tier": 2.0, - "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, - "info": { - "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" - } - }, - { - "tier": 3.0, - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" - } - }, - { - "tier": 4.0, - "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" - } - }, - { - "tier": 5.0, - "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" - } - }, - { - "tier": 6.0, - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.5", - "cum": "386950.0" - } - } - ], - "WOO/USDT": [ - { - "tier": 1.0, - "currency": "USDT", - "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, + "maintenanceMarginRate": 0.02, "maxLeverage": 20.0, "info": { "bracket": "1", "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -18395,7 +18303,7 @@ "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -18411,7 +18319,7 @@ "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -18427,7 +18335,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -18443,105 +18351,7 @@ "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" - } - } - ], - "XEM/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" + "cum": "11900.0" } }, { @@ -18557,11 +18367,697 @@ "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", + "cum": "386900.0" + } + } + ], + "UNI/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" + } + } + ], + "UNI/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" } } ], - "XLM/USDT": [ + "VET/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" + } + } + ], + "WAVES/BUSD:BUSD": [ + { + "tier": 1.0, + "currency": "BUSD", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 10.0, + "info": { + "bracket": "1", + "initialLeverage": "10", + "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": 8.0, + "info": { + "bracket": "2", + "initialLeverage": "8", + "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": 6.0, + "info": { + "bracket": "3", + "initialLeverage": "6", + "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" + } + } + ], + "WAVES/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 10.0, + "info": { + "bracket": "1", + "initialLeverage": "10", + "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": 8.0, + "info": { + "bracket": "2", + "initialLeverage": "8", + "notionalCap": "25000", + "notionalFloor": "5000", + "maintMarginRatio": "0.025", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "currency": "USDT", + "minNotional": 25000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 6.0, + "info": { + "bracket": "3", + "initialLeverage": "6", + "notionalCap": "100000", + "notionalFloor": "25000", + "maintMarginRatio": "0.05", + "cum": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "WOO/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" + } + } + ], + "XEM/USDT:USDT": [ + { + "tier": 1.0, + "currency": "USDT", + "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": "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": "25.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": "650.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": "5650.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": "11900.0" + } + }, + { + "tier": 6.0, + "currency": "USDT", + "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" + } + } + ], + "XLM/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -18675,7 +19171,7 @@ } } ], - "XMR/USDT": [ + "XMR/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -18789,7 +19285,7 @@ } } ], - "XRP/BUSD": [ + "XRP/BUSD:BUSD": [ { "tier": 1.0, "currency": "BUSD", @@ -18887,7 +19383,7 @@ } } ], - "XRP/USDT": [ + "XRP/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -19033,7 +19529,7 @@ } } ], - "XTZ/USDT": [ + "XTZ/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -19147,7 +19643,7 @@ } } ], - "YFI/USDT": [ + "YFI/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -19245,7 +19741,7 @@ } } ], - "ZEC/USDT": [ + "ZEC/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -19359,20 +19855,20 @@ } } ], - "ZEN/USDT": [ + "ZEN/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 20.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "20", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.01", + "maintMarginRatio": "0.02", "cum": "0.0" } }, @@ -19382,14 +19878,14 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.025", - "cum": "75.0" + "cum": "25.0" } }, { @@ -19398,14 +19894,14 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", - "cum": "700.0" + "cum": "650.0" } }, { @@ -19421,7 +19917,7 @@ "notionalCap": "250000", "notionalFloor": "100000", "maintMarginRatio": "0.1", - "cum": "5700.0" + "cum": "5650.0" } }, { @@ -19437,27 +19933,27 @@ "notionalCap": "1000000", "notionalFloor": "250000", "maintMarginRatio": "0.125", - "cum": "11950.0" + "cum": "11900.0" } }, { "tier": 6.0, "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "5000000", + "notionalCap": "3000000", "notionalFloor": "1000000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "386900.0" } } ], - "ZIL/USDT": [ + "ZIL/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", @@ -19555,7 +20051,7 @@ } } ], - "ZRX/USDT": [ + "ZRX/USDT:USDT": [ { "tier": 1.0, "currency": "USDT", diff --git a/freqtrade/exchange/bybit.py b/freqtrade/exchange/bybit.py index d14c7c192..c565b891f 100644 --- a/freqtrade/exchange/bybit.py +++ b/freqtrade/exchange/bybit.py @@ -1,9 +1,16 @@ """ Bybit exchange subclass """ import logging -from typing import Dict, List, Tuple +from datetime import datetime +from typing import Any, Dict, List, Optional, Tuple -from freqtrade.enums import MarginMode, TradingMode +import ccxt + +from freqtrade.constants import BuySell +from freqtrade.enums import MarginMode, PriceType, TradingMode +from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange +from freqtrade.exchange.common import retrier +from freqtrade.exchange.exchange_utils import timeframe_to_msecs logger = logging.getLogger(__name__) @@ -21,17 +28,27 @@ class Bybit(Exchange): _ft_has: Dict = { "ohlcv_candle_limit": 1000, - "ccxt_futures_name": "linear", "ohlcv_has_history": False, } _ft_has_futures: Dict = { + "ohlcv_candle_limit": 200, "ohlcv_has_history": True, + "mark_ohlcv_timeframe": "4h", + "funding_fee_timeframe": "8h", + "stoploss_on_exchange": True, + "stoploss_order_types": {"limit": "limit", "market": "market"}, + "stop_price_type_field": "triggerBy", + "stop_price_type_value_mapping": { + PriceType.LAST: "LastPrice", + PriceType.MARK: "MarkPrice", + PriceType.INDEX: "IndexPrice", + }, } _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ # TradingMode.SPOT always supported and not required in this list # (TradingMode.FUTURES, MarginMode.CROSS), - # (TradingMode.FUTURES, MarginMode.ISOLATED) + (TradingMode.FUTURES, MarginMode.ISOLATED) ] @property @@ -47,3 +64,158 @@ class Bybit(Exchange): }) config.update(super()._ccxt_config) return config + + def market_is_future(self, market: Dict[str, Any]) -> bool: + main = super().market_is_future(market) + # For ByBit, we'll only support USDT markets for now. + return ( + main and market['settle'] == 'USDT' + ) + + @retrier + def additional_exchange_init(self) -> None: + """ + Additional exchange initialization logic. + .api will be available at this point. + Must be overridden in child methods if required. + """ + try: + if self.trading_mode == TradingMode.FUTURES and not self._config['dry_run']: + position_mode = self._api.set_position_mode(False) + self._log_exchange_response('set_position_mode', position_mode) + except ccxt.DDoSProtection as e: + raise DDosProtection(e) from e + except (ccxt.NetworkError, ccxt.ExchangeError) as e: + raise TemporaryError( + f'Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}' + ) from e + except ccxt.BaseError as e: + raise OperationalException(e) from e + + async def _fetch_funding_rate_history( + self, + pair: str, + timeframe: str, + limit: int, + since_ms: Optional[int] = None, + ) -> List[List]: + """ + Fetch funding rate history + Necessary workaround until https://github.com/ccxt/ccxt/issues/15990 is fixed. + """ + params = {} + if since_ms: + until = since_ms + (timeframe_to_msecs(timeframe) * self._ft_has['ohlcv_candle_limit']) + params.update({'until': until}) + # Funding rate + data = await self._api_async.fetch_funding_rate_history( + pair, since=since_ms, + params=params) + # Convert funding rate to candle pattern + data = [[x['timestamp'], x['fundingRate'], 0, 0, 0, 0] for x in data] + return data + + def _lev_prep(self, pair: str, leverage: float, side: BuySell): + if self.trading_mode != TradingMode.SPOT: + params = {'leverage': leverage} + self.set_margin_mode(pair, self.margin_mode, accept_fail=True, params=params) + self._set_leverage(leverage, pair, accept_fail=True) + + def _get_params( + self, + side: BuySell, + ordertype: str, + leverage: float, + reduceOnly: bool, + time_in_force: str = 'GTC', + ) -> Dict: + params = super()._get_params( + side=side, + ordertype=ordertype, + leverage=leverage, + reduceOnly=reduceOnly, + time_in_force=time_in_force, + ) + if self.trading_mode == TradingMode.FUTURES and self.margin_mode: + params['position_idx'] = 0 + return params + + def dry_run_liquidation_price( + self, + pair: str, + open_rate: float, # Entry price of position + is_short: bool, + amount: float, + stake_amount: float, + leverage: float, + wallet_balance: float, # Or margin balance + mm_ex_1: float = 0.0, # (Binance) Cross only + upnl_ex_1: float = 0.0, # (Binance) Cross only + ) -> Optional[float]: + """ + Important: Must be fetching data from cached values as this is used by backtesting! + PERPETUAL: + bybit: + https://www.bybithelp.com/HelpCenterKnowledge/bybitHC_Article?language=en_US&id=000001067 + + Long: + Liquidation Price = ( + Entry Price * (1 - Initial Margin Rate + Maintenance Margin Rate) + - Extra Margin Added/ Contract) + Short: + Liquidation Price = ( + Entry Price * (1 + Initial Margin Rate - Maintenance Margin Rate) + + Extra Margin Added/ Contract) + + Implementation Note: Extra margin is currently not used. + + :param pair: Pair to calculate liquidation price for + :param open_rate: Entry price of position + :param is_short: True if the trade is a short, false otherwise + :param amount: Absolute value of position size incl. leverage (in base currency) + :param stake_amount: Stake amount - Collateral in settle currency. + :param leverage: Leverage used for this position. + :param trading_mode: SPOT, MARGIN, FUTURES, etc. + :param margin_mode: Either ISOLATED or CROSS + :param wallet_balance: Amount of margin_mode in the wallet being used to trade + Cross-Margin Mode: crossWalletBalance + Isolated-Margin Mode: isolatedWalletBalance + """ + + market = self.markets[pair] + mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, stake_amount) + + if self.trading_mode == TradingMode.FUTURES and self.margin_mode == MarginMode.ISOLATED: + + if market['inverse']: + raise OperationalException( + "Freqtrade does not yet support inverse contracts") + initial_margin_rate = 1 / leverage + + # See docstring - ignores extra margin! + if is_short: + return open_rate * (1 + initial_margin_rate - mm_ratio) + else: + return open_rate * (1 - initial_margin_rate + mm_ratio) + + else: + raise OperationalException( + "Freqtrade only supports isolated futures for leverage trading") + + def get_funding_fees( + self, pair: str, amount: float, is_short: bool, open_date: datetime) -> float: + """ + Fetch funding fees, either from the exchange (live) or calculates them + based on funding rate/mark price history + :param pair: The quote/base pair of the trade + :param is_short: trade direction + :param amount: Trade amount + :param open_date: Open date of the trade + :return: funding fee since open_date + :raises: ExchangeError if something goes wrong. + """ + # Bybit does not provide "applied" funding fees per position. + if self.trading_mode == TradingMode.FUTURES: + return self._fetch_and_calculate_funding_fees( + pair, amount, is_short, open_date) + return 0.0 diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index 6d09c4f95..42a7094ba 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -46,13 +46,13 @@ MAP_EXCHANGE_CHILDCLASS = { 'binanceje': 'binance', 'binanceusdm': 'binance', 'okex': 'okx', - 'gate': 'gateio', + 'gateio': 'gate', } SUPPORTED_EXCHANGES = [ 'binance', 'bittrex', - 'gateio', + 'gate', 'huobi', 'kraken', 'okx', diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d691738fe..332209246 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -3,11 +3,11 @@ Cryptocurrency Exchanges support """ import asyncio -import http import inspect import logging from copy import deepcopy from datetime import datetime, timedelta, timezone +from math import floor from threading import Lock from typing import Any, Coroutine, Dict, List, Literal, Optional, Tuple, Union @@ -24,6 +24,7 @@ from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHAN PairWithTimeframe) from freqtrade.data.converter import clean_ohlcv_dataframe, ohlcv_to_dataframe, trades_dict_to_list from freqtrade.enums import OPTIMIZE_MODES, CandleType, MarginMode, TradingMode +from freqtrade.enums.pricetype import PriceType from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFundsError, InvalidOrderException, OperationalException, PricingError, RetryableOrderError, TemporaryError) @@ -36,7 +37,7 @@ from freqtrade.exchange.exchange_utils import (CcxtModuleType, amount_to_contrac price_to_precision, timeframe_to_minutes, timeframe_to_msecs, timeframe_to_next_date, timeframe_to_prev_date, timeframe_to_seconds) -from freqtrade.exchange.types import Ticker, Tickers +from freqtrade.exchange.types import OHLCVResponse, Ticker, Tickers from freqtrade.misc import (chunks, deep_merge_dicts, file_dump_json, file_load_json, safe_value_fallback2) from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist @@ -45,12 +46,6 @@ from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist logger = logging.getLogger(__name__) -# Workaround for adding samesite support to pre 3.8 python -# Only applies to python3.7, and only on certain exchanges (kraken) -# Replicates the fix from starlette (which is actually causing this problem) -http.cookies.Morsel._reserved["samesite"] = "SameSite" # type: ignore - - class Exchange: # Parameters to add directly to buy/sell calls (like agreeing to trading agreement) @@ -474,7 +469,7 @@ class Exchange: try: if self._api_async: self.loop.run_until_complete( - self._api_async.load_markets(reload=reload)) + self._api_async.load_markets(reload=reload, params={})) except (asyncio.TimeoutError, ccxt.BaseError) as e: logger.warning('Could not load async markets. Reason: %s', e) @@ -483,7 +478,7 @@ class Exchange: def _load_markets(self) -> None: """ Initialize markets both sync and async """ try: - self._markets = self._api.load_markets() + self._markets = self._api.load_markets(params={}) self._load_async_markets() self._last_markets_refresh = arrow.utcnow().int_timestamp if self._ft_has['needs_trading_fees']: @@ -501,7 +496,7 @@ class Exchange: return None logger.debug("Performing scheduled market reload..") try: - self._markets = self._api.load_markets(reload=True) + self._markets = self._api.load_markets(reload=True, params={}) # Also reload async markets to avoid issues with newly listed pairs self._load_async_markets(reload=True) self._last_markets_refresh = arrow.utcnow().int_timestamp @@ -606,12 +601,27 @@ class Exchange: if not self.exchange_has('createMarketOrder'): raise OperationalException( f'Exchange {self.name} does not support market orders.') + self.validate_stop_ordertypes(order_types) + def validate_stop_ordertypes(self, order_types: Dict) -> None: + """ + Validate stoploss order types + """ if (order_types.get("stoploss_on_exchange") and not self._ft_has.get("stoploss_on_exchange", False)): raise OperationalException( f'On exchange stoploss is not supported for {self.name}.' ) + if self.trading_mode == TradingMode.FUTURES: + price_mapping = self._ft_has.get('stop_price_type_value_mapping', {}).keys() + if ( + order_types.get("stoploss_on_exchange", False) is True + and 'stoploss_price_type' in order_types + and order_types['stoploss_price_type'] not in price_mapping + ): + raise OperationalException( + f'On exchange stoploss price type is not supported for {self.name}.' + ) def validate_pricing(self, pricing: Dict) -> None: if pricing.get('use_order_book', False) and not self.exchange_has('fetchL2OrderBook'): @@ -682,7 +692,7 @@ class Exchange: f"Freqtrade does not support {mm_value} {trading_mode.value} on {self.name}" ) - def get_option(self, param: str, default: Any = None) -> Any: + def get_option(self, param: str, default: Optional[Any] = None) -> Any: """ Get parameter value from _ft_has """ @@ -1167,6 +1177,10 @@ class Exchange: stop_price=stop_price_norm) if self.trading_mode == TradingMode.FUTURES: params['reduceOnly'] = True + if 'stoploss_price_type' in order_types and 'stop_price_type_field' in self._ft_has: + price_type = self._ft_has['stop_price_type_value_mapping'][ + order_types.get('stoploss_price_type', PriceType.LAST)] + params[self._ft_has['stop_price_type_field']] = price_type amount = self.amount_to_precision(pair, self._amount_to_contracts(pair, amount)) @@ -1357,7 +1371,7 @@ class Exchange: raise OperationalException(e) from e @retrier - def fetch_positions(self, pair: str = None) -> List[Dict]: + def fetch_positions(self, pair: Optional[str] = None) -> List[Dict]: """ Fetch positions from the exchange. If no pair is given, all positions are returned. @@ -1705,7 +1719,7 @@ class Exchange: return self._config['fee'] # validate that markets are loaded before trying to get fee if self._api.markets is None or len(self._api.markets) == 0: - self._api.load_markets() + self._api.load_markets(params={}) return self._api.calculate_fee(symbol=symbol, type=type, side=side, amount=amount, price=price, takerOrMaker=taker_or_maker)['rate'] @@ -1801,7 +1815,7 @@ class Exchange: def get_historic_ohlcv(self, pair: str, timeframe: str, since_ms: int, candle_type: CandleType, is_new_pair: bool = False, - until_ms: int = None) -> List: + until_ms: Optional[int] = None) -> List: """ Get candle history using asyncio and returns the list of candles. Handles all async work for this. @@ -1813,32 +1827,18 @@ class Exchange: :param candle_type: '', mark, index, premiumIndex, or funding_rate :return: List with candle (OHLCV) data """ - pair, _, _, data = self.loop.run_until_complete( + pair, _, _, data, _ = self.loop.run_until_complete( self._async_get_historic_ohlcv(pair=pair, timeframe=timeframe, since_ms=since_ms, until_ms=until_ms, is_new_pair=is_new_pair, candle_type=candle_type)) logger.info(f"Downloaded data for {pair} with length {len(data)}.") return data - def get_historic_ohlcv_as_df(self, pair: str, timeframe: str, - since_ms: int, candle_type: CandleType) -> DataFrame: - """ - Minimal wrapper around get_historic_ohlcv - converting the result into a dataframe - :param pair: Pair to download - :param timeframe: Timeframe to get data for - :param since_ms: Timestamp in milliseconds to get history from - :param candle_type: Any of the enum CandleType (must match trading mode!) - :return: OHLCV DataFrame - """ - ticks = self.get_historic_ohlcv(pair, timeframe, since_ms=since_ms, candle_type=candle_type) - return ohlcv_to_dataframe(ticks, timeframe, pair=pair, fill_missing=True, - drop_incomplete=self._ohlcv_partial_candle) - async def _async_get_historic_ohlcv(self, pair: str, timeframe: str, since_ms: int, candle_type: CandleType, is_new_pair: bool = False, raise_: bool = False, until_ms: Optional[int] = None - ) -> Tuple[str, str, str, List]: + ) -> OHLCVResponse: """ Download historic ohlcv :param is_new_pair: used by binance subclass to allow "fast" new pair downloading @@ -1869,15 +1869,16 @@ class Exchange: continue else: # Deconstruct tuple if it's not an exception - p, _, c, new_data = res + p, _, c, new_data, _ = res if p == pair and c == candle_type: data.extend(new_data) # Sort data again after extending the result - above calls return in "async order" data = sorted(data, key=lambda x: x[0]) - return pair, timeframe, candle_type, data + return pair, timeframe, candle_type, data, self._ohlcv_partial_candle - def _build_coroutine(self, pair: str, timeframe: str, candle_type: CandleType, - since_ms: Optional[int], cache: bool) -> Coroutine: + def _build_coroutine( + self, pair: str, timeframe: str, candle_type: CandleType, + since_ms: Optional[int], cache: bool) -> Coroutine[Any, Any, OHLCVResponse]: not_all_data = cache and self.required_candle_call_count > 1 if cache and (pair, timeframe, candle_type) in self._klines: candle_limit = self.ohlcv_candle_limit(timeframe, candle_type) @@ -1914,7 +1915,7 @@ class Exchange: """ Build Coroutines to execute as part of refresh_latest_ohlcv """ - input_coroutines = [] + input_coroutines: List[Coroutine[Any, Any, OHLCVResponse]] = [] cached_pairs = [] for pair, timeframe, candle_type in set(pair_list): if (timeframe not in self.timeframes @@ -1978,7 +1979,6 @@ class Exchange: :return: Dict of [{(pair, timeframe): Dataframe}] """ logger.debug("Refreshing candle (OHLCV) data for %d pairs", len(pair_list)) - drop_incomplete = self._ohlcv_partial_candle if drop_incomplete is None else drop_incomplete # Gather coroutines to run input_coroutines, cached_pairs = self._build_ohlcv_dl_jobs(pair_list, since_ms, cache) @@ -1996,8 +1996,9 @@ class Exchange: if isinstance(res, Exception): logger.warning(f"Async code raised an exception: {repr(res)}") continue - # Deconstruct tuple (has 4 elements) - pair, timeframe, c_type, ticks = res + # Deconstruct tuple (has 5 elements) + pair, timeframe, c_type, ticks, drop_hint = res + drop_incomplete = drop_hint if drop_incomplete is None else drop_incomplete ohlcv_df = self._process_ohlcv_df( pair, timeframe, c_type, ticks, cache, drop_incomplete) @@ -2025,7 +2026,7 @@ class Exchange: timeframe: str, candle_type: CandleType, since_ms: Optional[int] = None, - ) -> Tuple[str, str, str, List]: + ) -> OHLCVResponse: """ Asynchronously get candle history data using fetch_ohlcv :param candle_type: '', mark, index, premiumIndex, or funding_rate @@ -2065,9 +2066,9 @@ class Exchange: data = sorted(data, key=lambda x: x[0]) except IndexError: logger.exception("Error loading %s. Result was %s.", pair, data) - return pair, timeframe, candle_type, [] + return pair, timeframe, candle_type, [], self._ohlcv_partial_candle logger.debug("Done fetching pair %s, interval %s ...", pair, timeframe) - return pair, timeframe, candle_type, data + return pair, timeframe, candle_type, data, self._ohlcv_partial_candle except ccxt.NotSupported as e: raise OperationalException( @@ -2504,7 +2505,8 @@ class Exchange: self, leverage: float, pair: Optional[str] = None, - trading_mode: Optional[TradingMode] = None + trading_mode: Optional[TradingMode] = None, + accept_fail: bool = False, ): """ Set's the leverage before making a trade, in order to not @@ -2513,12 +2515,18 @@ class Exchange: if self._config['dry_run'] or not self.exchange_has("setLeverage"): # Some exchanges only support one margin_mode type return - + if self._ft_has.get('floor_leverage', False) is True: + # Rounding for binance ... + leverage = floor(leverage) try: res = self._api.set_leverage(symbol=pair, leverage=leverage) self._log_exchange_response('set_leverage', res) except ccxt.DDoSProtection as e: raise DDosProtection(e) from e + except ccxt.BadRequest as e: + if not accept_fail: + raise TemporaryError( + f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: raise TemporaryError( f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e @@ -2540,7 +2548,8 @@ class Exchange: return open_date.minute > 0 or open_date.second > 0 @retrier - def set_margin_mode(self, pair: str, margin_mode: MarginMode, params: dict = {}): + def set_margin_mode(self, pair: str, margin_mode: MarginMode, accept_fail: bool = False, + params: dict = {}): """ Set's the margin mode on the exchange to cross or isolated for a specific pair :param pair: base/quote currency pair (e.g. "ADA/USDT") @@ -2554,6 +2563,10 @@ class Exchange: self._log_exchange_response('set_margin_mode', res) except ccxt.DDoSProtection as e: raise DDosProtection(e) from e + except ccxt.BadRequest as e: + if not accept_fail: + raise TemporaryError( + f'Could not set margin mode due to {e.__class__.__name__}. Message: {e}') from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: raise TemporaryError( f'Could not set margin mode due to {e.__class__.__name__}. Message: {e}') from e @@ -2687,7 +2700,7 @@ class Exchange: :param amount: Trade amount :param open_date: Open date of the trade :return: funding fee since open_date - :raies: ExchangeError if something goes wrong. + :raises: ExchangeError if something goes wrong. """ if self.trading_mode == TradingMode.FUTURES: if self._config['dry_run']: @@ -2707,6 +2720,7 @@ class Exchange: is_short: bool, amount: float, # Absolute value of position size stake_amount: float, + leverage: float, wallet_balance: float, mm_ex_1: float = 0.0, # (Binance) Cross only upnl_ex_1: float = 0.0, # (Binance) Cross only @@ -2728,6 +2742,7 @@ class Exchange: open_rate=open_rate, is_short=is_short, amount=amount, + leverage=leverage, stake_amount=stake_amount, wallet_balance=wallet_balance, mm_ex_1=mm_ex_1, @@ -2739,7 +2754,7 @@ class Exchange: pos = positions[0] isolated_liq = pos['liquidationPrice'] - if isolated_liq: + if isolated_liq is not None: buffer_amount = abs(open_rate - isolated_liq) * self.liquidation_buffer isolated_liq = ( isolated_liq - buffer_amount @@ -2757,6 +2772,7 @@ class Exchange: is_short: bool, amount: float, stake_amount: float, + leverage: float, wallet_balance: float, # Or margin balance mm_ex_1: float = 0.0, # (Binance) Cross only upnl_ex_1: float = 0.0, # (Binance) Cross only @@ -2764,7 +2780,7 @@ class Exchange: """ Important: Must be fetching data from cached values as this is used by backtesting! PERPETUAL: - gateio: https://www.gate.io/help/futures/futures/27724/liquidation-price-bankruptcy-price + gate: https://www.gate.io/help/futures/futures/27724/liquidation-price-bankruptcy-price > Liquidation Price = (Entry Price ± Margin / Contract Multiplier / Size) / [ 1 ± (Maintenance Margin Ratio + Taker Rate)] Wherein, "+" or "-" depends on whether the contract goes long or short: @@ -2778,13 +2794,14 @@ class Exchange: :param is_short: True if the trade is a short, false otherwise :param amount: Absolute value of position size incl. leverage (in base currency) :param stake_amount: Stake amount - Collateral in settle currency. + :param leverage: Leverage used for this position. :param trading_mode: SPOT, MARGIN, FUTURES, etc. :param margin_mode: Either ISOLATED or CROSS :param wallet_balance: Amount of margin_mode in the wallet being used to trade Cross-Margin Mode: crossWalletBalance Isolated-Margin Mode: isolatedWalletBalance - # * Not required by Gateio or OKX + # * Not required by Gate or OKX :param mm_ex_1: :param upnl_ex_1: """ diff --git a/freqtrade/exchange/exchange_utils.py b/freqtrade/exchange/exchange_utils.py index cb6333869..6d3371a59 100644 --- a/freqtrade/exchange/exchange_utils.py +++ b/freqtrade/exchange/exchange_utils.py @@ -15,18 +15,19 @@ from freqtrade.util import FtPrecise CcxtModuleType = Any -def is_exchange_known_ccxt(exchange_name: str, ccxt_module: CcxtModuleType = None) -> bool: +def is_exchange_known_ccxt( + exchange_name: str, ccxt_module: Optional[CcxtModuleType] = None) -> bool: return exchange_name in ccxt_exchanges(ccxt_module) -def ccxt_exchanges(ccxt_module: CcxtModuleType = None) -> List[str]: +def ccxt_exchanges(ccxt_module: Optional[CcxtModuleType] = None) -> List[str]: """ Return the list of all exchanges known to ccxt """ return ccxt_module.exchanges if ccxt_module is not None else ccxt.exchanges -def available_exchanges(ccxt_module: CcxtModuleType = None) -> List[str]: +def available_exchanges(ccxt_module: Optional[CcxtModuleType] = None) -> List[str]: """ Return exchanges available to the bot, i.e. non-bad exchanges in the ccxt list """ @@ -86,7 +87,7 @@ def timeframe_to_msecs(timeframe: str) -> int: return ccxt.Exchange.parse_timeframe(timeframe) * 1000 -def timeframe_to_prev_date(timeframe: str, date: datetime = None) -> datetime: +def timeframe_to_prev_date(timeframe: str, date: Optional[datetime] = None) -> datetime: """ Use Timeframe and determine the candle start date for this date. Does not round when given a candle start date. @@ -102,7 +103,7 @@ def timeframe_to_prev_date(timeframe: str, date: datetime = None) -> datetime: return datetime.fromtimestamp(new_timestamp, tz=timezone.utc) -def timeframe_to_next_date(timeframe: str, date: datetime = None) -> datetime: +def timeframe_to_next_date(timeframe: str, date: Optional[datetime] = None) -> datetime: """ Use Timeframe and determine next candle. :param timeframe: timeframe in string format (e.g. "5m") diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gate.py similarity index 92% rename from freqtrade/exchange/gateio.py rename to freqtrade/exchange/gate.py index de178af02..80ed4088a 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gate.py @@ -4,7 +4,7 @@ from datetime import datetime from typing import Any, Dict, List, Optional, Tuple from freqtrade.constants import BuySell -from freqtrade.enums import MarginMode, TradingMode +from freqtrade.enums import MarginMode, PriceType, TradingMode from freqtrade.exceptions import OperationalException from freqtrade.exchange import Exchange from freqtrade.misc import safe_value_fallback2 @@ -13,7 +13,7 @@ from freqtrade.misc import safe_value_fallback2 logger = logging.getLogger(__name__) -class Gateio(Exchange): +class Gate(Exchange): """ Gate.io exchange class. Contains adjustments needed for Freqtrade to work with this exchange. @@ -34,6 +34,12 @@ class Gateio(Exchange): "needs_trading_fees": True, "fee_cost_in_contracts": False, # Set explicitly to false for clarity "order_props_in_contracts": ['amount', 'filled', 'remaining'], + "stop_price_type_field": "price_type", + "stop_price_type_value_mapping": { + PriceType.LAST: 0, + PriceType.MARK: 1, + PriceType.INDEX: 2, + }, } _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ @@ -49,6 +55,7 @@ class Gateio(Exchange): 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, @@ -77,7 +84,7 @@ class Gateio(Exchange): if self.trading_mode == TradingMode.FUTURES: # Futures usually don't contain fees in the response. - # As such, futures orders on gateio will not contain a fee, which causes + # As such, futures orders on gate will not contain a fee, which causes # a repeated "update fee" cycle and wrong calculations. # Therefore we patch the response with fees if it's not available. # An alternative also contianing fees would be diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 5d8c1ad29..2b37c45bd 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -158,7 +158,8 @@ class Kraken(Exchange): self, leverage: float, pair: Optional[str] = None, - trading_mode: Optional[TradingMode] = None + trading_mode: Optional[TradingMode] = None, + accept_fail: bool = False, ): """ Kraken set's the leverage as an option in the order object, so we need to diff --git a/freqtrade/exchange/kucoin.py b/freqtrade/exchange/kucoin.py index 6c7d7acfc..797d9fbd2 100644 --- a/freqtrade/exchange/kucoin.py +++ b/freqtrade/exchange/kucoin.py @@ -36,3 +36,34 @@ class Kucoin(Exchange): 'stop': 'loss' }) return params + + def create_order( + self, + *, + pair: str, + ordertype: str, + side: BuySell, + amount: float, + rate: float, + leverage: float, + reduceOnly: bool = False, + time_in_force: str = 'GTC', + ) -> Dict: + + res = super().create_order( + pair=pair, + ordertype=ordertype, + side=side, + amount=amount, + rate=rate, + leverage=leverage, + reduceOnly=reduceOnly, + time_in_force=time_in_force, + ) + # Kucoin returns only the order-id. + # ccxt returns status = 'closed' at the moment - which is information ccxt invented. + # Since we rely on status heavily, we must set it to 'open' here. + # ref: https://github.com/ccxt/ccxt/pull/16674, (https://github.com/ccxt/ccxt/pull/16553) + res['type'] = ordertype + res['status'] = 'open' + return res diff --git a/freqtrade/exchange/okx.py b/freqtrade/exchange/okx.py index 6792c2cba..e7d658d24 100644 --- a/freqtrade/exchange/okx.py +++ b/freqtrade/exchange/okx.py @@ -5,6 +5,7 @@ import ccxt from freqtrade.constants import BuySell from freqtrade.enums import CandleType, MarginMode, TradingMode +from freqtrade.enums.pricetype import PriceType from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange, date_minus_candles from freqtrade.exchange.common import retrier @@ -27,6 +28,12 @@ class Okx(Exchange): _ft_has_futures: Dict = { "tickers_have_quoteVolume": False, "fee_cost_in_contracts": True, + "stop_price_type_field": "tpTriggerPxType", + "stop_price_type_value_mapping": { + PriceType.LAST: "last", + PriceType.MARK: "index", + PriceType.INDEX: "mark", + }, } _supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [ @@ -118,13 +125,15 @@ class Okx(Exchange): if self.trading_mode != TradingMode.SPOT and self.margin_mode is not None: try: # TODO-lev: Test me properly (check mgnMode passed) - self._api.set_leverage( + res = self._api.set_leverage( leverage=leverage, symbol=pair, params={ "mgnMode": self.margin_mode.value, "posSide": self._get_posSide(side, False), }) + self._log_exchange_response('set_leverage', res) + except ccxt.DDoSProtection as e: raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: diff --git a/freqtrade/exchange/types.py b/freqtrade/exchange/types.py index a60b454d4..813b09297 100644 --- a/freqtrade/exchange/types.py +++ b/freqtrade/exchange/types.py @@ -1,4 +1,6 @@ -from typing import Dict, Optional, TypedDict +from typing import Dict, List, Optional, Tuple, TypedDict + +from freqtrade.enums import CandleType class Ticker(TypedDict): @@ -14,3 +16,6 @@ class Ticker(TypedDict): Tickers = Dict[str, Ticker] + +# pair, timeframe, candleType, OHLCV, drop last?, +OHLCVResponse = Tuple[str, str, CandleType, List, bool] diff --git a/freqtrade/freqai/RL/BaseEnvironment.py b/freqtrade/freqai/RL/BaseEnvironment.py index ef1c02a3b..7a4467bf7 100644 --- a/freqtrade/freqai/RL/BaseEnvironment.py +++ b/freqtrade/freqai/RL/BaseEnvironment.py @@ -45,7 +45,8 @@ class BaseEnvironment(gym.Env): def __init__(self, df: DataFrame = DataFrame(), prices: DataFrame = DataFrame(), reward_kwargs: dict = {}, window_size=10, starting_point=True, id: str = 'baseenv-1', seed: int = 1, config: dict = {}, live: bool = False, - fee: float = 0.0015, can_short: bool = False): + fee: float = 0.0015, can_short: bool = False, pair: str = "", + df_raw: DataFrame = DataFrame()): """ Initializes the training/eval environment. :param df: dataframe of features @@ -60,12 +61,14 @@ class BaseEnvironment(gym.Env): :param fee: The fee to use for environmental interactions. :param can_short: Whether or not the environment can short """ - self.config = config - self.rl_config = config['freqai']['rl_config'] - self.add_state_info = self.rl_config.get('add_state_info', False) - self.id = id - self.max_drawdown = 1 - self.rl_config.get('max_training_drawdown_pct', 0.8) - self.compound_trades = config['stake_amount'] == 'unlimited' + self.config: dict = config + self.rl_config: dict = config['freqai']['rl_config'] + self.add_state_info: bool = self.rl_config.get('add_state_info', False) + self.id: str = id + self.max_drawdown: float = 1 - self.rl_config.get('max_training_drawdown_pct', 0.8) + self.compound_trades: bool = config['stake_amount'] == 'unlimited' + self.pair: str = pair + self.raw_features: DataFrame = df_raw if self.config.get('fee', None) is not None: self.fee = self.config['fee'] else: @@ -74,8 +77,8 @@ class BaseEnvironment(gym.Env): # set here to default 5Ac, but all children envs can override this self.actions: Type[Enum] = BaseActions self.tensorboard_metrics: dict = {} - self.can_short = can_short - self.live = live + self.can_short: bool = can_short + self.live: bool = live if not self.live and self.add_state_info: self.add_state_info = False logger.warning("add_state_info is not available in backtesting. Deactivating.") @@ -93,13 +96,12 @@ class BaseEnvironment(gym.Env): :param reward_kwargs: extra config settings assigned by user in `rl_config` :param starting_point: start at edge of window or not """ - self.df = df - self.signal_features = self.df - self.prices = prices - self.window_size = window_size - self.starting_point = starting_point - self.rr = reward_kwargs["rr"] - self.profit_aim = reward_kwargs["profit_aim"] + self.signal_features: DataFrame = df + self.prices: DataFrame = prices + self.window_size: int = window_size + self.starting_point: bool = starting_point + self.rr: float = reward_kwargs["rr"] + self.profit_aim: float = reward_kwargs["profit_aim"] # # spaces if self.add_state_info: diff --git a/freqtrade/freqai/RL/BaseReinforcementLearningModel.py b/freqtrade/freqai/RL/BaseReinforcementLearningModel.py index af0726c0b..a8ef69394 100644 --- a/freqtrade/freqai/RL/BaseReinforcementLearningModel.py +++ b/freqtrade/freqai/RL/BaseReinforcementLearningModel.py @@ -1,3 +1,4 @@ +import copy import importlib import logging from abc import abstractmethod @@ -50,6 +51,7 @@ class BaseReinforcementLearningModel(IFreqaiModel): self.eval_callback: Optional[EvalCallback] = None self.model_type = self.freqai_info['rl_config']['model_type'] self.rl_config = self.freqai_info['rl_config'] + self.df_raw: DataFrame = DataFrame() self.continual_learning = self.freqai_info.get('continual_learning', False) if self.model_type in SB3_MODELS: import_str = 'stable_baselines3' @@ -107,6 +109,7 @@ class BaseReinforcementLearningModel(IFreqaiModel): data_dictionary: Dict[str, Any] = dk.make_train_test_datasets( features_filtered, labels_filtered) + self.df_raw = copy.deepcopy(data_dictionary["train_features"]) dk.fit_labels() # FIXME useless for now, but just satiating append methods # normalize all data based on train_dataset only @@ -143,7 +146,7 @@ class BaseReinforcementLearningModel(IFreqaiModel): train_df = data_dictionary["train_features"] test_df = data_dictionary["test_features"] - env_info = self.pack_env_dict() + env_info = self.pack_env_dict(dk.pair) self.train_env = self.MyRLEnv(df=train_df, prices=prices_train, @@ -158,7 +161,7 @@ class BaseReinforcementLearningModel(IFreqaiModel): actions = self.train_env.get_actions() self.tensorboard_callback = TensorboardCallback(verbose=1, actions=actions) - def pack_env_dict(self) -> Dict[str, Any]: + def pack_env_dict(self, pair: str) -> Dict[str, Any]: """ Create dictionary of environment arguments """ @@ -166,7 +169,9 @@ class BaseReinforcementLearningModel(IFreqaiModel): "reward_kwargs": self.reward_params, "config": self.config, "live": self.live, - "can_short": self.can_short} + "can_short": self.can_short, + "pair": pair, + "df_raw": self.df_raw} if self.data_provider: env_info["fee"] = self.data_provider._exchange \ .get_fee(symbol=self.data_provider.current_whitelist()[0]) # type: ignore @@ -280,26 +285,36 @@ class BaseReinforcementLearningModel(IFreqaiModel): train_df = data_dictionary["train_features"] test_df = data_dictionary["test_features"] + # %-raw_volume_gen_shift-2_ETH/USDT_1h # price data for model training and evaluation tf = self.config['timeframe'] - ohlc_list = [f'%-{pair}raw_open_{tf}', f'%-{pair}raw_low_{tf}', - f'%-{pair}raw_high_{tf}', f'%-{pair}raw_close_{tf}'] - rename_dict = {f'%-{pair}raw_open_{tf}': 'open', f'%-{pair}raw_low_{tf}': 'low', - f'%-{pair}raw_high_{tf}': ' high', f'%-{pair}raw_close_{tf}': 'close'} + rename_dict = {'%-raw_open': 'open', '%-raw_low': 'low', + '%-raw_high': ' high', '%-raw_close': 'close'} + rename_dict_old = {f'%-{pair}raw_open_{tf}': 'open', f'%-{pair}raw_low_{tf}': 'low', + f'%-{pair}raw_high_{tf}': ' high', f'%-{pair}raw_close_{tf}': 'close'} + + prices_train = train_df.filter(rename_dict.keys(), axis=1) + prices_train_old = train_df.filter(rename_dict_old.keys(), axis=1) + if prices_train.empty or not prices_train_old.empty: + if not prices_train_old.empty: + prices_train = prices_train_old + rename_dict = rename_dict_old + logger.warning('Reinforcement learning module didnt find the correct raw prices ' + 'assigned in feature_engineering_standard(). ' + 'Please assign them with:\n' + 'dataframe["%-raw_close"] = dataframe["close"]\n' + 'dataframe["%-raw_open"] = dataframe["open"]\n' + 'dataframe["%-raw_high"] = dataframe["high"]\n' + 'dataframe["%-raw_low"] = dataframe["low"]\n' + 'inside `feature_engineering_standard()') + elif prices_train.empty: + raise OperationalException("No prices found, please follow log warning " + "instructions to correct the strategy.") - prices_train = train_df.filter(ohlc_list, axis=1) - if prices_train.empty: - raise OperationalException('Reinforcement learning module didnt find the raw prices ' - 'assigned in populate_any_indicators. Please assign them ' - 'with:\n' - 'informative[f"%-{pair}raw_close"] = informative["close"]\n' - 'informative[f"%-{pair}raw_open"] = informative["open"]\n' - 'informative[f"%-{pair}raw_high"] = informative["high"]\n' - 'informative[f"%-{pair}raw_low"] = informative["low"]\n') prices_train.rename(columns=rename_dict, inplace=True) prices_train.reset_index(drop=True) - prices_test = test_df.filter(ohlc_list, axis=1) + prices_test = test_df.filter(rename_dict.keys(), axis=1) prices_test.rename(columns=rename_dict, inplace=True) prices_test.reset_index(drop=True) @@ -337,7 +352,7 @@ class BaseReinforcementLearningModel(IFreqaiModel): sets a custom reward based on profit and trade duration. """ - def calculate_reward(self, action: int) -> float: + def calculate_reward(self, action: int) -> float: # noqa: C901 """ An example reward function. This is the one function that users will likely wish to inject their own creativity into. @@ -353,10 +368,19 @@ class BaseReinforcementLearningModel(IFreqaiModel): pnl = self.get_unrealized_profit() factor = 100. + # you can use feature values from dataframe + rsi_now = self.raw_features[f"%-rsi-period-10_shift-1_{self.pair}_" + f"{self.config['timeframe']}"].iloc[self._current_tick] + # reward agent for entering trades if (action in (Actions.Long_enter.value, Actions.Short_enter.value) and self._position == Positions.Neutral): - return 25 + if rsi_now < 40: + factor = 40 / rsi_now + else: + factor = 1 + return 25 * factor + # discourage agent from not entering trades if action == Actions.Neutral.value and self._position == Positions.Neutral: return -1 diff --git a/freqtrade/freqai/data_drawer.py b/freqtrade/freqai/data_drawer.py index 848fb20eb..cb5b0f0fb 100644 --- a/freqtrade/freqai/data_drawer.py +++ b/freqtrade/freqai/data_drawer.py @@ -59,7 +59,7 @@ class FreqaiDataDrawer: Juha Nykänen @suikula, Wagner Costa @wagnercosta, Johan Vlugt @Jooopieeert """ - def __init__(self, full_path: Path, config: Config, follow_mode: bool = False): + def __init__(self, full_path: Path, config: Config): self.config = config self.freqai_info = config.get("freqai", {}) @@ -84,9 +84,6 @@ class FreqaiDataDrawer: self.pair_dictionary_path = Path(self.full_path / "pair_dictionary.json") self.global_metadata_path = Path(self.full_path / "global_metadata.json") self.metric_tracker_path = Path(self.full_path / "metric_tracker.json") - self.follow_mode = follow_mode - if follow_mode: - self.create_follower_dict() self.load_drawer_from_disk() self.load_historic_predictions_from_disk() self.metric_tracker: Dict[str, Dict[str, Dict[str, list]]] = {} @@ -149,13 +146,8 @@ class FreqaiDataDrawer: if exists: with open(self.pair_dictionary_path, "r") as fp: self.pair_dict = rapidjson.load(fp, number_mode=rapidjson.NM_NATIVE) - elif not self.follow_mode: - logger.info("Could not find existing datadrawer, starting from scratch") else: - logger.warning( - f"Follower could not find pair_dictionary at {self.full_path} " - "sending null values back to strategy" - ) + logger.info("Could not find existing datadrawer, starting from scratch") def load_metric_tracker_from_disk(self): """ @@ -193,13 +185,8 @@ class FreqaiDataDrawer: self.historic_predictions = cloudpickle.load(fp) logger.warning('FreqAI successfully loaded the backup historical predictions file.') - elif not self.follow_mode: - logger.info("Could not find existing historic_predictions, starting from scratch") else: - logger.warning( - f"Follower could not find historic predictions at {self.full_path} " - "sending null values back to strategy" - ) + logger.info("Could not find existing historic_predictions, starting from scratch") return exists @@ -248,23 +235,6 @@ class FreqaiDataDrawer: rapidjson.dump(metadata, fp, default=self.np_encoder, number_mode=rapidjson.NM_NATIVE) - def create_follower_dict(self): - """ - Create or dictionary for each follower to maintain unique persistent prediction targets - """ - - whitelist_pairs = self.config.get("exchange", {}).get("pair_whitelist") - - exists = self.follower_dict_path.is_file() - - if exists: - logger.info("Found an existing follower dictionary") - - for pair in whitelist_pairs: - self.follower_dict[pair] = {} - - self.save_follower_dict_to_disk() - def np_encoder(self, object): if isinstance(object, np.generic): return object.item() @@ -282,27 +252,17 @@ class FreqaiDataDrawer: """ pair_dict = self.pair_dict.get(pair) - data_path_set = self.pair_dict.get(pair, self.empty_pair_dict).get("data_path", "") + # data_path_set = self.pair_dict.get(pair, self.empty_pair_dict).get("data_path", "") return_null_array = False if pair_dict: model_filename = pair_dict["model_filename"] trained_timestamp = pair_dict["trained_timestamp"] - elif not self.follow_mode: + else: self.pair_dict[pair] = self.empty_pair_dict.copy() model_filename = "" trained_timestamp = 0 - if not data_path_set and self.follow_mode: - logger.warning( - f"Follower could not find current pair {pair} in " - f"pair_dictionary at path {self.full_path}, sending null values " - "back to strategy." - ) - trained_timestamp = 0 - model_filename = '' - return_null_array = True - return model_filename, trained_timestamp, return_null_array def set_pair_dict_info(self, metadata: dict) -> None: @@ -311,7 +271,6 @@ class FreqaiDataDrawer: return else: self.pair_dict[metadata["pair"]] = self.empty_pair_dict.copy() - return def set_initial_return_values(self, pair: str, pred_df: DataFrame) -> None: diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 9c8158c8a..70e5549f9 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -1,10 +1,11 @@ import copy +import inspect import logging import shutil from datetime import datetime, timezone from math import cos, sin from pathlib import Path -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, List, Optional, Tuple import numpy as np import numpy.typing as npt @@ -23,6 +24,7 @@ from freqtrade.constants import Config from freqtrade.data.converter import reduce_dataframe_footprint from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_seconds +from freqtrade.strategy import merge_informative_pair from freqtrade.strategy.interface import IStrategy @@ -110,7 +112,7 @@ class FreqaiDataKitchen: def set_paths( self, pair: str, - trained_timestamp: int = None, + trained_timestamp: Optional[int] = None, ) -> None: """ Set the paths to the data for the present coin/botloop @@ -1145,9 +1147,9 @@ class FreqaiDataKitchen: for pair in pairs: pair = pair.replace(':', '') # lightgbm doesnt like colons - valid_strs = [f"%-{pair}", f"%{pair}", f"%_{pair}"] - pair_cols = [col for col in dataframe.columns if - any(substr in col for substr in valid_strs)] + pair_cols = [col for col in dataframe.columns if col.startswith("%") + and f"{pair}_" in col] + if pair_cols: pair_cols.insert(0, 'date') corr_dataframes[pair] = dataframe.filter(pair_cols, axis=1) @@ -1176,6 +1178,105 @@ class FreqaiDataKitchen: return dataframe + def get_pair_data_for_features(self, + pair: str, + tf: str, + strategy: IStrategy, + corr_dataframes: dict = {}, + base_dataframes: dict = {}, + is_corr_pairs: bool = False) -> DataFrame: + """ + Get the data for the pair. If it's not in the dictionary, get it from the data provider + :param pair: str = pair to get data for + :param tf: str = timeframe to get data for + :param strategy: IStrategy = user defined strategy object + :param corr_dataframes: dict = dict containing the df pair dataframes + (for user defined timeframes) + :param base_dataframes: dict = dict containing the current pair dataframes + (for user defined timeframes) + :param is_corr_pairs: bool = whether the pair is a corr pair or not + :return: dataframe = dataframe containing the pair data + """ + if is_corr_pairs: + dataframe = corr_dataframes[pair][tf] + if not dataframe.empty: + return dataframe + else: + dataframe = strategy.dp.get_pair_dataframe(pair=pair, timeframe=tf) + return dataframe + else: + dataframe = base_dataframes[tf] + if not dataframe.empty: + return dataframe + else: + dataframe = strategy.dp.get_pair_dataframe(pair=pair, timeframe=tf) + return dataframe + + def merge_features(self, df_main: DataFrame, df_to_merge: DataFrame, + tf: str, timeframe_inf: str, suffix: str) -> DataFrame: + """ + Merge the features of the dataframe and remove HLCV and date added columns + :param df_main: DataFrame = main dataframe + :param df_to_merge: DataFrame = dataframe to merge + :param tf: str = timeframe of the main dataframe + :param timeframe_inf: str = timeframe of the dataframe to merge + :param suffix: str = suffix to add to the columns of the dataframe to merge + :return: dataframe = merged dataframe + """ + dataframe = merge_informative_pair(df_main, df_to_merge, tf, timeframe_inf=timeframe_inf, + append_timeframe=False, suffix=suffix, ffill=True) + skip_columns = [ + (f"{s}_{suffix}") for s in ["date", "open", "high", "low", "close", "volume"] + ] + dataframe = dataframe.drop(columns=skip_columns) + return dataframe + + def populate_features(self, dataframe: DataFrame, pair: str, strategy: IStrategy, + corr_dataframes: dict, base_dataframes: dict, + is_corr_pairs: bool = False) -> DataFrame: + """ + Use the user defined strategy functions for populating features + :param dataframe: DataFrame = dataframe to populate + :param pair: str = pair to populate + :param strategy: IStrategy = user defined strategy object + :param corr_dataframes: dict = dict containing the df pair dataframes + :param base_dataframes: dict = dict containing the current pair dataframes + :param is_corr_pairs: bool = whether the pair is a corr pair or not + :return: dataframe = populated dataframe + """ + tfs: List[str] = self.freqai_config["feature_parameters"].get("include_timeframes") + + for tf in tfs: + metadata = {"pair": pair, "tf": tf} + informative_df = self.get_pair_data_for_features( + pair, tf, strategy, corr_dataframes, base_dataframes, is_corr_pairs) + informative_copy = informative_df.copy() + + for t in self.freqai_config["feature_parameters"]["indicator_periods_candles"]: + df_features = strategy.feature_engineering_expand_all( + informative_copy.copy(), t, metadata=metadata) + suffix = f"{t}" + informative_df = self.merge_features(informative_df, df_features, tf, tf, suffix) + + generic_df = strategy.feature_engineering_expand_basic( + informative_copy.copy(), metadata=metadata) + suffix = "gen" + + informative_df = self.merge_features(informative_df, generic_df, tf, tf, suffix) + + indicators = [col for col in informative_df if col.startswith("%")] + for n in range(self.freqai_config["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + df_shift = informative_df[indicators].shift(n) + df_shift = df_shift.add_suffix("_shift-" + str(n)) + informative_df = pd.concat((informative_df, df_shift), axis=1) + + dataframe = self.merge_features(dataframe.copy(), informative_df, + self.config["timeframe"], tf, f'{pair}_{tf}') + + return dataframe + def use_strategy_to_populate_indicators( self, strategy: IStrategy, @@ -1188,7 +1289,87 @@ class FreqaiDataKitchen: """ Use the user defined strategy for populating indicators during retrain :param strategy: IStrategy = user defined strategy object - :param corr_dataframes: dict = dict containing the informative pair dataframes + :param corr_dataframes: dict = dict containing the df pair dataframes + (for user defined timeframes) + :param base_dataframes: dict = dict containing the current pair dataframes + (for user defined timeframes) + :param pair: str = pair to populate + :param prediction_dataframe: DataFrame = dataframe containing the pair data + used for prediction + :param do_corr_pairs: bool = whether to populate corr pairs or not + :return: + dataframe: DataFrame = dataframe containing populated indicators + """ + + # this is a hack to check if the user is using the populate_any_indicators function + new_version = inspect.getsource(strategy.populate_any_indicators) == ( + inspect.getsource(IStrategy.populate_any_indicators)) + + if new_version: + tfs: List[str] = self.freqai_config["feature_parameters"].get("include_timeframes") + pairs: List[str] = self.freqai_config["feature_parameters"].get( + "include_corr_pairlist", []) + + for tf in tfs: + if tf not in base_dataframes: + base_dataframes[tf] = pd.DataFrame() + for p in pairs: + if p not in corr_dataframes: + corr_dataframes[p] = {} + if tf not in corr_dataframes[p]: + corr_dataframes[p][tf] = pd.DataFrame() + + if not prediction_dataframe.empty: + dataframe = prediction_dataframe.copy() + else: + dataframe = base_dataframes[self.config["timeframe"]].copy() + + corr_pairs: List[str] = self.freqai_config["feature_parameters"].get( + "include_corr_pairlist", []) + dataframe = self.populate_features(dataframe.copy(), pair, strategy, + corr_dataframes, base_dataframes) + metadata = {"pair": pair} + dataframe = strategy.feature_engineering_standard(dataframe.copy(), metadata=metadata) + # ensure corr pairs are always last + for corr_pair in corr_pairs: + if pair == corr_pair: + continue # dont repeat anything from whitelist + if corr_pairs and do_corr_pairs: + dataframe = self.populate_features(dataframe.copy(), corr_pair, strategy, + corr_dataframes, base_dataframes, True) + + dataframe = strategy.set_freqai_targets(dataframe.copy(), metadata=metadata) + + self.get_unique_classes_from_labels(dataframe) + + dataframe = self.remove_special_chars_from_feature_names(dataframe) + + if self.config.get('reduce_df_footprint', False): + dataframe = reduce_dataframe_footprint(dataframe) + + return dataframe + + else: + # the user is using the populate_any_indicators functions which is deprecated + + df = self.use_strategy_to_populate_indicators_old_version( + strategy, corr_dataframes, base_dataframes, pair, + prediction_dataframe, do_corr_pairs) + return df + + def use_strategy_to_populate_indicators_old_version( + self, + strategy: IStrategy, + corr_dataframes: dict = {}, + base_dataframes: dict = {}, + pair: str = "", + prediction_dataframe: DataFrame = pd.DataFrame(), + do_corr_pairs: bool = True, + ) -> DataFrame: + """ + Use the user defined strategy for populating indicators during retrain + :param strategy: IStrategy = user defined strategy object + :param corr_dataframes: dict = dict containing the df pair dataframes (for user defined timeframes) :param base_dataframes: dict = dict containing the current pair dataframes (for user defined timeframes) diff --git a/freqtrade/freqai/freqai_interface.py b/freqtrade/freqai/freqai_interface.py index 9025f358a..00342cc6b 100644 --- a/freqtrade/freqai/freqai_interface.py +++ b/freqtrade/freqai/freqai_interface.py @@ -1,3 +1,4 @@ +import inspect import logging import threading import time @@ -65,12 +66,11 @@ class IFreqaiModel(ABC): self.retrain = False self.first = True self.set_full_path() - self.follow_mode: bool = self.freqai_info.get("follow_mode", False) self.save_backtest_models: bool = self.freqai_info.get("save_backtest_models", True) if self.save_backtest_models: logger.info('Backtesting module configured to save all models.') - self.dd = FreqaiDataDrawer(Path(self.full_path), self.config, self.follow_mode) + self.dd = FreqaiDataDrawer(Path(self.full_path), self.config) # set current candle to arbitrary historical date self.current_candle: datetime = datetime.fromtimestamp(637887600, tz=timezone.utc) self.dd.current_candle = self.current_candle @@ -106,6 +106,8 @@ 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.warned_deprecated_populate_any_indicators = False + record_params(config, self.full_path) def __getstate__(self): @@ -136,6 +138,9 @@ class IFreqaiModel(ABC): self.data_provider = strategy.dp self.can_short = strategy.can_short + # check if the strategy has deprecated populate_any_indicators function + self.check_deprecated_populate_any_indicators(strategy) + if self.live: self.inference_timer('start') self.dk = FreqaiDataKitchen(self.config, self.live, metadata["pair"]) @@ -147,14 +152,11 @@ class IFreqaiModel(ABC): # (backtest window, i.e. window immediately following the training window). # FreqAI slides the window and sequentially builds the backtesting results before returning # the concatenated results for the full backtesting period back to the strategy. - elif not self.follow_mode: + else: self.dk = FreqaiDataKitchen(self.config, self.live, metadata["pair"]) - dataframe = self.dk.use_strategy_to_populate_indicators( - strategy, prediction_dataframe=dataframe, pair=metadata["pair"] - ) if not self.config.get("freqai_backtest_live_models", False): logger.info(f"Training {len(self.dk.training_timeranges)} timeranges") - dk = self.start_backtesting(dataframe, metadata, self.dk) + dk = self.start_backtesting(dataframe, metadata, self.dk, strategy) dataframe = dk.remove_features_from_df(dk.return_dataframe) else: logger.info( @@ -255,7 +257,7 @@ class IFreqaiModel(ABC): self.dd.save_metric_tracker_to_disk() def start_backtesting( - self, dataframe: DataFrame, metadata: dict, dk: FreqaiDataKitchen + self, dataframe: DataFrame, metadata: dict, dk: FreqaiDataKitchen, strategy: IStrategy ) -> FreqaiDataKitchen: """ The main broad execution for backtesting. For backtesting, each pair enters and then gets @@ -267,19 +269,22 @@ class IFreqaiModel(ABC): :param dataframe: DataFrame = strategy passed dataframe :param metadata: Dict = pair metadata :param dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only + :param strategy: Strategy to train on :return: FreqaiDataKitchen = Data management/analysis tool associated to present pair only """ self.pair_it += 1 train_it = 0 + pair = metadata["pair"] + populate_indicators = True + check_features = True # Loop enforcing the sliding window training/backtesting paradigm # tr_train is the training time range e.g. 1 historical month # tr_backtest is the backtesting time range e.g. the week directly # following tr_train. Both of these windows slide through the # entire backtest for tr_train, tr_backtest in zip(dk.training_timeranges, dk.backtesting_timeranges): - pair = metadata["pair"] (_, _, _) = self.dd.get_pair_dict_info(pair) train_it += 1 total_trains = len(dk.backtesting_timeranges) @@ -301,18 +306,44 @@ class IFreqaiModel(ABC): dk.set_new_model_names(pair, timestamp_model_id) if dk.check_if_backtest_prediction_is_valid(len_backtest_df): - self.dd.load_metadata(dk) - dk.find_features(dataframe) - self.check_if_feature_list_matches_strategy(dk) + if check_features: + self.dd.load_metadata(dk) + dataframe_dummy_features = self.dk.use_strategy_to_populate_indicators( + strategy, prediction_dataframe=dataframe.tail(1), pair=metadata["pair"] + ) + dk.find_features(dataframe_dummy_features) + self.check_if_feature_list_matches_strategy(dk) + check_features = False append_df = dk.get_backtesting_prediction() dk.append_predictions(append_df) else: - dataframe_train = dk.slice_dataframe(tr_train, dataframe) - dataframe_backtest = dk.slice_dataframe(tr_backtest, dataframe) + if populate_indicators: + dataframe = self.dk.use_strategy_to_populate_indicators( + strategy, prediction_dataframe=dataframe, pair=metadata["pair"] + ) + populate_indicators = False + + dataframe_base_train = dataframe.loc[dataframe["date"] < tr_train.stopdt, :] + dataframe_base_train = strategy.set_freqai_targets( + dataframe_base_train, metadata=metadata) + dataframe_base_backtest = dataframe.loc[dataframe["date"] < tr_backtest.stopdt, :] + dataframe_base_backtest = strategy.set_freqai_targets( + dataframe_base_backtest, metadata=metadata) + + dataframe_train = dk.slice_dataframe(tr_train, dataframe_base_train) + dataframe_backtest = dk.slice_dataframe(tr_backtest, dataframe_base_backtest) + if not self.model_exists(dk): dk.find_features(dataframe_train) dk.find_labels(dataframe_train) - self.model = self.train(dataframe_train, pair, dk) + + try: + self.model = self.train(dataframe_train, pair, dk) + except Exception as msg: + logger.warning( + f"Training {pair} raised exception {msg.__class__.__name__}. " + f"Message: {msg}, skipping.") + self.dd.pair_dict[pair]["trained_timestamp"] = int( tr_train.stopts) if self.plot_features: @@ -350,46 +381,27 @@ class IFreqaiModel(ABC): dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only """ - # update follower - if self.follow_mode: - self.dd.update_follower_metadata() - # get the model metadata associated with the current pair (_, trained_timestamp, return_null_array) = self.dd.get_pair_dict_info(metadata["pair"]) - # if the metadata doesn't exist, the follower returns null arrays to strategy - if self.follow_mode and return_null_array: - logger.info("Returning null array from follower to strategy") - self.dd.return_null_values_to_strategy(dataframe, dk) - return dk - # append the historic data once per round if self.dd.historic_data: self.dd.update_historic_data(strategy, dk) logger.debug(f'Updating historic data on pair {metadata["pair"]}') self.track_current_candle() - if not self.follow_mode: + (_, new_trained_timerange, data_load_timerange) = dk.check_if_new_training_required( + trained_timestamp + ) + dk.set_paths(metadata["pair"], new_trained_timerange.stopts) - (_, new_trained_timerange, data_load_timerange) = dk.check_if_new_training_required( - trained_timestamp - ) - dk.set_paths(metadata["pair"], new_trained_timerange.stopts) + # load candle history into memory if it is not yet. + if not self.dd.historic_data: + self.dd.load_all_pair_histories(data_load_timerange, dk) - # load candle history into memory if it is not yet. - if not self.dd.historic_data: - self.dd.load_all_pair_histories(data_load_timerange, dk) - - if not self.scanning: - self.scanning = True - self.start_scanning(strategy) - - elif self.follow_mode: - dk.set_paths(metadata["pair"], trained_timestamp) - logger.info( - "FreqAI instance set to follow_mode, finding existing pair " - f"using { self.identifier }" - ) + if not self.scanning: + self.scanning = True + self.start_scanning(strategy) # load the model and associated data into the data kitchen self.model = self.dd.load_data(metadata["pair"], dk) @@ -913,9 +925,28 @@ class IFreqaiModel(ABC): dk.return_dataframe = dk.return_dataframe.drop(columns=list(columns_to_drop)) dk.return_dataframe = pd.merge( dk.return_dataframe, saved_dataframe, how='left', left_on='date', right_on="date_pred") - # dk.return_dataframe = dk.return_dataframe[saved_dataframe.columns].fillna(0) return dk + def check_deprecated_populate_any_indicators(self, strategy: IStrategy): + """ + Check and warn if the deprecated populate_any_indicators function is used. + :param strategy: strategy object + """ + + if not self.warned_deprecated_populate_any_indicators: + self.warned_deprecated_populate_any_indicators = True + old_version = inspect.getsource(strategy.populate_any_indicators) != ( + inspect.getsource(IStrategy.populate_any_indicators)) + + if old_version: + logger.warning("DEPRECATION WARNING: " + "You are using the deprecated populate_any_indicators function. " + "This function will raise an error on March 1 2023. " + "Please update your strategy by using " + "the new feature_engineering functions. See \n" + "https://www.freqtrade.io/en/latest/freqai-feature-engineering/" + "for details.") + # Following methods which are overridden by user made prediction models. # See freqai/prediction_models/CatboostPredictionModel.py for an example. diff --git a/freqtrade/freqai/prediction_models/ReinforcementLearner_multiproc.py b/freqtrade/freqai/prediction_models/ReinforcementLearner_multiproc.py index a9be87b0b..9ee035c95 100644 --- a/freqtrade/freqai/prediction_models/ReinforcementLearner_multiproc.py +++ b/freqtrade/freqai/prediction_models/ReinforcementLearner_multiproc.py @@ -34,7 +34,7 @@ class ReinforcementLearner_multiproc(ReinforcementLearner): train_df = data_dictionary["train_features"] test_df = data_dictionary["test_features"] - env_info = self.pack_env_dict() + env_info = self.pack_env_dict(dk.pair) env_id = "train_env" self.train_env = SubprocVecEnv([make_env(self.MyRLEnv, env_id, i, 1, diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 258a45008..0db420758 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -33,6 +33,7 @@ from freqtrade.rpc.external_message_consumer import ExternalMessageConsumer from freqtrade.strategy.interface import IStrategy from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.util import FtPrecise +from freqtrade.util.binance_mig import migrate_binance_futures_names from freqtrade.wallets import Wallets @@ -177,6 +178,8 @@ class FreqtradeBot(LoggingMixin): Called on startup and after reloading the bot - triggers notifications and performs startup tasks """ + migrate_binance_futures_names(self.config) + self.rpc.startup_messages(self.config, self.pairlists, self.protections) # Update older trades with precision and precision mode self.startup_backpopulate_precision() @@ -341,7 +344,15 @@ class FreqtradeBot(LoggingMixin): try: fo = self.exchange.fetch_order_or_stoploss_order(order.order_id, order.ft_pair, order.ft_order_side == 'stoploss') - + if not order.trade: + # This should not happen, but it does if trades were deleted manually. + # This can only incur on sqlite, which doesn't enforce foreign constraints. + logger.warning( + f"Order {order.order_id} has no trade attached. " + "This may suggest a database corruption. " + f"The expected trade ID is {order.ft_trade_id}. Ignoring this order." + ) + continue self.update_trade_state(order.trade, order.order_id, fo, stoploss_order=(order.ft_order_side == 'stoploss')) @@ -352,7 +363,7 @@ class FreqtradeBot(LoggingMixin): "Order is older than 5 days. Assuming order was fully cancelled.") fo = order.to_ccxt_object() fo['status'] = 'canceled' - self.handle_timedout_order(fo, order.trade) + self.handle_cancel_order(fo, order.trade, constants.CANCEL_REASON['TIMEOUT']) except ExchangeError as e: @@ -374,7 +385,7 @@ class FreqtradeBot(LoggingMixin): for trade in trades: if not trade.is_open and not trade.fee_updated(trade.exit_side): # Get sell fee - order = trade.select_order(trade.exit_side, False) + order = trade.select_order(trade.exit_side, False, only_filled=True) if not order: order = trade.select_order('stoploss', False) if order: @@ -390,7 +401,7 @@ class FreqtradeBot(LoggingMixin): for trade in trades: with self._exit_lock: if trade.is_open and not trade.fee_updated(trade.entry_side): - order = trade.select_order(trade.entry_side, False) + order = trade.select_order(trade.entry_side, False, only_filled=True) open_order = trade.select_order(trade.entry_side, True) if order and open_order is None: logger.info( @@ -720,7 +731,7 @@ class FreqtradeBot(LoggingMixin): time_in_force=time_in_force, leverage=leverage ) - order_obj = Order.parse_from_ccxt_object(order, pair, side) + order_obj = Order.parse_from_ccxt_object(order, pair, side, amount, enter_limit_requested) order_id = order['id'] order_status = order.get('status') logger.info(f"Order #{order_id} was created for {pair} and status is {order_status}.") @@ -747,13 +758,15 @@ class FreqtradeBot(LoggingMixin): self.exchange.name, order['filled'], order['amount'], order['remaining'] ) - amount = safe_value_fallback(order, 'filled', 'amount') - enter_limit_filled_price = safe_value_fallback(order, 'average', 'price') + amount = safe_value_fallback(order, 'filled', 'amount', amount) + enter_limit_filled_price = safe_value_fallback( + order, 'average', 'price', enter_limit_filled_price) # in case of FOK the order may be filled immediately and fully elif order_status == 'closed': - amount = safe_value_fallback(order, 'filled', 'amount') - enter_limit_filled_price = safe_value_fallback(order, 'average', 'price') + amount = safe_value_fallback(order, 'filled', 'amount', amount) + enter_limit_filled_price = safe_value_fallback( + order, 'average', 'price', enter_limit_requested) # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') @@ -1094,7 +1107,8 @@ class FreqtradeBot(LoggingMixin): leverage=trade.leverage ) - order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair, 'stoploss') + order_obj = Order.parse_from_ccxt_object(stoploss_order, trade.pair, 'stoploss', + trade.amount, stop_price) trade.orders.append(order_obj) trade.stoploss_order_id = str(stoploss_order['id']) trade.stoploss_last_update = datetime.now(timezone.utc) @@ -1156,15 +1170,13 @@ class FreqtradeBot(LoggingMixin): # If enter order is fulfilled but there is no stoploss, we add a stoploss on exchange if not stoploss_order: - stoploss = ( - self.edge.stoploss(pair=trade.pair) - if self.edge else - trade.stop_loss_pct / trade.leverage - ) - if trade.is_short: - stop_price = trade.open_rate * (1 - stoploss) - else: - stop_price = trade.open_rate * (1 + stoploss) + stop_price = trade.stoploss_or_liquidation + if self.edge: + stoploss = self.edge.stoploss(pair=trade.pair) + stop_price = ( + trade.open_rate * (1 - stoploss) if trade.is_short + else trade.open_rate * (1 + stoploss) + ) if self.create_stoploss_order(trade=trade, stop_price=stop_price): # The above will return False if the placement failed and the trade was force-sold. @@ -1249,11 +1261,11 @@ class FreqtradeBot(LoggingMixin): if not_closed: if fully_cancelled or (order_obj and self.strategy.ft_check_timed_out( trade, order_obj, datetime.now(timezone.utc))): - self.handle_timedout_order(order, trade) + self.handle_cancel_order(order, trade, constants.CANCEL_REASON['TIMEOUT']) else: self.replace_order(order, order_obj, trade) - def handle_timedout_order(self, order: Dict, trade: Trade) -> None: + def handle_cancel_order(self, order: Dict, trade: Trade, reason: str) -> None: """ Check if current analyzed order timed out and cancel if necessary. :param order: Order dict grabbed with exchange.fetch_order() @@ -1261,10 +1273,10 @@ class FreqtradeBot(LoggingMixin): :return: None """ if order['side'] == trade.entry_side: - self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT']) + self.handle_cancel_enter(trade, order, reason) else: canceled = self.handle_cancel_exit( - trade, order, constants.CANCEL_REASON['TIMEOUT']) + trade, order, reason) canceled_count = trade.get_exit_order_count() max_timeouts = self.config.get('unfilledtimeout', {}).get('exit_timeout_count', 0) if canceled and max_timeouts > 0 and canceled_count >= max_timeouts: @@ -1518,7 +1530,7 @@ class FreqtradeBot(LoggingMixin): *, exit_tag: Optional[str] = None, ordertype: Optional[str] = None, - sub_trade_amt: float = None, + sub_trade_amt: Optional[float] = None, ) -> bool: """ Executes a trade exit for the given trade and limit @@ -1595,7 +1607,7 @@ class FreqtradeBot(LoggingMixin): self.handle_insufficient_funds(trade) return False - order_obj = Order.parse_from_ccxt_object(order, trade.pair, trade.exit_side) + order_obj = Order.parse_from_ccxt_object(order, trade.pair, trade.exit_side, amount, limit) trade.orders.append(order_obj) trade.open_order_id = order['id'] @@ -1612,7 +1624,7 @@ class FreqtradeBot(LoggingMixin): return True def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False, - sub_trade: bool = False, order: Order = None) -> None: + sub_trade: bool = False, order: Optional[Order] = None) -> None: """ Sends rpc notification when a sell occurred. """ @@ -1622,7 +1634,7 @@ class FreqtradeBot(LoggingMixin): # second condition is for mypy only; order will always be passed during sub trade if sub_trade and order is not None: - amount = order.safe_filled if fill else order.amount + amount = order.safe_filled if fill else order.safe_amount order_rate: float = order.safe_price profit = trade.calc_profit(rate=order_rate, amount=amount, open_rate=trade.open_rate) @@ -1725,8 +1737,9 @@ class FreqtradeBot(LoggingMixin): # Common update trade state methods # - def update_trade_state(self, trade: Trade, order_id: str, action_order: Dict[str, Any] = None, - stoploss_order: bool = False, send_msg: bool = True) -> bool: + def update_trade_state( + self, trade: Trade, order_id: str, action_order: Optional[Dict[str, Any]] = None, + stoploss_order: bool = False, send_msg: bool = True) -> bool: """ Checks trades with open orders and updates the amount if necessary Handles closing both buy and sell orders. @@ -1784,6 +1797,7 @@ class FreqtradeBot(LoggingMixin): is_short=trade.is_short, amount=trade.amount, stake_amount=trade.stake_amount, + leverage=trade.leverage, wallet_balance=trade.stake_amount, )) diff --git a/freqtrade/main.py b/freqtrade/main.py index 0a46747ea..a10620498 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -5,7 +5,7 @@ Read the documentation to know what cli arguments you need. """ import logging import sys -from typing import Any, List +from typing import Any, List, Optional from freqtrade.util.gc_setup import gc_set_threshold @@ -23,7 +23,7 @@ from freqtrade.loggers import setup_logging_pre logger = logging.getLogger('freqtrade') -def main(sysargv: List[str] = None) -> None: +def main(sysargv: Optional[List[str]] = None) -> None: """ This function will initiate the bot and start the trading loop. :return: None diff --git a/freqtrade/misc.py b/freqtrade/misc.py index 93e8da6dd..9d9cf38d7 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -6,7 +6,7 @@ import logging import re from datetime import datetime from pathlib import Path -from typing import Any, Dict, Iterator, List, Mapping, Union +from typing import Any, Dict, Iterator, List, Mapping, Optional, Union from typing.io import IO from urllib.parse import urlparse @@ -205,7 +205,7 @@ def safe_value_fallback2(dict1: dictMap, dict2: dictMap, key1: str, key2: str, d return default_value -def plural(num: float, singular: str, plural: str = None) -> str: +def plural(num: float, singular: str, plural: Optional[str] = None) -> str: return singular if (num == 1 or num == -1) else plural or singular + 's' @@ -269,6 +269,8 @@ def dataframe_to_json(dataframe: pd.DataFrame) -> str: def default(z): if isinstance(z, pd.Timestamp): return z.timestamp() * 1e3 + if z is pd.NaT: + return 'NaT' raise TypeError return str(orjson.dumps(dataframe.to_dict(orient='split'), default=default), 'utf-8') diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 81e05ade0..065a88f40 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -15,7 +15,7 @@ from pandas import DataFrame from freqtrade import constants from freqtrade.configuration import TimeRange, validate_config_consistency -from freqtrade.constants import DATETIME_PRINT_FORMAT, Config, LongShort +from freqtrade.constants import DATETIME_PRINT_FORMAT, Config, IntOrInf, LongShort from freqtrade.data import history from freqtrade.data.btanalysis import find_existing_backtest_stats, trade_list_to_dataframe from freqtrade.data.converter import trim_dataframe, trim_dataframes @@ -37,6 +37,7 @@ from freqtrade.plugins.protectionmanager import ProtectionManager from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.strategy.interface import IStrategy from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper +from freqtrade.util.binance_mig import migrate_binance_futures_data from freqtrade.wallets import Wallets @@ -157,6 +158,7 @@ class Backtesting: self._can_short = self.trading_mode != TradingMode.SPOT self._position_stacking: bool = self.config.get('position_stacking', False) self.enable_protections: bool = self.config.get('enable_protections', False) + migrate_binance_futures_data(config) self.init_backtest() @@ -573,26 +575,6 @@ class Backtesting: """ Rate is within candle, therefore filled""" return row[LOW_IDX] <= rate <= row[HIGH_IDX] - def _get_exit_trade_entry_for_candle(self, trade: LocalTrade, - row: Tuple) -> Optional[LocalTrade]: - - # Check if we need to adjust our current positions - if self.strategy.position_adjustment_enable: - trade = self._get_adjust_trade_entry_for_candle(trade, row) - - enter = row[SHORT_IDX] if trade.is_short else row[LONG_IDX] - exit_sig = row[ESHORT_IDX] if trade.is_short else row[ELONG_IDX] - exits = self.strategy.should_exit( - trade, row[OPEN_IDX], row[DATE_IDX].to_pydatetime(), # type: ignore - enter=enter, exit_=exit_sig, - low=row[LOW_IDX], high=row[HIGH_IDX] - ) - for exit_ in exits: - t = self._get_exit_for_signal(trade, row, exit_) - if t: - return t - return None - def _get_exit_for_signal( self, trade: LocalTrade, row: Tuple, exit_: ExitCheckTuple, amount: Optional[float] = None) -> Optional[LocalTrade]: @@ -662,7 +644,7 @@ class Backtesting: return None def _exit_trade(self, trade: LocalTrade, sell_row: Tuple, - close_rate: float, amount: float = None) -> Optional[LocalTrade]: + close_rate: float, amount: Optional[float] = None) -> Optional[LocalTrade]: self.order_id_counter += 1 exit_candle_time = sell_row[DATE_IDX].to_pydatetime() order_type = self.strategy.order_types['exit'] @@ -692,11 +674,10 @@ class Backtesting: trade.orders.append(order) return trade - def _get_exit_trade_entry( - self, trade: LocalTrade, row: Tuple, is_first: bool) -> Optional[LocalTrade]: + def _check_trade_exit(self, trade: LocalTrade, row: Tuple) -> Optional[LocalTrade]: exit_candle_time: datetime = row[DATE_IDX].to_pydatetime() - if is_first and self.trading_mode == TradingMode.FUTURES: + if self.trading_mode == TradingMode.FUTURES: trade.funding_fees = self.exchange.calculate_funding_fees( self.futures_data[trade.pair], amount=trade.amount, @@ -705,7 +686,22 @@ class Backtesting: close_date=exit_candle_time, ) - return self._get_exit_trade_entry_for_candle(trade, row) + # Check if we need to adjust our current positions + if self.strategy.position_adjustment_enable: + trade = self._get_adjust_trade_entry_for_candle(trade, row) + + enter = row[SHORT_IDX] if trade.is_short else row[LONG_IDX] + exit_sig = row[ESHORT_IDX] if trade.is_short else row[ELONG_IDX] + exits = self.strategy.should_exit( + trade, row[OPEN_IDX], row[DATE_IDX].to_pydatetime(), # type: ignore + enter=enter, exit_=exit_sig, + low=row[LOW_IDX], high=row[HIGH_IDX] + ) + for exit_ in exits: + t = self._get_exit_for_signal(trade, row, exit_) + if t: + return t + return None def get_valid_price_and_stake( self, pair: str, row: Tuple, propose_rate: float, stake_amount: float, @@ -779,6 +775,11 @@ class Backtesting: trade: Optional[LocalTrade] = None, requested_rate: Optional[float] = None, requested_stake: Optional[float] = None) -> Optional[LocalTrade]: + """ + :param trade: Trade to adjust - initial entry if None + :param requested_rate: Adjusted entry rate + :param requested_stake: Stake amount for adjusted orders (`adjust_entry_price`). + """ current_time = row[DATE_IDX].to_pydatetime() entry_tag = row[ENTER_TAG_IDX] if len(row) >= ENTER_TAG_IDX + 1 else None @@ -804,7 +805,7 @@ class Backtesting: return trade time_in_force = self.strategy.order_time_in_force['entry'] - if stake_amount and (not min_stake_amount or stake_amount > min_stake_amount): + if stake_amount and (not min_stake_amount or stake_amount >= min_stake_amount): self.order_id_counter += 1 base_currency = self.exchange.get_pair_base_currency(pair) amount_p = (stake_amount / propose_rate) * leverage @@ -867,6 +868,7 @@ class Backtesting: open_rate=propose_rate, amount=amount, stake_amount=trade.stake_amount, + leverage=trade.leverage, wallet_balance=trade.stake_amount, is_short=is_short, )) @@ -920,8 +922,9 @@ class Backtesting: trade.close(exit_row[OPEN_IDX], show_msg=False) LocalTrade.close_bt_trade(trade) - def trade_slot_available(self, max_open_trades: int, open_trade_count: int) -> bool: + def trade_slot_available(self, open_trade_count: int) -> bool: # Always allow trades when max_open_trades is enabled. + max_open_trades: IntOrInf = self.config['max_open_trades'] if max_open_trades <= 0 or open_trade_count < max_open_trades: return True # Rejected trade @@ -1051,7 +1054,8 @@ class Backtesting: def backtest_loop( self, row: Tuple, pair: str, current_time: datetime, end_date: datetime, - max_open_trades: int, open_trade_count_start: int, is_first: bool = True) -> int: + open_trade_count_start: int, trade_dir: Optional[LongShort], + is_first: bool = True) -> int: """ NOTE: This method is used by Hyperopt at each iteration. Please keep it optimized. @@ -1070,11 +1074,10 @@ class Backtesting: # max_open_trades must be respected # don't open on the last row # We only open trades on the main candle, not on detail candles - trade_dir = self.check_for_trade_entry(row) if ( (self._position_stacking or len(LocalTrade.bt_trades_open_pp[pair]) == 0) and is_first - and self.trade_slot_available(max_open_trades, open_trade_count_start) + and self.trade_slot_available(open_trade_count_start) and current_time != end_date and trade_dir is not None and not PairLocks.is_pair_locked(pair, row[DATE_IDX], trade_dir) @@ -1099,7 +1102,7 @@ class Backtesting: # 4. Create exit orders (if any) if not trade.open_order_id: - self._get_exit_trade_entry(trade, row, is_first) # Place exit order if necessary + self._check_trade_exit(trade, row) # Place exit order if necessary # 5. Process exit orders. order = trade.select_order(trade.exit_side, is_open=True) @@ -1121,8 +1124,7 @@ class Backtesting: return open_trade_count_start def backtest(self, processed: Dict, - start_date: datetime, end_date: datetime, - max_open_trades: int = 0) -> Dict[str, Any]: + start_date: datetime, end_date: datetime) -> Dict[str, Any]: """ Implement backtesting functionality @@ -1134,7 +1136,6 @@ class Backtesting: optimize memory usage! :param start_date: backtesting timerange start datetime :param end_date: backtesting timerange end datetime - :param max_open_trades: maximum number of concurrent trades, <= 0 means unlimited :return: DataFrame with trades (results of backtesting) """ self.prepare_backtest(self.enable_protections) @@ -1164,7 +1165,15 @@ class Backtesting: indexes[pair] = row_index self.dataprovider._set_dataframe_max_index(row_index) current_detail_time: datetime = row[DATE_IDX].to_pydatetime() - if self.timeframe_detail and pair in self.detail_data: + trade_dir: Optional[LongShort] = self.check_for_trade_entry(row) + + if ( + (trade_dir is not None or len(LocalTrade.bt_trades_open_pp[pair]) > 0) + and self.timeframe_detail and pair in self.detail_data + ): + # Spread out into detail timeframe. + # Should only happen when we are either in a trade for this pair + # or when we got the signal for a new trade. exit_candle_end = current_detail_time + timedelta(minutes=self.timeframe_min) detail_data = self.detail_data[pair] @@ -1175,8 +1184,8 @@ class Backtesting: if len(detail_data) == 0: # Fall back to "regular" data if no detail data was found for this candle open_trade_count_start = self.backtest_loop( - row, pair, current_time, end_date, max_open_trades, - open_trade_count_start) + row, pair, current_time, end_date, + open_trade_count_start, trade_dir) continue detail_data.loc[:, 'enter_long'] = row[LONG_IDX] detail_data.loc[:, 'exit_long'] = row[ELONG_IDX] @@ -1188,13 +1197,14 @@ class Backtesting: current_time_det = current_time for det_row in detail_data[HEADERS].values.tolist(): open_trade_count_start = self.backtest_loop( - det_row, pair, current_time_det, end_date, max_open_trades, - open_trade_count_start, is_first) + det_row, pair, current_time_det, end_date, + open_trade_count_start, trade_dir, is_first) current_time_det += timedelta(minutes=self.timeframe_detail_min) is_first = False else: open_trade_count_start = self.backtest_loop( - row, pair, current_time, end_date, max_open_trades, open_trade_count_start) + row, pair, current_time, end_date, + open_trade_count_start, trade_dir) # Move time one configured time_interval ahead. self.progress.increment() @@ -1226,13 +1236,11 @@ class Backtesting: self._set_strategy(strat) # Use max_open_trades in backtesting, except --disable-max-market-positions is set - if self.config.get('use_max_market_positions', True): - # Must come from strategy config, as the strategy may modify this setting. - max_open_trades = self.strategy.config['max_open_trades'] - else: + if not self.config.get('use_max_market_positions', True): logger.info( 'Ignoring max_open_trades (--disable-max-market-positions was used) ...') - max_open_trades = 0 + self.strategy.max_open_trades = float('inf') + self.config.update({'max_open_trades': self.strategy.max_open_trades}) # need to reprocess data every time to populate signals preprocessed = self.strategy.advise_all_indicators(data) @@ -1255,7 +1263,6 @@ class Backtesting: processed=preprocessed, start_date=min_date, end_date=max_date, - max_open_trades=max_open_trades, ) backtest_end_time = datetime.now(timezone.utc) results.update({ diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index b459d59f2..96c95c4a2 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -74,6 +74,7 @@ class Hyperopt: self.roi_space: List[Dimension] = [] self.stoploss_space: List[Dimension] = [] self.trailing_space: List[Dimension] = [] + self.max_open_trades_space: List[Dimension] = [] self.dimensions: List[Dimension] = [] self.config = config @@ -117,11 +118,10 @@ class Hyperopt: self.current_best_epoch: Optional[Dict[str, Any]] = None # Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set - if self.config.get('use_max_market_positions', True): - self.max_open_trades = self.config['max_open_trades'] - else: + if not self.config.get('use_max_market_positions', True): logger.debug('Ignoring max_open_trades (--disable-max-market-positions was used) ...') - self.max_open_trades = 0 + self.backtesting.strategy.max_open_trades = float('inf') + config.update({'max_open_trades': self.backtesting.strategy.max_open_trades}) if HyperoptTools.has_space(self.config, 'sell'): # Make sure use_exit_signal is enabled @@ -209,6 +209,10 @@ class Hyperopt: result['stoploss'] = {p.name: params.get(p.name) for p in self.stoploss_space} if HyperoptTools.has_space(self.config, 'trailing'): result['trailing'] = self.custom_hyperopt.generate_trailing_params(params) + if HyperoptTools.has_space(self.config, 'trades'): + result['max_open_trades'] = { + 'max_open_trades': self.backtesting.strategy.max_open_trades + if self.backtesting.strategy.max_open_trades != float('inf') else -1} return result @@ -229,6 +233,8 @@ class Hyperopt: 'trailing_stop_positive_offset': strategy.trailing_stop_positive_offset, 'trailing_only_offset_is_reached': strategy.trailing_only_offset_is_reached, } + if not HyperoptTools.has_space(self.config, 'trades'): + result['max_open_trades'] = {'max_open_trades': strategy.max_open_trades} return result def print_results(self, results) -> None: @@ -280,8 +286,13 @@ class Hyperopt: logger.debug("Hyperopt has 'trailing' space") self.trailing_space = self.custom_hyperopt.trailing_space() + if HyperoptTools.has_space(self.config, 'trades'): + logger.debug("Hyperopt has 'trades' space") + self.max_open_trades_space = self.custom_hyperopt.max_open_trades_space() + self.dimensions = (self.buy_space + self.sell_space + self.protection_space - + self.roi_space + self.stoploss_space + self.trailing_space) + + self.roi_space + self.stoploss_space + self.trailing_space + + self.max_open_trades_space) def assign_params(self, params_dict: Dict, category: str) -> None: """ @@ -328,6 +339,20 @@ class Hyperopt: self.backtesting.strategy.trailing_only_offset_is_reached = \ d['trailing_only_offset_is_reached'] + if HyperoptTools.has_space(self.config, 'trades'): + if self.config["stake_amount"] == "unlimited" and \ + (params_dict['max_open_trades'] == -1 or params_dict['max_open_trades'] == 0): + # Ignore unlimited max open trades if stake amount is unlimited + params_dict.update({'max_open_trades': self.config['max_open_trades']}) + + updated_max_open_trades = int(params_dict['max_open_trades']) \ + if (params_dict['max_open_trades'] != -1 + and params_dict['max_open_trades'] != 0) else float('inf') + + self.config.update({'max_open_trades': updated_max_open_trades}) + + self.backtesting.strategy.max_open_trades = updated_max_open_trades + with self.data_pickle_file.open('rb') as f: processed = load(f, mmap_mode='r') if self.analyze_per_epoch: @@ -337,8 +362,7 @@ class Hyperopt: bt_results = self.backtesting.backtest( processed=processed, start_date=self.min_date, - end_date=self.max_date, - max_open_trades=self.max_open_trades, + end_date=self.max_date ) backtest_end_time = datetime.now(timezone.utc) bt_results.update({ diff --git a/freqtrade/optimize/hyperopt_auto.py b/freqtrade/optimize/hyperopt_auto.py index 5bc0af42b..13c036a28 100644 --- a/freqtrade/optimize/hyperopt_auto.py +++ b/freqtrade/optimize/hyperopt_auto.py @@ -91,5 +91,8 @@ class HyperOptAuto(IHyperOpt): def trailing_space(self) -> List['Dimension']: return self._get_func('trailing_space')() + def max_open_trades_space(self) -> List['Dimension']: + return self._get_func('max_open_trades_space')() + def generate_estimator(self, dimensions: List['Dimension'], **kwargs) -> EstimatorType: return self._get_func('generate_estimator')(dimensions=dimensions, **kwargs) diff --git a/freqtrade/optimize/hyperopt_interface.py b/freqtrade/optimize/hyperopt_interface.py index a7c64ffb0..65dd7ed87 100644 --- a/freqtrade/optimize/hyperopt_interface.py +++ b/freqtrade/optimize/hyperopt_interface.py @@ -191,6 +191,16 @@ class IHyperOpt(ABC): Categorical([True, False], name='trailing_only_offset_is_reached'), ] + def max_open_trades_space(self) -> List[Dimension]: + """ + Create a max open trades space. + + You may override it in your custom Hyperopt class. + """ + return [ + Integer(-1, 10, name='max_open_trades'), + ] + # This is needed for proper unpickling the class attribute timeframe # which is set to the actual value by the resolver. # Why do I still need such shamanic mantras in modern python? diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_calmar.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_calmar.py index 2b591824f..b8935b08e 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_calmar.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_calmar.py @@ -5,13 +5,11 @@ This module defines the alternative HyperOptLoss class which can be used for Hyperoptimization. """ from datetime import datetime -from math import sqrt as msqrt -from typing import Any, Dict from pandas import DataFrame from freqtrade.constants import Config -from freqtrade.data.metrics import calculate_max_drawdown +from freqtrade.data.metrics import calculate_calmar from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -23,42 +21,15 @@ class CalmarHyperOptLoss(IHyperOptLoss): """ @staticmethod - def hyperopt_loss_function( - results: DataFrame, - trade_count: int, - min_date: datetime, - max_date: datetime, - config: Config, - processed: Dict[str, DataFrame], - backtest_stats: Dict[str, Any], - *args, - **kwargs - ) -> float: + def hyperopt_loss_function(results: DataFrame, trade_count: int, + min_date: datetime, max_date: datetime, + config: Config, *args, **kwargs) -> float: """ Objective function, returns smaller number for more optimal results. Uses Calmar Ratio calculation. """ - total_profit = backtest_stats["profit_total"] - days_period = (max_date - min_date).days - - # adding slippage of 0.1% per trade - total_profit = total_profit - 0.0005 - expected_returns_mean = total_profit.sum() / days_period * 100 - - # calculate max drawdown - try: - _, _, _, _, _, max_drawdown = calculate_max_drawdown( - results, value_col="profit_abs" - ) - except ValueError: - max_drawdown = 0 - - if max_drawdown != 0: - calmar_ratio = expected_returns_mean / max_drawdown * msqrt(365) - else: - # Define high (negative) calmar ratio to be clear that this is NOT optimal. - calmar_ratio = -20.0 - + starting_balance = config['dry_run_wallet'] + calmar_ratio = calculate_calmar(results, min_date, max_date, starting_balance) # print(expected_returns_mean, max_drawdown, calmar_ratio) return -calmar_ratio diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe.py index 2c8ae552d..8ebb90fc5 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe.py @@ -6,9 +6,10 @@ Hyperoptimization. """ from datetime import datetime -import numpy as np from pandas import DataFrame +from freqtrade.constants import Config +from freqtrade.data.metrics import calculate_sharpe from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -22,25 +23,13 @@ class SharpeHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function(results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, - *args, **kwargs) -> float: + config: Config, *args, **kwargs) -> float: """ Objective function, returns smaller number for more optimal results. Uses Sharpe Ratio calculation. """ - total_profit = results["profit_ratio"] - days_period = (max_date - min_date).days - - # adding slippage of 0.1% per trade - total_profit = total_profit - 0.0005 - expected_returns_mean = total_profit.sum() / days_period - up_stdev = np.std(total_profit) - - if up_stdev != 0: - sharp_ratio = expected_returns_mean / up_stdev * np.sqrt(365) - else: - # Define high (negative) sharpe ratio to be clear that this is NOT optimal. - sharp_ratio = -20. - + starting_balance = config['dry_run_wallet'] + sharp_ratio = calculate_sharpe(results, min_date, max_date, starting_balance) # print(expected_returns_mean, up_stdev, sharp_ratio) return -sharp_ratio diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe_daily.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe_daily.py index 9520123ee..88c97989a 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe_daily.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe_daily.py @@ -44,7 +44,7 @@ class SharpeHyperOptLossDaily(IHyperOptLoss): sum_daily = ( results.resample(resample_freq, on='close_date').agg( - {"profit_ratio_after_slippage": sum}).reindex(t_index).fillna(0) + {"profit_ratio_after_slippage": 'sum'}).reindex(t_index).fillna(0) ) total_profit = sum_daily["profit_ratio_after_slippage"] - risk_free_rate diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino.py index b231370dd..a0122a0bf 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino.py @@ -6,9 +6,10 @@ Hyperoptimization. """ from datetime import datetime -import numpy as np from pandas import DataFrame +from freqtrade.constants import Config +from freqtrade.data.metrics import calculate_sortino from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -22,28 +23,13 @@ class SortinoHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function(results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, - *args, **kwargs) -> float: + config: Config, *args, **kwargs) -> float: """ Objective function, returns smaller number for more optimal results. Uses Sortino Ratio calculation. """ - total_profit = results["profit_ratio"] - days_period = (max_date - min_date).days - - # adding slippage of 0.1% per trade - total_profit = total_profit - 0.0005 - expected_returns_mean = total_profit.sum() / days_period - - results['downside_returns'] = 0 - results.loc[total_profit < 0, 'downside_returns'] = results['profit_ratio'] - down_stdev = np.std(results['downside_returns']) - - if down_stdev != 0: - sortino_ratio = expected_returns_mean / down_stdev * np.sqrt(365) - else: - # Define high (negative) sortino ratio to be clear that this is NOT optimal. - sortino_ratio = -20. - + starting_balance = config['dry_run_wallet'] + sortino_ratio = calculate_sortino(results, min_date, max_date, starting_balance) # print(expected_returns_mean, down_stdev, sortino_ratio) return -sortino_ratio diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino_daily.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino_daily.py index fac96664d..f5fe4590e 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino_daily.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino_daily.py @@ -46,7 +46,7 @@ class SortinoHyperOptLossDaily(IHyperOptLoss): sum_daily = ( results.resample(resample_freq, on='close_date').agg( - {"profit_ratio_after_slippage": sum}).reindex(t_index).fillna(0) + {"profit_ratio_after_slippage": 'sum'}).reindex(t_index).fillna(0) ) total_profit = sum_daily["profit_ratio_after_slippage"] - minimum_acceptable_return diff --git a/freqtrade/optimize/hyperopt_tools.py b/freqtrade/optimize/hyperopt_tools.py index 7007ec55e..cf0650f7d 100755 --- a/freqtrade/optimize/hyperopt_tools.py +++ b/freqtrade/optimize/hyperopt_tools.py @@ -96,7 +96,7 @@ class HyperoptTools(): Tell if the space value is contained in the configuration """ # 'trailing' and 'protection spaces are not included in the 'default' set of spaces - if space in ('trailing', 'protection'): + if space in ('trailing', 'protection', 'trades'): return any(s in config['spaces'] for s in [space, 'all']) else: return any(s in config['spaces'] for s in [space, 'all', 'default']) @@ -170,7 +170,7 @@ class HyperoptTools(): @staticmethod def show_epoch_details(results, total_epochs: int, print_json: bool, - no_header: bool = False, header_str: str = None) -> None: + no_header: bool = False, header_str: Optional[str] = None) -> None: """ Display details of the hyperopt result """ @@ -187,7 +187,8 @@ class HyperoptTools(): if print_json: result_dict: Dict = {} - for s in ['buy', 'sell', 'protection', 'roi', 'stoploss', 'trailing']: + for s in ['buy', 'sell', 'protection', + 'roi', 'stoploss', 'trailing', 'max_open_trades']: HyperoptTools._params_update_for_json(result_dict, params, non_optimized, s) print(rapidjson.dumps(result_dict, default=str, number_mode=rapidjson.NM_NATIVE)) @@ -201,6 +202,8 @@ class HyperoptTools(): HyperoptTools._params_pretty_print(params, 'roi', "ROI table:", non_optimized) HyperoptTools._params_pretty_print(params, 'stoploss', "Stoploss:", non_optimized) HyperoptTools._params_pretty_print(params, 'trailing', "Trailing stop:", non_optimized) + HyperoptTools._params_pretty_print( + params, 'max_open_trades', "Max Open Trades:", non_optimized) @staticmethod def _params_update_for_json(result_dict, params, non_optimized, space: str) -> None: @@ -239,7 +242,9 @@ class HyperoptTools(): if space == "stoploss": stoploss = safe_value_fallback2(space_params, no_params, space, space) result += (f"stoploss = {stoploss}{appendix}") - + elif space == "max_open_trades": + max_open_trades = safe_value_fallback2(space_params, no_params, space, space) + result += (f"max_open_trades = {max_open_trades}{appendix}") elif space == "roi": result = result[:-1] + f'{appendix}\n' minimal_roi_result = rapidjson.dumps({ @@ -259,7 +264,7 @@ class HyperoptTools(): print(result) @staticmethod - def _space_params(params, space: str, r: int = None) -> Dict: + def _space_params(params, space: str, r: Optional[int] = None) -> Dict: d = params.get(space) if d: # Round floats to `r` digits after the decimal point if requested diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 7de8f1a47..83f698fbe 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -8,7 +8,7 @@ from pandas import DataFrame, to_datetime from tabulate import tabulate from freqtrade.constants import (DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN, UNLIMITED_STAKE_AMOUNT, - Config) + Config, IntOrInf) from freqtrade.data.metrics import (calculate_cagr, calculate_calmar, calculate_csum, calculate_expectancy, calculate_market_change, calculate_max_drawdown, calculate_sharpe, calculate_sortino) @@ -191,7 +191,7 @@ def generate_tag_metrics(tag_type: str, return [] -def generate_exit_reason_stats(max_open_trades: int, results: DataFrame) -> List[Dict]: +def generate_exit_reason_stats(max_open_trades: IntOrInf, results: DataFrame) -> List[Dict]: """ Generate small table outlining Backtest results :param max_open_trades: Max_open_trades parameter diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index 44a6756d1..87b172846 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -214,17 +214,22 @@ def migrate_orders_table(engine, table_back_name: str, cols_order: List): average = get_column_def(cols_order, 'average', 'null') stop_price = get_column_def(cols_order, 'stop_price', 'null') funding_fee = get_column_def(cols_order, 'funding_fee', '0.0') + ft_amount = get_column_def(cols_order, 'ft_amount', 'coalesce(amount, 0.0)') + ft_price = get_column_def(cols_order, 'ft_price', 'coalesce(price, 0.0)') # sqlite does not support literals for booleans with engine.begin() as connection: connection.execute(text(f""" insert into orders (id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id, status, symbol, order_type, side, price, amount, filled, average, remaining, cost, - stop_price, order_date, order_filled_date, order_update_date, ft_fee_base, funding_fee) + stop_price, order_date, order_filled_date, order_update_date, ft_fee_base, funding_fee, + ft_amount, ft_price + ) select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id, status, symbol, order_type, side, price, amount, filled, {average} average, remaining, cost, {stop_price} stop_price, order_date, order_filled_date, - order_update_date, {ft_fee_base} ft_fee_base, {funding_fee} funding_fee + order_update_date, {ft_fee_base} ft_fee_base, {funding_fee} funding_fee, + {ft_amount} ft_amount, {ft_price} ft_price from {table_back_name} """)) @@ -311,8 +316,8 @@ def check_migrate(engine, decl_base, previous_tables) -> None: # if ('orders' not in previous_tables # or not has_column(cols_orders, 'funding_fee')): migrating = False - # if not has_column(cols_orders, 'funding_fee'): - if not has_column(cols_trades, 'max_stake_amount'): + # if not has_column(cols_trades, 'max_stake_amount'): + if not has_column(cols_orders, 'ft_price'): migrating = True logger.info(f"Running database migration for trades - " f"backup: {table_back_name}, {order_table_bak_name}") diff --git a/freqtrade/persistence/pairlock.py b/freqtrade/persistence/pairlock.py index 926c641b0..938cd14bc 100644 --- a/freqtrade/persistence/pairlock.py +++ b/freqtrade/persistence/pairlock.py @@ -21,9 +21,9 @@ class PairLock(_DECL_BASE): side = Column(String(25), nullable=False, default="*") reason = Column(String(255), nullable=True) # Time the pair was locked (start time) - lock_time = Column(DateTime, nullable=False) + lock_time = Column(DateTime(), nullable=False) # Time until the pair is locked (end time) - lock_end_time = Column(DateTime, nullable=False, index=True) + lock_end_time = Column(DateTime(), nullable=False, index=True) active = Column(Boolean, nullable=False, default=True, index=True) diff --git a/freqtrade/persistence/pairlock_middleware.py b/freqtrade/persistence/pairlock_middleware.py index 69d8b098b..4485bb88e 100644 --- a/freqtrade/persistence/pairlock_middleware.py +++ b/freqtrade/persistence/pairlock_middleware.py @@ -30,8 +30,8 @@ class PairLocks(): PairLocks.locks = [] @staticmethod - def lock_pair(pair: str, until: datetime, reason: str = None, *, - now: datetime = None, side: str = '*') -> PairLock: + def lock_pair(pair: str, until: datetime, reason: Optional[str] = None, *, + now: Optional[datetime] = None, side: str = '*') -> PairLock: """ Create PairLock from now to "until". Uses database by default, unless PairLocks.use_db is set to False, diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 0c36d2378..535067084 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -46,29 +46,31 @@ class Order(_DECL_BASE): trade = relationship("Trade", back_populates="orders") # order_side can only be 'buy', 'sell' or 'stoploss' - ft_order_side: str = Column(String(25), nullable=False) - ft_pair: str = Column(String(25), nullable=False) + ft_order_side = Column(String(25), nullable=False) + ft_pair = Column(String(25), nullable=False) ft_is_open = Column(Boolean, nullable=False, default=True, index=True) + ft_amount = Column(Float(), nullable=False) + ft_price = Column(Float(), nullable=False) - order_id: str = Column(String(255), nullable=False, index=True) + order_id = Column(String(255), nullable=False, index=True) status = Column(String(255), nullable=True) symbol = Column(String(25), nullable=True) - order_type: str = Column(String(50), nullable=True) + order_type = Column(String(50), nullable=True) side = Column(String(25), nullable=True) - price = Column(Float, nullable=True) - average = Column(Float, nullable=True) - amount = Column(Float, nullable=True) - filled = Column(Float, nullable=True) - remaining = Column(Float, nullable=True) - cost = Column(Float, nullable=True) - stop_price = Column(Float, nullable=True) - order_date = Column(DateTime, nullable=True, default=datetime.utcnow) - order_filled_date = Column(DateTime, nullable=True) - order_update_date = Column(DateTime, nullable=True) + price = Column(Float(), nullable=True) + average = Column(Float(), nullable=True) + amount = Column(Float(), nullable=True) + filled = Column(Float(), nullable=True) + remaining = Column(Float(), nullable=True) + cost = Column(Float(), nullable=True) + stop_price = Column(Float(), nullable=True) + order_date = Column(DateTime(), nullable=True, default=datetime.utcnow) + order_filled_date = Column(DateTime(), nullable=True) + order_update_date = Column(DateTime(), nullable=True) - funding_fee = Column(Float, nullable=True) + funding_fee = Column(Float(), nullable=True) - ft_fee_base = Column(Float, nullable=True) + ft_fee_base = Column(Float(), nullable=True) @property def order_date_utc(self) -> datetime: @@ -82,9 +84,13 @@ class Order(_DECL_BASE): self.order_filled_date.replace(tzinfo=timezone.utc) if self.order_filled_date else None ) + @property + def safe_amount(self) -> float: + return self.amount or self.ft_amount + @property def safe_price(self) -> float: - return self.average or self.price or self.stop_price + return self.average or self.price or self.stop_price or self.ft_price @property def safe_filled(self) -> float: @@ -94,7 +100,7 @@ class Order(_DECL_BASE): def safe_remaining(self) -> float: return ( self.remaining if self.remaining is not None else - self.amount - (self.filled or 0.0) + self.safe_amount - (self.filled or 0.0) ) @property @@ -140,7 +146,7 @@ class Order(_DECL_BASE): # Assign funding fee up to this point # (represents the funding fee since the last order) self.funding_fee = self.trade.funding_fees - if (order.get('filled', 0.0) or 0.0) > 0: + if (order.get('filled', 0.0) or 0.0) > 0 and not self.order_filled_date: self.order_filled_date = datetime.now(timezone.utc) self.order_update_date = datetime.now(timezone.utc) @@ -166,7 +172,7 @@ class Order(_DECL_BASE): def to_json(self, entry_side: str, minified: bool = False) -> Dict[str, Any]: resp = { - 'amount': self.amount, + 'amount': self.safe_amount, 'safe_price': self.safe_price, 'ft_order_side': self.ft_order_side, 'order_filled_timestamp': int(self.order_filled_date.replace( @@ -227,11 +233,20 @@ class Order(_DECL_BASE): logger.warning(f"Did not find order for {order}.") @staticmethod - def parse_from_ccxt_object(order: Dict[str, Any], pair: str, side: str) -> 'Order': + def parse_from_ccxt_object( + order: Dict[str, Any], pair: str, side: str, + amount: Optional[float] = None, price: Optional[float] = None) -> 'Order': """ Parse an order from a ccxt object and return a new order Object. + Optional support for overriding amount and price is only used for test simplification. """ - o = Order(order_id=str(order['id']), ft_order_side=side, ft_pair=pair) + o = Order( + order_id=str(order['id']), + ft_order_side=side, + ft_pair=pair, + ft_amount=amount if amount else order['amount'], + ft_price=price if price else order['price'], + ) o.update_from_ccxt_object(order) return o @@ -784,7 +799,7 @@ class LocalTrade(): else: return close_trade - fees - def calc_close_trade_value(self, rate: float, amount: float = None) -> float: + def calc_close_trade_value(self, rate: float, amount: Optional[float] = None) -> float: """ Calculate the Trade's close value including fees :param rate: rate to compare with. @@ -822,7 +837,8 @@ class LocalTrade(): raise OperationalException( f"{self.trading_mode.value} trading is not yet available using freqtrade") - def calc_profit(self, rate: float, amount: float = None, open_rate: float = None) -> float: + def calc_profit(self, rate: float, amount: Optional[float] = None, + open_rate: Optional[float] = None) -> float: """ Calculate the absolute profit in stake currency between Close and Open trade :param rate: close rate to compare with. @@ -843,7 +859,8 @@ class LocalTrade(): return float(f"{profit:.8f}") def calc_profit_ratio( - self, rate: float, amount: float = None, open_rate: float = None) -> float: + self, rate: float, amount: Optional[float] = None, + open_rate: Optional[float] = None) -> float: """ Calculates the profit as ratio (including fee). :param rate: rate to compare with. @@ -956,11 +973,12 @@ class LocalTrade(): return None def select_order(self, order_side: Optional[str] = None, - is_open: Optional[bool] = None) -> Optional[Order]: + is_open: Optional[bool] = None, only_filled: bool = False) -> Optional[Order]: """ Finds latest order for this orderside and status :param order_side: ft_order_side of the order (either 'buy', 'sell' or 'stoploss') :param is_open: Only search for open orders? + :param only_filled: Only search for Filled orders (only valid with is_open=False). :return: latest Order object if it exists, else None """ orders = self.orders @@ -968,6 +986,8 @@ class LocalTrade(): orders = [o for o in orders if o.ft_order_side == order_side] if is_open is not None: orders = [o for o in orders if o.ft_is_open == is_open] + if is_open is False and only_filled: + orders = [o for o in orders if o.filled and o.status in NON_OPEN_EXCHANGE_STATES] if len(orders) > 0: return orders[-1] else: @@ -1041,8 +1061,9 @@ class LocalTrade(): return self.exit_reason @staticmethod - def get_trades_proxy(*, pair: str = None, is_open: bool = None, - open_date: datetime = None, close_date: datetime = None, + def get_trades_proxy(*, pair: Optional[str] = None, is_open: Optional[bool] = None, + open_date: Optional[datetime] = None, + close_date: Optional[datetime] = None, ) -> List['LocalTrade']: """ Helper function to query Trades. @@ -1156,44 +1177,44 @@ class Trade(_DECL_BASE, LocalTrade): base_currency = Column(String(25), nullable=True) stake_currency = Column(String(25), nullable=True) is_open = Column(Boolean, nullable=False, default=True, index=True) - fee_open = Column(Float, nullable=False, default=0.0) - fee_open_cost = Column(Float, nullable=True) + fee_open = Column(Float(), nullable=False, default=0.0) + fee_open_cost = Column(Float(), nullable=True) fee_open_currency = Column(String(25), nullable=True) - fee_close = Column(Float, nullable=False, default=0.0) - fee_close_cost = Column(Float, nullable=True) + fee_close = Column(Float(), nullable=False, default=0.0) + fee_close_cost = Column(Float(), nullable=True) fee_close_currency = Column(String(25), nullable=True) - open_rate: float = Column(Float) - open_rate_requested = Column(Float) + open_rate: float = Column(Float()) + open_rate_requested = Column(Float()) # open_trade_value - calculated via _calc_open_trade_value - open_trade_value = Column(Float) - close_rate: Optional[float] = Column(Float) - close_rate_requested = Column(Float) - realized_profit = Column(Float, default=0.0) - close_profit = Column(Float) - close_profit_abs = Column(Float) - stake_amount = Column(Float, nullable=False) - max_stake_amount = Column(Float) - amount = Column(Float) - amount_requested = Column(Float) - open_date = Column(DateTime, nullable=False, default=datetime.utcnow) - close_date = Column(DateTime) + open_trade_value = Column(Float()) + close_rate: Optional[float] = Column(Float()) + close_rate_requested = Column(Float()) + realized_profit = Column(Float(), default=0.0) + close_profit = Column(Float()) + close_profit_abs = Column(Float()) + stake_amount = Column(Float(), nullable=False) + max_stake_amount = Column(Float()) + amount = Column(Float()) + amount_requested = Column(Float()) + open_date = Column(DateTime(), nullable=False, default=datetime.utcnow) + close_date = Column(DateTime()) open_order_id = Column(String(255)) # absolute value of the stop loss - stop_loss = Column(Float, nullable=True, default=0.0) + stop_loss = Column(Float(), nullable=True, default=0.0) # percentage value of the stop loss - stop_loss_pct = Column(Float, nullable=True) + stop_loss_pct = Column(Float(), nullable=True) # absolute value of the initial stop loss - initial_stop_loss = Column(Float, nullable=True, default=0.0) + initial_stop_loss = Column(Float(), nullable=True, default=0.0) # percentage value of the initial stop loss - initial_stop_loss_pct = Column(Float, nullable=True) + initial_stop_loss_pct = Column(Float(), nullable=True) # stoploss order id which is on exchange stoploss_order_id = Column(String(255), nullable=True, index=True) # last update time of the stoploss order on exchange - stoploss_last_update = Column(DateTime, nullable=True) + stoploss_last_update = Column(DateTime(), nullable=True) # absolute value of the highest reached price - max_rate = Column(Float, nullable=True, default=0.0) + max_rate = Column(Float(), nullable=True, default=0.0) # Lowest price reached - min_rate = Column(Float, nullable=True) + min_rate = Column(Float(), nullable=True) exit_reason = Column(String(100), nullable=True) exit_order_status = Column(String(100), nullable=True) strategy = Column(String(100), nullable=True) @@ -1201,21 +1222,21 @@ class Trade(_DECL_BASE, LocalTrade): timeframe = Column(Integer, nullable=True) trading_mode = Column(Enum(TradingMode), nullable=True) - amount_precision = Column(Float, nullable=True) - price_precision = Column(Float, nullable=True) + amount_precision = Column(Float(), nullable=True) + price_precision = Column(Float(), nullable=True) precision_mode = Column(Integer, nullable=True) - contract_size = Column(Float, nullable=True) + contract_size = Column(Float(), nullable=True) # Leverage trading properties - leverage = Column(Float, nullable=True, default=1.0) + leverage = Column(Float(), nullable=True, default=1.0) is_short = Column(Boolean, nullable=False, default=False) - liquidation_price = Column(Float, nullable=True) + liquidation_price = Column(Float(), nullable=True) # Margin Trading Properties - interest_rate = Column(Float, nullable=False, default=0.0) + interest_rate = Column(Float(), nullable=False, default=0.0) # Futures properties - funding_fees = Column(Float, nullable=True, default=None) + funding_fees = Column(Float(), nullable=True, default=None) def __init__(self, **kwargs): super().__init__(**kwargs) @@ -1239,8 +1260,9 @@ class Trade(_DECL_BASE, LocalTrade): Trade.query.session.rollback() @staticmethod - def get_trades_proxy(*, pair: str = None, is_open: bool = None, - open_date: datetime = None, close_date: datetime = None, + def get_trades_proxy(*, pair: Optional[str] = None, is_open: Optional[bool] = None, + open_date: Optional[datetime] = None, + close_date: Optional[datetime] = None, ) -> List['LocalTrade']: """ Helper function to query Trades.j diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 9c8787242..1b2ee44da 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -436,11 +436,11 @@ def create_scatter( return None -def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFrame = None, *, - indicators1: List[str] = [], - indicators2: List[str] = [], - plot_config: Dict[str, Dict] = {}, - ) -> go.Figure: +def generate_candlestick_graph( + pair: str, data: pd.DataFrame, trades: Optional[pd.DataFrame] = None, *, + indicators1: List[str] = [], indicators2: List[str] = [], + plot_config: Dict[str, Dict] = {}, + ) -> go.Figure: """ Generate the graph from the data generated by Backtesting or from DB Volume will always be ploted in row2, so Row 1 and 3 are to our disposal for custom indicators diff --git a/freqtrade/plugins/pairlistmanager.py b/freqtrade/plugins/pairlistmanager.py index 20a264fd8..b300f06be 100644 --- a/freqtrade/plugins/pairlistmanager.py +++ b/freqtrade/plugins/pairlistmanager.py @@ -23,7 +23,8 @@ logger = logging.getLogger(__name__) class PairListManager(LoggingMixin): - def __init__(self, exchange, config: Config, dataprovider: DataProvider = None) -> None: + def __init__( + self, exchange, config: Config, dataprovider: Optional[DataProvider] = None) -> None: self._exchange = exchange self._config = config self._whitelist = self._config['exchange'].get('pair_whitelist') @@ -153,7 +154,8 @@ class PairListManager(LoggingMixin): return [] return whitelist - def create_pair_list(self, pairs: List[str], timeframe: str = None) -> ListPairsWithTimeframes: + def create_pair_list( + self, pairs: List[str], timeframe: Optional[str] = None) -> ListPairsWithTimeframes: """ Create list of pair tuples with (pair, timeframe) """ diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py index 0b484394a..2b20560e2 100644 --- a/freqtrade/resolvers/iresolver.py +++ b/freqtrade/resolvers/iresolver.py @@ -89,7 +89,8 @@ class IResolver: module = importlib.util.module_from_spec(spec) try: spec.loader.exec_module(module) # type: ignore # importlib does not use typehints - except (ModuleNotFoundError, SyntaxError, ImportError, NameError) as err: + except (AttributeError, ModuleNotFoundError, SyntaxError, + ImportError, NameError) as err: # Catch errors in case a specific module is not installed logger.warning(f"Could not import {module_path} due to '{err}'") if enum_failed: diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 67df49dcb..6f5b6655d 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -33,7 +33,7 @@ class StrategyResolver(IResolver): extra_path = "strategy_path" @staticmethod - def load_strategy(config: Config = None) -> IStrategy: + def load_strategy(config: Optional[Config] = None) -> IStrategy: """ Load the custom class from config parameter :param config: configuration dictionary or None @@ -76,6 +76,7 @@ class StrategyResolver(IResolver): ("ignore_buying_expired_candle_after", 0), ("position_adjustment_enable", False), ("max_entry_position_adjustment", -1), + ("max_open_trades", -1) ] for attribute, default in attributes: StrategyResolver._override_attribute_helper(strategy, config, @@ -110,7 +111,11 @@ class StrategyResolver(IResolver): val = getattr(strategy, attribute) # None's cannot exist in the config, so do not copy them if val is not None: - config[attribute] = val + # max_open_trades set to -1 in the strategy will be copied as infinity in the config + if attribute == 'max_open_trades' and val == -1: + config[attribute] = float('inf') + else: + config[attribute] = val # Explicitly check for None here as other "falsy" values are possible elif default is not None: setattr(strategy, attribute, default) @@ -128,6 +133,8 @@ class StrategyResolver(IResolver): key=lambda t: t[0])) if hasattr(strategy, 'stoploss'): strategy.stoploss = float(strategy.stoploss) + if hasattr(strategy, 'max_open_trades') and strategy.max_open_trades < 0: + strategy.max_open_trades = float('inf') return strategy @staticmethod diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 404d64d16..58f6ad583 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional, Union from pydantic import BaseModel -from freqtrade.constants import DATETIME_PRINT_FORMAT +from freqtrade.constants import DATETIME_PRINT_FORMAT, IntOrInf from freqtrade.enums import OrderTypeValues, SignalDirection, TradingMode @@ -165,9 +165,10 @@ class ShowConfig(BaseModel): stake_amount: str available_capital: Optional[float] stake_currency_decimals: int - max_open_trades: int + max_open_trades: IntOrInf minimal_roi: Dict[str, Any] stoploss: Optional[float] + stoploss_on_exchange: bool trailing_stop: Optional[bool] trailing_stop_positive: Optional[float] trailing_stop_positive_offset: Optional[float] @@ -422,7 +423,7 @@ class BacktestRequest(BaseModel): timeframe: Optional[str] timeframe_detail: Optional[str] timerange: Optional[str] - max_open_trades: Optional[int] + max_open_trades: Optional[IntOrInf] stake_amount: Optional[str] enable_protections: bool dry_run_wallet: Optional[float] diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index e26df6eea..73bdde86b 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -40,7 +40,9 @@ logger = logging.getLogger(__name__) # 2.20: Add websocket endpoints # 2.21: Add new_candle messagetype # 2.22: Add FreqAI to backtesting -API_VERSION = 2.22 +# 2.23: Allow plot config request in webserver mode +# 2.24: Add cancel_open_order endpoint +API_VERSION = 2.24 # Public API, requires no auth. router_public = APIRouter() @@ -122,6 +124,12 @@ def trades_delete(tradeid: int, rpc: RPC = Depends(get_rpc)): return rpc._rpc_delete(tradeid) +@router.delete('/trades/{tradeid}/open-order', response_model=OpenTradeSchema, tags=['trading']) +def cancel_open_order(tradeid: int, rpc: RPC = Depends(get_rpc)): + rpc._rpc_cancel_open_order(tradeid) + return rpc._rpc_trade_status([tradeid])[0] + + # TODO: Missing response model @router.get('/edge', tags=['info']) def edge(rpc: RPC = Depends(get_rpc)): @@ -248,8 +256,18 @@ def pair_history(pair: str, timeframe: str, timerange: str, strategy: str, @router.get('/plot_config', response_model=PlotConfig, tags=['candle data']) -def plot_config(rpc: RPC = Depends(get_rpc)): - return PlotConfig.parse_obj(rpc._rpc_plot_config()) +def plot_config(strategy: Optional[str] = None, config=Depends(get_config), + rpc: Optional[RPC] = Depends(get_rpc_optional)): + if not strategy: + if not rpc: + raise RPCException("Strategy is mandatory in webserver mode.") + return PlotConfig.parse_obj(rpc._rpc_plot_config()) + else: + config1 = deepcopy(config) + config1.update({ + 'strategy': strategy + }) + return PlotConfig.parse_obj(RPC._rpc_plot_config_with_strategy(config1)) @router.get('/strategies', response_model=StrategyListResponse, tags=['strategy']) diff --git a/freqtrade/rpc/api_server/api_ws.py b/freqtrade/rpc/api_server/api_ws.py index 18714f15f..b253d66c2 100644 --- a/freqtrade/rpc/api_server/api_ws.py +++ b/freqtrade/rpc/api_server/api_ws.py @@ -90,7 +90,7 @@ async def _process_consumer_request( elif type == RPCRequestType.ANALYZED_DF: # Limit the amount of candles per dataframe to 'limit' or 1500 - limit = min(data.get('limit', 1500), 1500) if data else None + limit = int(min(data.get('limit', 1500), 1500)) if data else None pair = data.get('pair', None) if data else None # For every pair in the generator, send a separate message diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index ed905d844..83bffb779 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -122,6 +122,7 @@ class RPC: if config['max_open_trades'] != float('inf') else -1), 'minimal_roi': config['minimal_roi'].copy() if 'minimal_roi' in config else {}, 'stoploss': config.get('stoploss'), + 'stoploss_on_exchange': config.get('stoploss_on_exchange', False), 'trailing_stop': config.get('trailing_stop'), 'trailing_stop_positive': config.get('trailing_stop_positive'), 'trailing_stop_positive_offset': config.get('trailing_stop_positive_offset'), @@ -673,6 +674,7 @@ class RPC: if self._freqtrade.state == State.RUNNING: # Set 'max_open_trades' to 0 self._freqtrade.config['max_open_trades'] = 0 + self._freqtrade.strategy.max_open_trades = 0 return {'status': 'No more entries will occur from now. Run /reload_config to reset.'} @@ -811,6 +813,29 @@ class RPC: else: raise RPCException(f'Failed to enter position for {pair}.') + def _rpc_cancel_open_order(self, trade_id: int): + if self._freqtrade.state != State.RUNNING: + raise RPCException('trader is not running') + with self._freqtrade._exit_lock: + # Query for trade + trade = Trade.get_trades( + trade_filter=[Trade.id == trade_id, Trade.is_open.is_(True), ] + ).first() + if not trade: + logger.warning('cancel_open_order: Invalid trade_id received.') + raise RPCException('Invalid trade_id.') + if not trade.open_order_id: + logger.warning('cancel_open_order: No open order for trade_id.') + raise RPCException('No open order for trade_id.') + + try: + order = self._freqtrade.exchange.fetch_order(trade.open_order_id, trade.pair) + except ExchangeError as e: + logger.info(f"Cannot query order for {trade} due to {e}.", exc_info=True) + raise RPCException("Order not found.") + self._freqtrade.handle_cancel_order(order, trade, CANCEL_REASON['USER_CANCEL']) + Trade.commit() + def _rpc_delete(self, trade_id: int) -> Dict[str, Union[str, int]]: """ Handler for delete . @@ -944,7 +969,7 @@ class RPC: resp['errors'] = errors return resp - def _rpc_blacklist(self, add: List[str] = None) -> Dict: + def _rpc_blacklist(self, add: Optional[List[str]] = None) -> Dict: """ Returns the currently active blacklist""" errors = {} if add: @@ -1126,12 +1151,12 @@ class RPC: return self._freqtrade.active_pair_whitelist @staticmethod - def _rpc_analysed_history_full(config, pair: str, timeframe: str, + def _rpc_analysed_history_full(config: Config, pair: str, timeframe: str, timerange: str, exchange) -> Dict[str, Any]: timerange_parsed = TimeRange.parse_timerange(timerange) _data = load_data( - datadir=config.get("datadir"), + datadir=config["datadir"], pairs=[pair], timeframe=timeframe, timerange=timerange_parsed, @@ -1156,6 +1181,16 @@ class RPC: self._freqtrade.strategy.plot_config['subplots'] = {} return self._freqtrade.strategy.plot_config + @staticmethod + def _rpc_plot_config_with_strategy(config: Config) -> Dict[str, Any]: + + from freqtrade.resolvers.strategy_resolver import StrategyResolver + strategy = StrategyResolver.load_strategy(config) + + if (strategy.plot_config and 'subplots' not in strategy.plot_config): + strategy.plot_config['subplots'] = {} + return strategy.plot_config + @staticmethod def _rpc_sysinfo() -> Dict[str, Any]: return { diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 38fe0cd13..fbd675d02 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -174,6 +174,7 @@ class Telegram(RPCHandler): self._force_enter, order_side=SignalDirection.SHORT)), CommandHandler('trades', self._trades), CommandHandler('delete', self._delete_trade), + CommandHandler(['coo', 'cancel_open_order'], self._cancel_open_order), CommandHandler('performance', self._performance), CommandHandler(['buys', 'entries'], self._enter_tag_performance), CommandHandler(['sells', 'exits'], self._exit_reason_performance), @@ -1144,10 +1145,25 @@ class Telegram(RPCHandler): raise RPCException("Trade-id not set.") trade_id = int(context.args[0]) msg = self._rpc._rpc_delete(trade_id) - self._send_msg(( + self._send_msg( f"`{msg['result_msg']}`\n" 'Please make sure to take care of this asset on the exchange manually.' - )) + ) + + @authorized_only + def _cancel_open_order(self, update: Update, context: CallbackContext) -> None: + """ + Handler for /cancel_open_order . + Cancel open order for tradeid + :param bot: telegram bot + :param update: message update + :return: None + """ + if not context.args or len(context.args) == 0: + raise RPCException("Trade-id not set.") + trade_id = int(context.args[0]) + self._rpc._rpc_cancel_open_order(trade_id) + self._send_msg('Open order canceled.') @authorized_only def _performance(self, update: Update, context: CallbackContext) -> None: @@ -1456,6 +1472,10 @@ class Telegram(RPCHandler): "*/fx |all:* `Alias to /forceexit`\n" f"{force_enter_text if self._config.get('force_entry_enable', False) else ''}" "*/delete :* `Instantly delete the given trade in the database`\n" + "*/cancel_open_order :* `Cancels open orders for trade. " + "Only valid when the trade has open orders.`\n" + "*/coo |all:* `Alias to /cancel_open_order`\n" + "*/whitelist [sorted] [baseonly]:* `Show current whitelist. Optionally in " "order and/or only displaying the base currency of each pairing.`\n" "*/blacklist [pair]:* `Show current blacklist, or adds one or more pairs " @@ -1605,7 +1625,7 @@ class Telegram(RPCHandler): def _send_msg(self, msg: str, parse_mode: str = ParseMode.MARKDOWN, disable_notification: bool = False, - keyboard: List[List[InlineKeyboardButton]] = None, + keyboard: Optional[List[List[InlineKeyboardButton]]] = None, callback_path: str = "", reload_able: bool = False, query: Optional[CallbackQuery] = None) -> None: diff --git a/freqtrade/strategy/hyper.py b/freqtrade/strategy/hyper.py index 6f62c9d3d..2be1d7e86 100644 --- a/freqtrade/strategy/hyper.py +++ b/freqtrade/strategy/hyper.py @@ -4,7 +4,7 @@ This module defines a base class for auto-hyperoptable strategies. """ import logging from pathlib import Path -from typing import Any, Dict, Iterator, List, Tuple, Type, Union +from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, Union from freqtrade.constants import Config from freqtrade.exceptions import OperationalException @@ -36,7 +36,8 @@ class HyperStrategyMixin: self._ft_params_from_file = params # Init/loading of parameters is done as part of ft_bot_start(). - def enumerate_parameters(self, category: str = None) -> Iterator[Tuple[str, BaseParameter]]: + def enumerate_parameters( + self, category: Optional[str] = None) -> Iterator[Tuple[str, BaseParameter]]: """ Find all optimizable parameters and return (name, attr) iterator. :param category: @@ -80,6 +81,8 @@ class HyperStrategyMixin: self.stoploss = params.get('stoploss', {}).get( 'stoploss', getattr(self, 'stoploss', -0.1)) + self.max_open_trades = params.get('max_open_trades', {}).get( + 'max_open_trades', getattr(self, 'max_open_trades', -1)) trailing = params.get('trailing', {}) self.trailing_stop = trailing.get( 'trailing_stop', getattr(self, 'trailing_stop', False)) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 781ae6c5c..70d656199 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -10,7 +10,7 @@ from typing import Dict, List, Optional, Tuple, Union import arrow from pandas import DataFrame -from freqtrade.constants import Config, ListPairsWithTimeframes +from freqtrade.constants import Config, IntOrInf, ListPairsWithTimeframes from freqtrade.data.dataprovider import DataProvider from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, RunMode, SignalDirection, SignalTagType, SignalType, TradingMode) @@ -54,6 +54,9 @@ class IStrategy(ABC, HyperStrategyMixin): # associated stoploss stoploss: float + # max open trades for the strategy + max_open_trades: IntOrInf + # trailing stoploss trailing_stop: bool = False trailing_stop_positive: Optional[float] = None @@ -595,9 +598,10 @@ class IStrategy(ABC, HyperStrategyMixin): return None def populate_any_indicators(self, pair: str, df: DataFrame, tf: str, - informative: DataFrame = None, + informative: Optional[DataFrame] = None, set_generalized_indicators: bool = False) -> DataFrame: """ + DEPRECATED - USE FEATURE ENGINEERING FUNCTIONS INSTEAD Function designed to automatically generate, name and merge features from user indicated timeframes in the configuration file. User can add additional features here, but must follow the naming convention. @@ -610,6 +614,102 @@ class IStrategy(ABC, HyperStrategyMixin): """ return df + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, + metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and + `include_corr_pairs`. In other words, a single feature defined in this function + will automatically expand to a total of + `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` * + `include_corr_pairs` numbers of features added to the model. + + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details on how these config defined parameters accelerate feature engineering + in the documentation at: + + https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters + + https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features + + :param dataframe: strategy dataframe which will receive the features + :param period: period of the indicator - usage example: + :param metadata: metadata of current pair + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) + """ + return dataframe + + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. + In other words, a single feature defined in this function + will automatically expand to a total of + `include_timeframes` * `include_shifted_candles` * `include_corr_pairs` + numbers of features added to the model. + + Features defined here will *not* be automatically duplicated on user defined + `indicator_periods_candles` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details on how these config defined parameters accelerate feature engineering + in the documentation at: + + https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters + + https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features + + :param dataframe: strategy dataframe which will receive the features + :param metadata: metadata of current pair + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200) + """ + return dataframe + + def feature_engineering_standard(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This optional function will be called once with the dataframe of the base timeframe. + This is the final function to be called, which means that the dataframe entering this + function will contain all the features and columns created by all other + freqai_feature_engineering_* functions. + + This function is a good place to do custom exotic feature extractions (e.g. tsfresh). + This function is a good place for any feature that should not be auto-expanded upon + (e.g. day of the week). + + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param dataframe: strategy dataframe which will receive the features + :param metadata: metadata of current pair + usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + """ + return dataframe + + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param dataframe: strategy dataframe which will receive the targets + :param metadata: metadata of current pair + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + return dataframe + ### # END - Intended to be overridden by strategy ### @@ -663,7 +763,8 @@ class IStrategy(ABC, HyperStrategyMixin): """ return self.__class__.__name__ - def lock_pair(self, pair: str, until: datetime, reason: str = None, side: str = '*') -> None: + def lock_pair(self, pair: str, until: datetime, + reason: Optional[str] = None, side: str = '*') -> None: """ Locks pair until a given timestamp happens. Locked pairs are not analyzed, and are prevented from opening new trades. @@ -695,7 +796,8 @@ class IStrategy(ABC, HyperStrategyMixin): """ PairLocks.unlock_reason(reason, datetime.now(timezone.utc)) - def is_pair_locked(self, pair: str, *, candle_date: datetime = None, side: str = '*') -> bool: + def is_pair_locked(self, pair: str, *, candle_date: Optional[datetime] = None, + side: str = '*') -> bool: """ Checks if a pair is currently locked The 2nd, optional parameter ensures that locks are applied until the new candle arrives, @@ -866,7 +968,7 @@ class IStrategy(ABC, HyperStrategyMixin): pair: str, timeframe: str, dataframe: DataFrame, - is_short: bool = None + is_short: Optional[bool] = None ) -> Tuple[bool, bool, Optional[str]]: """ Calculates current exit signal based based on the dataframe @@ -965,7 +1067,7 @@ class IStrategy(ABC, HyperStrategyMixin): def should_exit(self, trade: Trade, rate: float, current_time: datetime, *, enter: bool, exit_: bool, - low: float = None, high: float = None, + low: Optional[float] = None, high: Optional[float] = None, force_stoploss: float = 0) -> List[ExitCheckTuple]: """ This function evaluates if one of the conditions required to trigger an exit order @@ -1053,8 +1155,8 @@ class IStrategy(ABC, HyperStrategyMixin): def stop_loss_reached(self, current_rate: float, trade: Trade, current_time: datetime, current_profit: float, - force_stoploss: float, low: float = None, - high: float = None) -> ExitCheckTuple: + force_stoploss: float, low: Optional[float] = None, + high: Optional[float] = None) -> ExitCheckTuple: """ Based on current profit of the trade and configured (trailing) stoploss, decides to exit or not diff --git a/freqtrade/templates/FreqaiExampleHybridStrategy.py b/freqtrade/templates/FreqaiExampleHybridStrategy.py index 9d1842cd7..ee574fda3 100644 --- a/freqtrade/templates/FreqaiExampleHybridStrategy.py +++ b/freqtrade/templates/FreqaiExampleHybridStrategy.py @@ -1,4 +1,5 @@ import logging +from typing import Dict import numpy as np import pandas as pd @@ -95,65 +96,137 @@ class FreqaiExampleHybridStrategy(IStrategy): short_rsi = IntParameter(low=51, high=100, default=70, space='sell', optimize=True, load=True) exit_short_rsi = IntParameter(low=1, high=50, default=30, space='buy', optimize=True, load=True) - # FreqAI required function, user can add or remove indicators, but general structure - # must stay the same. - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, + metadata: Dict, **kwargs): """ - User feeds these indicators to FreqAI to train a classifier to decide - if the market will go up or down. + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and + `include_corr_pairs`. In other words, a single feature defined in this function + will automatically expand to a total of + `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` * + `include_corr_pairs` numbers of features added to the model. - :param pair: pair to be used as informative - :param df: strategy dataframe which will receive merges from informatives - :param tf: timeframe of the dataframe which will modify the feature names - :param informative: the dataframe associated with the informative pair + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details on how these config defined parameters accelerate feature engineering + in the documentation at: + + https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters + + https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features + + :param dataframe: strategy dataframe which will receive the features + :param period: period of the indicator - usage example: + :param metadata: metadata of current pair + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) """ - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) + dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period) + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + bollinger = qtpylib.bollinger_bands( + qtpylib.typical_price(dataframe), window=period, stds=2.2 + ) + dataframe["bb_lowerband-period"] = bollinger["lower"] + dataframe["bb_middleband-period"] = bollinger["mid"] + dataframe["bb_upperband-period"] = bollinger["upper"] - t = int(t) - informative[f"%-{pair}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{pair}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{pair}adx-period_{t}"] = ta.ADX(informative, timeperiod=t) - informative[f"%-{pair}sma-period_{t}"] = ta.SMA(informative, timeperiod=t) - informative[f"%-{pair}ema-period_{t}"] = ta.EMA(informative, timeperiod=t) - informative[f"%-{pair}roc-period_{t}"] = ta.ROC(informative, timeperiod=t) - informative[f"%-{pair}relative_volume-period_{t}"] = ( - informative["volume"] / informative["volume"].rolling(t).mean() - ) + dataframe["%-bb_width-period"] = ( + dataframe["bb_upperband-period"] + - dataframe["bb_lowerband-period"] + ) / dataframe["bb_middleband-period"] + dataframe["%-close-bb_lower-period"] = ( + dataframe["close"] / dataframe["bb_lowerband-period"] + ) - # FreqAI needs the following lines in order to detect features and automatically - # expand upon them. - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + dataframe["%-relative_volume-period"] = ( + dataframe["volume"] / dataframe["volume"].rolling(period).mean() + ) - # User can set the "target" here (in present case it is the - # "up" or "down") - if set_generalized_indicators: - # User "looks into the future" here to figure out if the future - # will be "up" or "down". This same column name is available to - # the user - df['&s-up_or_down'] = np.where(df["close"].shift(-50) > - df["close"], 'up', 'down') + return dataframe - return df + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. + In other words, a single feature defined in this function + will automatically expand to a total of + `include_timeframes` * `include_shifted_candles` * `include_corr_pairs` + numbers of features added to the model. + + Features defined here will *not* be automatically duplicated on user defined + `indicator_periods_candles` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details on how these config defined parameters accelerate feature engineering + in the documentation at: + + https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters + + https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features + + :param dataframe: strategy dataframe which will receive the features + :param metadata: metadata of current pair + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200) + """ + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] + return dataframe + + def feature_engineering_standard(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This optional function will be called once with the dataframe of the base timeframe. + This is the final function to be called, which means that the dataframe entering this + function will contain all the features and columns created by all other + freqai_feature_engineering_* functions. + + This function is a good place to do custom exotic feature extractions (e.g. tsfresh). + This function is a good place for any feature that should not be auto-expanded upon + (e.g. day of the week). + + All features must be prepended with `%` to be recognized by FreqAI internals. + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param dataframe: strategy dataframe which will receive the features + :param metadata: metadata of current pair + usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + """ + dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek + dataframe["%-hour_of_day"] = dataframe["date"].dt.hour + return dataframe + + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param dataframe: strategy dataframe which will receive the targets + :param metadata: metadata of current pair + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + dataframe['&s-up_or_down'] = np.where(dataframe["close"].shift(-50) > + dataframe["close"], 'up', 'down') + + return dataframe # flake8: noqa: C901 def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 4690a6ccb..0093c7f7a 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -1,12 +1,12 @@ import logging from functools import reduce +from typing import Dict -import pandas as pd import talib.abstract as ta from pandas import DataFrame from technical import qtpylib -from freqtrade.strategy import CategoricalParameter, IStrategy, merge_informative_pair +from freqtrade.strategy import CategoricalParameter, IStrategy logger = logging.getLogger(__name__) @@ -18,8 +18,8 @@ class FreqaiExampleStrategy(IStrategy): IFreqaiModel to the strategy. Namely, the user uses: self.freqai.start(dataframe, metadata) - to make predictions on their data. populate_any_indicators() automatically - generates the variety of features indicated by the user in the + to make predictions on their data. feature_engineering_*() automatically + generate the variety of features indicated by the user in the canonical freqtrade configuration file under config['freqai']. """ @@ -40,134 +40,200 @@ class FreqaiExampleStrategy(IStrategy): use_exit_signal = True # this is the maximum period fed to talib (timeframe independent) startup_candle_count: int = 40 - can_short = False + can_short = True std_dev_multiplier_buy = CategoricalParameter( [0.75, 1, 1.25, 1.5, 1.75], default=1.25, space="buy", optimize=True) std_dev_multiplier_sell = CategoricalParameter( [0.75, 1, 1.25, 1.5, 1.75], space="sell", default=1.25, optimize=True) - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, + metadata: Dict, **kwargs): """ - Function designed to automatically generate, name and merge features - from user indicated timeframes in the configuration file. User controls the indicators - passed to the training/prediction by prepending indicators with `f'%-{pair}` - (see convention below). I.e. user should not prepend any supporting metrics - (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the - model. - :param pair: pair to be used as informative - :param df: strategy dataframe which will receive merges from informatives - :param tf: timeframe of the dataframe which will modify the feature names - :param informative: the dataframe associated with the informative pair + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and + `include_corr_pairs`. In other words, a single feature defined in this function + will automatically expand to a total of + `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` * + `include_corr_pairs` numbers of features added to the model. + + All features must be prepended with `%` to be recognized by FreqAI internals. + + Access metadata such as the current pair/timeframe with: + + `metadata["pair"]` `metadata["tf"]` + + More details on how these config defined parameters accelerate feature engineering + in the documentation at: + + https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters + + https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features + + :param dataframe: strategy dataframe which will receive the features + :param period: period of the indicator - usage example: + :param metadata: metadata of current pair + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) """ - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) + dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period) + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + bollinger = qtpylib.bollinger_bands( + qtpylib.typical_price(dataframe), window=period, stds=2.2 + ) + dataframe["bb_lowerband-period"] = bollinger["lower"] + dataframe["bb_middleband-period"] = bollinger["mid"] + dataframe["bb_upperband-period"] = bollinger["upper"] - t = int(t) - informative[f"%-{pair}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{pair}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{pair}adx-period_{t}"] = ta.ADX(informative, timeperiod=t) - informative[f"%-{pair}sma-period_{t}"] = ta.SMA(informative, timeperiod=t) - informative[f"%-{pair}ema-period_{t}"] = ta.EMA(informative, timeperiod=t) + dataframe["%-bb_width-period"] = ( + dataframe["bb_upperband-period"] + - dataframe["bb_lowerband-period"] + ) / dataframe["bb_middleband-period"] + dataframe["%-close-bb_lower-period"] = ( + dataframe["close"] / dataframe["bb_lowerband-period"] + ) - bollinger = qtpylib.bollinger_bands( - qtpylib.typical_price(informative), window=t, stds=2.2 - ) - informative[f"{pair}bb_lowerband-period_{t}"] = bollinger["lower"] - informative[f"{pair}bb_middleband-period_{t}"] = bollinger["mid"] - informative[f"{pair}bb_upperband-period_{t}"] = bollinger["upper"] + dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) - informative[f"%-{pair}bb_width-period_{t}"] = ( - informative[f"{pair}bb_upperband-period_{t}"] - - informative[f"{pair}bb_lowerband-period_{t}"] - ) / informative[f"{pair}bb_middleband-period_{t}"] - informative[f"%-{pair}close-bb_lower-period_{t}"] = ( - informative["close"] / informative[f"{pair}bb_lowerband-period_{t}"] + dataframe["%-relative_volume-period"] = ( + dataframe["volume"] / dataframe["volume"].rolling(period).mean() + ) + + return dataframe + + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. + In other words, a single feature defined in this function + will automatically expand to a total of + `include_timeframes` * `include_shifted_candles` * `include_corr_pairs` + numbers of features added to the model. + + Features defined here will *not* be automatically duplicated on user defined + `indicator_periods_candles` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + Access metadata such as the current pair/timeframe with: + + `metadata["pair"]` `metadata["tf"]` + + More details on how these config defined parameters accelerate feature engineering + in the documentation at: + + https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters + + https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features + + :param dataframe: strategy dataframe which will receive the features + :param metadata: metadata of current pair + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200) + """ + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] + return dataframe + + def feature_engineering_standard(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + This optional function will be called once with the dataframe of the base timeframe. + This is the final function to be called, which means that the dataframe entering this + function will contain all the features and columns created by all other + freqai_feature_engineering_* functions. + + This function is a good place to do custom exotic feature extractions (e.g. tsfresh). + This function is a good place for any feature that should not be auto-expanded upon + (e.g. day of the week). + + All features must be prepended with `%` to be recognized by FreqAI internals. + + Access metadata such as the current pair with: + + `metadata["pair"]` + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param dataframe: strategy dataframe which will receive the features + :param metadata: metadata of current pair + usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + """ + dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek + dataframe["%-hour_of_day"] = dataframe["date"].dt.hour + return dataframe + + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs): + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + Access metadata such as the current pair with: + + `metadata["pair"]` + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param dataframe: strategy dataframe which will receive the targets + :param metadata: metadata of current pair + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 ) - informative[f"%-{pair}roc-period_{t}"] = ta.ROC(informative, timeperiod=t) + # Classifiers are typically set up with strings as targets: + # df['&s-up_or_down'] = np.where( df["close"].shift(-100) > + # df["close"], 'up', 'down') - informative[f"%-{pair}relative_volume-period_{t}"] = ( - informative["volume"] / informative["volume"].rolling(t).mean() - ) + # If user wishes to use multiple targets, they can add more by + # appending more columns with '&'. User should keep in mind that multi targets + # requires a multioutput prediction model such as + # freqai/prediction_models/CatboostRegressorMultiTarget.py, + # freqtrade trade --freqaimodel CatboostRegressorMultiTarget - informative[f"%-{pair}pct-change"] = informative["close"].pct_change() - informative[f"%-{pair}raw_volume"] = informative["volume"] - informative[f"%-{pair}raw_price"] = informative["close"] + # df["&-s_range"] = ( + # df["close"] + # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + # .max() + # - + # df["close"] + # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + # .min() + # ) - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) - - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) - - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 - - # user adds targets here by prepending them with &- (see convention below) - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 - ) - - # Classifiers are typically set up with strings as targets: - # df['&s-up_or_down'] = np.where( df["close"].shift(-100) > - # df["close"], 'up', 'down') - - # If user wishes to use multiple targets, they can add more by - # appending more columns with '&'. User should keep in mind that multi targets - # requires a multioutput prediction model such as - # freqai/prediction_models/CatboostRegressorMultiTarget.py, - # freqtrade trade --freqaimodel CatboostRegressorMultiTarget - - # df["&-s_range"] = ( - # df["close"] - # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - # .max() - # - - # df["close"] - # .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - # .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - # .min() - # ) - - return df + return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - # All indicators must be populated by populate_any_indicators() for live functionality - # to work correctly. + # All indicators must be populated by feature_engineering_*() functions - # the model will return all labels created by user in `populate_any_indicators` + # the model will return all labels created by user in `feature_engineering_*` # (& appended targets), an indication of whether or not the prediction should be accepted, # the target mean/std values for each of the labels created by user in - # `populate_any_indicators()` for each training period. + # `set_freqai_targets()` for each training period. dataframe = self.freqai.start(dataframe, metadata, self) + for val in self.std_dev_multiplier_buy.range: dataframe[f'target_roi_{val}'] = ( dataframe["&-s_close_mean"] + dataframe["&-s_close_std"] * val diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 index 299734a50..1a4552c11 100644 --- a/freqtrade/templates/base_config.json.j2 +++ b/freqtrade/templates/base_config.json.j2 @@ -41,20 +41,6 @@ "pairlists": [ {{ '{"method": "StaticPairList"}' if exchange_name == 'bittrex' else volume_pairlist }} ], - "edge": { - "enabled": false, - "process_throttle_secs": 3600, - "calculate_since_number_of_days": 7, - "allowed_risk": 0.01, - "stoploss_range_min": -0.01, - "stoploss_range_max": -0.1, - "stoploss_range_step": -0.01, - "minimum_winrate": 0.60, - "minimum_expectancy": 0.20, - "min_trade_number": 10, - "max_trade_duration_minute": 1440, - "remove_pumps": false - }, "telegram": { "enabled": {{ telegram | lower }}, "token": "{{ telegram_token }}", diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index dfbcedb72..2bfa4155d 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -118,6 +118,7 @@ "from freqtrade.data.dataprovider import DataProvider\n", "strategy = StrategyResolver.load_strategy(config)\n", "strategy.dp = DataProvider(config, None, None)\n", + "strategy.ft_bot_start()\n", "\n", "# Generate buy/sell signals using strategy\n", "df = strategy.analyze_ticker(candles, {'pair': pair})\n", diff --git a/freqtrade/util/binance_mig.py b/freqtrade/util/binance_mig.py new file mode 100644 index 000000000..708bb1db7 --- /dev/null +++ b/freqtrade/util/binance_mig.py @@ -0,0 +1,78 @@ +import logging + +from packaging import version + +from freqtrade.constants import Config +from freqtrade.enums.tradingmode import TradingMode +from freqtrade.exceptions import OperationalException +from freqtrade.persistence.pairlock import PairLock +from freqtrade.persistence.trade_model import Trade + + +logger = logging.getLogger(__name__) + + +def migrate_binance_futures_names(config: Config): + + if ( + not (config.get('trading_mode', TradingMode.SPOT) == TradingMode.FUTURES + and config['exchange']['name'] == 'binance') + ): + # only act on new futures + return + import ccxt + if version.parse("2.6.26") > version.parse(ccxt.__version__): + raise OperationalException( + "Please follow the update instructions in the docs " + "(https://www.freqtrade.io/en/latest/updating/) to install a compatible ccxt version.") + _migrate_binance_futures_db(config) + migrate_binance_futures_data(config) + + +def _migrate_binance_futures_db(config: Config): + logger.warning('Migrating binance futures pairs in database.') + trades = Trade.get_trades([Trade.exchange == 'binance', Trade.trading_mode == 'FUTURES']).all() + for trade in trades: + if ':' in trade.pair: + # already migrated + continue + new_pair = f"{trade.pair}:{trade.stake_currency}" + trade.pair = new_pair + + for order in trade.orders: + order.ft_pair = new_pair + # Should symbol be migrated too? + # order.symbol = new_pair + Trade.commit() + pls = PairLock.query.filter(PairLock.pair.notlike('%:%')) + for pl in pls: + pl.pair = f"{pl.pair}:{config['stake_currency']}" + # print(pls) + # pls.update({'pair': concat(PairLock.pair,':USDT')}) + Trade.commit() + logger.warning('Done migrating binance futures pairs in database.') + + +def migrate_binance_futures_data(config: Config): + + if ( + not (config.get('trading_mode', TradingMode.SPOT) == TradingMode.FUTURES + and config['exchange']['name'] == 'binance') + ): + # only act on new futures + return + + from freqtrade.data.history.idatahandler import get_datahandler + dhc = get_datahandler(config['datadir'], config.get('dataformat_ohlcv', 'json')) + + paircombs = dhc.ohlcv_get_available_data( + config['datadir'], + config.get('trading_mode', TradingMode.SPOT) + ) + + for pair, timeframe, candle_type in paircombs: + if ':' in pair: + # already migrated + continue + new_pair = f"{pair}:{config['stake_currency']}" + dhc.rename_futures_data(pair, new_pair, timeframe, candle_type) diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 97db3fba5..8dcc92af4 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -297,16 +297,16 @@ class Wallets: logger.debug(f"Stake amount is {stake_amount}, ignoring possible trade for {pair}.") return 0 - max_stake_amount = min(max_stake_amount, self.get_available_stake_amount()) + max_allowed_stake = min(max_stake_amount, self.get_available_stake_amount()) if trade_amount: # if in a trade, then the resulting trade size cannot go beyond the max stake # Otherwise we could no longer exit. - max_stake_amount = min(max_stake_amount, max_stake_amount - trade_amount) + max_allowed_stake = min(max_allowed_stake, max_stake_amount - trade_amount) - if min_stake_amount is not None and min_stake_amount > max_stake_amount: + if min_stake_amount is not None and min_stake_amount > max_allowed_stake: if self._log: logger.warning("Minimum stake amount > available balance. " - f"{min_stake_amount} > {max_stake_amount}") + f"{min_stake_amount} > {max_allowed_stake}") return 0 if min_stake_amount is not None and stake_amount < min_stake_amount: if self._log: @@ -325,11 +325,11 @@ class Wallets: return 0 stake_amount = min_stake_amount - if stake_amount > max_stake_amount: + if stake_amount > max_allowed_stake: if self._log: logger.info( f"Stake amount for pair {pair} is too big " - f"({stake_amount} > {max_stake_amount}), adjusting to {max_stake_amount}." + f"({stake_amount} > {max_allowed_stake}), adjusting to {max_allowed_stake}." ) - stake_amount = max_stake_amount + stake_amount = max_allowed_stake return stake_amount diff --git a/freqtrade/worker.py b/freqtrade/worker.py index 27f067b07..388163678 100755 --- a/freqtrade/worker.py +++ b/freqtrade/worker.py @@ -26,7 +26,7 @@ class Worker: Freqtradebot worker class """ - def __init__(self, args: Dict[str, Any], config: Config = None) -> None: + def __init__(self, args: Dict[str, Any], config: Optional[Config] = None) -> None: """ Init all variables and objects the bot needs to work """ diff --git a/mkdocs.yml b/mkdocs.yml index c44e4640e..3f9e8a880 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -59,7 +59,11 @@ theme: favicon: "images/logo.png" custom_dir: "docs/overrides" features: + - content.code.annotate - search.share + - content.code.copy + - navigation.top + - navigation.footer palette: - scheme: default primary: "blue grey" diff --git a/pyproject.toml b/pyproject.toml index 2de2c957b..82d4ceaf8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,6 @@ asyncio_mode = "auto" [tool.mypy] ignore_missing_imports = true namespace_packages = false -implicit_optional = true warn_unused_ignores = true exclude = [ '^build_helpers\.py$' @@ -41,6 +40,11 @@ exclude = [ module = "tests.*" ignore_errors = true +[[tool.mypy.overrides]] +# Telegram does not use implicit_optional = false in the current version. +module = "telegram.*" +implicit_optional = true + [build-system] requires = ["setuptools >= 46.4.0", "wheel"] build-backend = "setuptools.build_meta" @@ -52,6 +56,3 @@ exclude = [ "build_helpers/*.py", ] ignore = ["freqtrade/vendor/**"] - -# Align pyright to mypy config -strictParameterNoneValue = false diff --git a/requirements-dev.txt b/requirements-dev.txt index cf7a75d98..3488fdbfd 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,24 +10,24 @@ coveralls==3.3.1 flake8==6.0.0 flake8-tidy-imports==4.8.0 mypy==0.991 -pre-commit==2.21.0 -pytest==7.2.0 +pre-commit==3.0.4 +pytest==7.2.1 pytest-asyncio==0.20.3 pytest-cov==4.0.0 pytest-mock==3.10.0 pytest-random-order==1.1.0 -isort==5.11.4 +isort==5.12.0 # For datetime mocking time-machine==2.9.0 # fastapi testing -httpx==0.23.1 +httpx==0.23.3 # Convert jupyter notebooks to markdown documents -nbconvert==7.2.7 +nbconvert==7.2.9 # mypy types -types-cachetools==5.2.1 +types-cachetools==5.3.0.0 types-filelock==3.2.7 -types-requests==2.28.11.7 +types-requests==2.28.11.8 types-tabulate==0.9.0.0 -types-python-dateutil==2.8.19.5 +types-python-dateutil==2.8.19.6 diff --git a/requirements-freqai-rl.txt b/requirements-freqai-rl.txt index db8d8d169..c242af43e 100644 --- a/requirements-freqai-rl.txt +++ b/requirements-freqai-rl.txt @@ -3,7 +3,8 @@ # Required for freqai-rl torch==1.13.1 -stable-baselines3==1.6.2 -sb3-contrib==1.6.2 +stable-baselines3==1.7.0 +sb3-contrib==1.7.0 # Gym is forced to this version by stable-baselines3. +setuptools==65.5.1 # Should be removed when gym is fixed. gym==0.21 diff --git a/requirements-freqai.txt b/requirements-freqai.txt index 215a312bf..914dbb745 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -6,6 +6,6 @@ scikit-learn==1.1.3 joblib==1.2.0 catboost==1.1.1; platform_machine != 'aarch64' -lightgbm==3.3.3 -xgboost==1.7.2 -tensorboard==2.11.0 +lightgbm==3.3.5 +xgboost==1.7.3 +tensorboard==2.11.2 diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 0cfd6cfa1..171ede929 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -2,7 +2,7 @@ -r requirements.txt # Required for hyperopt -scipy==1.9.3 +scipy==1.10.0 scikit-learn==1.1.3 scikit-optimize==0.9.0 filelock==3.9.0 diff --git a/requirements-plot.txt b/requirements-plot.txt index 75e3234a1..b97d42fb6 100644 --- a/requirements-plot.txt +++ b/requirements-plot.txt @@ -1,4 +1,4 @@ # Include all requirements to run the bot. -r requirements.txt -plotly==5.11.0 +plotly==5.13.0 diff --git a/requirements.txt b/requirements.txt index 7aeb63128..b6ce09a75 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,28 +1,28 @@ -numpy==1.24.1 -pandas==1.5.2 +numpy==1.24.2 +pandas==1.5.3 pandas-ta==0.3.14b -ccxt==2.4.60 +ccxt==2.7.80 # Pin cryptography for now due to rust build errors with piwheels cryptography==38.0.1; platform_machine == 'armv7l' -cryptography==38.0.4; platform_machine != 'armv7l' +cryptography==39.0.1; platform_machine != 'armv7l' aiohttp==3.8.3 -SQLAlchemy==1.4.45 +SQLAlchemy==1.4.46 python-telegram-bot==13.15 arrow==1.2.3 cachetools==4.2.2 -requests==2.28.1 -urllib3==1.26.13 +requests==2.28.2 +urllib3==1.26.14 jsonschema==4.17.3 TA-Lib==0.4.25 -technical==1.3.0 +technical==1.4.0 tabulate==0.9.0 pycoingecko==3.1.0 jinja2==3.1.2 tables==3.8.0 blosc==1.11.1 joblib==1.2.0 -pyarrow==10.0.1; platform_machine != 'armv7l' +pyarrow==11.0.0; platform_machine != 'armv7l' # find first, C search in arrays py_find_1st==1.1.5 @@ -30,13 +30,13 @@ py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.9 # Properly format api responses -orjson==3.8.3 +orjson==3.8.5 # Notify systemd sdnotify==0.3.2 # API Server -fastapi==0.88.0 +fastapi==0.89.1 pydantic==1.10.4 uvicorn==0.20.0 pyjwt==2.6.0 diff --git a/scripts/rest_client.py b/scripts/rest_client.py index ac6d97133..144d428e5 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -14,6 +14,7 @@ import logging import re import sys from pathlib import Path +from typing import Optional from urllib.parse import urlencode, urlparse, urlunparse import rapidjson @@ -36,7 +37,7 @@ class FtRestClient(): self._session = requests.Session() self._session.auth = (username, password) - def _call(self, method, apipath, params: dict = None, data=None, files=None): + def _call(self, method, apipath, params: Optional[dict] = None, data=None, files=None): if str(method).upper() not in ('GET', 'POST', 'PUT', 'DELETE'): raise ValueError(f'invalid method <{method}>') @@ -60,13 +61,13 @@ class FtRestClient(): except ConnectionError: logger.warning("Connection error") - def _get(self, apipath, params: dict = None): + def _get(self, apipath, params: Optional[dict] = None): return self._call("GET", apipath, params=params) - def _delete(self, apipath, params: dict = None): + def _delete(self, apipath, params: Optional[dict] = None): return self._call("DELETE", apipath, params=params) - def _post(self, apipath, params: dict = None, data: dict = None): + def _post(self, apipath, params: Optional[dict] = None, data: Optional[dict] = None): return self._call("POST", apipath, params=params, data=data) def start(self): @@ -176,8 +177,7 @@ class FtRestClient(): return self._get("version") def show_config(self): - """ - Returns part of the configuration, relevant for trading operations. + """ Returns part of the configuration, relevant for trading operations. :return: json object containing the version """ return self._get("show_config") @@ -231,6 +231,14 @@ class FtRestClient(): """ return self._delete(f"trades/{trade_id}") + def cancel_open_order(self, trade_id): + """Cancel open order for trade. + + :param trade_id: Cancels open orders for this trade. + :return: json object + """ + return self._delete(f"trades/{trade_id}/open-order") + def whitelist(self): """Show the current whitelist. diff --git a/setup.py b/setup.py index 894388554..30aacc3f2 100644 --- a/setup.py +++ b/setup.py @@ -60,7 +60,7 @@ setup( ], install_requires=[ # from requirements.txt - 'ccxt>=1.92.9', + 'ccxt>=2.6.26', 'SQLAlchemy', 'python-telegram-bot>=13.4', 'arrow>=0.17.0', diff --git a/setup.sh b/setup.sh index 4cb504853..a9ff36536 100755 --- a/setup.sh +++ b/setup.sh @@ -49,48 +49,50 @@ function updateenv() { source .env/bin/activate SYS_ARCH=$(uname -m) echo "pip install in-progress. Please wait..." - ${PYTHON} -m pip install --upgrade pip - read -p "Do you want to install dependencies for dev [y/N]? " + # Setuptools 65.5.0 is the last version that can install gym==0.21.0 + ${PYTHON} -m pip install --upgrade pip wheel setuptools==65.5.1 + REQUIREMENTS_HYPEROPT="" + REQUIREMENTS_PLOT="" + REQUIREMENTS_FREQAI="" + REQUIREMENTS_FREQAI_RL="" + REQUIREMENTS=requirements.txt + + read -p "Do you want to install dependencies for development (Performs a full install with all dependencies) [y/N]? " dev=$REPLY if [[ $REPLY =~ ^[Yy]$ ]] then REQUIREMENTS=requirements-dev.txt else - REQUIREMENTS=requirements.txt - fi - REQUIREMENTS_HYPEROPT="" - REQUIREMENTS_PLOT="" - read -p "Do you want to install plotting dependencies (plotly) [y/N]? " - if [[ $REPLY =~ ^[Yy]$ ]] - then - REQUIREMENTS_PLOT="-r requirements-plot.txt" - fi - if [ "${SYS_ARCH}" == "armv7l" ] || [ "${SYS_ARCH}" == "armv6l" ]; then - echo "Detected Raspberry, installing cython, skipping hyperopt installation." - ${PYTHON} -m pip install --upgrade cython - else - # Is not Raspberry - read -p "Do you want to install hyperopt dependencies [y/N]? " + # requirements-dev.txt includes all the below requirements already, so further questions are pointless. + read -p "Do you want to install plotting dependencies (plotly) [y/N]? " if [[ $REPLY =~ ^[Yy]$ ]] then - REQUIREMENTS_HYPEROPT="-r requirements-hyperopt.txt" + REQUIREMENTS_PLOT="-r requirements-plot.txt" + fi + if [ "${SYS_ARCH}" == "armv7l" ] || [ "${SYS_ARCH}" == "armv6l" ]; then + echo "Detected Raspberry, installing cython, skipping hyperopt installation." + ${PYTHON} -m pip install --upgrade cython + else + # Is not Raspberry + read -p "Do you want to install hyperopt dependencies [y/N]? " + if [[ $REPLY =~ ^[Yy]$ ]] + then + REQUIREMENTS_HYPEROPT="-r requirements-hyperopt.txt" + fi fi - fi - REQUIREMENTS_FREQAI="" - REQUIREMENTS_FREQAI_RL="" - read -p "Do you want to install dependencies for freqai [y/N]? " - dev=$REPLY - if [[ $REPLY =~ ^[Yy]$ ]] - then - REQUIREMENTS_FREQAI="-r requirements-freqai.txt --use-pep517" - read -p "Do you also want dependencies for freqai-rl (~700mb additional space required) [y/N]? " - dev=$REPLY + read -p "Do you want to install dependencies for freqai [y/N]? " if [[ $REPLY =~ ^[Yy]$ ]] then - REQUIREMENTS_FREQAI="-r requirements-freqai-rl.txt" + REQUIREMENTS_FREQAI="-r requirements-freqai.txt --use-pep517" + read -p "Do you also want dependencies for freqai-rl (~700mb additional space required) [y/N]? " + if [[ $REPLY =~ ^[Yy]$ ]] + then + REQUIREMENTS_FREQAI="-r requirements-freqai-rl.txt" + fi fi fi + install_talib ${PYTHON} -m pip install --upgrade -r ${REQUIREMENTS} ${REQUIREMENTS_HYPEROPT} ${REQUIREMENTS_PLOT} ${REQUIREMENTS_FREQAI} ${REQUIREMENTS_FREQAI_RL} if [ $? -ne 0 ]; then @@ -168,21 +170,18 @@ function install_macos() { if [[ $version -ge 9 ]]; then #Checks if python version >= 3.9 install_mac_newer_python_dependencies fi - install_talib } # Install bot Debian_ubuntu function install_debian() { sudo apt-get update sudo apt-get install -y gcc build-essential autoconf libtool pkg-config make wget git curl $(echo lib${PYTHON}-dev ${PYTHON}-venv) - install_talib } # Install bot RedHat_CentOS function install_redhat() { sudo yum update sudo yum install -y gcc gcc-c++ make autoconf libtool pkg-config wget git $(echo ${PYTHON}-devel | sed 's/\.//g') - install_talib } # Upgrade the bot @@ -191,26 +190,37 @@ function update() { updateenv } +function check_git_changes() { + if [ -z "$(git status --porcelain)" ]; then + echo "No changes in git directory" + return 1 + else + echo "Changes in git directory" + return 0 + fi +} + # Reset Develop or Stable branch function reset() { echo_block "Resetting branch and virtual env" if [ "1" == $(git branch -vv |grep -cE "\* develop|\* stable") ] then + if check_git_changes; then + read -p "Keep your local changes? (Otherwise will remove all changes you made!) [Y/n]? " + if [[ $REPLY =~ ^[Nn]$ ]]; then - read -p "Reset git branch? (This will remove all changes you made!) [y/N]? " - if [[ $REPLY =~ ^[Yy]$ ]]; then + git fetch -a - git fetch -a - - if [ "1" == $(git branch -vv | grep -c "* develop") ] - then - echo "- Hard resetting of 'develop' branch." - git reset --hard origin/develop - elif [ "1" == $(git branch -vv | grep -c "* stable") ] - then - echo "- Hard resetting of 'stable' branch." - git reset --hard origin/stable + if [ "1" == $(git branch -vv | grep -c "* develop") ] + then + echo "- Hard resetting of 'develop' branch." + git reset --hard origin/develop + elif [ "1" == $(git branch -vv | grep -c "* stable") ] + then + echo "- Hard resetting of 'stable' branch." + git reset --hard origin/stable + fi fi fi else diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index d568f48f6..55ffaccb0 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -746,9 +746,7 @@ def test_download_data_no_exchange(mocker, caplog): start_download_data(pargs) -def test_download_data_no_pairs(mocker, caplog): - - mocker.patch.object(Path, "exists", MagicMock(return_value=False)) +def test_download_data_no_pairs(mocker): mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', MagicMock(return_value=["ETH/BTC", "XRP/BTC"])) @@ -770,8 +768,6 @@ def test_download_data_no_pairs(mocker, caplog): def test_download_data_all_pairs(mocker, markets): - mocker.patch.object(Path, "exists", MagicMock(return_value=False)) - dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', MagicMock(return_value=["ETH/BTC", "XRP/BTC"])) patch_exchange(mocker) @@ -1454,10 +1450,10 @@ def test_start_list_data(testdatadir, capsys): start_list_data(pargs) captured = capsys.readouterr() - assert "Found 5 pair / timeframe combinations." in captured.out - assert "\n| Pair | Timeframe | Type |\n" in captured.out - assert "\n| XRP/USDT | 1h | futures |\n" in captured.out - assert "\n| XRP/USDT | 1h, 8h | mark |\n" in captured.out + assert "Found 6 pair / timeframe combinations." in captured.out + assert "\n| Pair | Timeframe | Type |\n" in captured.out + assert "\n| XRP/USDT:USDT | 5m, 1h | futures |\n" in captured.out + assert "\n| XRP/USDT:USDT | 1h, 8h | mark |\n" in captured.out args = [ "list-data", diff --git a/tests/conftest.py b/tests/conftest.py index c9af5a171..06a86c3b3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -241,7 +241,6 @@ def get_patched_freqtradebot(mocker, config) -> FreqtradeBot: :return: FreqtradeBot """ patch_freqtradebot(mocker, config) - config['datadir'] = Path(config['datadir']) return FreqtradeBot(config) @@ -510,7 +509,7 @@ def get_default_conf(testdatadir): "chat_id": "0", "notification_settings": {}, }, - "datadir": str(testdatadir), + "datadir": Path(testdatadir), "initial_state": "running", "db_url": "sqlite://", "user_data_dir": Path("user_data"), @@ -2606,6 +2605,8 @@ def open_trade(): ft_order_side='buy', ft_pair=trade.pair, ft_is_open=False, + ft_amount=trade.amount, + ft_price=trade.open_rate, order_id='123456789', status="closed", symbol=trade.pair, @@ -2642,6 +2643,8 @@ def open_trade_usdt(): ft_order_side='buy', ft_pair=trade.pair, ft_is_open=False, + ft_amount=trade.amount, + ft_price=trade.open_rate, order_id='123456789', status="closed", symbol=trade.pair, @@ -2659,6 +2662,8 @@ def open_trade_usdt(): ft_order_side='exit', ft_pair=trade.pair, ft_is_open=True, + ft_amount=trade.amount, + ft_price=trade.open_rate, order_id='123456789_exit', status="open", symbol=trade.pair, @@ -3103,7 +3108,7 @@ def funding_rate_history_octohourly(): @pytest.fixture(scope='function') def leverage_tiers(): return { - "1000SHIB/USDT": [ + "1000SHIB/USDT:USDT": [ { 'minNotional': 0, 'maxNotional': 50000, @@ -3154,7 +3159,7 @@ def leverage_tiers(): 'maintAmt': 654500.0 }, ], - "1INCH/USDT": [ + "1INCH/USDT:USDT": [ { 'minNotional': 0, 'maxNotional': 5000, @@ -3198,7 +3203,7 @@ def leverage_tiers(): 'maintAmt': 386940.0 }, ], - "AAVE/USDT": [ + "AAVE/USDT:USDT": [ { 'minNotional': 0, 'maxNotional': 5000, @@ -3242,7 +3247,7 @@ def leverage_tiers(): 'maintAmt': 386950.0 }, ], - "ADA/BUSD": [ + "ADA/BUSD:BUSD": [ { "minNotional": 0, "maxNotional": 100000, @@ -3286,7 +3291,7 @@ def leverage_tiers(): "maintAmt": 1527500.0 }, ], - 'BNB/BUSD': [ + 'BNB/BUSD:BUSD': [ { "minNotional": 0, # stake(before leverage) = 0 "maxNotional": 100000, # max stake(before leverage) = 5000 @@ -3330,7 +3335,7 @@ def leverage_tiers(): "maintAmt": 1527500.0 } ], - 'BNB/USDT': [ + 'BNB/USDT:USDT': [ { "minNotional": 0, # stake = 0.0 "maxNotional": 10000, # max_stake = 133.33333333333334 @@ -3395,7 +3400,7 @@ def leverage_tiers(): "maintAmt": 6233035.0 }, ], - 'BTC/USDT': [ + 'BTC/USDT:USDT': [ { "minNotional": 0, # stake = 0.0 "maxNotional": 50000, # max_stake = 400.0 @@ -3467,7 +3472,7 @@ def leverage_tiers(): "maintAmt": 1.997038E8 }, ], - "ZEC/USDT": [ + "ZEC/USDT:USDT": [ { 'minNotional': 0, 'maxNotional': 50000, diff --git a/tests/data/test_converter.py b/tests/data/test_converter.py index 760ad8b76..b37a2100d 100644 --- a/tests/data/test_converter.py +++ b/tests/data/test_converter.py @@ -294,8 +294,8 @@ def test_convert_trades_format(default_conf, testdatadir, tmpdir): @pytest.mark.parametrize('file_base,candletype', [ (['XRP_ETH-5m', 'XRP_ETH-1m'], CandleType.SPOT), - (['UNITTEST_USDT-1h-mark', 'XRP_USDT-1h-mark'], CandleType.MARK), - (['XRP_USDT-1h-futures'], CandleType.FUTURES), + (['UNITTEST_USDT_USDT-1h-mark', 'XRP_USDT_USDT-1h-mark'], CandleType.MARK), + (['XRP_USDT_USDT-1h-futures'], CandleType.FUTURES), ]) def test_convert_ohlcv_format(default_conf, testdatadir, tmpdir, file_base, candletype): tmpdir1 = Path(tmpdir) @@ -315,7 +315,10 @@ def test_convert_ohlcv_format(default_conf, testdatadir, tmpdir, file_base, cand files_new.append(file_new) default_conf['datadir'] = tmpdir1 - default_conf['pairs'] = ['XRP_ETH', 'XRP_USDT', 'UNITTEST_USDT'] + if candletype == CandleType.SPOT: + default_conf['pairs'] = ['XRP/ETH', 'XRP/USDT', 'UNITTEST/USDT'] + else: + default_conf['pairs'] = ['XRP/ETH:ETH', 'XRP/USDT:USDT', 'UNITTEST/USDT:USDT'] default_conf['timeframes'] = ['1m', '5m', '1h'] assert not file_new.exists() diff --git a/tests/data/test_datahandler.py b/tests/data/test_datahandler.py index 4d6489f11..f673ede6e 100644 --- a/tests/data/test_datahandler.py +++ b/tests/data/test_datahandler.py @@ -33,10 +33,10 @@ def test_datahandler_ohlcv_get_pairs(testdatadir): assert set(pairs) == {'UNITTEST/BTC'} pairs = JsonDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.MARK) - assert set(pairs) == {'UNITTEST/USDT', 'XRP/USDT'} + assert set(pairs) == {'UNITTEST/USDT:USDT', 'XRP/USDT:USDT'} pairs = JsonGzDataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.FUTURES) - assert set(pairs) == {'XRP/USDT'} + assert set(pairs) == {'XRP/USDT:USDT'} pairs = HDF5DataHandler.ohlcv_get_pairs(testdatadir, '1h', candle_type=CandleType.MARK) assert set(pairs) == {'UNITTEST/USDT:USDT'} @@ -104,11 +104,12 @@ def test_datahandler_ohlcv_get_available_data(testdatadir): paircombs = JsonDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.FUTURES) # Convert to set to avoid failures due to sorting assert set(paircombs) == { - ('UNITTEST/USDT', '1h', 'mark'), - ('XRP/USDT', '1h', 'futures'), - ('XRP/USDT', '1h', 'mark'), - ('XRP/USDT', '8h', 'mark'), - ('XRP/USDT', '8h', 'funding_rate'), + ('UNITTEST/USDT:USDT', '1h', 'mark'), + ('XRP/USDT:USDT', '5m', 'futures'), + ('XRP/USDT:USDT', '1h', 'futures'), + ('XRP/USDT:USDT', '1h', 'mark'), + ('XRP/USDT:USDT', '8h', 'mark'), + ('XRP/USDT:USDT', '8h', 'funding_rate'), } paircombs = JsonGzDataHandler.ohlcv_get_available_data(testdatadir, TradingMode.SPOT) @@ -142,7 +143,7 @@ def test_jsondatahandler_ohlcv_load(testdatadir, caplog): df = dh.ohlcv_load('XRP/ETH', '5m', 'spot') assert len(df) == 712 - df_mark = dh.ohlcv_load('UNITTEST/USDT', '1h', candle_type="mark") + df_mark = dh.ohlcv_load('UNITTEST/USDT:USDT', '1h', candle_type="mark") assert len(df_mark) == 100 df_no_mark = dh.ohlcv_load('UNITTEST/USDT', '1h', 'spot') @@ -424,7 +425,7 @@ def test_hdf5datahandler_ohlcv_load_and_resave( # Data goes from 2018-01-10 - 2018-01-30 ('UNITTEST/BTC', '5m', 'spot', '', '2018-01-15', '2018-01-19'), # Mark data goes from to 2021-11-15 2021-11-19 - ('UNITTEST/USDT', '1h', 'mark', '-mark', '2021-11-16', '2021-11-18'), + ('UNITTEST/USDT:USDT', '1h', 'mark', '-mark', '2021-11-16', '2021-11-18'), ]) @pytest.mark.parametrize('datahandler', ['hdf5', 'feather', 'parquet']) def test_generic_datahandler_ohlcv_load_and_resave( diff --git a/tests/data/test_dataprovider.py b/tests/data/test_dataprovider.py index e0c79d52a..c6b1dcc5a 100644 --- a/tests/data/test_dataprovider.py +++ b/tests/data/test_dataprovider.py @@ -437,6 +437,7 @@ def test_dp__add_external_df(default_conf_usdt): # Add the same dataframe again - dataframe size shall not change. res = dp._add_external_df('ETH/USDT', df, last_analyzed, timeframe, CandleType.SPOT) assert res[0] is True + assert isinstance(res[1], int) assert res[1] == 0 df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT) assert len(df) == 24 @@ -446,6 +447,7 @@ def test_dp__add_external_df(default_conf_usdt): res = dp._add_external_df('ETH/USDT', df2, last_analyzed, timeframe, CandleType.SPOT) assert res[0] is True + assert isinstance(res[1], int) assert res[1] == 0 df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT) assert len(df) == 48 @@ -455,6 +457,7 @@ def test_dp__add_external_df(default_conf_usdt): res = dp._add_external_df('ETH/USDT', df3, last_analyzed, timeframe, CandleType.SPOT) assert res[0] is True + assert isinstance(res[1], int) assert res[1] == 0 df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT) # New length = 48 + 12 (since we have a 12 hour offset). @@ -478,6 +481,7 @@ def test_dp__add_external_df(default_conf_usdt): res = dp._add_external_df('ETH/USDT', df4, last_analyzed, timeframe, CandleType.SPOT) assert res[0] is False # 36 hours - from 2022-01-03 12:00:00+00:00 to 2022-01-05 00:00:00+00:00 + assert isinstance(res[1], int) assert res[1] == 36 df, _ = dp.get_producer_df('ETH/USDT', timeframe, CandleType.SPOT) # New length = 61 + 1 @@ -488,4 +492,5 @@ def test_dp__add_external_df(default_conf_usdt): res = dp._add_external_df('ETH/USDT', df4, last_analyzed, timeframe, CandleType.SPOT) assert res[0] is False # 36 hours - from 2022-01-03 12:00:00+00:00 to 2022-01-05 00:00:00+00:00 + assert isinstance(res[1], int) assert res[1] == 0 diff --git a/tests/data/test_entryexitanalysis.py b/tests/data/test_entryexitanalysis.py index e33ed4955..3b073bc32 100755 --- a/tests/data/test_entryexitanalysis.py +++ b/tests/data/test_entryexitanalysis.py @@ -190,6 +190,15 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp assert '1' in captured.out assert '2.5' in captured.out + # test group 5 + args = get_args(base_args + ['--analysis-groups', "5"]) + start_analysis_entries_exits(args) + captured = capsys.readouterr() + assert 'exit_signal' in captured.out + assert 'roi' in captured.out + assert 'stop_loss' in captured.out + assert 'trailing_stop_loss' in captured.out + # test date filtering args = get_args(base_args + ['--timerange', "20180129-20180130"]) start_analysis_entries_exits(args) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index b985666cc..7d313c446 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -78,11 +78,11 @@ def test_load_data_1min_timeframe(ohlcv_history, mocker, caplog, testdatadir) -> def test_load_data_mark(ohlcv_history, mocker, caplog, testdatadir) -> None: mocker.patch('freqtrade.exchange.Exchange.get_historic_ohlcv', return_value=ohlcv_history) - file = testdatadir / 'futures/UNITTEST_USDT-1h-mark.json' + file = testdatadir / 'futures/UNITTEST_USDT_USDT-1h-mark.json' load_data(datadir=testdatadir, timeframe='1h', pairs=['UNITTEST/BTC'], candle_type='mark') assert file.is_file() assert not log_has( - 'Download history data for pair: "UNITTEST/USDT", interval: 1m ' + 'Download history data for pair: "UNITTEST/USDT:USDT", interval: 1m ' 'and store in None.', caplog ) diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index 306a30985..432747be0 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -50,7 +50,7 @@ def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side ) api_mock.create_order.reset_mock() - order_types = {'stoploss': 'limit'} + order_types = {'stoploss': 'limit', 'stoploss_price_type': 'mark'} if limitratio is not None: order_types.update({'stoploss_on_exchange_limit_ratio': limitratio}) @@ -75,7 +75,7 @@ def test_stoploss_order_binance(default_conf, mocker, limitratio, expected, side if trademode == TradingMode.SPOT: params_dict = {'stopPrice': 220} else: - params_dict = {'stopPrice': 220, 'reduceOnly': True} + params_dict = {'stopPrice': 220, 'reduceOnly': True, 'workingType': 'MARK_PRICE'} assert api_mock.create_order.call_args_list[0][1]['params'] == params_dict # test exception handling @@ -522,8 +522,15 @@ def test__set_leverage_binance(mocker, default_conf): api_mock.set_leverage = MagicMock() type(api_mock).has = PropertyMock(return_value={'setLeverage': True}) default_conf['dry_run'] = False - exchange = get_patched_exchange(mocker, default_conf, id="binance") - exchange._set_leverage(3.0, trading_mode=TradingMode.MARGIN) + default_conf['trading_mode'] = TradingMode.FUTURES + default_conf['margin_mode'] = MarginMode.ISOLATED + + exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance") + exchange._set_leverage(3.2, 'BTC/USDT:USDT') + assert api_mock.set_leverage.call_count == 1 + # Leverage is rounded to 3. + assert api_mock.set_leverage.call_args_list[0][1]['leverage'] == 3 + assert api_mock.set_leverage.call_args_list[0][1]['symbol'] == 'BTC/USDT:USDT' ccxt_exceptionhandlers( mocker, @@ -557,7 +564,7 @@ async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog, c exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv) pair = 'ETH/BTC' - respair, restf, restype, res = await exchange._async_get_historic_ohlcv( + respair, restf, restype, res, _ = await exchange._async_get_historic_ohlcv( pair, "5m", 1500000000000, is_new_pair=False, candle_type=candle_type) assert respair == pair assert restf == '5m' @@ -566,7 +573,7 @@ async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog, c assert exchange._api_async.fetch_ohlcv.call_count > 400 # assert res == ohlcv exchange._api_async.fetch_ohlcv.reset_mock() - _, _, _, res = await exchange._async_get_historic_ohlcv( + _, _, _, res, _ = await exchange._async_get_historic_ohlcv( pair, "5m", 1500000000000, is_new_pair=True, candle_type=candle_type) # Called twice - one "init" call - and one to get the actual data. @@ -575,25 +582,13 @@ async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog, c assert log_has_re(r"Candle-data for ETH/BTC available starting with .*", caplog) -@pytest.mark.parametrize("trading_mode,margin_mode,config", [ - ("spot", "", {}), - ("margin", "cross", {"options": {"defaultType": "margin"}}), - ("futures", "isolated", {"options": {"defaultType": "future"}}), -]) -def test__ccxt_config(default_conf, mocker, trading_mode, margin_mode, config): - default_conf['trading_mode'] = trading_mode - default_conf['margin_mode'] = margin_mode - exchange = get_patched_exchange(mocker, default_conf, id="binance") - assert exchange._ccxt_config == config - - @pytest.mark.parametrize('pair,nominal_value,mm_ratio,amt', [ - ("BNB/BUSD", 0.0, 0.025, 0), - ("BNB/USDT", 100.0, 0.0065, 0), - ("BTC/USDT", 170.30, 0.004, 0), - ("BNB/BUSD", 999999.9, 0.1, 27500.0), - ("BNB/USDT", 5000000.0, 0.15, 233035.0), - ("BTC/USDT", 600000000, 0.5, 1.997038E8), + ("BNB/BUSD:BUSD", 0.0, 0.025, 0), + ("BNB/USDT:USDT", 100.0, 0.0065, 0), + ("BTC/USDT:USDT", 170.30, 0.004, 0), + ("BNB/BUSD:BUSD", 999999.9, 0.1, 27500.0), + ("BNB/USDT:USDT", 5000000.0, 0.15, 233035.0), + ("BTC/USDT:USDT", 600000000, 0.5, 1.997038E8), ]) def test_get_maintenance_ratio_and_amt_binance( default_conf, diff --git a/tests/exchange/test_bybit.py b/tests/exchange/test_bybit.py new file mode 100644 index 000000000..7c8324bf6 --- /dev/null +++ b/tests/exchange/test_bybit.py @@ -0,0 +1,57 @@ +from unittest.mock import MagicMock + +from freqtrade.enums.marginmode import MarginMode +from freqtrade.enums.tradingmode import TradingMode +from freqtrade.exchange.exchange_utils import timeframe_to_msecs +from tests.conftest import get_mock_coro, get_patched_exchange +from tests.exchange.test_exchange import ccxt_exceptionhandlers + + +def test_additional_exchange_init_bybit(default_conf, mocker): + default_conf['dry_run'] = False + default_conf['trading_mode'] = TradingMode.FUTURES + default_conf['margin_mode'] = MarginMode.ISOLATED + api_mock = MagicMock() + api_mock.set_position_mode = MagicMock(return_value={"dualSidePosition": False}) + get_patched_exchange(mocker, default_conf, id="bybit", api_mock=api_mock) + assert api_mock.set_position_mode.call_count == 1 + ccxt_exceptionhandlers(mocker, default_conf, api_mock, 'bybit', + "additional_exchange_init", "set_position_mode") + + +async def test_bybit_fetch_funding_rate(default_conf, mocker): + default_conf['trading_mode'] = 'futures' + default_conf['margin_mode'] = 'isolated' + api_mock = MagicMock() + api_mock.fetch_funding_rate_history = get_mock_coro(return_value=[]) + exchange = get_patched_exchange(mocker, default_conf, id='bybit', api_mock=api_mock) + limit = 200 + # Test fetch_funding_rate_history (current data) + await exchange._fetch_funding_rate_history( + pair='BTC/USDT:USDT', + timeframe='4h', + limit=limit, + ) + + assert api_mock.fetch_funding_rate_history.call_count == 1 + assert api_mock.fetch_funding_rate_history.call_args_list[0][0][0] == 'BTC/USDT:USDT' + kwargs = api_mock.fetch_funding_rate_history.call_args_list[0][1] + assert kwargs['params'] == {} + assert kwargs['since'] is None + + api_mock.fetch_funding_rate_history.reset_mock() + since_ms = 1610000000000 + since_ms_end = since_ms + (timeframe_to_msecs('4h') * limit) + # Test fetch_funding_rate_history (current data) + await exchange._fetch_funding_rate_history( + pair='BTC/USDT:USDT', + timeframe='4h', + limit=limit, + since_ms=since_ms, + ) + + assert api_mock.fetch_funding_rate_history.call_count == 1 + assert api_mock.fetch_funding_rate_history.call_args_list[0][0][0] == 'BTC/USDT:USDT' + kwargs = api_mock.fetch_funding_rate_history.call_args_list[0][1] + assert kwargs['params'] == {'until': since_ms_end} + assert kwargs['since'] == since_ms diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index e721ee2c9..483a3ae06 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -12,6 +12,7 @@ from typing import Tuple import pytest +from freqtrade.constants import Config from freqtrade.enums import CandleType from freqtrade.exchange import timeframe_to_minutes, timeframe_to_prev_date from freqtrade.exchange.exchange import Exchange, timeframe_to_msecs @@ -31,15 +32,61 @@ EXCHANGES = { 'leverage_tiers_public': False, 'leverage_in_spot_market': False, }, - # 'binance': { - # 'pair': 'BTC/USDT', - # 'stake_currency': 'USDT', - # 'hasQuoteVolume': True, - # 'timeframe': '5m', - # 'futures': True, - # 'leverage_tiers_public': False, - # 'leverage_in_spot_market': False, - # }, + 'binance': { + 'pair': 'BTC/USDT', + 'stake_currency': 'USDT', + 'use_ci_proxy': True, + 'hasQuoteVolume': True, + 'timeframe': '5m', + 'futures': True, + 'futures_pair': 'BTC/USDT:USDT', + 'hasQuoteVolumeFutures': True, + 'leverage_tiers_public': False, + 'leverage_in_spot_market': False, + 'sample_order': [{ + "symbol": "SOLUSDT", + "orderId": 3551312894, + "orderListId": -1, + "clientOrderId": "x-R4DD3S8297c73a11ccb9dc8f2811ba", + "transactTime": 1674493798550, + "price": "15.50000000", + "origQty": "1.10000000", + "executedQty": "0.00000000", + "cummulativeQuoteQty": "0.00000000", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "workingTime": 1674493798550, + "fills": [], + "selfTradePreventionMode": "NONE", + }] + }, + 'binanceus': { + 'pair': 'BTC/USDT', + 'stake_currency': 'USDT', + 'hasQuoteVolume': True, + 'timeframe': '5m', + 'futures': False, + 'sample_order': [{ + "symbol": "SOLUSDT", + "orderId": 3551312894, + "orderListId": -1, + "clientOrderId": "x-R4DD3S8297c73a11ccb9dc8f2811ba", + "transactTime": 1674493798550, + "price": "15.50000000", + "origQty": "1.10000000", + "executedQty": "0.00000000", + "cummulativeQuoteQty": "0.00000000", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "workingTime": 1674493798550, + "fills": [], + "selfTradePreventionMode": "NONE", + }] + }, 'kraken': { 'pair': 'BTC/USDT', 'stake_currency': 'USDT', @@ -55,18 +102,127 @@ EXCHANGES = { 'timeframe': '5m', 'leverage_tiers_public': False, 'leverage_in_spot_market': True, + 'sample_order': [ + {'id': '63d6742d0adc5570001d2bbf7'}, # create order + { + 'id': '63d6742d0adc5570001d2bbf7', + 'symbol': 'SOL-USDT', + 'opType': 'DEAL', + 'type': 'limit', + 'side': 'buy', + 'price': '15.5', + 'size': '1.1', + 'funds': '0', + 'dealFunds': '17.05', + 'dealSize': '1.1', + 'fee': '0.000065252', + 'feeCurrency': 'USDT', + 'stp': '', + 'stop': '', + 'stopTriggered': False, + 'stopPrice': '0', + 'timeInForce': 'GTC', + 'postOnly': False, + 'hidden': False, + 'iceberg': False, + 'visibleSize': '0', + 'cancelAfter': 0, + 'channel': 'API', + 'clientOid': '0a053870-11bf-41e5-be61-b272a4cb62e1', + 'remark': None, + 'tags': 'partner:ccxt', + 'isActive': False, + 'cancelExist': False, + 'createdAt': 1674493798550, + 'tradeType': 'TRADE' + }], }, - 'gateio': { + 'gate': { 'pair': 'BTC/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, 'timeframe': '5m', 'futures': True, 'futures_pair': 'BTC/USDT:USDT', + 'hasQuoteVolumeFutures': True, 'leverage_tiers_public': True, 'leverage_in_spot_market': True, + 'sample_order': [ + { + "id": "276266139423", + "text": "apiv4", + "create_time": "1674493798", + "update_time": "1674493798", + "create_time_ms": "1674493798550", + "update_time_ms": "1674493798550", + "status": "closed", + "currency_pair": "SOL_USDT", + "type": "limit", + "account": "spot", + "side": "buy", + "amount": "1.1", + "price": "15.5", + "time_in_force": "gtc", + "iceberg": "0", + "left": "0", + "fill_price": "17.05", + "filled_total": "17.05", + "avg_deal_price": "15.5", + "fee": "0.0000018", + "fee_currency": "SOL", + "point_fee": "0", + "gt_fee": "0", + "gt_maker_fee": "0", + "gt_taker_fee": "0.0015", + "gt_discount": True, + "rebated_fee": "0", + "rebated_fee_currency": "USDT" + }, + { + # market order + 'id': '276401180529', + 'text': 'apiv4', + 'create_time': '1674493798', + 'update_time': '1674493798', + 'create_time_ms': '1674493798550', + 'update_time_ms': '1674493798550', + 'status': 'cancelled', + 'currency_pair': 'SOL_USDT', + 'type': 'market', + 'account': 'spot', + 'side': 'buy', + 'amount': '17.05', + 'price': '0', + 'time_in_force': 'ioc', + 'iceberg': '0', + 'left': '0.0000000016228', + 'fill_price': '17.05', + 'filled_total': '17.05', + 'avg_deal_price': '15.5', + 'fee': '0', + 'fee_currency': 'SOL', + 'point_fee': '0.0199999999967544', + 'gt_fee': '0', + 'gt_maker_fee': '0', + 'gt_taker_fee': '0', + 'gt_discount': False, + 'rebated_fee': '0', + 'rebated_fee_currency': 'USDT' + } + ], }, 'okx': { + 'pair': 'BTC/USDT', + 'stake_currency': 'USDT', + 'hasQuoteVolume': True, + 'timeframe': '5m', + 'futures': True, + 'futures_pair': 'BTC/USDT:USDT', + 'hasQuoteVolumeFutures': False, + 'leverage_tiers_public': True, + 'leverage_in_spot_market': True, + }, + 'bybit': { 'pair': 'BTC/USDT', 'stake_currency': 'USDT', 'hasQuoteVolume': True, @@ -75,10 +231,27 @@ EXCHANGES = { 'futures': True, 'leverage_tiers_public': True, 'leverage_in_spot_market': True, + 'sample_order': [ + { + "orderId": "1274754916287346280", + "orderLinkId": "1666798627015730", + "symbol": "SOLUSDT", + "createTime": "1674493798550", + "orderPrice": "15.5", + "orderQty": "1.1", + "orderType": "LIMIT", + "side": "BUY", + "status": "NEW", + "timeInForce": "GTC", + "accountId": "5555555", + "execQty": "0", + "orderCategory": "0" + } + ] }, 'huobi': { - 'pair': 'BTC/USDT', - 'stake_currency': 'USDT', + 'pair': 'ETH/BTC', + 'stake_currency': 'BTC', 'hasQuoteVolume': True, 'timeframe': '5m', 'futures': False, @@ -106,8 +279,27 @@ def exchange_conf(): return config +def set_test_proxy(config: Config, use_proxy: bool) -> Config: + # Set proxy to test in CI. + import os + if use_proxy and (proxy := os.environ.get('CI_WEB_PROXY')): + config1 = deepcopy(config) + config1['exchange']['ccxt_config'] = { + "aiohttp_proxy": proxy, + 'proxies': { + 'https': proxy, + 'http': proxy, + } + } + return config1 + + return config + + @pytest.fixture(params=EXCHANGES, scope="class") def exchange(request, exchange_conf): + exchange_conf = set_test_proxy( + exchange_conf, EXCHANGES[request.param].get('use_ci_proxy', False)) exchange_conf['exchange']['name'] = request.param exchange_conf['stake_currency'] = EXCHANGES[request.param]['stake_currency'] exchange = ExchangeResolver.load_exchange(request.param, exchange_conf, validate=True) @@ -120,6 +312,8 @@ def exchange_futures(request, exchange_conf, class_mocker): if not EXCHANGES[request.param].get('futures') is True: yield None, request.param else: + exchange_conf = set_test_proxy( + exchange_conf, EXCHANGES[request.param].get('use_ci_proxy', False)) exchange_conf = deepcopy(exchange_conf) exchange_conf['exchange']['name'] = request.param exchange_conf['trading_mode'] = 'futures' @@ -131,6 +325,7 @@ def exchange_futures(request, exchange_conf, class_mocker): class_mocker.patch('freqtrade.exchange.exchange.Exchange.fetch_trading_fees') class_mocker.patch('freqtrade.exchange.okx.Okx.additional_exchange_init') class_mocker.patch('freqtrade.exchange.binance.Binance.additional_exchange_init') + class_mocker.patch('freqtrade.exchange.bybit.Bybit.additional_exchange_init') class_mocker.patch('freqtrade.exchange.exchange.Exchange.load_cached_leverage_tiers', return_value=None) class_mocker.patch('freqtrade.exchange.exchange.Exchange.cache_leverage_tiers') @@ -162,8 +357,8 @@ class TestCCXTExchange(): 'stoploss': 'limit', }) - if exchangename == 'gateio': - # gateio doesn't have market orders on spot + if exchangename == 'gate': + # gate doesn't have market orders on spot return exch.validate_ordertypes({ 'entry': 'market', @@ -184,6 +379,32 @@ class TestCCXTExchange(): assert exchange.market_is_future(markets[pair]) + def test_ccxt_order_parse(self, exchange: EXCHANGE_FIXTURE_TYPE): + exch, exchange_name = exchange + if orders := EXCHANGES[exchange_name].get('sample_order'): + for order in orders: + po = exch._api.parse_order(order) + assert isinstance(po['id'], str) + assert po['id'] is not None + if len(order.keys()) < 5: + # Kucoin case + assert po['status'] == 'closed' + continue + assert po['timestamp'] == 1674493798550 + assert isinstance(po['datetime'], str) + assert isinstance(po['timestamp'], int) + assert isinstance(po['price'], float) + assert po['price'] == 15.5 + if po['average'] is not None: + assert isinstance(po['average'], float) + assert po['average'] == 15.5 + assert po['symbol'] == 'SOL/USDT' + assert isinstance(po['amount'], float) + assert po['amount'] == 1.1 + assert isinstance(po['status'], str) + else: + pytest.skip(f"No sample order available for exchange {exchange_name}") + def test_ccxt_fetch_tickers(self, exchange: EXCHANGE_FIXTURE_TYPE): exch, exchangename = exchange pair = EXCHANGES[exchangename]['pair'] @@ -198,6 +419,25 @@ class TestCCXTExchange(): if EXCHANGES[exchangename].get('hasQuoteVolume'): assert tickers[pair]['quoteVolume'] is not None + def test_ccxt_fetch_tickers_futures(self, exchange_futures: EXCHANGE_FIXTURE_TYPE): + exch, exchangename = exchange_futures + if not exch or exchangename in ('gate'): + # exchange_futures only returns values for supported exchanges + return + + pair = EXCHANGES[exchangename]['pair'] + pair = EXCHANGES[exchangename].get('futures_pair', pair) + + tickers = exch.get_tickers() + assert pair in tickers + assert 'ask' in tickers[pair] + assert tickers[pair]['ask'] is not None + assert 'bid' in tickers[pair] + assert tickers[pair]['bid'] is not None + assert 'quoteVolume' in tickers[pair] + if EXCHANGES[exchangename].get('hasQuoteVolumeFutures'): + assert tickers[pair]['quoteVolume'] is not None + def test_ccxt_fetch_ticker(self, exchange: EXCHANGE_FIXTURE_TYPE): exch, exchangename = exchange pair = EXCHANGES[exchangename]['pair'] @@ -221,8 +461,8 @@ class TestCCXTExchange(): assert len(l2['bids']) >= 1 l2_limit_range = exch._ft_has['l2_limit_range'] l2_limit_range_required = exch._ft_has['l2_limit_range_required'] - if exchangename == 'gateio': - # TODO: Gateio is unstable here at the moment, ignoring the limit partially. + if exchangename == 'gate': + # TODO: Gate is unstable here at the moment, ignoring the limit partially. return for val in [1, 2, 5, 25, 100]: l2 = exch.fetch_l2_order_book(pair, val) @@ -294,9 +534,13 @@ class TestCCXTExchange(): def test_ccxt__async_get_candle_history(self, exchange: EXCHANGE_FIXTURE_TYPE): exc, exchangename = exchange - # For some weired reason, this test returns random lengths for bittrex. - if not exc._ft_has['ohlcv_has_history'] or exchangename in ('bittrex'): - return + if exchangename in ('binanceus', 'bittrex'): + # TODO: reenable binanceus test once downtime "ages out" (2023-02-06) + # For some weired reason, this test returns random lengths for bittrex. + pytest.skip("Exchange doesn't provide stable ohlcv history") + + if not exc._ft_has['ohlcv_has_history']: + pytest.skip("Exchange does not support candle history") pair = EXCHANGES[exchangename]['pair'] timeframe = EXCHANGES[exchangename]['timeframe'] self.ccxt__async_get_candle_history( @@ -476,23 +720,25 @@ class TestCCXTExchange(): ) liquidation_price = futures.dry_run_liquidation_price( - futures_pair, - 40000, - False, - 100, - 100, - 100, + pair=futures_pair, + open_rate=40000, + is_short=False, + amount=100, + stake_amount=100, + leverage=5, + wallet_balance=100, ) assert (isinstance(liquidation_price, float)) assert liquidation_price >= 0.0 liquidation_price = futures.dry_run_liquidation_price( - futures_pair, - 40000, - False, - 100, - 100, - 100, + pair=futures_pair, + open_rate=40000, + is_short=False, + amount=100, + stake_amount=100, + leverage=5, + wallet_balance=100, ) assert (isinstance(liquidation_price, float)) assert liquidation_price >= 0.0 diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 280e20ff0..0cd2a528a 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -27,7 +27,7 @@ from tests.conftest import (generate_test_data_raw, get_mock_coro, get_patched_e # Make sure to always keep one exchange here which is NOT subclassed!! -EXCHANGES = ['bittrex', 'binance', 'kraken', 'gateio'] +EXCHANGES = ['bittrex', 'binance', 'kraken', 'gate'] get_entry_rate_data = [ ('other', 20, 19, 10, 0.0, 20), # Full ask side @@ -1060,6 +1060,47 @@ def test_validate_ordertypes(default_conf, mocker): Exchange(default_conf) +@pytest.mark.parametrize('exchange_name,stopadv, expected', [ + ('binance', 'last', True), + ('binance', 'mark', True), + ('binance', 'index', False), + ('bybit', 'last', True), + ('bybit', 'mark', True), + ('bybit', 'index', True), + # ('okx', 'last', True), + # ('okx', 'mark', True), + # ('okx', 'index', True), + ('gate', 'last', True), + ('gate', 'mark', True), + ('gate', 'index', True), + ]) +def test_validate_ordertypes_stop_advanced(default_conf, mocker, exchange_name, stopadv, expected): + + api_mock = MagicMock() + default_conf['trading_mode'] = TradingMode.FUTURES + default_conf['margin_mode'] = MarginMode.ISOLATED + type(api_mock).has = PropertyMock(return_value={'createMarketOrder': True}) + mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) + mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) + mocker.patch('freqtrade.exchange.Exchange.validate_pairs') + mocker.patch('freqtrade.exchange.Exchange.validate_timeframes') + mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency') + mocker.patch('freqtrade.exchange.Exchange.validate_pricing') + default_conf['order_types'] = { + 'entry': 'limit', + 'exit': 'limit', + 'stoploss': 'limit', + 'stoploss_on_exchange': True, + 'stoploss_price_type': stopadv, + } + if expected: + ExchangeResolver.load_exchange(exchange_name, default_conf) + else: + with pytest.raises(OperationalException, + match=r'On exchange stoploss price type is not supported for .*'): + ExchangeResolver.load_exchange(exchange_name, default_conf) + + def test_validate_order_types_not_in_config(default_conf, mocker): api_mock = MagicMock() mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) @@ -1742,7 +1783,7 @@ def test_fetch_trading_fees(default_conf, mocker): 'maker': 0.0, 'taker': 0.0005} } - exchange_name = 'gateio' + exchange_name = 'gate' default_conf['dry_run'] = False default_conf['trading_mode'] = TradingMode.FUTURES default_conf['margin_mode'] = MarginMode.ISOLATED @@ -1955,7 +1996,7 @@ def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_ pair = 'ETH/BTC' async def mock_candle_hist(pair, timeframe, candle_type, since_ms): - return pair, timeframe, candle_type, ohlcv + return pair, timeframe, candle_type, ohlcv, True exchange._async_get_candle_history = Mock(wraps=mock_candle_hist) # one_call calculation * 1.8 should do 2 calls @@ -1988,62 +2029,6 @@ def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_ assert log_has_re(r"Async code raised an exception: .*", caplog) -@pytest.mark.parametrize("exchange_name", EXCHANGES) -@pytest.mark.parametrize('candle_type', ['mark', '']) -def test_get_historic_ohlcv_as_df(default_conf, mocker, exchange_name, candle_type): - exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) - ohlcv = [ - [ - arrow.utcnow().int_timestamp * 1000, # unix timestamp ms - 1, # open - 2, # high - 3, # low - 4, # close - 5, # volume (in quote currency) - ], - [ - arrow.utcnow().shift(minutes=5).int_timestamp * 1000, # unix timestamp ms - 1, # open - 2, # high - 3, # low - 4, # close - 5, # volume (in quote currency) - ], - [ - arrow.utcnow().shift(minutes=10).int_timestamp * 1000, # unix timestamp ms - 1, # open - 2, # high - 3, # low - 4, # close - 5, # volume (in quote currency) - ] - ] - pair = 'ETH/BTC' - - async def mock_candle_hist(pair, timeframe, candle_type, since_ms): - return pair, timeframe, candle_type, ohlcv - - exchange._async_get_candle_history = Mock(wraps=mock_candle_hist) - # one_call calculation * 1.8 should do 2 calls - - since = 5 * 60 * exchange.ohlcv_candle_limit('5m', CandleType.SPOT) * 1.8 - ret = exchange.get_historic_ohlcv_as_df( - pair, - "5m", - int((arrow.utcnow().int_timestamp - since) * 1000), - candle_type=candle_type - ) - - assert exchange._async_get_candle_history.call_count == 2 - # Returns twice the above OHLCV data - assert len(ret) == 2 - assert isinstance(ret, DataFrame) - assert 'date' in ret.columns - assert 'open' in ret.columns - assert 'close' in ret.columns - assert 'high' in ret.columns - - @pytest.mark.asyncio @pytest.mark.parametrize("exchange_name", EXCHANGES) @pytest.mark.parametrize('candle_type', [CandleType.MARK, CandleType.SPOT]) @@ -2063,7 +2048,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_ exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv) pair = 'ETH/USDT' - respair, restf, _, res = await exchange._async_get_historic_ohlcv( + respair, restf, _, res, _ = await exchange._async_get_historic_ohlcv( pair, "5m", 1500000000000, candle_type=candle_type, is_new_pair=False) assert respair == pair assert restf == '5m' @@ -2074,7 +2059,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_ exchange._api_async.fetch_ohlcv.reset_mock() end_ts = 1_500_500_000_000 start_ts = 1_500_000_000_000 - respair, restf, _, res = await exchange._async_get_historic_ohlcv( + respair, restf, _, res, _ = await exchange._async_get_historic_ohlcv( pair, "5m", since_ms=start_ts, candle_type=candle_type, is_new_pair=False, until_ms=end_ts ) @@ -2306,7 +2291,7 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_ pair = 'ETH/BTC' res = await exchange._async_get_candle_history(pair, "5m", CandleType.SPOT) assert type(res) is tuple - assert len(res) == 4 + assert len(res) == 5 assert res[0] == pair assert res[1] == "5m" assert res[2] == CandleType.SPOT @@ -2393,7 +2378,7 @@ async def test__async_get_candle_history_empty(default_conf, mocker, caplog): pair = 'ETH/BTC' res = await exchange._async_get_candle_history(pair, "5m", CandleType.SPOT) assert type(res) is tuple - assert len(res) == 4 + assert len(res) == 5 assert res[0] == pair assert res[1] == "5m" assert res[2] == CandleType.SPOT @@ -3162,24 +3147,24 @@ def test_cancel_stoploss_order(default_conf, mocker, exchange_name): def test_cancel_stoploss_order_with_result(default_conf, mocker, exchange_name): default_conf['dry_run'] = False mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', return_value={'for': 123}) - mocker.patch('freqtrade.exchange.Gateio.fetch_stoploss_order', return_value={'for': 123}) + mocker.patch('freqtrade.exchange.Gate.fetch_stoploss_order', return_value={'for': 123}) exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) res = {'fee': {}, 'status': 'canceled', 'amount': 1234} mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', return_value=res) - mocker.patch('freqtrade.exchange.Gateio.cancel_stoploss_order', return_value=res) + mocker.patch('freqtrade.exchange.Gate.cancel_stoploss_order', return_value=res) co = exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=555) assert co == res mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', return_value='canceled') - mocker.patch('freqtrade.exchange.Gateio.cancel_stoploss_order', return_value='canceled') + mocker.patch('freqtrade.exchange.Gate.cancel_stoploss_order', return_value='canceled') # Fall back to fetch_stoploss_order co = exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=555) assert co == {'for': 123} exc = InvalidOrderException("") mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', side_effect=exc) - mocker.patch('freqtrade.exchange.Gateio.fetch_stoploss_order', side_effect=exc) + mocker.patch('freqtrade.exchange.Gate.fetch_stoploss_order', side_effect=exc) co = exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=555) assert co['amount'] == 555 assert co == {'fee': {}, 'status': 'canceled', 'amount': 555, 'info': {}} @@ -3187,7 +3172,7 @@ def test_cancel_stoploss_order_with_result(default_conf, mocker, exchange_name): with pytest.raises(InvalidOrderException): exc = InvalidOrderException("Did not find order") mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', side_effect=exc) - mocker.patch('freqtrade.exchange.Gateio.cancel_stoploss_order', side_effect=exc) + mocker.patch('freqtrade.exchange.Gate.cancel_stoploss_order', side_effect=exc) exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=123) @@ -3967,14 +3952,14 @@ def test_set_margin_mode(mocker, default_conf, margin_mode): ("bittrex", TradingMode.MARGIN, MarginMode.ISOLATED, True), ("bittrex", TradingMode.FUTURES, MarginMode.CROSS, True), ("bittrex", TradingMode.FUTURES, MarginMode.ISOLATED, True), - ("gateio", TradingMode.MARGIN, MarginMode.ISOLATED, True), + ("gate", TradingMode.MARGIN, MarginMode.ISOLATED, True), ("okx", TradingMode.SPOT, None, False), ("okx", TradingMode.MARGIN, MarginMode.CROSS, True), ("okx", TradingMode.MARGIN, MarginMode.ISOLATED, True), ("okx", TradingMode.FUTURES, MarginMode.CROSS, True), ("binance", TradingMode.FUTURES, MarginMode.ISOLATED, False), - ("gateio", TradingMode.FUTURES, MarginMode.ISOLATED, False), + ("gate", TradingMode.FUTURES, MarginMode.ISOLATED, False), ("okx", TradingMode.FUTURES, MarginMode.ISOLATED, False), # * Remove once implemented @@ -3982,16 +3967,16 @@ def test_set_margin_mode(mocker, default_conf, margin_mode): ("binance", TradingMode.FUTURES, MarginMode.CROSS, True), ("kraken", TradingMode.MARGIN, MarginMode.CROSS, True), ("kraken", TradingMode.FUTURES, MarginMode.CROSS, True), - ("gateio", TradingMode.MARGIN, MarginMode.CROSS, True), - ("gateio", TradingMode.FUTURES, MarginMode.CROSS, True), + ("gate", TradingMode.MARGIN, MarginMode.CROSS, True), + ("gate", TradingMode.FUTURES, MarginMode.CROSS, True), # * Uncomment once implemented # ("binance", TradingMode.MARGIN, MarginMode.CROSS, False), # ("binance", TradingMode.FUTURES, MarginMode.CROSS, False), # ("kraken", TradingMode.MARGIN, MarginMode.CROSS, False), # ("kraken", TradingMode.FUTURES, MarginMode.CROSS, False), - # ("gateio", TradingMode.MARGIN, MarginMode.CROSS, False), - # ("gateio", TradingMode.FUTURES, MarginMode.CROSS, False), + # ("gate", TradingMode.MARGIN, MarginMode.CROSS, False), + # ("gate", TradingMode.FUTURES, MarginMode.CROSS, False), ]) def test_validate_trading_mode_and_margin_mode( default_conf, @@ -4013,10 +3998,10 @@ def test_validate_trading_mode_and_margin_mode( @pytest.mark.parametrize("exchange_name,trading_mode,ccxt_config", [ ("binance", "spot", {}), ("binance", "margin", {"options": {"defaultType": "margin"}}), - ("binance", "futures", {"options": {"defaultType": "future"}}), + ("binance", "futures", {"options": {"defaultType": "swap"}}), ("bybit", "spot", {"options": {"defaultType": "spot"}}), - ("bybit", "futures", {"options": {"defaultType": "linear"}}), - ("gateio", "futures", {"options": {"defaultType": "swap"}}), + ("bybit", "futures", {"options": {"defaultType": "swap"}}), + ("gate", "futures", {"options": {"defaultType": "swap"}}), ("hitbtc", "futures", {"options": {"defaultType": "swap"}}), ("kraken", "futures", {"options": {"defaultType": "swap"}}), ("kucoin", "futures", {"options": {"defaultType": "swap"}}), @@ -4047,7 +4032,7 @@ def test_get_max_leverage_from_margin(default_conf, mocker, pair, nominal_value, default_conf['margin_mode'] = 'isolated' api_mock = MagicMock() type(api_mock).has = PropertyMock(return_value={'fetchLeverageTiers': False}) - exchange = get_patched_exchange(mocker, default_conf, api_mock, id="gateio") + exchange = get_patched_exchange(mocker, default_conf, api_mock, id="gate") assert exchange.get_max_leverage(pair, nominal_value) == max_lev @@ -4192,10 +4177,10 @@ def test_combine_funding_and_mark( # ('kraken', "2021-09-01 00:00:00", "2021-09-01 07:59:59", 30.0, -0.0012443999999999999), # ('kraken', "2021-09-01 00:00:00", "2021-09-01 12:00:00", 30.0, 0.0045759), # ('kraken', "2021-09-01 00:00:01", "2021-09-01 08:00:00", 30.0, -0.0008289), - ('gateio', 0, 2, "2021-09-01 00:10:00", "2021-09-01 04:00:00", 30.0, 0.0), - ('gateio', 0, 2, "2021-09-01 00:00:00", "2021-09-01 08:00:00", 30.0, -0.0009140999), - ('gateio', 0, 2, "2021-09-01 00:00:00", "2021-09-01 12:00:00", 30.0, -0.0009140999), - ('gateio', 1, 2, "2021-09-01 00:00:01", "2021-09-01 08:00:00", 30.0, -0.0002493), + ('gate', 0, 2, "2021-09-01 00:10:00", "2021-09-01 04:00:00", 30.0, 0.0), + ('gate', 0, 2, "2021-09-01 00:00:00", "2021-09-01 08:00:00", 30.0, -0.0009140999), + ('gate', 0, 2, "2021-09-01 00:00:00", "2021-09-01 12:00:00", 30.0, -0.0009140999), + ('gate', 1, 2, "2021-09-01 00:00:01", "2021-09-01 08:00:00", 30.0, -0.0002493), ('binance', 0, 2, "2021-09-01 00:00:00", "2021-09-01 08:00:00", 50.0, -0.0015235), # TODO: Uncoment once _calculate_funding_fees can pas time_in_ratio to exchange._get_funding_fee # ('kraken', "2021-09-01 00:00:00", "2021-09-01 08:00:00", 50.0, -0.0024895), @@ -4253,7 +4238,7 @@ def test__fetch_and_calculate_funding_fees( d2 = datetime.strptime(f"{d2} +0000", '%Y-%m-%d %H:%M:%S %z') funding_rate_history = { 'binance': funding_rate_history_octohourly, - 'gateio': funding_rate_history_octohourly, + 'gate': funding_rate_history_octohourly, }[exchange][rate_start:rate_end] api_mock = MagicMock() api_mock.fetch_funding_rate_history = get_mock_coro(return_value=funding_rate_history) @@ -4282,7 +4267,7 @@ def test__fetch_and_calculate_funding_fees( @pytest.mark.parametrize('exchange,expected_fees', [ ('binance', -0.0009140999999999999), - ('gateio', -0.0009140999999999999), + ('gate', -0.0009140999999999999), ]) def test__fetch_and_calculate_funding_fees_datetime_called( mocker, @@ -4423,7 +4408,7 @@ def test__order_contracts_to_amount( 'info': {}, }, { - # Realistic stoploss order on gateio. + # Realistic stoploss order on gate. 'id': '123456380', 'clientOrderId': '12345638203', 'timestamp': None, @@ -4622,6 +4607,7 @@ def test_liquidation_price_is_none( is_short=is_short, amount=71200.81144, stake_amount=open_rate * 71200.81144, + leverage=5, wallet_balance=-56354.57, mm_ex_1=0.10, upnl_ex_1=0.0 @@ -4642,7 +4628,7 @@ def test_liquidation_price_is_none( ("binance", False, 'futures', 'cross', 1535443.01, 356512.508, -448192.89, 16300.000, 109.488, 32481.980, 0.025, 26316.89) ]) -def test_liquidation_price( +def test_liquidation_price_binance( mocker, default_conf, exchange_name, open_rate, is_short, trading_mode, margin_mode, wallet_balance, mm_ex_1, upnl_ex_1, maintenance_amt, amount, mm_ratio, expected ): @@ -4660,6 +4646,7 @@ def test_liquidation_price( upnl_ex_1=upnl_ex_1, amount=amount, stake_amount=open_rate * amount, + leverage=5, ), 2)) == expected @@ -4954,22 +4941,22 @@ def test_get_maintenance_ratio_and_amt_exceptions(mocker, default_conf, leverage OperationalException, match='nominal value can not be lower than 0', ): - exchange.get_maintenance_ratio_and_amt('1000SHIB/USDT', -1) + exchange.get_maintenance_ratio_and_amt('1000SHIB/USDT:USDT', -1) exchange._leverage_tiers = {} with pytest.raises( InvalidOrderException, - match="Maintenance margin rate for 1000SHIB/USDT is unavailable for", + match="Maintenance margin rate for 1000SHIB/USDT:USDT is unavailable for", ): - exchange.get_maintenance_ratio_and_amt('1000SHIB/USDT', 10000) + exchange.get_maintenance_ratio_and_amt('1000SHIB/USDT:USDT', 10000) @pytest.mark.parametrize('pair,value,mmr,maintAmt', [ - ('ADA/BUSD', 500, 0.025, 0.0), - ('ADA/BUSD', 20000000, 0.5, 1527500.0), - ('ZEC/USDT', 500, 0.01, 0.0), - ('ZEC/USDT', 20000000, 0.5, 654500.0), + ('ADA/BUSD:BUSD', 500, 0.025, 0.0), + ('ADA/BUSD:BUSD', 20000000, 0.5, 1527500.0), + ('ZEC/USDT:USDT', 500, 0.01, 0.0), + ('ZEC/USDT:USDT', 20000000, 0.5, 654500.0), ]) def test_get_maintenance_ratio_and_amt( mocker, @@ -5002,24 +4989,24 @@ def test_get_max_leverage_futures(default_conf, mocker, leverage_tiers): exchange._leverage_tiers = leverage_tiers - assert exchange.get_max_leverage("BNB/BUSD", 1.0) == 20.0 - assert exchange.get_max_leverage("BNB/USDT", 100.0) == 75.0 - assert exchange.get_max_leverage("BTC/USDT", 170.30) == 125.0 - assert pytest.approx(exchange.get_max_leverage("BNB/BUSD", 99999.9)) == 5.000005 - assert pytest.approx(exchange.get_max_leverage("BNB/USDT", 1500)) == 33.333333333333333 - assert exchange.get_max_leverage("BTC/USDT", 300000000) == 2.0 - assert exchange.get_max_leverage("BTC/USDT", 600000000) == 1.0 # Last tier + assert exchange.get_max_leverage("BNB/BUSD:BUSD", 1.0) == 20.0 + assert exchange.get_max_leverage("BNB/USDT:USDT", 100.0) == 75.0 + assert exchange.get_max_leverage("BTC/USDT:USDT", 170.30) == 125.0 + assert pytest.approx(exchange.get_max_leverage("BNB/BUSD:BUSD", 99999.9)) == 5.000005 + assert pytest.approx(exchange.get_max_leverage("BNB/USDT:USDT", 1500)) == 33.333333333333333 + assert exchange.get_max_leverage("BTC/USDT:USDT", 300000000) == 2.0 + assert exchange.get_max_leverage("BTC/USDT:USDT", 600000000) == 1.0 # Last tier - assert exchange.get_max_leverage("SPONGE/USDT", 200) == 1.0 # Pair not in leverage_tiers - assert exchange.get_max_leverage("BTC/USDT", 0.0) == 125.0 # No stake amount + assert exchange.get_max_leverage("SPONGE/USDT:USDT", 200) == 1.0 # Pair not in leverage_tiers + assert exchange.get_max_leverage("BTC/USDT:USDT", 0.0) == 125.0 # No stake amount with pytest.raises( InvalidOrderException, - match=r'Amount 1000000000.01 too high for BTC/USDT' + match=r'Amount 1000000000.01 too high for BTC/USDT:USDT' ): - exchange.get_max_leverage("BTC/USDT", 1000000000.01) + exchange.get_max_leverage("BTC/USDT:USDT", 1000000000.01) -@pytest.mark.parametrize("exchange_name", ['bittrex', 'binance', 'kraken', 'gateio', 'okx']) +@pytest.mark.parametrize("exchange_name", ['bittrex', 'binance', 'kraken', 'gate', 'okx']) def test__get_params(mocker, default_conf, exchange_name): api_mock = MagicMock() mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True) @@ -5081,6 +5068,7 @@ def test__get_params(mocker, default_conf, exchange_name): def test_get_liquidation_price1(mocker, default_conf): api_mock = MagicMock() + leverage = 9.97 positions = [ { 'info': {}, @@ -5093,7 +5081,7 @@ def test_get_liquidation_price1(mocker, default_conf): 'maintenanceMarginPercentage': 0.025, 'entryPrice': 18.884, 'notional': 15.1072, - 'leverage': 9.97, + 'leverage': leverage, 'unrealizedPnl': 0.0048, 'contracts': 8, 'contractSize': 0.1, @@ -5123,6 +5111,7 @@ def test_get_liquidation_price1(mocker, default_conf): is_short=False, amount=0.8, stake_amount=18.884 * 0.8, + leverage=leverage, wallet_balance=18.884 * 0.8, ) assert liq_price == 17.47 @@ -5135,6 +5124,7 @@ def test_get_liquidation_price1(mocker, default_conf): is_short=False, amount=0.8, stake_amount=18.884 * 0.8, + leverage=leverage, wallet_balance=18.884 * 0.8, ) assert liq_price == 17.540699999999998 @@ -5147,6 +5137,7 @@ def test_get_liquidation_price1(mocker, default_conf): is_short=False, amount=0.8, stake_amount=18.884 * 0.8, + leverage=leverage, wallet_balance=18.884 * 0.8, ) assert liq_price is None @@ -5160,17 +5151,18 @@ def test_get_liquidation_price1(mocker, default_conf): is_short=False, amount=0.8, stake_amount=18.884 * 0.8, + leverage=leverage, wallet_balance=18.884 * 0.8, ) -@pytest.mark.parametrize('liquidation_buffer', [0.0, 0.05]) +@pytest.mark.parametrize('liquidation_buffer', [0.0]) @pytest.mark.parametrize( "is_short,trading_mode,exchange_name,margin_mode,leverage,open_rate,amount,expected_liq", [ (False, 'spot', 'binance', '', 5.0, 10.0, 1.0, None), (True, 'spot', 'binance', '', 5.0, 10.0, 1.0, None), - (False, 'spot', 'gateio', '', 5.0, 10.0, 1.0, None), - (True, 'spot', 'gateio', '', 5.0, 10.0, 1.0, None), + (False, 'spot', 'gate', '', 5.0, 10.0, 1.0, None), + (True, 'spot', 'gate', '', 5.0, 10.0, 1.0, None), (False, 'spot', 'okx', '', 5.0, 10.0, 1.0, None), (True, 'spot', 'okx', '', 5.0, 10.0, 1.0, None), # Binance, short @@ -5183,16 +5175,26 @@ def test_get_liquidation_price1(mocker, default_conf): (False, 'futures', 'binance', 'isolated', 5, 8, 1.0, 6.454545454545454), (False, 'futures', 'binance', 'isolated', 3, 10, 1.0, 6.723905723905723), (False, 'futures', 'binance', 'isolated', 5, 10, 0.6, 8.063973063973064), - # Gateio/okx, short - (True, 'futures', 'gateio', 'isolated', 5, 10, 1.0, 11.87413417771621), - (True, 'futures', 'gateio', 'isolated', 5, 10, 2.0, 11.87413417771621), - (True, 'futures', 'gateio', 'isolated', 3, 10, 1.0, 13.193482419684678), - (True, 'futures', 'gateio', 'isolated', 5, 8, 1.0, 9.499307342172967), + # Gate/okx, short + (True, 'futures', 'gate', 'isolated', 5, 10, 1.0, 11.87413417771621), + (True, 'futures', 'gate', 'isolated', 5, 10, 2.0, 11.87413417771621), + (True, 'futures', 'gate', 'isolated', 3, 10, 1.0, 13.193482419684678), + (True, 'futures', 'gate', 'isolated', 5, 8, 1.0, 9.499307342172967), (True, 'futures', 'okx', 'isolated', 3, 10, 1.0, 13.193482419684678), - # Gateio/okx, long - (False, 'futures', 'gateio', 'isolated', 5.0, 10.0, 1.0, 8.085708510208207), - (False, 'futures', 'gateio', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506), + # Gate/okx, long + (False, 'futures', 'gate', 'isolated', 5.0, 10.0, 1.0, 8.085708510208207), + (False, 'futures', 'gate', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506), (False, 'futures', 'okx', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506), + # bybit, long + (False, 'futures', 'bybit', 'isolated', 1.0, 10.0, 1.0, 0.1), + (False, 'futures', 'bybit', 'isolated', 3.0, 10.0, 1.0, 6.7666666), + (False, 'futures', 'bybit', 'isolated', 5.0, 10.0, 1.0, 8.1), + (False, 'futures', 'bybit', 'isolated', 10.0, 10.0, 1.0, 9.1), + # bybit, short + (True, 'futures', 'bybit', 'isolated', 1.0, 10.0, 1.0, 19.9), + (True, 'futures', 'bybit', 'isolated', 3.0, 10.0, 1.0, 13.233333), + (True, 'futures', 'bybit', 'isolated', 5.0, 10.0, 1.0, 11.9), + (True, 'futures', 'bybit', 'isolated', 10.0, 10.0, 1.0, 10.9), ] ) def test_get_liquidation_price( @@ -5238,7 +5240,7 @@ def test_get_liquidation_price( leverage = 5, open_rate = 10, amount = 0.6 ((1.6 + 0.01) - (1 * 0.6 * 10)) / ((0.6 * 0.01) - (1 * 0.6)) = 7.39057239057239 - Gateio/Okx, Short + Gate/Okx, Short leverage = 5, open_rate = 10, amount = 1.0 (open_rate + (wallet_balance / position)) / (1 + (mm_ratio + taker_fee_rate)) (10 + (2 / 1.0)) / (1 + (0.01 + 0.0006)) = 11.87413417771621 @@ -5249,7 +5251,7 @@ def test_get_liquidation_price( leverage = 5, open_rate = 8, amount = 1.0 (8 + (1.6 / 1.0)) / (1 + (0.01 + 0.0006)) = 9.499307342172967 - Gateio/Okx, Long + Gate/Okx, Long leverage = 5, open_rate = 10, amount = 1.0 (open_rate - (wallet_balance / position)) / (1 - (mm_ratio + taker_fee_rate)) (10 - (2 / 1)) / (1 - (0.01 + 0.0006)) = 8.085708510208207 @@ -5264,7 +5266,7 @@ def test_get_liquidation_price( default_conf_usdt['trading_mode'] = trading_mode default_conf_usdt['exchange']['name'] = exchange_name default_conf_usdt['margin_mode'] = margin_mode - mocker.patch('freqtrade.exchange.Gateio.validate_ordertypes') + mocker.patch('freqtrade.exchange.Gate.validate_ordertypes') exchange = get_patched_exchange(mocker, default_conf_usdt, id=exchange_name) exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(0.01, 0.01)) @@ -5278,7 +5280,7 @@ def test_get_liquidation_price( amount=amount, stake_amount=amount * open_rate / leverage, wallet_balance=amount * open_rate / leverage, - # leverage=leverage, + leverage=leverage, is_short=is_short, ) if expected_liq is None: diff --git a/tests/exchange/test_gateio.py b/tests/exchange/test_gate.py similarity index 85% rename from tests/exchange/test_gateio.py rename to tests/exchange/test_gate.py index dabdbba65..f777dd7d0 100644 --- a/tests/exchange/test_gateio.py +++ b/tests/exchange/test_gate.py @@ -5,22 +5,22 @@ import pytest from freqtrade.enums import MarginMode, TradingMode from freqtrade.exceptions import OperationalException -from freqtrade.exchange import Gateio +from freqtrade.exchange import Gate from freqtrade.resolvers.exchange_resolver import ExchangeResolver from tests.conftest import get_patched_exchange -def test_validate_order_types_gateio(default_conf, mocker): - default_conf['exchange']['name'] = 'gateio' +def test_validate_order_types_gate(default_conf, mocker): + default_conf['exchange']['name'] = 'gate' mocker.patch('freqtrade.exchange.Exchange._init_ccxt') mocker.patch('freqtrade.exchange.Exchange._load_markets', return_value={}) mocker.patch('freqtrade.exchange.Exchange.validate_pairs') mocker.patch('freqtrade.exchange.Exchange.validate_timeframes') mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency') mocker.patch('freqtrade.exchange.Exchange.validate_pricing') - mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex') - exch = ExchangeResolver.load_exchange('gateio', default_conf, True) - assert isinstance(exch, Gateio) + mocker.patch('freqtrade.exchange.Exchange.name', 'Gate') + exch = ExchangeResolver.load_exchange('gate', default_conf, True) + assert isinstance(exch, Gate) default_conf['order_types'] = { 'entry': 'market', @@ -31,18 +31,18 @@ def test_validate_order_types_gateio(default_conf, mocker): with pytest.raises(OperationalException, match=r'Exchange .* does not support market orders.'): - ExchangeResolver.load_exchange('gateio', default_conf, True) + 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('gateio', default_conf, True) + ex = ExchangeResolver.load_exchange('gate', default_conf, True) assert ex @pytest.mark.usefixtures("init_persistence") -def test_fetch_stoploss_order_gateio(default_conf, mocker): - exchange = get_patched_exchange(mocker, default_conf, id='gateio') +def test_fetch_stoploss_order_gate(default_conf, mocker): + exchange = get_patched_exchange(mocker, default_conf, id='gate') fetch_order_mock = MagicMock() exchange.fetch_order = fetch_order_mock @@ -56,7 +56,7 @@ def test_fetch_stoploss_order_gateio(default_conf, mocker): default_conf['trading_mode'] = 'futures' default_conf['margin_mode'] = 'isolated' - exchange = get_patched_exchange(mocker, default_conf, id='gateio') + exchange = get_patched_exchange(mocker, default_conf, id='gate') exchange.fetch_order = MagicMock(return_value={ 'status': 'closed', @@ -73,8 +73,8 @@ def test_fetch_stoploss_order_gateio(default_conf, mocker): assert exchange.fetch_order.call_args_list[1][1]['order_id'] == '222555' -def test_cancel_stoploss_order_gateio(default_conf, mocker): - exchange = get_patched_exchange(mocker, default_conf, id='gateio') +def test_cancel_stoploss_order_gate(default_conf, mocker): + exchange = get_patched_exchange(mocker, default_conf, id='gate') cancel_order_mock = MagicMock() exchange.cancel_order = cancel_order_mock @@ -90,8 +90,8 @@ def test_cancel_stoploss_order_gateio(default_conf, mocker): (1501, 1499, 1501, "sell"), (1499, 1501, 1499, "buy") ]) -def test_stoploss_adjust_gateio(mocker, default_conf, sl1, sl2, sl3, side): - exchange = get_patched_exchange(mocker, default_conf, id='gateio') +def test_stoploss_adjust_gate(mocker, default_conf, sl1, sl2, sl3, side): + exchange = get_patched_exchange(mocker, default_conf, id='gate') order = { 'price': 1500, 'stopPrice': 1500, @@ -104,7 +104,7 @@ def test_stoploss_adjust_gateio(mocker, default_conf, sl1, sl2, sl3, side): ('taker', 0.0005, 0.0001554325), ('maker', 0.0, 0.0), ]) -def test_fetch_my_trades_gateio(mocker, default_conf, takerormaker, rate, cost): +def test_fetch_my_trades_gate(mocker, default_conf, takerormaker, rate, cost): mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True) tick = {'ETH/USDT:USDT': { 'info': {'user_id': '', @@ -134,7 +134,7 @@ def test_fetch_my_trades_gateio(mocker, default_conf, takerormaker, rate, cost): 'takerOrMaker': takerormaker, 'amount': 1, # 1 contract }]) - exchange = get_patched_exchange(mocker, default_conf, api_mock=api_mock, id='gateio') + exchange = get_patched_exchange(mocker, default_conf, api_mock=api_mock, id='gate') exchange._trading_fees = tick trades = exchange.get_trades_for_order('22255', 'ETH/USDT:USDT', datetime.now(timezone.utc)) trade = trades[0] diff --git a/tests/exchange/test_okx.py b/tests/exchange/test_okx.py index ac5c81ebb..46b1852a0 100644 --- a/tests/exchange/test_okx.py +++ b/tests/exchange/test_okx.py @@ -195,12 +195,12 @@ def test_get_max_pair_stake_amount_okx(default_conf, mocker, leverage_tiers): exchange = get_patched_exchange(mocker, default_conf, id="okx") exchange._leverage_tiers = leverage_tiers - assert exchange.get_max_pair_stake_amount('BNB/BUSD', 1.0) == 30000000 - assert exchange.get_max_pair_stake_amount('BNB/USDT', 1.0) == 50000000 - assert exchange.get_max_pair_stake_amount('BTC/USDT', 1.0) == 1000000000 - assert exchange.get_max_pair_stake_amount('BTC/USDT', 1.0, 10.0) == 100000000 + assert exchange.get_max_pair_stake_amount('BNB/BUSD:BUSD', 1.0) == 30000000 + assert exchange.get_max_pair_stake_amount('BNB/USDT:USDT', 1.0) == 50000000 + assert exchange.get_max_pair_stake_amount('BTC/USDT:USDT', 1.0) == 1000000000 + assert exchange.get_max_pair_stake_amount('BTC/USDT:USDT', 1.0, 10.0) == 100000000 - assert exchange.get_max_pair_stake_amount('TTT/USDT', 1.0) == float('inf') # Not in tiers + assert exchange.get_max_pair_stake_amount('TTT/USDT:USDT', 1.0) == float('inf') # Not in tiers @pytest.mark.parametrize('mode,side,reduceonly,result', [ diff --git a/tests/freqai/test_freqai_datakitchen.py b/tests/freqai/test_freqai_datakitchen.py index 0dc897916..95665a775 100644 --- a/tests/freqai/test_freqai_datakitchen.py +++ b/tests/freqai/test_freqai_datakitchen.py @@ -82,7 +82,7 @@ def test_compute_distances(mocker, freqai_conf): freqai = make_data_dictionary(mocker, freqai_conf) freqai_conf['freqai']['feature_parameters'].update({"DI_threshold": 1}) avg_mean_dist = freqai.dk.compute_distances() - assert round(avg_mean_dist, 2) == 1.99 + assert round(avg_mean_dist, 2) == 1.98 def test_use_SVM_to_remove_outliers_and_outlier_protection(mocker, freqai_conf, caplog): @@ -90,7 +90,7 @@ def test_use_SVM_to_remove_outliers_and_outlier_protection(mocker, freqai_conf, freqai_conf['freqai']['feature_parameters'].update({"outlier_protection_percentage": 0.1}) freqai.dk.use_SVM_to_remove_outliers(predict=False) assert log_has_re( - "SVM detected 7.36%", + "SVM detected 7.83%", caplog, ) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index af104f3d2..79c04e6b3 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -222,6 +222,9 @@ def test_start_backtesting(mocker, freqai_conf, model, num_files, strat, caplog) if 'test_4ac' in model: freqai_conf["freqaimodel_path"] = str(Path(__file__).parents[1] / "freqai" / "test_models") + freqai_conf.get("freqai", {}).get("feature_parameters", {}).update( + {"indicator_periods_candles": [2]}) + strategy = get_patched_freqai_strategy(mocker, freqai_conf) exchange = get_patched_exchange(mocker, freqai_conf) strategy.dp = DataProvider(freqai_conf, exchange) @@ -232,15 +235,14 @@ def test_start_backtesting(mocker, freqai_conf, model, num_files, strat, caplog) timerange = TimeRange.parse_timerange("20180110-20180130") freqai.dd.load_all_pair_histories(timerange, freqai.dk) sub_timerange = TimeRange.parse_timerange("20180110-20180130") - corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) + _, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) + df = base_df[freqai_conf["timeframe"]] - df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") - df = freqai.cache_corr_pairlist_dfs(df, freqai.dk) for i in range(5): df[f'%-constant_{i}'] = i metadata = {"pair": "LTC/BTC"} - freqai.start_backtesting(df, metadata, freqai.dk) + freqai.start_backtesting(df, metadata, freqai.dk, strategy) model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()] assert len(model_folders) == num_files @@ -261,6 +263,8 @@ def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf): freqai_conf.update({"timerange": "20180120-20180124"}) freqai_conf.get("freqai", {}).update({"backtest_period_days": 0.5}) freqai_conf.get("freqai", {}).update({"save_backtest_models": True}) + freqai_conf.get("freqai", {}).get("feature_parameters", {}).update( + {"indicator_periods_candles": [2]}) strategy = get_patched_freqai_strategy(mocker, freqai_conf) exchange = get_patched_exchange(mocker, freqai_conf) strategy.dp = DataProvider(freqai_conf, exchange) @@ -271,12 +275,11 @@ def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf): timerange = TimeRange.parse_timerange("20180110-20180130") freqai.dd.load_all_pair_histories(timerange, freqai.dk) sub_timerange = TimeRange.parse_timerange("20180110-20180130") - corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) - - df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") + _, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) + df = base_df[freqai_conf["timeframe"]] metadata = {"pair": "LTC/BTC"} - freqai.start_backtesting(df, metadata, freqai.dk) + freqai.start_backtesting(df, metadata, freqai.dk, strategy) model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()] assert len(model_folders) == 9 @@ -287,6 +290,8 @@ def test_start_backtesting_subdaily_backtest_period(mocker, freqai_conf): def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): freqai_conf.update({"timerange": "20180120-20180130"}) freqai_conf.get("freqai", {}).update({"save_backtest_models": True}) + freqai_conf.get("freqai", {}).get("feature_parameters", {}).update( + {"indicator_periods_candles": [2]}) strategy = get_patched_freqai_strategy(mocker, freqai_conf) exchange = get_patched_exchange(mocker, freqai_conf) strategy.dp = DataProvider(freqai_conf, exchange) @@ -296,15 +301,14 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): freqai.dk = FreqaiDataKitchen(freqai_conf) timerange = TimeRange.parse_timerange("20180110-20180130") freqai.dd.load_all_pair_histories(timerange, freqai.dk) - sub_timerange = TimeRange.parse_timerange("20180110-20180130") - corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) - - df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") + sub_timerange = TimeRange.parse_timerange("20180101-20180130") + _, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) + df = base_df[freqai_conf["timeframe"]] pair = "ADA/BTC" metadata = {"pair": pair} freqai.dk.pair = pair - freqai.start_backtesting(df, metadata, freqai.dk) + freqai.start_backtesting(df, metadata, freqai.dk, strategy) model_folders = [x for x in freqai.dd.full_path.iterdir() if x.is_dir()] assert len(model_folders) == 2 @@ -322,14 +326,13 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): timerange = TimeRange.parse_timerange("20180110-20180130") freqai.dd.load_all_pair_histories(timerange, freqai.dk) sub_timerange = TimeRange.parse_timerange("20180110-20180130") - corr_df, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) - - df = freqai.dk.use_strategy_to_populate_indicators(strategy, corr_df, base_df, "LTC/BTC") + _, base_df = freqai.dd.get_base_and_corr_dataframes(sub_timerange, "LTC/BTC", freqai.dk) + df = base_df[freqai_conf["timeframe"]] pair = "ADA/BTC" metadata = {"pair": pair} freqai.dk.pair = pair - freqai.start_backtesting(df, metadata, freqai.dk) + freqai.start_backtesting(df, metadata, freqai.dk, strategy) assert log_has_re( "Found backtesting prediction file ", @@ -339,7 +342,7 @@ def test_start_backtesting_from_existing_folder(mocker, freqai_conf, caplog): pair = "ETH/BTC" metadata = {"pair": pair} freqai.dk.pair = pair - freqai.start_backtesting(df, metadata, freqai.dk) + freqai.start_backtesting(df, metadata, freqai.dk, strategy) path = (freqai.dd.full_path / freqai.dk.backtest_predictions_folder) prediction_files = [x for x in path.iterdir() if x.is_file()] @@ -373,57 +376,6 @@ def test_backtesting_fit_live_predictions(mocker, freqai_conf, caplog): shutil.rmtree(Path(freqai.dk.full_path)) -def test_follow_mode(mocker, freqai_conf): - freqai_conf.update({"timerange": "20180110-20180130"}) - - strategy = get_patched_freqai_strategy(mocker, freqai_conf) - exchange = get_patched_exchange(mocker, freqai_conf) - strategy.dp = DataProvider(freqai_conf, exchange) - strategy.freqai_info = freqai_conf.get("freqai", {}) - freqai = strategy.freqai - freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf) - timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dd.load_all_pair_histories(timerange, freqai.dk) - - metadata = {"pair": "ADA/BTC"} - freqai.dd.set_pair_dict_info(metadata) - - data_load_timerange = TimeRange.parse_timerange("20180110-20180130") - new_timerange = TimeRange.parse_timerange("20180120-20180130") - - freqai.extract_data_and_train_model( - new_timerange, "ADA/BTC", strategy, freqai.dk, data_load_timerange) - - assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_model.joblib").is_file() - assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_metadata.json").is_file() - assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_trained_df.pkl").is_file() - assert Path(freqai.dk.data_path / f"{freqai.dk.model_filename}_svm_model.joblib").is_file() - - # start the follower and ask it to predict on existing files - - freqai_conf.get("freqai", {}).update({"follow_mode": "true"}) - - strategy = get_patched_freqai_strategy(mocker, freqai_conf) - exchange = get_patched_exchange(mocker, freqai_conf) - strategy.dp = DataProvider(freqai_conf, exchange) - strategy.freqai_info = freqai_conf.get("freqai", {}) - freqai = strategy.freqai - freqai.live = True - freqai.dk = FreqaiDataKitchen(freqai_conf, freqai.live) - timerange = TimeRange.parse_timerange("20180110-20180130") - freqai.dd.load_all_pair_histories(timerange, freqai.dk) - - df = strategy.dp.get_pair_dataframe('ADA/BTC', '5m') - - freqai.dk.pair = "ADA/BTC" - freqai.start_live(df, metadata, strategy, freqai.dk) - - assert len(freqai.dk.return_dataframe.index) == 5702 - - shutil.rmtree(Path(freqai.dk.full_path)) - - def test_principal_component_analysis(mocker, freqai_conf): freqai_conf.update({"timerange": "20180110-20180130"}) freqai_conf.get("freqai", {}).get("feature_parameters", {}).update( diff --git a/tests/optimize/conftest.py b/tests/optimize/conftest.py index 3d50f37dd..4d257addc 100644 --- a/tests/optimize/conftest.py +++ b/tests/optimize/conftest.py @@ -48,8 +48,8 @@ def hyperopt_results(): return pd.DataFrame( { 'pair': ['ETH/USDT', 'ETH/USDT', 'ETH/USDT', 'ETH/USDT'], - 'profit_ratio': [-0.1, 0.2, -0.1, 0.3], - 'profit_abs': [-0.2, 0.4, -0.2, 0.6], + 'profit_ratio': [-0.1, 0.2, -0.12, 0.3], + 'profit_abs': [-0.2, 0.4, -0.21, 0.6], 'trade_duration': [10, 30, 10, 10], 'amount': [0.1, 0.1, 0.1, 0.1], 'exit_reason': [ExitType.STOP_LOSS, ExitType.ROI, ExitType.STOP_LOSS, ExitType.ROI], diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index a18196507..4e78fc139 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -919,6 +919,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) default_conf["trailing_stop_positive"] = data.trailing_stop_positive default_conf["trailing_stop_positive_offset"] = data.trailing_stop_positive_offset default_conf["use_exit_signal"] = data.use_exit_signal + default_conf["max_open_trades"] = 10 mocker.patch("freqtrade.exchange.Exchange.get_fee", return_value=0.0) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) @@ -951,7 +952,6 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data: BTContainer) processed=data_processed, start_date=min_date, end_date=max_date, - max_open_trades=10, ) results = result['results'] diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index fc14a0f88..e407b4173 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -19,12 +19,12 @@ from freqtrade.data.btanalysis import BT_DATA_COLUMNS, evaluate_result_multi from freqtrade.data.converter import clean_ohlcv_dataframe from freqtrade.data.dataprovider import DataProvider from freqtrade.data.history import get_timerange -from freqtrade.enums import ExitType, RunMode +from freqtrade.enums import CandleType, ExitType, RunMode from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exchange.exchange import timeframe_to_next_date from freqtrade.optimize.backtest_caching import get_strategy_run_id from freqtrade.optimize.backtesting import Backtesting -from freqtrade.persistence import LocalTrade +from freqtrade.persistence import LocalTrade, Trade from freqtrade.resolvers import StrategyResolver from tests.conftest import (CURRENT_TEST_STRATEGY, get_args, log_has, log_has_re, patch_exchange, patched_configuration_load_config_file) @@ -96,7 +96,6 @@ def _make_backtest_conf(mocker, datadir, conf=None, pair='UNITTEST/BTC'): 'processed': processed, 'start_date': min_date, 'end_date': max_date, - 'max_open_trades': 10, } @@ -360,7 +359,6 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: PropertyMock(return_value=['UNITTEST/BTC'])) default_conf['timeframe'] = '1m' - default_conf['datadir'] = testdatadir default_conf['export'] = 'signals' default_conf['exportfilename'] = 'export.txt' default_conf['timerange'] = '-1510694220' @@ -396,7 +394,6 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) -> PropertyMock(return_value=['UNITTEST/BTC'])) default_conf['timeframe'] = "1m" - default_conf['datadir'] = testdatadir default_conf['export'] = 'none' default_conf['timerange'] = '20180101-20180102' @@ -417,7 +414,6 @@ def test_backtesting_no_pair_left(default_conf, mocker, caplog, testdatadir) -> PropertyMock(return_value=[])) default_conf['timeframe'] = "1m" - default_conf['datadir'] = testdatadir default_conf['export'] = 'none' default_conf['timerange'] = '20180101-20180102' @@ -451,7 +447,6 @@ def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, ti mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.refresh_pairlist') default_conf['ticker_interval'] = "1m" - default_conf['datadir'] = testdatadir default_conf['export'] = 'none' # Use stoploss from strategy del default_conf['stoploss'] @@ -619,7 +614,7 @@ def test_backtest__enter_trade_futures(default_conf_usdt, fee, mocker) -> None: assert trade is None -def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None: +def test_backtest__check_trade_exit(default_conf, fee, mocker) -> None: default_conf['use_exit_signal'] = False mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) @@ -665,7 +660,7 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None: ] # No data available. - res = backtesting._get_exit_trade_entry(trade, row_sell, True) + res = backtesting._check_trade_exit(trade, row_sell) assert res is not None assert res.exit_reason == ExitType.ROI.value assert res.close_date_utc == datetime(2020, 1, 1, 5, 0, tzinfo=timezone.utc) @@ -678,12 +673,14 @@ def test_backtest__get_sell_trade_entry(default_conf, fee, mocker) -> None: [], columns=['date', 'open', 'high', 'low', 'close', 'enter_long', 'exit_long', 'enter_short', 'exit_short', 'long_tag', 'short_tag', 'exit_tag']) - res = backtesting._get_exit_trade_entry(trade, row, True) + res = backtesting._check_trade_exit(trade, row) assert res is None def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None: default_conf['use_exit_signal'] = False + default_conf['max_open_trades'] = 10 + mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) @@ -701,7 +698,6 @@ def test_backtest_one(default_conf, fee, mocker, testdatadir) -> None: processed=deepcopy(processed), start_date=min_date, end_date=max_date, - max_open_trades=10, ) results = result['results'] assert not results.empty @@ -785,6 +781,8 @@ def test_backtest_one_detail(default_conf_usdt, fee, mocker, testdatadir, use_de def custom_entry_price(proposed_rate, **kwargs): return proposed_rate * 0.997 + default_conf_usdt['max_open_trades'] = 10 + backtesting = Backtesting(default_conf_usdt) backtesting._set_strategy(backtesting.strategylist[0]) backtesting.strategy.populate_entry_trend = advise_entry @@ -792,10 +790,10 @@ def test_backtest_one_detail(default_conf_usdt, fee, mocker, testdatadir, use_de pair = 'XRP/ETH' # Pick a timerange adapted to the pair we use to test timerange = TimeRange.parse_timerange('20191010-20191013') - data = history.load_data(datadir=testdatadir, timeframe='5m', pairs=['XRP/ETH'], + data = history.load_data(datadir=testdatadir, timeframe='5m', pairs=[pair], timerange=timerange) if use_detail: - data_1m = history.load_data(datadir=testdatadir, timeframe='1m', pairs=['XRP/ETH'], + data_1m = history.load_data(datadir=testdatadir, timeframe='1m', pairs=[pair], timerange=timerange) backtesting.detail_data = data_1m processed = backtesting.strategy.advise_all_indicators(data) @@ -805,7 +803,6 @@ def test_backtest_one_detail(default_conf_usdt, fee, mocker, testdatadir, use_de processed=deepcopy(processed), start_date=min_date, end_date=max_date, - max_open_trades=10, ) results = result['results'] assert not results.empty @@ -849,6 +846,164 @@ def test_backtest_one_detail(default_conf_usdt, fee, mocker, testdatadir, use_de assert late_entry > 0 +@pytest.mark.parametrize('use_detail', [True, False]) +def test_backtest_one_detail_futures( + default_conf_usdt, fee, mocker, testdatadir, use_detail) -> None: + default_conf_usdt['use_exit_signal'] = False + default_conf_usdt['trading_mode'] = 'futures' + default_conf_usdt['margin_mode'] = 'isolated' + default_conf_usdt['candle_type_def'] = CandleType.FUTURES + + mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) + mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) + mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) + mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', + PropertyMock(return_value=['XRP/USDT:USDT'])) + mocker.patch("freqtrade.exchange.Exchange.get_maintenance_ratio_and_amt", + return_value=(0.01, 0.01)) + default_conf_usdt['timeframe'] = '1h' + if use_detail: + default_conf_usdt['timeframe_detail'] = '5m' + patch_exchange(mocker) + + def advise_entry(df, *args, **kwargs): + # Mock function to force several entries + df.loc[(df['rsi'] < 40), 'enter_long'] = 1 + return df + + def custom_entry_price(proposed_rate, **kwargs): + return proposed_rate * 0.997 + + default_conf_usdt['max_open_trades'] = 10 + + backtesting = Backtesting(default_conf_usdt) + backtesting._set_strategy(backtesting.strategylist[0]) + backtesting.strategy.populate_entry_trend = advise_entry + backtesting.strategy.custom_entry_price = custom_entry_price + pair = 'XRP/USDT:USDT' + # Pick a timerange adapted to the pair we use to test + timerange = TimeRange.parse_timerange('20211117-20211119') + data = history.load_data(datadir=Path(testdatadir), timeframe='1h', pairs=[pair], + timerange=timerange, candle_type=CandleType.FUTURES) + backtesting.load_bt_data_detail() + processed = backtesting.strategy.advise_all_indicators(data) + min_date, max_date = get_timerange(processed) + + result = backtesting.backtest( + processed=deepcopy(processed), + start_date=min_date, + end_date=max_date, + ) + results = result['results'] + assert not results.empty + # Timeout settings from default_conf = entry: 10, exit: 30 + assert len(results) == (5 if use_detail else 2) + + assert 'orders' in results.columns + data_pair = processed[pair] + + data_1m_pair = backtesting.detail_data[pair] if use_detail else pd.DataFrame() + late_entry = 0 + for _, t in results.iterrows(): + assert len(t['orders']) == 2 + + entryo = t['orders'][0] + entry_ts = datetime.fromtimestamp(entryo['order_filled_timestamp'] // 1000, tz=timezone.utc) + if entry_ts > t['open_date']: + late_entry += 1 + + # Get "entry fill" candle + ln = (data_1m_pair.loc[data_1m_pair["date"] == entry_ts] + if use_detail else data_pair.loc[data_pair["date"] == entry_ts]) + # Check open trade rate aligns to open rate + assert not ln.empty + + assert round(ln.iloc[0]["low"], 6) <= round( + t["open_rate"], 6) <= round(ln.iloc[0]["high"], 6) + # check close trade rate aligns to close rate or is between high and low + ln1 = data_pair.loc[data_pair["date"] == t["close_date"]] + if use_detail: + ln1_1m = data_1m_pair.loc[data_1m_pair["date"] == t["close_date"]] + assert not ln1.empty or not ln1_1m.empty + else: + assert not ln1.empty + ln2 = ln1_1m if ln1.empty else ln1 + + assert (round(ln2.iloc[0]["low"], 6) <= round( + t["close_rate"], 6) <= round(ln2.iloc[0]["high"], 6)) + assert -0.0181 < Trade.trades[1].funding_fees < -0.01 + # assert late_entry > 0 + + +@pytest.mark.parametrize('use_detail', [True, False]) +def test_backtest_one_detail_futures_funding_fees( + default_conf_usdt, fee, mocker, testdatadir, use_detail) -> None: + default_conf_usdt['use_exit_signal'] = False + default_conf_usdt['trading_mode'] = 'futures' + default_conf_usdt['margin_mode'] = 'isolated' + default_conf_usdt['candle_type_def'] = CandleType.FUTURES + default_conf_usdt['minimal_roi'] = {'0': 1} + default_conf_usdt['dry_run_wallet'] = 100000 + + mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) + mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) + mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) + mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', + PropertyMock(return_value=['XRP/USDT:USDT'])) + mocker.patch("freqtrade.exchange.Exchange.get_maintenance_ratio_and_amt", + return_value=(0.01, 0.01)) + default_conf_usdt['timeframe'] = '1h' + if use_detail: + default_conf_usdt['timeframe_detail'] = '5m' + patch_exchange(mocker) + + def advise_entry(df, *args, **kwargs): + # Mock function to force several entries + df.loc[:, 'enter_long'] = 1 + return df + + def adjust_trade_position(trade, current_time, **kwargs): + if current_time > datetime(2021, 11, 18, 2, 0, 0, tzinfo=timezone.utc): + return None + return default_conf_usdt['stake_amount'] + + default_conf_usdt['max_open_trades'] = 1 + + backtesting = Backtesting(default_conf_usdt) + backtesting._set_strategy(backtesting.strategylist[0]) + backtesting.strategy.populate_entry_trend = advise_entry + backtesting.strategy.adjust_trade_position = adjust_trade_position + backtesting.strategy.leverage = lambda **kwargs: 1 + backtesting.strategy.position_adjustment_enable = True + pair = 'XRP/USDT:USDT' + # Pick a timerange adapted to the pair we use to test + timerange = TimeRange.parse_timerange('20211117-20211119') + data = history.load_data(datadir=Path(testdatadir), timeframe='1h', pairs=[pair], + timerange=timerange, candle_type=CandleType.FUTURES) + backtesting.load_bt_data_detail() + processed = backtesting.strategy.advise_all_indicators(data) + min_date, max_date = get_timerange(processed) + + result = backtesting.backtest( + processed=deepcopy(processed), + start_date=min_date, + end_date=max_date, + ) + results = result['results'] + assert not results.empty + # Only one result - as we're not selling. + assert len(results) == 1 + + assert 'orders' in results.columns + + for t in Trade.trades: + # At least 4 adjustment orders + assert t.nr_of_successful_entries >= 6 + # Funding fees will vary depending on the number of adjustment orders + # That number is a lot higher with detail data. + assert -20 < t.funding_fees < -0.1 + + def test_backtest_timedout_entry_orders(default_conf, fee, mocker, testdatadir) -> None: # This strategy intentionally places unfillable orders. default_conf['strategy'] = 'StrategyTestV3CustomEntryPrice' @@ -859,6 +1014,7 @@ def test_backtest_timedout_entry_orders(default_conf, fee, mocker, testdatadir) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) patch_exchange(mocker) + default_conf['max_open_trades'] = 1 backtesting = Backtesting(default_conf) backtesting._set_strategy(backtesting.strategylist[0]) # Testing dataframe contains 11 candles. Expecting 10 timed out orders. @@ -871,7 +1027,6 @@ def test_backtest_timedout_entry_orders(default_conf, fee, mocker, testdatadir) processed=deepcopy(data), start_date=min_date, end_date=max_date, - max_open_trades=1, ) assert result['timedout_entry_orders'] == 10 @@ -879,6 +1034,7 @@ def test_backtest_timedout_entry_orders(default_conf, fee, mocker, testdatadir) def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None: default_conf['use_exit_signal'] = False + default_conf['max_open_trades'] = 1 mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) @@ -896,7 +1052,6 @@ def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None processed=processed, start_date=min_date, end_date=max_date, - max_open_trades=1, ) assert not results['results'].empty assert len(results['results']) == 1 @@ -904,6 +1059,8 @@ def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None def test_backtest_trim_no_data_left(default_conf, fee, mocker, testdatadir) -> None: default_conf['use_exit_signal'] = False + default_conf['max_open_trades'] = 10 + mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) @@ -927,7 +1084,6 @@ def test_backtest_trim_no_data_left(default_conf, fee, mocker, testdatadir) -> N processed=deepcopy(processed), start_date=min_date, end_date=max_date, - max_open_trades=10, ) @@ -948,6 +1104,7 @@ def test_processed(default_conf, mocker, testdatadir) -> None: def test_backtest_dataprovider_analyzed_df(default_conf, fee, mocker, testdatadir) -> None: default_conf['use_exit_signal'] = False + default_conf['max_open_trades'] = 10 mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=100000) @@ -981,7 +1138,6 @@ def test_backtest_dataprovider_analyzed_df(default_conf, fee, mocker, testdatadi processed=deepcopy(processed), start_date=min_date, end_date=max_date, - max_open_trades=10, ) assert count == 5 @@ -998,6 +1154,7 @@ def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatad default_conf['enable_protections'] = True default_conf['timeframe'] = '1m' + default_conf['max_open_trades'] = 1 mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) @@ -1024,7 +1181,6 @@ def test_backtest_pricecontours_protections(default_conf, fee, mocker, testdatad processed=processed, start_date=min_date, end_date=max_date, - max_open_trades=1, ) assert len(results['results']) == numres @@ -1062,11 +1218,12 @@ def test_backtest_pricecontours(default_conf, fee, mocker, testdatadir, processed = backtesting.strategy.advise_all_indicators(data) min_date, max_date = get_timerange(processed) assert isinstance(processed, dict) + backtesting.strategy.max_open_trades = 1 + backtesting.config.update({'max_open_trades': 1}) results = backtesting.backtest( processed=processed, start_date=min_date, end_date=max_date, - max_open_trades=1, ) assert len(results['results']) == expected @@ -1077,7 +1234,7 @@ def test_backtest_clash_buy_sell(mocker, default_conf, testdatadir): buy_value = 1 sell_value = 1 return _trend(dataframe, buy_value, sell_value) - + default_conf['max_open_trades'] = 10 backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir) backtesting = Backtesting(default_conf) backtesting._set_strategy(backtesting.strategylist[0]) @@ -1094,6 +1251,7 @@ def test_backtest_only_sell(mocker, default_conf, testdatadir): sell_value = 1 return _trend(dataframe, buy_value, sell_value) + default_conf['max_open_trades'] = 10 backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir) backtesting = Backtesting(default_conf) backtesting._set_strategy(backtesting.strategylist[0]) @@ -1107,6 +1265,7 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir): mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=0.00001) mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf')) mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) + default_conf['max_open_trades'] = 10 backtest_conf = _make_backtest_conf(mocker, conf=default_conf, pair='UNITTEST/BTC', datadir=testdatadir) default_conf['timeframe'] = '1m' @@ -1165,6 +1324,7 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir) if tres > 0: data[pair] = data[pair][tres:].reset_index() default_conf['timeframe'] = '5m' + default_conf['max_open_trades'] = 3 backtesting = Backtesting(default_conf) backtesting._set_strategy(backtesting.strategylist[0]) @@ -1173,11 +1333,11 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir) processed = backtesting.strategy.advise_all_indicators(data) min_date, max_date = get_timerange(processed) + backtest_conf = { 'processed': deepcopy(processed), 'start_date': min_date, 'end_date': max_date, - 'max_open_trades': 3, } results = backtesting.backtest(**backtest_conf) @@ -1195,11 +1355,12 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir) backtesting.dataprovider.get_analyzed_dataframe('NXT/BTC', '5m')[0] ) == len(data['NXT/BTC']) - 1 - backtesting.strategy.startup_candle_count + backtesting.strategy.max_open_trades = 1 + backtesting.config.update({'max_open_trades': 1}) backtest_conf = { 'processed': deepcopy(processed), 'start_date': min_date, 'end_date': max_date, - 'max_open_trades': 1, } results = backtesting.backtest(**backtest_conf) assert len(evaluate_result_multi(results['results'], '5m', 1)) == 0 @@ -1460,7 +1621,7 @@ def test_backtest_start_futures_noliq(default_conf_usdt, mocker, patch_exchange(mocker) mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', - PropertyMock(return_value=['HULUMULU/USDT', 'XRP/USDT'])) + PropertyMock(return_value=['HULUMULU/USDT', 'XRP/USDT:USDT'])) # mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock) patched_configuration_load_config_file(mocker, default_conf_usdt) @@ -1491,7 +1652,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, "strategy": CURRENT_TEST_STRATEGY, }) patch_exchange(mocker) - result1 = pd.DataFrame({'pair': ['XRP/USDT', 'XRP/USDT'], + result1 = pd.DataFrame({'pair': ['XRP/USDT:USDT', 'XRP/USDT:USDT'], 'profit_ratio': [0.0, 0.0], 'profit_abs': [0.0, 0.0], 'open_date': pd.to_datetime(['2021-11-18 18:00:00', @@ -1507,7 +1668,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, 'close_rate': [0.104969, 0.103541], 'exit_reason': [ExitType.ROI, ExitType.ROI] }) - result2 = pd.DataFrame({'pair': ['XRP/USDT', 'XRP/USDT', 'XRP/USDT'], + result2 = pd.DataFrame({'pair': ['XRP/USDT:USDT', 'XRP/USDT:USDT', 'XRP/USDT:USDT'], 'profit_ratio': [0.03, 0.01, 0.1], 'profit_abs': [0.01, 0.02, 0.2], 'open_date': pd.to_datetime(['2021-11-19 18:00:00', @@ -1552,7 +1713,7 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, } ]) mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', - PropertyMock(return_value=['XRP/USDT'])) + PropertyMock(return_value=['XRP/USDT:USDT'])) mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock) patched_configuration_load_config_file(mocker, default_conf_usdt) @@ -1575,8 +1736,8 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker, 'up to 2021-11-21 04:00:00 (4 days).', 'Backtesting with data from 2021-11-17 21:00:00 ' 'up to 2021-11-21 04:00:00 (3 days).', - 'XRP/USDT, funding_rate, 8h, data starts at 2021-11-18 00:00:00', - 'XRP/USDT, mark, 8h, data starts at 2021-11-18 00:00:00', + 'XRP/USDT:USDT, funding_rate, 8h, data starts at 2021-11-18 00:00:00', + 'XRP/USDT:USDT, mark, 8h, data starts at 2021-11-18 00:00:00', f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}', ] diff --git a/tests/optimize/test_backtesting_adjust_position.py b/tests/optimize/test_backtesting_adjust_position.py index 5c740458f..23b5eb93b 100644 --- a/tests/optimize/test_backtesting_adjust_position.py +++ b/tests/optimize/test_backtesting_adjust_position.py @@ -17,6 +17,7 @@ from tests.conftest import patch_exchange def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) -> None: default_conf['use_exit_signal'] = False + default_conf['max_open_trades'] = 10 mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch('freqtrade.optimize.backtesting.amount_to_contract_precision', lambda x, *args, **kwargs: round(x, 8)) @@ -41,7 +42,6 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) -> processed=deepcopy(processed), start_date=min_date, end_date=max_date, - max_open_trades=10, ) results = result['results'] assert not results.empty diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 5bce9f419..36ceaeab2 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -1,5 +1,6 @@ # pragma pylint: disable=missing-docstring,W0212,C0103 from datetime import datetime, timedelta +from functools import wraps from pathlib import Path from unittest.mock import ANY, MagicMock, PropertyMock @@ -7,6 +8,7 @@ import pandas as pd import pytest from arrow import Arrow from filelock import Timeout +from skopt.space import Integer from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_hyperopt from freqtrade.data.history import load_data @@ -292,6 +294,8 @@ def test_params_no_optimize_details(hyperopt) -> None: assert res['roi']['0'] == 0.04 assert "stoploss" in res assert res['stoploss']['stoploss'] == -0.1 + assert "max_open_trades" in res + assert res['max_open_trades']['max_open_trades'] == 1 def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None: @@ -334,8 +338,7 @@ def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None: assert dumper2.call_count == 1 assert hasattr(hyperopt.backtesting.strategy, "advise_exit") assert hasattr(hyperopt.backtesting.strategy, "advise_entry") - assert hasattr(hyperopt, "max_open_trades") - assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] + assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt.backtesting, "_position_stacking") @@ -474,6 +477,7 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None: 'trailing_stop_positive': 0.02, 'trailing_stop_positive_offset_p1': 0.05, 'trailing_only_offset_is_reached': False, + 'max_open_trades': 3, } response_expected = { 'loss': 1.9147239021396234, @@ -499,7 +503,9 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None: 'trailing': {'trailing_only_offset_is_reached': False, 'trailing_stop': True, 'trailing_stop_positive': 0.02, - 'trailing_stop_positive_offset': 0.07}}, + 'trailing_stop_positive_offset': 0.07}, + 'max_open_trades': {'max_open_trades': 3} + }, 'params_dict': optimizer_param, 'params_not_optimized': {'buy': {}, 'protection': {}, 'sell': {}}, 'results_metrics': ANY, @@ -548,7 +554,8 @@ def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None: 'buy': {'mfi-value': None}, 'sell': {'sell-mfi-value': None}, 'roi': {}, 'stoploss': {'stoploss': None}, - 'trailing': {'trailing_stop': None} + 'trailing': {'trailing_stop': None}, + 'max_open_trades': {'max_open_trades': None} }, 'results_metrics': generate_result_metrics(), }]) @@ -571,7 +578,7 @@ def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None: out, err = capsys.readouterr() result_str = ( '{"params":{"mfi-value":null,"sell-mfi-value":null},"minimal_roi"' - ':{},"stoploss":null,"trailing_stop":null}' + ':{},"stoploss":null,"trailing_stop":null,"max_open_trades":null}' ) assert result_str in out # noqa: E501 # Should be called for historical candle data @@ -702,8 +709,7 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non assert hasattr(hyperopt.backtesting.strategy, "advise_exit") assert hasattr(hyperopt.backtesting.strategy, "advise_entry") - assert hasattr(hyperopt, "max_open_trades") - assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] + assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt.backtesting, "_position_stacking") @@ -776,8 +782,7 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None: assert dumper2.call_count == 1 assert hasattr(hyperopt.backtesting.strategy, "advise_exit") assert hasattr(hyperopt.backtesting.strategy, "advise_entry") - assert hasattr(hyperopt, "max_open_trades") - assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] + assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt.backtesting, "_position_stacking") @@ -819,8 +824,7 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None: assert dumper2.call_count == 1 assert hasattr(hyperopt.backtesting.strategy, "advise_exit") assert hasattr(hyperopt.backtesting.strategy, "advise_entry") - assert hasattr(hyperopt, "max_open_trades") - assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] + assert hyperopt.backtesting.strategy.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt.backtesting, "_position_stacking") @@ -874,6 +878,7 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None: assert hyperopt.backtesting.strategy.buy_rsi.value == 35 assert hyperopt.backtesting.strategy.sell_rsi.value == 74 assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value == 30 + assert hyperopt.backtesting.strategy.max_open_trades == 1 buy_rsi_range = hyperopt.backtesting.strategy.buy_rsi.range assert isinstance(buy_rsi_range, range) # Range from 0 - 50 (inclusive) @@ -884,6 +889,7 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmpdir, fee) -> None: assert hyperopt.backtesting.strategy.protection_cooldown_lookback.value != 30 assert hyperopt.backtesting.strategy.buy_rsi.value != 35 assert hyperopt.backtesting.strategy.sell_rsi.value != 74 + assert hyperopt.backtesting.strategy.max_open_trades != 1 hyperopt.custom_hyperopt.generate_estimator = lambda *args, **kwargs: 'ET1' with pytest.raises(OperationalException, match="Estimator ET1 not supported."): @@ -984,3 +990,124 @@ def test_SKDecimal(): assert space.transform([2.0]) == [200] assert space.transform([1.0]) == [100] assert space.transform([1.5, 1.6]) == [150, 160] + + +def test_stake_amount_unlimited_max_open_trades(mocker, hyperopt_conf, tmpdir, fee) -> None: + # This test is to ensure that unlimited max_open_trades are ignored for the backtesting + # if we have an unlimited stake amount + patch_exchange(mocker) + mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) + (Path(tmpdir) / 'hyperopt_results').mkdir(parents=True) + hyperopt_conf.update({ + 'strategy': 'HyperoptableStrategy', + 'user_data_dir': Path(tmpdir), + 'hyperopt_random_state': 42, + 'spaces': ['trades'], + 'stake_amount': 'unlimited' + }) + hyperopt = Hyperopt(hyperopt_conf) + mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._get_params_dict', + return_value={ + 'max_open_trades': -1 + }) + + assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto) + + assert hyperopt.backtesting.strategy.max_open_trades == 1 + + hyperopt.start() + + assert hyperopt.backtesting.strategy.max_open_trades == 1 + + +def test_max_open_trades_dump(mocker, hyperopt_conf, tmpdir, fee, capsys) -> None: + # This test is to ensure that after hyperopting, max_open_trades is never + # saved as inf in the output json params + patch_exchange(mocker) + mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) + (Path(tmpdir) / 'hyperopt_results').mkdir(parents=True) + hyperopt_conf.update({ + 'strategy': 'HyperoptableStrategy', + 'user_data_dir': Path(tmpdir), + 'hyperopt_random_state': 42, + 'spaces': ['trades'], + }) + hyperopt = Hyperopt(hyperopt_conf) + mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._get_params_dict', + return_value={ + 'max_open_trades': -1 + }) + + assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto) + + hyperopt.start() + + out, err = capsys.readouterr() + + assert 'max_open_trades = -1' in out + assert 'max_open_trades = inf' not in out + + ############## + + hyperopt_conf.update({'print_json': True}) + + hyperopt = Hyperopt(hyperopt_conf) + mocker.patch('freqtrade.optimize.hyperopt.Hyperopt._get_params_dict', + return_value={ + 'max_open_trades': -1 + }) + + assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto) + + hyperopt.start() + + out, err = capsys.readouterr() + + assert '"max_open_trades":-1' in out + + +def test_max_open_trades_consistency(mocker, hyperopt_conf, tmpdir, fee) -> None: + # This test is to ensure that max_open_trades is the same across all functions needing it + # after it has been changed from the hyperopt + patch_exchange(mocker) + mocker.patch('freqtrade.exchange.Exchange.get_fee', return_value=0) + + (Path(tmpdir) / 'hyperopt_results').mkdir(parents=True) + hyperopt_conf.update({ + 'strategy': 'HyperoptableStrategy', + 'user_data_dir': Path(tmpdir), + 'hyperopt_random_state': 42, + 'spaces': ['trades'], + 'stake_amount': 'unlimited', + 'dry_run_wallet': 8, + 'available_capital': 8, + 'dry_run': True, + 'epochs': 1 + }) + hyperopt = Hyperopt(hyperopt_conf) + + assert isinstance(hyperopt.custom_hyperopt, HyperOptAuto) + + hyperopt.custom_hyperopt.max_open_trades_space = lambda: [ + Integer(1, 10, name='max_open_trades')] + + first_time_evaluated = False + + def stake_amount_interceptor(func): + @wraps(func) + def wrapper(*args, **kwargs): + nonlocal first_time_evaluated + stake_amount = func(*args, **kwargs) + if first_time_evaluated is False: + assert stake_amount == 1 + first_time_evaluated = True + return stake_amount + return wrapper + + hyperopt.backtesting.wallets._calculate_unlimited_stake_amount = stake_amount_interceptor( + hyperopt.backtesting.wallets._calculate_unlimited_stake_amount) + + hyperopt.start() + + assert hyperopt.backtesting.strategy.max_open_trades == 8 + assert hyperopt.config['max_open_trades'] == 8 diff --git a/tests/optimize/test_hyperopt_tools.py b/tests/optimize/test_hyperopt_tools.py index 7d4fef3bd..eace78eee 100644 --- a/tests/optimize/test_hyperopt_tools.py +++ b/tests/optimize/test_hyperopt_tools.py @@ -66,52 +66,58 @@ def test_load_previous_results2(mocker, testdatadir, caplog) -> None: @pytest.mark.parametrize("spaces, expected_results", [ (['buy'], {'buy': True, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': False, - 'protection': False}), + 'protection': False, 'trades': False}), (['sell'], {'buy': False, 'sell': True, 'roi': False, 'stoploss': False, 'trailing': False, - 'protection': False}), + 'protection': False, 'trades': False}), (['roi'], {'buy': False, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False, - 'protection': False}), + 'protection': False, 'trades': False}), (['stoploss'], {'buy': False, 'sell': False, 'roi': False, 'stoploss': True, 'trailing': False, - 'protection': False}), + 'protection': False, 'trades': False}), (['trailing'], {'buy': False, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': True, - 'protection': False}), + 'protection': False, 'trades': False}), (['buy', 'sell', 'roi', 'stoploss'], {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False, - 'protection': False}), + 'protection': False, 'trades': False}), (['buy', 'sell', 'roi', 'stoploss', 'trailing'], {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True, - 'protection': False}), + 'protection': False, 'trades': False}), (['buy', 'roi'], {'buy': True, 'sell': False, 'roi': True, 'stoploss': False, 'trailing': False, - 'protection': False}), + 'protection': False, 'trades': False}), (['all'], {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True, - 'protection': True}), + 'protection': True, 'trades': True}), (['default'], {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False, - 'protection': False}), + 'protection': False, 'trades': False}), (['default', 'trailing'], {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True, - 'protection': False}), + 'protection': False, 'trades': False}), (['all', 'buy'], {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True, - 'protection': True}), + 'protection': True, 'trades': True}), (['default', 'buy'], {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False, - 'protection': False}), + 'protection': False, 'trades': False}), (['all'], {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': True, - 'protection': True}), + 'protection': True, 'trades': True}), (['protection'], {'buy': False, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': False, - 'protection': True}), + 'protection': True, 'trades': False}), + (['trades'], + {'buy': False, 'sell': False, 'roi': False, 'stoploss': False, 'trailing': False, + 'protection': False, 'trades': True}), + (['default', 'trades'], + {'buy': True, 'sell': True, 'roi': True, 'stoploss': True, 'trailing': False, + 'protection': False, 'trades': True}), ]) def test_has_space(hyperopt_conf, spaces, expected_results): - for s in ['buy', 'sell', 'roi', 'stoploss', 'trailing', 'protection']: + for s in ['buy', 'sell', 'roi', 'stoploss', 'trailing', 'protection', 'trades']: hyperopt_conf.update({'spaces': spaces}) assert HyperoptTools.has_space(hyperopt_conf, s) == expected_results[s] @@ -193,6 +199,9 @@ def test_export_params(tmpdir): "346": 0.08499, "507": 0.049, "1595": 0 + }, + "max_open_trades": { + "max_open_trades": 5 } }, "params_not_optimized": { @@ -219,6 +228,7 @@ def test_export_params(tmpdir): assert "roi" in content["params"] assert "stoploss" in content["params"] assert "trailing" in content["params"] + assert "max_open_trades" in content["params"] def test_try_export_params(default_conf, tmpdir, caplog, mocker): @@ -297,6 +307,9 @@ def test_params_print(capsys): "trailing_stop_positive_offset": 0.1, "trailing_only_offset_is_reached": True }, + "max_open_trades": { + "max_open_trades": 5 + } } HyperoptTools._params_pretty_print(params, 'buy', 'No header', non_optimized) @@ -327,6 +340,13 @@ def test_params_print(capsys): assert re.search('trailing_stop_positive_offset = 0.1 # value loaded.*\n', captured.out) assert re.search('trailing_only_offset_is_reached = True # value loaded.*\n', captured.out) + HyperoptTools._params_pretty_print( + params, 'max_open_trades', "Max Open Trades:", non_optimized) + captured = capsys.readouterr() + + assert re.search("# Max Open Trades:", captured.out) + assert re.search('max_open_trades = 5 # value loaded.*\n', captured.out) + def test_hyperopt_serializer(): diff --git a/tests/persistence/test_persistence.py b/tests/persistence/test_persistence.py index 830d84288..d06f05179 100644 --- a/tests/persistence/test_persistence.py +++ b/tests/persistence/test_persistence.py @@ -1868,13 +1868,18 @@ def test_get_exit_order_count(fee, is_short): @pytest.mark.usefixtures("init_persistence") -def test_update_order_from_ccxt(caplog): +def test_update_order_from_ccxt(caplog, time_machine): + start = datetime(2023, 1, 1, 4, tzinfo=timezone.utc) + time_machine.move_to(start, tick=False) + # Most basic order return (only has orderid) - o = Order.parse_from_ccxt_object({'id': '1234'}, 'ADA/USDT', 'buy') + o = Order.parse_from_ccxt_object({'id': '1234'}, 'ADA/USDT', 'buy', 20.01, 1234.6) assert isinstance(o, Order) assert o.ft_pair == 'ADA/USDT' assert o.ft_order_side == 'buy' assert o.order_id == '1234' + assert o.ft_price == 1234.6 + assert o.ft_amount == 20.01 assert o.ft_is_open ccxt_order = { 'id': '1234', @@ -1888,13 +1893,15 @@ def test_update_order_from_ccxt(caplog): 'status': 'open', 'timestamp': 1599394315123 } - o = Order.parse_from_ccxt_object(ccxt_order, 'ADA/USDT', 'buy') + o = Order.parse_from_ccxt_object(ccxt_order, 'ADA/USDT', 'buy', 20.01, 1234.6) assert isinstance(o, Order) assert o.ft_pair == 'ADA/USDT' assert o.ft_order_side == 'buy' assert o.order_id == '1234' assert o.order_type == 'limit' assert o.price == 1234.5 + assert o.ft_price == 1234.6 + assert o.ft_amount == 20.01 assert o.filled == 9 assert o.remaining == 11 assert o.order_date is not None @@ -1913,7 +1920,9 @@ def test_update_order_from_ccxt(caplog): assert o.filled == 20.0 assert o.remaining == 0.0 assert not o.ft_is_open - assert o.order_filled_date is not None + assert o.order_filled_date == start + # Move time + time_machine.move_to(start + timedelta(hours=1), tick=False) ccxt_order.update({'id': 'somethingelse'}) with pytest.raises(DependencyException, match=r"Order-id's don't match"): @@ -1926,6 +1935,12 @@ def test_update_order_from_ccxt(caplog): # Call regular update - shouldn't fail. Order.update_orders([o], {'id': '1234'}) + assert o.order_filled_date == start + + # Fill order again - shouldn't update filled date + ccxt_order.update({'id': '1234'}) + Order.update_orders([o], ccxt_order) + assert o.order_filled_date == start @pytest.mark.usefixtures("init_persistence") @@ -2539,6 +2554,8 @@ def test_recalc_trade_from_orders_dca(data) -> None: ft_pair=trade.pair, order_id=f"order_{order[0]}_{idx}", ft_is_open=False, + ft_amount=amount, + ft_price=price, status="closed", symbol=trade.pair, order_type="market", diff --git a/tests/plugins/test_protections.py b/tests/plugins/test_protections.py index 820eced20..2bbdf3d4f 100644 --- a/tests/plugins/test_protections.py +++ b/tests/plugins/test_protections.py @@ -39,6 +39,8 @@ def generate_mock_trade(pair: str, fee: float, is_open: bool, order_id=f'{pair}-{trade.entry_side}-{trade.open_date}', ft_is_open=False, ft_pair=pair, + ft_amount=trade.amount, + ft_price=trade.open_rate, amount=trade.amount, filled=trade.amount, remaining=0, @@ -49,16 +51,19 @@ def generate_mock_trade(pair: str, fee: float, is_open: bool, side=trade.entry_side, )) if not is_open: + close_price = open_rate * (2 - profit_rate if is_short else profit_rate) trade.orders.append(Order( ft_order_side=trade.exit_side, order_id=f'{pair}-{trade.exit_side}-{trade.close_date}', ft_is_open=False, ft_pair=pair, + ft_amount=trade.amount, + ft_price=trade.open_rate, amount=trade.amount, filled=trade.amount, remaining=0, - price=open_rate * (2 - profit_rate if is_short else profit_rate), - average=open_rate * (2 - profit_rate if is_short else profit_rate), + price=close_price, + average=close_price, status="closed", order_type="market", side=trade.exit_side, @@ -66,7 +71,7 @@ def generate_mock_trade(pair: str, fee: float, is_open: bool, trade.recalc_open_trade_value() if not is_open: - trade.close(open_rate * (2 - profit_rate if is_short else profit_rate)) + trade.close(close_price) trade.exit_reason = exit_reason Trade.query.session.add(trade) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index c130e9373..89a1b791d 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1,8 +1,6 @@ """ Unit test file for rpc/api_server.py """ - -import json import logging import time from datetime import datetime, timedelta, timezone @@ -68,22 +66,23 @@ def botclient(default_conf, mocker): ApiServer.shutdown() -def client_post(client, url, data={}): +def client_post(client: TestClient, url, data={}): + return client.post(url, - content=data, + json=data, headers={'Authorization': _basic_auth_str(_TEST_USER, _TEST_PASS), 'Origin': 'http://example.com', 'content-type': 'application/json' }) -def client_get(client, url): +def client_get(client: TestClient, url): # Add fake Origin to ensure CORS kicks in return client.get(url, headers={'Authorization': _basic_auth_str(_TEST_USER, _TEST_PASS), 'Origin': 'http://example.com'}) -def client_delete(client, url): +def client_delete(client: TestClient, url): # Add fake Origin to ensure CORS kicks in return client.delete(url, headers={'Authorization': _basic_auth_str(_TEST_USER, _TEST_PASS), 'Origin': 'http://example.com'}) @@ -561,7 +560,7 @@ def test_api_locks(botclient): assert rc.json()['lock_count'] == 1 rc = client_post(client, f"{BASE_URI}/locks/delete", - data='{"pair": "XRP/BTC"}') + data={"pair": "XRP/BTC"}) assert_response(rc) assert rc.json()['lock_count'] == 0 @@ -707,6 +706,46 @@ def test_api_delete_trade(botclient, mocker, fee, markets, is_short): assert_response(rc, 502) +@pytest.mark.parametrize('is_short', [True, False]) +def test_api_delete_open_order(botclient, mocker, fee, markets, ticker, is_short): + ftbot, client = botclient + patch_get_signal(ftbot, enter_long=not is_short, enter_short=is_short) + stoploss_mock = MagicMock() + cancel_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + markets=PropertyMock(return_value=markets), + fetch_ticker=ticker, + cancel_order=cancel_mock, + cancel_stoploss_order=stoploss_mock, + ) + + rc = client_delete(client, f"{BASE_URI}/trades/10/open-order") + assert_response(rc, 502) + assert 'Invalid trade_id.' in rc.json()['error'] + + create_mock_trades(fee, is_short=is_short) + Trade.commit() + + rc = client_delete(client, f"{BASE_URI}/trades/5/open-order") + assert_response(rc, 502) + assert 'No open order for trade_id' in rc.json()['error'] + trade = Trade.get_trades([Trade.id == 6]).first() + mocker.patch('freqtrade.exchange.Exchange.fetch_order', + side_effect=ExchangeError) + rc = client_delete(client, f"{BASE_URI}/trades/6/open-order") + assert_response(rc, 502) + assert 'Order not found.' in rc.json()['error'] + + trade = Trade.get_trades([Trade.id == 6]).first() + mocker.patch('freqtrade.exchange.Exchange.fetch_order', + return_value=trade.orders[-1].to_ccxt_object()) + + rc = client_delete(client, f"{BASE_URI}/trades/6/open-order") + assert_response(rc) + assert cancel_mock.call_count == 1 + + def test_api_logs(botclient): ftbot, client = botclient rc = client_get(client, f"{BASE_URI}/logs") @@ -1062,7 +1101,7 @@ def test_api_blacklist(botclient, mocker): # Add ETH/BTC to blacklist rc = client_post(client, f"{BASE_URI}/blacklist", - data='{"blacklist": ["ETH/BTC"]}') + data={"blacklist": ["ETH/BTC"]}) assert_response(rc) assert rc.json() == {"blacklist": ["DOGE/BTC", "HOT/BTC", "ETH/BTC"], "blacklist_expanded": ["ETH/BTC"], @@ -1072,7 +1111,7 @@ def test_api_blacklist(botclient, mocker): } rc = client_post(client, f"{BASE_URI}/blacklist", - data='{"blacklist": ["XRP/.*"]}') + data={"blacklist": ["XRP/.*"]}) assert_response(rc) assert rc.json() == {"blacklist": ["DOGE/BTC", "HOT/BTC", "ETH/BTC", "XRP/.*"], "blacklist_expanded": ["ETH/BTC", "XRP/BTC", "XRP/USDT"], @@ -1134,7 +1173,7 @@ def test_api_force_entry(botclient, mocker, fee, endpoint): ftbot, client = botclient rc = client_post(client, f"{BASE_URI}/{endpoint}", - data='{"pair": "ETH/BTC"}') + data={"pair": "ETH/BTC"}) assert_response(rc, 502) assert rc.json() == {"error": f"Error querying /api/v1/{endpoint}: Force_entry not enabled."} @@ -1144,7 +1183,7 @@ def test_api_force_entry(botclient, mocker, fee, endpoint): fbuy_mock = MagicMock(return_value=None) mocker.patch("freqtrade.rpc.RPC._rpc_force_entry", fbuy_mock) rc = client_post(client, f"{BASE_URI}/{endpoint}", - data='{"pair": "ETH/BTC"}') + data={"pair": "ETH/BTC"}) assert_response(rc) assert rc.json() == {"status": "Error entering long trade for pair ETH/BTC."} @@ -1171,7 +1210,7 @@ def test_api_force_entry(botclient, mocker, fee, endpoint): mocker.patch("freqtrade.rpc.RPC._rpc_force_entry", fbuy_mock) rc = client_post(client, f"{BASE_URI}/{endpoint}", - data='{"pair": "ETH/BTC"}') + data={"pair": "ETH/BTC"}) assert_response(rc) assert rc.json() == { 'amount': 1.0, @@ -1246,7 +1285,7 @@ def test_api_forceexit(botclient, mocker, ticker, fee, markets): patch_get_signal(ftbot) rc = client_post(client, f"{BASE_URI}/forceexit", - data='{"tradeid": "1"}') + data={"tradeid": "1"}) assert_response(rc, 502) assert rc.json() == {"error": "Error querying /api/v1/forceexit: invalid argument"} Trade.query.session.rollback() @@ -1255,7 +1294,7 @@ def test_api_forceexit(botclient, mocker, ticker, fee, markets): trade = Trade.get_trades([Trade.id == 5]).first() assert pytest.approx(trade.amount) == 123 rc = client_post(client, f"{BASE_URI}/forceexit", - data='{"tradeid": "5", "ordertype": "market", "amount": 23}') + data={"tradeid": "5", "ordertype": "market", "amount": 23}) assert_response(rc) assert rc.json() == {'result': 'Created sell order for trade 5.'} Trade.query.session.rollback() @@ -1265,7 +1304,7 @@ def test_api_forceexit(botclient, mocker, ticker, fee, markets): assert trade.is_open is True rc = client_post(client, f"{BASE_URI}/forceexit", - data='{"tradeid": "5"}') + data={"tradeid": "5"}) assert_response(rc) assert rc.json() == {'result': 'Created sell order for trade 5.'} Trade.query.session.rollback() @@ -1418,7 +1457,7 @@ def test_api_pair_history(botclient, ohlcv_history): "No data for UNITTEST/BTC, 5m in 20200111-20200112 found.") -def test_api_plot_config(botclient): +def test_api_plot_config(botclient, mocker): ftbot, client = botclient rc = client_get(client, f"{BASE_URI}/plot_config") @@ -1442,6 +1481,21 @@ def test_api_plot_config(botclient): assert isinstance(rc.json()['main_plot'], dict) assert isinstance(rc.json()['subplots'], dict) + rc = client_get(client, f"{BASE_URI}/plot_config?strategy=freqai_test_classifier") + assert_response(rc) + res = rc.json() + assert 'target_roi' in res['subplots'] + assert 'do_predict' in res['subplots'] + + rc = client_get(client, f"{BASE_URI}/plot_config?strategy=HyperoptableStrategy") + assert_response(rc) + assert rc.json()['subplots'] == {} + + mocker.patch('freqtrade.rpc.api_server.api_v1.get_rpc_optional', return_value=None) + + rc = client_get(client, f"{BASE_URI}/plot_config") + assert_response(rc) + def test_api_strategies(botclient, tmpdir): ftbot, client = botclient @@ -1554,13 +1608,13 @@ def test_list_available_pairs(botclient): client, f"{BASE_URI}/available_pairs?timeframe=1h") assert_response(rc) assert rc.json()['length'] == 1 - assert rc.json()['pairs'] == ['XRP/USDT'] + assert rc.json()['pairs'] == ['XRP/USDT:USDT'] rc = client_get( client, f"{BASE_URI}/available_pairs?timeframe=1h&candletype=mark") assert_response(rc) assert rc.json()['length'] == 2 - assert rc.json()['pairs'] == ['UNITTEST/USDT', 'XRP/USDT'] + assert rc.json()['pairs'] == ['UNITTEST/USDT:USDT', 'XRP/USDT:USDT'] assert len(rc.json()['pair_interval']) == 2 @@ -1616,7 +1670,7 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmpdir): "dry_run_wallet": 1000, "enable_protections": False } - rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data)) + rc = client_post(client, f"{BASE_URI}/backtest", data=data) assert_response(rc) result = rc.json() @@ -1667,7 +1721,7 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmpdir): assert result['status'] == 'running' # Post to backtest that's still running - rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data)) + rc = client_post(client, f"{BASE_URI}/backtest", data=data) assert_response(rc, 502) result = rc.json() assert 'Bot Background task already running' in result['error'] @@ -1675,7 +1729,7 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmpdir): ApiServer._bgtask_running = False # Rerun backtest (should get previous result) - rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data)) + rc = client_post(client, f"{BASE_URI}/backtest", data=data) assert_response(rc) result = rc.json() assert log_has_re('Reusing result of previous backtest.*', caplog) @@ -1684,7 +1738,7 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmpdir): mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest_one_strategy', side_effect=DependencyException()) - rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data)) + rc = client_post(client, f"{BASE_URI}/backtest", data=data) assert log_has("Backtesting caused an error: ", caplog) # Delete backtesting to avoid leakage since the backtest-object may stick around. @@ -1698,7 +1752,7 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmpdir): # Disallow base64 strategies data['strategy'] = "xx:cHJpbnQoImhlbGxvIHdvcmxkIik=" - rc = client_post(client, f"{BASE_URI}/backtest", data=json.dumps(data)) + rc = client_post(client, f"{BASE_URI}/backtest", data=data) assert_response(rc, 500) @@ -1766,7 +1820,7 @@ def test_api_ws_subscribe(botclient, mocker): assert sub_mock.call_count == 1 -def test_api_ws_requests(botclient, mocker, caplog): +def test_api_ws_requests(botclient, caplog): caplog.set_level(logging.DEBUG) ftbot, client = botclient diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 58977a94a..5e3c2bd18 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -99,7 +99,7 @@ def test_telegram_init(default_conf, mocker, caplog) -> None: message_str = ("rpc.telegram is listening for following commands: [['status'], ['profit'], " "['balance'], ['start'], ['stop'], " "['forcesell', 'forceexit', 'fx'], ['forcebuy', 'forcelong'], ['forceshort'], " - "['trades'], ['delete'], ['performance'], " + "['trades'], ['delete'], ['coo', 'cancel_open_order'], ['performance'], " "['buys', 'entries'], ['sells', 'exits'], ['mix_tags'], " "['stats'], ['daily'], ['weekly'], ['monthly'], " "['count'], ['locks'], ['unlock', 'delete_locks'], " @@ -253,6 +253,8 @@ def test_telegram_status_multi_entry(default_conf, update, mocker, fee) -> None: ft_order_side='buy', ft_pair=trade.pair, ft_is_open=False, + ft_amount=trade.amount, + ft_price=trade.open_rate, status="closed", symbol=trade.pair, order_type="market", @@ -1676,6 +1678,40 @@ def test_telegram_delete_trade(mocker, update, default_conf, fee, is_short): assert "Please make sure to take care of this asset" in msg_mock.call_args_list[0][0][0] +@pytest.mark.parametrize('is_short', [True, False]) +def test_telegram_delete_open_order(mocker, update, default_conf, fee, is_short, ticker): + + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + fetch_ticker=ticker, + ) + telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) + context = MagicMock() + context.args = [] + + telegram._cancel_open_order(update=update, context=context) + assert "Trade-id not set." in msg_mock.call_args_list[0][0][0] + + msg_mock.reset_mock() + create_mock_trades(fee, is_short=is_short) + + context = MagicMock() + context.args = [5] + telegram._cancel_open_order(update=update, context=context) + assert "No open order for trade_id" in msg_mock.call_args_list[0][0][0] + + msg_mock.reset_mock() + + trade = Trade.get_trades([Trade.id == 6]).first() + mocker.patch('freqtrade.exchange.Exchange.fetch_order', + return_value=trade.orders[-1].to_ccxt_object()) + context = MagicMock() + context.args = [6] + telegram._cancel_open_order(update=update, context=context) + assert msg_mock.call_count == 1 + assert "Open order canceled." in msg_mock.call_args_list[0][0][0] + + def test_help_handle(default_conf, update, mocker) -> None: telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) diff --git a/tests/strategy/strats/freqai_rl_test_strat.py b/tests/strategy/strats/freqai_rl_test_strat.py index f32a4adca..2bf4aaa30 100644 --- a/tests/strategy/strats/freqai_rl_test_strat.py +++ b/tests/strategy/strats/freqai_rl_test_strat.py @@ -1,11 +1,11 @@ import logging from functools import reduce +from typing import Dict -import pandas as pd import talib.abstract as ta from pandas import DataFrame -from freqtrade.strategy import IStrategy, merge_informative_pair +from freqtrade.strategy import IStrategy logger = logging.getLogger(__name__) @@ -22,52 +22,40 @@ class freqai_rl_test_strat(IStrategy): process_only_new_candles = True stoploss = -0.05 use_exit_signal = True - startup_candle_count: int = 30 + startup_candle_count: int = 300 can_short = False - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, + metadata: Dict, **kwargs): - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + return dataframe - t = int(t) - informative[f"%-{pair}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: Dict, **kwargs): - # The following columns are necessary for RL models. - informative[f"%-{pair}raw_close"] = informative["close"] - informative[f"%-{pair}raw_open"] = informative["open"] - informative[f"%-{pair}raw_high"] = informative["high"] - informative[f"%-{pair}raw_low"] = informative["low"] + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + return dataframe - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + def feature_engineering_standard(self, dataframe: DataFrame, metadata: Dict, **kwargs): - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - # For RL, there are no direct targets to set. This is filler (neutral) - # until the agent sends an action. - df["&-action"] = 0 + dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek + dataframe["%-hour_of_day"] = dataframe["date"].dt.hour - return df + dataframe["%-raw_close"] = dataframe["close"] + dataframe["%-raw_open"] = dataframe["open"] + dataframe["%-raw_high"] = dataframe["high"] + dataframe["%-raw_low"] = dataframe["low"] + + return dataframe + + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs): + + dataframe["&-action"] = 0 + + return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/tests/strategy/strats/freqai_test_classifier.py b/tests/strategy/strats/freqai_test_classifier.py index a1e8cb6bf..61b9f0c37 100644 --- a/tests/strategy/strats/freqai_test_classifier.py +++ b/tests/strategy/strats/freqai_test_classifier.py @@ -1,12 +1,12 @@ import logging from functools import reduce +from typing import Dict import numpy as np -import pandas as pd import talib.abstract as ta from pandas import DataFrame -from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, merge_informative_pair +from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy logger = logging.getLogger(__name__) @@ -57,55 +57,36 @@ class freqai_test_classifier(IStrategy): informative_pairs.append((pair, tf)) return informative_pairs - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, + metadata: Dict, **kwargs): - coin = pair.split('/')[0] + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + return dataframe - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: Dict, **kwargs): - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] - informative[f"%-{coin}pct-change"] = informative["close"].pct_change() - informative[f"%-{coin}raw_volume"] = informative["volume"] - informative[f"%-{coin}raw_price"] = informative["close"] + return dataframe - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + def feature_engineering_standard(self, dataframe: DataFrame, metadata: Dict, **kwargs): - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek + dataframe["%-hour_of_day"] = dataframe["date"].dt.hour - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + return dataframe - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df['&s-up_or_down'] = np.where(df["close"].shift(-100) > df["close"], 'up', 'down') + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs): - return df + dataframe['&s-up_or_down'] = np.where(dataframe["close"].shift(-100) > + dataframe["close"], 'up', 'down') + + return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/tests/strategy/strats/freqai_test_multimodel_classifier_strat.py b/tests/strategy/strats/freqai_test_multimodel_classifier_strat.py index 9188fa331..b2ddc21e3 100644 --- a/tests/strategy/strats/freqai_test_multimodel_classifier_strat.py +++ b/tests/strategy/strats/freqai_test_multimodel_classifier_strat.py @@ -1,12 +1,12 @@ import logging from functools import reduce +from typing import Dict import numpy as np -import pandas as pd import talib.abstract as ta from pandas import DataFrame -from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, merge_informative_pair +from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy logger = logging.getLogger(__name__) @@ -44,59 +44,39 @@ class freqai_test_multimodel_classifier_strat(IStrategy): ) max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True) - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, + metadata: Dict, **kwargs): - coin = pair.split('/')[0] + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + return dataframe - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: Dict, **kwargs): - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] - informative[f"%-{coin}pct-change"] = informative["close"].pct_change() - informative[f"%-{coin}raw_volume"] = informative["volume"] - informative[f"%-{coin}raw_price"] = informative["close"] + return dataframe - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + def feature_engineering_standard(self, dataframe: DataFrame, metadata: Dict, **kwargs): - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek + dataframe["%-hour_of_day"] = dataframe["date"].dt.hour - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + return dataframe - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df['&s-up_or_down'] = np.where(df["close"].shift(-50) > - df["close"], 'up', 'down') + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs): - df['&s-up_or_down2'] = np.where(df["close"].shift(-50) > - df["close"], 'up2', 'down2') + dataframe['&s-up_or_down'] = np.where(dataframe["close"].shift(-50) > + dataframe["close"], 'up', 'down') - return df + dataframe['&s-up_or_down2'] = np.where(dataframe["close"].shift(-50) > + dataframe["close"], 'up2', 'down2') + + return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/tests/strategy/strats/freqai_test_multimodel_strat.py b/tests/strategy/strats/freqai_test_multimodel_strat.py index ada4b25f0..5b09598a5 100644 --- a/tests/strategy/strats/freqai_test_multimodel_strat.py +++ b/tests/strategy/strats/freqai_test_multimodel_strat.py @@ -1,11 +1,11 @@ import logging from functools import reduce +from typing import Dict -import pandas as pd import talib.abstract as ta from pandas import DataFrame -from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, merge_informative_pair +from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy logger = logging.getLogger(__name__) @@ -43,74 +43,54 @@ class freqai_test_multimodel_strat(IStrategy): ) max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True) - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, + metadata: Dict, **kwargs): - coin = pair.split('/')[0] + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + return dataframe - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: Dict, **kwargs): - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] - informative[f"%-{coin}pct-change"] = informative["close"].pct_change() - informative[f"%-{coin}raw_volume"] = informative["volume"] - informative[f"%-{coin}raw_price"] = informative["close"] + return dataframe - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + def feature_engineering_standard(self, dataframe: DataFrame, metadata: Dict, **kwargs): - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek + dataframe["%-hour_of_day"] = dataframe["date"].dt.hour - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + return dataframe - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs): + + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 ) - df["&-s_range"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .max() - - - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .min() - ) + dataframe["&-s_range"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .max() + - + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .min() + ) - return df + return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/tests/strategy/strats/freqai_test_strat.py b/tests/strategy/strats/freqai_test_strat.py index cdfb7f4d0..6db308406 100644 --- a/tests/strategy/strats/freqai_test_strat.py +++ b/tests/strategy/strats/freqai_test_strat.py @@ -1,11 +1,11 @@ import logging from functools import reduce +from typing import Dict -import pandas as pd import talib.abstract as ta from pandas import DataFrame -from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy, merge_informative_pair +from freqtrade.strategy import DecimalParameter, IntParameter, IStrategy logger = logging.getLogger(__name__) @@ -43,62 +43,42 @@ class freqai_test_strat(IStrategy): ) max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True) - def populate_any_indicators( - self, pair, df, tf, informative=None, set_generalized_indicators=False - ): + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, + metadata: Dict, **kwargs): - coin = pair.split('/')[0] + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) - if informative is None: - informative = self.dp.get_pair_dataframe(pair, tf) + return dataframe - # first loop is automatically duplicating indicators for time periods - for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: Dict, **kwargs): - t = int(t) - informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) - informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) - informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] - informative[f"%-{coin}pct-change"] = informative["close"].pct_change() - informative[f"%-{coin}raw_volume"] = informative["volume"] - informative[f"%-{coin}raw_price"] = informative["close"] + return dataframe - indicators = [col for col in informative if col.startswith("%")] - # This loop duplicates and shifts all indicators to add a sense of recency to data - for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): - if n == 0: - continue - informative_shift = informative[indicators].shift(n) - informative_shift = informative_shift.add_suffix("_shift-" + str(n)) - informative = pd.concat((informative, informative_shift), axis=1) + def feature_engineering_standard(self, dataframe: DataFrame, metadata: Dict, **kwargs): - df = merge_informative_pair(df, informative, self.config["timeframe"], tf, ffill=True) - skip_columns = [ - (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] - ] - df = df.drop(columns=skip_columns) + dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek + dataframe["%-hour_of_day"] = dataframe["date"].dt.hour - # Add generalized indicators here (because in live, it will call this - # function to populate indicators during training). Notice how we ensure not to - # add them multiple times - if set_generalized_indicators: - df["%-day_of_week"] = (df["date"].dt.dayofweek + 1) / 7 - df["%-hour_of_day"] = (df["date"].dt.hour + 1) / 25 + return dataframe - # user adds targets here by prepending them with &- (see convention below) - # If user wishes to use multiple targets, a multioutput prediction model - # needs to be used such as templates/CatboostPredictionMultiModel.py - df["&-s_close"] = ( - df["close"] - .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) - .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) - .mean() - / df["close"] - - 1 + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs): + + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 ) - return df + return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/tests/strategy/strats/hyperoptable_strategy.py b/tests/strategy/strats/hyperoptable_strategy.py index 9850a5675..eadbc533f 100644 --- a/tests/strategy/strats/hyperoptable_strategy.py +++ b/tests/strategy/strats/hyperoptable_strategy.py @@ -34,6 +34,11 @@ class HyperoptableStrategy(StrategyTestV3): protection_enabled = BooleanParameter(default=True) protection_cooldown_lookback = IntParameter([0, 50], default=30) + # Invalid plot config ... + plot_config = { + "main_plot": {}, + } + @property def protections(self): prot = [] diff --git a/tests/strategy/strats/strategy_test_v3.py b/tests/strategy/strats/strategy_test_v3.py index 088ab21d4..6f5ff573b 100644 --- a/tests/strategy/strats/strategy_test_v3.py +++ b/tests/strategy/strats/strategy_test_v3.py @@ -30,6 +30,9 @@ class StrategyTestV3(IStrategy): "0": 0.04 } + # Optimal max_open_trades for the strategy + max_open_trades = -1 + # Optimal stoploss designed for the strategy stoploss = -0.10 diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index 5fcc75026..98185e152 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -6,6 +6,7 @@ from pathlib import Path import pytest from pandas import DataFrame +from freqtrade.configuration import Configuration from freqtrade.exceptions import OperationalException from freqtrade.resolvers import StrategyResolver from freqtrade.strategy.interface import IStrategy @@ -175,6 +176,18 @@ def test_strategy_override_stoploss(caplog, default_conf): assert log_has("Override strategy 'stoploss' with value in config file: -0.5.", caplog) +def test_strategy_override_max_open_trades(caplog, default_conf): + caplog.set_level(logging.INFO) + default_conf.update({ + 'strategy': CURRENT_TEST_STRATEGY, + 'max_open_trades': 7 + }) + strategy = StrategyResolver.load_strategy(default_conf) + + assert strategy.max_open_trades == 7 + assert log_has("Override strategy 'max_open_trades' with value in config file: 7.", caplog) + + def test_strategy_override_trailing_stop(caplog, default_conf): caplog.set_level(logging.INFO) default_conf.update({ @@ -349,6 +362,38 @@ def test_strategy_override_use_exit_profit_only(caplog, default_conf): assert log_has("Override strategy 'exit_profit_only' with value in config file: True.", caplog) +def test_strategy_max_open_trades_infinity_from_strategy(caplog, default_conf): + caplog.set_level(logging.INFO) + default_conf.update({ + 'strategy': CURRENT_TEST_STRATEGY, + }) + del default_conf['max_open_trades'] + + strategy = StrategyResolver.load_strategy(default_conf) + + # this test assumes -1 set to 'max_open_trades' in CURRENT_TEST_STRATEGY + assert strategy.max_open_trades == float('inf') + assert default_conf['max_open_trades'] == float('inf') + + +def test_strategy_max_open_trades_infinity_from_config(caplog, default_conf, mocker): + caplog.set_level(logging.INFO) + default_conf.update({ + 'strategy': CURRENT_TEST_STRATEGY, + 'max_open_trades': -1, + 'exchange': 'binance' + }) + + configuration = Configuration(args=default_conf) + parsed_config = configuration.get_config() + + assert parsed_config['max_open_trades'] == float('inf') + + strategy = StrategyResolver.load_strategy(parsed_config) + + assert strategy.max_open_trades == float('inf') + + @ pytest.mark.filterwarnings("ignore:deprecated") def test_missing_implements(default_conf, caplog): @@ -438,3 +483,19 @@ def test_strategy_interface_versioning(dataframe_1m, default_conf): assert isinstance(exitdf, DataFrame) assert 'sell' not in exitdf assert 'exit_long' in exitdf + + +def test_strategy_ft_load_params_from_file(mocker, default_conf): + default_conf.update({'strategy': 'StrategyTestV2'}) + del default_conf['max_open_trades'] + mocker.patch('freqtrade.strategy.hyper.HyperStrategyMixin.load_params_from_file', + return_value={ + 'params': { + 'max_open_trades': { + 'max_open_trades': -1 + } + } + }) + strategy = StrategyResolver.load_strategy(default_conf) + assert strategy.max_open_trades == float('inf') + assert strategy.config['max_open_trades'] == float('inf') diff --git a/tests/test_binance_mig.py b/tests/test_binance_mig.py new file mode 100644 index 000000000..5a5bbe9dc --- /dev/null +++ b/tests/test_binance_mig.py @@ -0,0 +1,58 @@ + + +import shutil +from pathlib import Path + +import pytest + +from freqtrade.persistence import Trade +from freqtrade.util.binance_mig import migrate_binance_futures_data, migrate_binance_futures_names +from tests.conftest import create_mock_trades_usdt, log_has + + +def test_binance_mig_data_conversion(default_conf_usdt, tmpdir, testdatadir): + + # call doing nothing (spot mode) + migrate_binance_futures_data(default_conf_usdt) + default_conf_usdt['trading_mode'] = 'futures' + pair_old = 'XRP_USDT' + pair_unified = 'XRP_USDT_USDT' + futures_src = testdatadir / 'futures' + futures_dst = tmpdir / 'futures' + futures_dst.mkdir() + files = [ + '-1h-mark.json', + '-1h-futures.json', + '-8h-funding_rate.json', + '-8h-mark.json', + ] + + # Copy files to tmpdir and rename to old naming + for file in files: + fn_after = futures_dst / f'{pair_old}{file}' + shutil.copy(futures_src / f'{pair_unified}{file}', fn_after) + + default_conf_usdt['datadir'] = Path(tmpdir) + # Migrate files to unified namings + migrate_binance_futures_data(default_conf_usdt) + + for file in files: + fn_after = futures_dst / f'{pair_unified}{file}' + assert fn_after.exists() + + +@pytest.mark.usefixtures("init_persistence") +def test_binance_mig_db_conversion(default_conf_usdt, fee, caplog): + # Does nothing in spot mode + migrate_binance_futures_names(default_conf_usdt) + + create_mock_trades_usdt(fee, None) + + for t in Trade.get_trades(): + t.trading_mode = 'FUTURES' + t.exchange = 'binance' + Trade.commit() + + default_conf_usdt['trading_mode'] = 'futures' + migrate_binance_futures_names(default_conf_usdt) + assert log_has('Migrating binance futures pairs in database.', caplog) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index cdf9f2f2e..a2a1b72cc 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -58,6 +58,7 @@ def test_load_config_incorrect_stake_amount(default_conf) -> None: def test_load_config_file(default_conf, mocker, caplog) -> None: del default_conf['user_data_dir'] + default_conf['datadir'] = str(default_conf['datadir']) file_mock = mocker.patch('freqtrade.configuration.load_config.open', mocker.mock_open( read_data=json.dumps(default_conf) )) @@ -69,6 +70,7 @@ def test_load_config_file(default_conf, mocker, caplog) -> None: def test_load_config_file_error(default_conf, mocker, caplog) -> None: del default_conf['user_data_dir'] + default_conf['datadir'] = str(default_conf['datadir']) filedata = json.dumps(default_conf).replace( '"stake_amount": 0.001,', '"stake_amount": .001,') mocker.patch('freqtrade.configuration.load_config.open', mocker.mock_open(read_data=filedata)) @@ -80,6 +82,7 @@ def test_load_config_file_error(default_conf, mocker, caplog) -> None: def test_load_config_file_error_range(default_conf, mocker, caplog) -> None: del default_conf['user_data_dir'] + default_conf['datadir'] = str(default_conf['datadir']) filedata = json.dumps(default_conf).replace( '"stake_amount": 0.001,', '"stake_amount": .001,') mocker.patch.object(Path, "read_text", MagicMock(return_value=filedata)) @@ -238,6 +241,7 @@ def test_print_config(default_conf, mocker, caplog) -> None: conf1 = deepcopy(default_conf) # Delete non-json elements from default_conf del conf1['user_data_dir'] + conf1['datadir'] = str(conf1['datadir']) config_files = [conf1] configsmock = MagicMock(side_effect=config_files) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a4431358f..5e580e4fa 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -737,20 +737,22 @@ def test_process_informative_pairs_added(default_conf_usdt, ticker_usdt, mocker) @pytest.mark.parametrize("is_short,trading_mode,exchange_name,margin_mode,liq_buffer,liq_price", [ (False, 'spot', 'binance', None, 0.0, None), (True, 'spot', 'binance', None, 0.0, None), - (False, 'spot', 'gateio', None, 0.0, None), - (True, 'spot', 'gateio', None, 0.0, None), + (False, 'spot', 'gate', None, 0.0, None), + (True, 'spot', 'gate', None, 0.0, None), (False, 'spot', 'okx', None, 0.0, None), (True, 'spot', 'okx', None, 0.0, None), (True, 'futures', 'binance', 'isolated', 0.0, 11.88151815181518), (False, 'futures', 'binance', 'isolated', 0.0, 8.080471380471382), - (True, 'futures', 'gateio', 'isolated', 0.0, 11.87413417771621), - (False, 'futures', 'gateio', 'isolated', 0.0, 8.085708510208207), + (True, 'futures', 'gate', 'isolated', 0.0, 11.87413417771621), + (False, 'futures', 'gate', 'isolated', 0.0, 8.085708510208207), (True, 'futures', 'binance', 'isolated', 0.05, 11.7874422442244), (False, 'futures', 'binance', 'isolated', 0.05, 8.17644781144781), - (True, 'futures', 'gateio', 'isolated', 0.05, 11.7804274688304), - (False, 'futures', 'gateio', 'isolated', 0.05, 8.181423084697796), + (True, 'futures', 'gate', 'isolated', 0.05, 11.7804274688304), + (False, 'futures', 'gate', 'isolated', 0.05, 8.181423084697796), (True, 'futures', 'okx', 'isolated', 0.0, 11.87413417771621), (False, 'futures', 'okx', 'isolated', 0.0, 8.085708510208207), + (True, 'futures', 'bybit', 'isolated', 0.0, 11.9), + (False, 'futures', 'bybit', 'isolated', 0.0, 8.1), ]) def test_execute_entry(mocker, default_conf_usdt, fee, limit_order, limit_order_open, is_short, trading_mode, @@ -766,11 +768,11 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order, ((wb + cum_b) - (side_1 * position * ep1)) / ((position * mmr_b) - (side_1 * position)) ((2 + 0.01) - (1 * 1 * 10)) / ((1 * 0.01) - (1 * 1)) = 8.070707070707071 - exchange_name = gateio/okx, is_short = true + exchange_name = gate/okx, is_short = true (open_rate + (wallet_balance / position)) / (1 + (mm_ratio + taker_fee_rate)) (10 + (2 / 1)) / (1 + (0.01 + 0.0006)) = 11.87413417771621 - exchange_name = gateio/okx, is_short = false + exchange_name = gate/okx, is_short = false (open_rate - (wallet_balance / position)) / (1 - (mm_ratio + taker_fee_rate)) (10 - (2 / 1)) / (1 - (0.01 + 0.0006)) = 8.085708510208207 """ @@ -783,7 +785,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order, default_conf_usdt['exchange']['name'] = exchange_name if margin_mode: default_conf_usdt['margin_mode'] = margin_mode - mocker.patch('freqtrade.exchange.Gateio.validate_ordertypes') + mocker.patch('freqtrade.exchange.Gate.validate_ordertypes') patch_RPCManager(mocker) patch_exchange(mocker, id=exchange_name) freqtrade = FreqtradeBot(default_conf_usdt) @@ -1168,6 +1170,8 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_ order_id='100', ft_pair=trade.pair, ft_is_open=True, + ft_amount=trade.amount, + ft_price=0.0, )) assert trade @@ -4615,6 +4619,7 @@ def test_get_real_amount_open_trade_usdt(default_conf_usdt, fee, mocker): 'amount': amount, 'status': 'open', 'side': 'buy', + 'price': 0.245441, } freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) order_obj = Order.parse_from_ccxt_object(order, 'LTC/ETH', 'buy') @@ -5023,7 +5028,7 @@ def test_startup_update_open_orders(mocker, default_conf_usdt, fee, caplog, is_s assert log_has_re(r"Error updating Order .*", caplog) mocker.patch('freqtrade.exchange.Exchange.fetch_order', side_effect=InvalidOrderException) - hto_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_timedout_order') + hto_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_order') # Orders which are no longer found after X days should be assumed as canceled. freqtrade.startup_update_open_orders() assert log_has_re(r"Order is older than \d days.*", caplog) diff --git a/tests/test_misc.py b/tests/test_misc.py index 2da45bad9..596c7bd51 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -5,6 +5,7 @@ from copy import deepcopy from pathlib import Path from unittest.mock import MagicMock +import pandas as pd import pytest from freqtrade.misc import (dataframe_to_json, decimals_per_coin, deep_merge_dicts, file_dump_json, @@ -231,3 +232,7 @@ def test_dataframe_json(ohlcv_history): assert len(ohlcv_history) == len(dataframe) assert_frame_equal(ohlcv_history, dataframe) + ohlcv_history.at[1, 'date'] = pd.NaT + json = dataframe_to_json(ohlcv_history) + + dataframe = json_to_dataframe(json) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 7662ea7f1..9f04ba20a 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -45,7 +45,6 @@ def test_init_plotscript(default_conf, mocker, testdatadir): default_conf['timerange'] = "20180110-20180112" default_conf['trade_source'] = "file" default_conf['timeframe'] = "5m" - default_conf["datadir"] = testdatadir default_conf['exportfilename'] = testdatadir / "backtest-result.json" supported_markets = ["TRX/BTC", "ADA/BTC"] ret = init_plotscript(default_conf, supported_markets) @@ -394,7 +393,6 @@ def test_load_and_plot_trades(default_conf, mocker, caplog, testdatadir): patch_exchange(mocker) default_conf['trade_source'] = 'file' - default_conf["datadir"] = testdatadir default_conf['exportfilename'] = testdatadir / "backtest-result.json" default_conf['indicators1'] = ["sma5", "ema10"] default_conf['indicators2'] = ["macd"] @@ -451,7 +449,6 @@ def test_start_plot_profit_error(mocker): def test_plot_profit(default_conf, mocker, testdatadir): patch_exchange(mocker) default_conf['trade_source'] = 'file' - default_conf['datadir'] = testdatadir default_conf['exportfilename'] = testdatadir / 'backtest-result_test_nofile.json' default_conf['pairs'] = ['ETH/BTC', 'LTC/BTC'] diff --git a/tests/test_wallets.py b/tests/test_wallets.py index 0117f7427..61e8f279d 100644 --- a/tests/test_wallets.py +++ b/tests/test_wallets.py @@ -190,7 +190,7 @@ def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker, balance_r (1, 15, 10, 10000, None, 0), # Below min stake and min_stake > stake_available (20, 50, 100, 10000, None, 0), # Below min stake and stake * 1.3 > min_stake (1000, None, 1000, 10000, None, 1000), # No min-stake-amount could be determined - (2000, 15, 2000, 3000, 1500, 500), # Rebuy - resulting in too high stake amount. Adjusting. + (2000, 15, 2000, 3000, 1500, 1500), # Rebuy - resulting in too high stake amount. Adjusting. ]) def test_validate_stake_amount( mocker, diff --git a/tests/testdata/futures/UNITTEST_USDT-1h-mark.json b/tests/testdata/futures/UNITTEST_USDT_USDT-1h-mark.json similarity index 100% rename from tests/testdata/futures/UNITTEST_USDT-1h-mark.json rename to tests/testdata/futures/UNITTEST_USDT_USDT-1h-mark.json diff --git a/tests/testdata/futures/XRP_USDT-1h-futures.json b/tests/testdata/futures/XRP_USDT_USDT-1h-futures.json similarity index 100% rename from tests/testdata/futures/XRP_USDT-1h-futures.json rename to tests/testdata/futures/XRP_USDT_USDT-1h-futures.json diff --git a/tests/testdata/futures/XRP_USDT-1h-futures.json.gz b/tests/testdata/futures/XRP_USDT_USDT-1h-futures.json.gz similarity index 100% rename from tests/testdata/futures/XRP_USDT-1h-futures.json.gz rename to tests/testdata/futures/XRP_USDT_USDT-1h-futures.json.gz diff --git a/tests/testdata/futures/XRP_USDT-1h-mark.json b/tests/testdata/futures/XRP_USDT_USDT-1h-mark.json similarity index 100% rename from tests/testdata/futures/XRP_USDT-1h-mark.json rename to tests/testdata/futures/XRP_USDT_USDT-1h-mark.json diff --git a/tests/testdata/futures/XRP_USDT_USDT-5m-futures.json b/tests/testdata/futures/XRP_USDT_USDT-5m-futures.json new file mode 100644 index 000000000..006bc7508 --- /dev/null +++ b/tests/testdata/futures/XRP_USDT_USDT-5m-futures.json @@ -0,0 +1 @@ +[[1636934400000,1.1893,1.1954,1.1891,1.1941,9289043.5],[1636934700000,1.1941,1.1993,1.1934,1.1972,7267451.9000000004],[1636935000000,1.1972,1.1994,1.1958,1.1963,4199874.2999999998],[1636935300000,1.1963,1.199,1.1963,1.198,3834762.5],[1636935600000,1.198,1.2017,1.198,1.2,5362935.4000000004],[1636935900000,1.2,1.2092,1.1975,1.2083,12116690.4000000004],[1636936200000,1.2084,1.2097,1.2061,1.2079,6959499.2000000002],[1636936500000,1.2079,1.2082,1.2034,1.2056,4608466.2000000002],[1636936800000,1.2056,1.2066,1.2038,1.2055,2005115.8999999999],[1636937100000,1.2055,1.2091,1.2043,1.209,3365548.1000000001],[1636937400000,1.209,1.2159,1.2084,1.2157,8496118.9000000004],[1636937700000,1.2157,1.2165,1.2109,1.2119,5183792.7999999998],[1636938000000,1.2118,1.2147,1.2116,1.2123,3034201.2999999998],[1636938300000,1.2122,1.2133,1.2047,1.2068,5546199.0],[1636938600000,1.2069,1.2089,1.2046,1.2083,2961523.7999999998],[1636938900000,1.2084,1.2092,1.2033,1.2054,2755246.6000000001],[1636939200000,1.2053,1.2059,1.2005,1.2012,3574142.2000000002],[1636939500000,1.2013,1.2047,1.2007,1.2038,2085164.5],[1636939800000,1.2037,1.2064,1.2032,1.2053,1930387.6000000001],[1636940100000,1.2052,1.2074,1.2046,1.2071,1563690.5],[1636940400000,1.207,1.208,1.2064,1.2067,1470500.0],[1636940700000,1.2067,1.2085,1.2062,1.2065,1511111.2],[1636941000000,1.2065,1.2119,1.206,1.2116,3196613.7000000002],[1636941300000,1.2115,1.2119,1.2094,1.2101,2474041.2000000002],[1636941600000,1.2102,1.2116,1.2084,1.2089,1966194.3],[1636941900000,1.2089,1.2102,1.2086,1.2088,1051071.8999999999],[1636942200000,1.2089,1.2092,1.2054,1.2067,1718919.5],[1636942500000,1.2066,1.2088,1.2064,1.2064,1276834.8],[1636942800000,1.2064,1.2074,1.2038,1.2039,1389505.0],[1636943100000,1.2039,1.2076,1.2038,1.2064,1828371.2],[1636943400000,1.2065,1.2082,1.2056,1.2082,1072101.5],[1636943700000,1.2082,1.2116,1.2081,1.2115,2157606.0],[1636944000000,1.2116,1.2136,1.2103,1.2129,1364511.6000000001],[1636944300000,1.2129,1.2138,1.209,1.2095,2037732.3999999999],[1636944600000,1.2095,1.2102,1.2081,1.2086,1376262.8999999999],[1636944900000,1.2087,1.2098,1.2081,1.2089,791578.0],[1636945200000,1.2088,1.2099,1.2075,1.2084,949445.9],[1636945500000,1.2084,1.209,1.2055,1.2073,3957253.0],[1636945800000,1.2071,1.2094,1.207,1.209,1755194.3999999999],[1636946100000,1.2091,1.2091,1.2054,1.2065,2235814.1000000001],[1636946400000,1.2064,1.2079,1.2064,1.2076,1314946.5],[1636946700000,1.2076,1.2076,1.2042,1.2058,1554830.8999999999],[1636947000000,1.2058,1.2073,1.2048,1.2053,1266664.8],[1636947300000,1.2053,1.207,1.2047,1.2067,1332565.7],[1636947600000,1.2067,1.2088,1.2062,1.2083,1539348.6000000001],[1636947900000,1.2082,1.2089,1.207,1.2076,1084474.8999999999],[1636948200000,1.2076,1.2082,1.2067,1.2077,573314.1],[1636948500000,1.2077,1.2095,1.2072,1.2086,1612433.1000000001],[1636948800000,1.2087,1.2114,1.2087,1.2106,1800229.5],[1636949100000,1.2106,1.2109,1.2093,1.2105,1069802.8999999999],[1636949400000,1.2105,1.2105,1.2084,1.2097,1522400.1000000001],[1636949700000,1.2097,1.2126,1.2095,1.2122,1581693.3999999999],[1636950000000,1.2121,1.2124,1.211,1.2113,1502370.0],[1636950300000,1.2113,1.2133,1.2112,1.2125,1275382.6000000001],[1636950600000,1.2127,1.2129,1.2108,1.2112,1669161.7],[1636950900000,1.2112,1.2118,1.2103,1.2109,1281564.8999999999],[1636951200000,1.211,1.2128,1.2107,1.212,1004090.0],[1636951500000,1.212,1.2156,1.2111,1.2155,2016559.1000000001],[1636951800000,1.2154,1.2205,1.2145,1.2178,5314030.4000000004],[1636952100000,1.2178,1.2179,1.2142,1.2148,2687145.2000000002],[1636952400000,1.2148,1.2178,1.2148,1.2178,1223842.8],[1636952700000,1.2177,1.2181,1.2147,1.2152,1500519.6000000001],[1636953000000,1.2152,1.2152,1.211,1.2113,2474496.5],[1636953300000,1.2113,1.214,1.2113,1.2125,1248090.0],[1636953600000,1.2125,1.2141,1.2122,1.2139,921049.0],[1636953900000,1.2139,1.2141,1.2118,1.2128,1198193.3999999999],[1636954200000,1.2127,1.2141,1.211,1.2116,1361937.5],[1636954500000,1.2115,1.2121,1.2104,1.2113,1435204.8999999999],[1636954800000,1.2113,1.2114,1.2091,1.2092,1602274.8999999999],[1636955100000,1.2093,1.2102,1.2092,1.2095,802606.0],[1636955400000,1.2095,1.2095,1.2078,1.2083,1139815.6000000001],[1636955700000,1.2083,1.2109,1.2081,1.2097,1182689.6000000001],[1636956000000,1.2097,1.2103,1.2083,1.2093,1121184.0],[1636956300000,1.2092,1.2112,1.2086,1.2105,1252210.1000000001],[1636956600000,1.2106,1.2162,1.2105,1.2158,2003334.0],[1636956900000,1.2158,1.2158,1.2134,1.2145,2058967.3999999999],[1636957200000,1.2144,1.2177,1.2141,1.2174,1881352.6000000001],[1636957500000,1.2174,1.2189,1.217,1.2184,1592213.6000000001],[1636957800000,1.2183,1.2184,1.2143,1.2151,2138606.5],[1636958100000,1.215,1.2159,1.2127,1.2152,1740152.5],[1636958400000,1.2153,1.2157,1.2145,1.2147,837984.7],[1636958700000,1.2146,1.2159,1.214,1.2145,1068054.1000000001],[1636959000000,1.2144,1.2152,1.2129,1.2129,1080074.0],[1636959300000,1.213,1.2156,1.2126,1.2152,1149888.7],[1636959600000,1.2153,1.2214,1.2152,1.2161,6266177.5999999996],[1636959900000,1.2162,1.217,1.2136,1.2142,1969411.0],[1636960200000,1.2141,1.2192,1.2136,1.2187,2066013.8999999999],[1636960500000,1.2187,1.2188,1.2159,1.217,1351267.1000000001],[1636960800000,1.217,1.2178,1.2153,1.2156,1334536.7],[1636961100000,1.2155,1.2158,1.2128,1.2134,1485421.2],[1636961400000,1.2133,1.2148,1.2105,1.2109,1854928.3999999999],[1636961700000,1.211,1.2128,1.2106,1.2121,1148625.1000000001],[1636962000000,1.2121,1.214,1.2106,1.2112,1123669.3999999999],[1636962300000,1.211,1.212,1.2106,1.2118,877979.1],[1636962600000,1.2118,1.2136,1.2112,1.212,1362349.8],[1636962900000,1.2121,1.2121,1.21,1.21,1193089.0],[1636963200000,1.2101,1.2126,1.2092,1.2105,2158603.5],[1636963500000,1.2105,1.2113,1.2048,1.2055,4513172.2000000002],[1636963800000,1.2055,1.2076,1.2048,1.2067,2875763.3999999999],[1636964100000,1.2066,1.2067,1.2005,1.201,4649136.9000000004],[1636964400000,1.201,1.2044,1.2005,1.2035,2734988.8999999999],[1636964700000,1.2034,1.2047,1.2029,1.2038,1696384.0],[1636965000000,1.2039,1.2047,1.2026,1.2044,1652360.6000000001],[1636965300000,1.2043,1.2063,1.2039,1.206,1682635.8],[1636965600000,1.2061,1.2085,1.2056,1.2081,3810080.7000000002],[1636965900000,1.2081,1.2109,1.2069,1.21,3426972.6000000001],[1636966200000,1.21,1.2108,1.2094,1.2099,1948298.3999999999],[1636966500000,1.2099,1.2108,1.2088,1.2105,1358895.3999999999],[1636966800000,1.2104,1.215,1.2089,1.215,5488008.9000000004],[1636967100000,1.2149,1.2175,1.2145,1.2156,4423040.2000000002],[1636967400000,1.2156,1.2199,1.2156,1.2193,3209461.7000000002],[1636967700000,1.2193,1.22,1.2161,1.2177,3136263.2999999998],[1636968000000,1.2177,1.2178,1.2144,1.2154,2973911.8999999999],[1636968300000,1.2155,1.2185,1.2151,1.2161,2313273.1000000001],[1636968600000,1.2161,1.2161,1.2118,1.2138,2457956.6000000001],[1636968900000,1.2139,1.2147,1.2111,1.212,1467335.5],[1636969200000,1.212,1.2121,1.2102,1.2102,1479763.0],[1636969500000,1.2102,1.2124,1.2101,1.2116,1759979.3],[1636969800000,1.2115,1.2126,1.2114,1.2125,597927.7],[1636970100000,1.2123,1.2127,1.2109,1.2113,846797.8],[1636970400000,1.2113,1.2116,1.2054,1.206,4003530.2999999998],[1636970700000,1.2061,1.2085,1.2061,1.2083,1407880.3],[1636971000000,1.2084,1.2092,1.2071,1.209,686922.7],[1636971300000,1.209,1.2098,1.2089,1.2094,969569.7],[1636971600000,1.2095,1.2101,1.2085,1.2101,958910.5],[1636971900000,1.2101,1.2107,1.206,1.2066,1750771.2],[1636972200000,1.2065,1.2091,1.2065,1.2085,863380.4],[1636972500000,1.2085,1.2112,1.2085,1.211,885808.6],[1636972800000,1.2111,1.2111,1.2091,1.2093,768551.4],[1636973100000,1.2096,1.21,1.2086,1.2088,596104.7],[1636973400000,1.2088,1.2116,1.2088,1.2102,1013463.8],[1636973700000,1.2102,1.2108,1.2089,1.21,868464.8],[1636974000000,1.21,1.2105,1.2084,1.2088,1146027.1000000001],[1636974300000,1.2089,1.2106,1.2088,1.2105,775161.5],[1636974600000,1.2106,1.2106,1.2093,1.2093,549029.5],[1636974900000,1.2094,1.2097,1.2079,1.2085,616718.4],[1636975200000,1.2085,1.2089,1.2049,1.2064,4021848.5],[1636975500000,1.2063,1.2076,1.205,1.2056,1516604.6000000001],[1636975800000,1.2056,1.2056,1.2027,1.2037,3276909.2000000002],[1636976100000,1.2038,1.2058,1.2032,1.2058,1671933.3],[1636976400000,1.2058,1.2075,1.2058,1.2068,1309347.1000000001],[1636976700000,1.2068,1.2069,1.2057,1.2063,945417.0],[1636977000000,1.2063,1.2077,1.2059,1.2071,919673.8],[1636977300000,1.2072,1.2074,1.2062,1.2073,742663.2],[1636977600000,1.2073,1.209,1.205,1.2075,2478967.0],[1636977900000,1.2075,1.2077,1.204,1.2054,1870332.3],[1636978200000,1.2055,1.2059,1.2049,1.2053,565997.4],[1636978500000,1.2052,1.2053,1.2015,1.2037,2654152.1000000001],[1636978800000,1.2036,1.2047,1.2022,1.2038,1807444.1000000001],[1636979100000,1.2038,1.2046,1.2026,1.2027,1065979.8],[1636979400000,1.2027,1.206,1.2027,1.2054,1477203.8],[1636979700000,1.2053,1.2067,1.204,1.2045,2211979.5],[1636980000000,1.2047,1.2059,1.204,1.2058,804279.6],[1636980300000,1.2058,1.2066,1.205,1.2066,1313472.0],[1636980600000,1.2066,1.2067,1.2055,1.2066,834835.7],[1636980900000,1.2067,1.2073,1.2047,1.2047,1000096.8],[1636981200000,1.2047,1.207,1.2046,1.2068,1046862.8],[1636981500000,1.2068,1.2077,1.2066,1.207,1188865.6000000001],[1636981800000,1.2071,1.2104,1.207,1.2101,1875017.0],[1636982100000,1.2102,1.2114,1.2069,1.2072,2439900.5],[1636982400000,1.2072,1.2084,1.2066,1.2078,865686.6],[1636982700000,1.2078,1.2079,1.2064,1.2066,633128.7],[1636983000000,1.2065,1.2087,1.202,1.202,5720475.0999999996],[1636983300000,1.2021,1.2038,1.2005,1.2038,3417445.1000000001],[1636983600000,1.2038,1.2047,1.1915,1.1991,14721245.0999999996],[1636983900000,1.1992,1.1995,1.1953,1.1974,5430137.5],[1636984200000,1.1974,1.1996,1.1973,1.1983,1598326.5],[1636984500000,1.1983,1.1996,1.1979,1.1989,1487378.3999999999],[1636984800000,1.1989,1.1991,1.1941,1.195,3172429.0],[1636985100000,1.195,1.1965,1.1941,1.1964,3403294.0],[1636985400000,1.1965,1.1977,1.1934,1.1945,2772952.6000000001],[1636985700000,1.1944,1.1965,1.1924,1.1928,2853416.8999999999],[1636986000000,1.1927,1.1944,1.1864,1.1881,9859645.0999999996],[1636986300000,1.1881,1.1934,1.1865,1.192,4374940.7000000002],[1636986600000,1.1921,1.1931,1.1904,1.1927,2201904.7000000002],[1636986900000,1.1926,1.1944,1.1924,1.1928,1807342.7],[1636987200000,1.193,1.1941,1.1925,1.193,1354005.2],[1636987500000,1.193,1.193,1.1899,1.1906,2118339.0],[1636987800000,1.1905,1.1918,1.1879,1.1905,4748915.5],[1636988100000,1.1906,1.1927,1.1902,1.191,1886338.7],[1636988400000,1.1911,1.1916,1.1866,1.1866,4544292.0999999996],[1636988700000,1.1866,1.1887,1.1844,1.1871,7310980.2000000002],[1636989000000,1.1872,1.1914,1.1862,1.1908,3315857.5],[1636989300000,1.1908,1.1922,1.189,1.1914,2196378.0],[1636989600000,1.1913,1.1913,1.1895,1.1909,1199510.5],[1636989900000,1.1908,1.1927,1.189,1.1899,1838353.0],[1636990200000,1.1899,1.1923,1.1885,1.1917,1453015.3],[1636990500000,1.1915,1.192,1.1883,1.1893,1395222.3999999999],[1636990800000,1.1893,1.1893,1.186,1.1862,2115580.1000000001],[1636991100000,1.1862,1.1909,1.1854,1.1907,2681118.7000000002],[1636991400000,1.1907,1.1908,1.186,1.1875,1802497.2],[1636991700000,1.1875,1.1896,1.1873,1.1885,1338971.5],[1636992000000,1.1885,1.19,1.1855,1.19,4843721.2000000002],[1636992300000,1.19,1.1919,1.1888,1.1892,2129650.7000000002],[1636992600000,1.1892,1.1904,1.1865,1.187,2149370.6000000001],[1636992900000,1.1871,1.1896,1.1861,1.1872,1778567.1000000001],[1636993200000,1.1871,1.1875,1.1862,1.1864,1184527.7],[1636993500000,1.1864,1.1873,1.1821,1.185,5233565.7999999998],[1636993800000,1.185,1.1894,1.1836,1.1894,2780444.8999999999],[1636994100000,1.1894,1.1913,1.1879,1.1881,1948790.6000000001],[1636994400000,1.1881,1.1893,1.1844,1.1847,2805736.3999999999],[1636994700000,1.1847,1.1857,1.1816,1.1821,3092493.8999999999],[1636995000000,1.1822,1.1849,1.1811,1.1849,2919570.1000000001],[1636995300000,1.1848,1.1897,1.1845,1.1897,2529541.7000000002],[1636995600000,1.1897,1.1898,1.1865,1.1881,1987137.8999999999],[1636995900000,1.188,1.1883,1.1864,1.1882,1229479.8999999999],[1636996200000,1.1882,1.1904,1.188,1.1894,2329656.5],[1636996500000,1.1894,1.1907,1.1877,1.1885,1635524.7],[1636996800000,1.1885,1.1885,1.1861,1.1866,1464212.6000000001],[1636997100000,1.1866,1.1881,1.1859,1.1872,1498541.1000000001],[1636997400000,1.1872,1.1884,1.1866,1.1877,645062.1],[1636997700000,1.1878,1.189,1.1877,1.1887,976463.5],[1636998000000,1.1886,1.1903,1.1884,1.1894,936264.1],[1636998300000,1.1893,1.1902,1.188,1.1881,1076340.3],[1636998600000,1.1881,1.1884,1.1855,1.1877,1660911.8],[1636998900000,1.1877,1.1877,1.1847,1.1848,1546267.1000000001],[1636999200000,1.1848,1.1857,1.1831,1.1843,3223795.7000000002],[1636999500000,1.1842,1.1878,1.184,1.1873,1328197.3999999999],[1636999800000,1.1873,1.1885,1.1849,1.1851,1479273.8999999999],[1637000100000,1.1851,1.1858,1.1826,1.1847,2957345.1000000001],[1637000400000,1.1846,1.1875,1.1841,1.1863,1262899.8999999999],[1637000700000,1.1863,1.1866,1.1846,1.1855,1498078.8],[1637001000000,1.1854,1.186,1.1845,1.1847,907889.9],[1637001300000,1.1847,1.186,1.1846,1.1848,681753.2],[1637001600000,1.1847,1.1852,1.1814,1.1825,1997175.0],[1637001900000,1.1824,1.1826,1.18,1.1804,4002404.7999999998],[1637002200000,1.1804,1.1812,1.1756,1.1811,6730780.9000000004],[1637002500000,1.1811,1.1836,1.1805,1.1825,2072583.3],[1637002800000,1.1825,1.1826,1.1785,1.181,2788627.7999999998],[1637003100000,1.181,1.1817,1.1791,1.1808,1166716.5],[1637003400000,1.1808,1.1835,1.1806,1.1835,1356426.8999999999],[1637003700000,1.1835,1.1839,1.1826,1.1831,791629.1],[1637004000000,1.1831,1.1834,1.1806,1.1833,1158697.8],[1637004300000,1.1833,1.1863,1.1831,1.1853,2155591.2000000002],[1637004600000,1.1854,1.1879,1.1843,1.1878,922252.4],[1637004900000,1.1879,1.1879,1.1847,1.1851,1403022.8],[1637005200000,1.185,1.1875,1.1847,1.1865,1031169.4],[1637005500000,1.1865,1.1874,1.1848,1.1852,662437.6],[1637005800000,1.1853,1.1855,1.184,1.1846,751629.5],[1637006100000,1.1847,1.1859,1.1842,1.1857,949722.6],[1637006400000,1.1857,1.1857,1.1806,1.1816,1733988.6000000001],[1637006700000,1.1815,1.1816,1.1784,1.1796,2888343.2000000002],[1637007000000,1.1796,1.1816,1.1785,1.1808,1077627.7],[1637007300000,1.1807,1.1807,1.178,1.1785,1101824.3999999999],[1637007600000,1.1785,1.1788,1.1764,1.1777,2142094.7000000002],[1637007900000,1.1776,1.1783,1.1759,1.1759,2095915.1000000001],[1637008200000,1.1758,1.1796,1.1755,1.1789,2472558.2000000002],[1637008500000,1.1789,1.1804,1.1764,1.1765,1733359.2],[1637008800000,1.1764,1.1788,1.1735,1.1778,4928727.0],[1637009100000,1.1778,1.1809,1.1766,1.1804,1891969.1000000001],[1637009400000,1.1804,1.1826,1.1793,1.1797,1792413.3999999999],[1637009700000,1.1796,1.1803,1.1768,1.1777,1422290.8],[1637010000000,1.1776,1.1776,1.165,1.1737,15867137.6999999993],[1637010300000,1.1737,1.1766,1.1721,1.1729,2896715.1000000001],[1637010600000,1.1729,1.1765,1.1726,1.1759,1538151.0],[1637010900000,1.1759,1.179,1.1758,1.1784,2383917.6000000001],[1637011200000,1.1785,1.1794,1.1768,1.1777,1266720.3],[1637011500000,1.1776,1.1799,1.1749,1.1772,2843606.2999999998],[1637011800000,1.1773,1.1803,1.1758,1.1801,1386825.8999999999],[1637012100000,1.1801,1.1802,1.1771,1.1783,1025132.1],[1637012400000,1.1781,1.1799,1.1771,1.1798,1095931.5],[1637012700000,1.1797,1.1807,1.1788,1.179,824766.1],[1637013000000,1.179,1.1802,1.178,1.1788,736602.1],[1637013300000,1.1789,1.1827,1.1789,1.1805,1921139.5],[1637013600000,1.1805,1.1807,1.177,1.1775,1388575.0],[1637013900000,1.1774,1.1786,1.1772,1.1777,851274.7],[1637014200000,1.1778,1.1781,1.1754,1.1756,1229630.5],[1637014500000,1.1755,1.1756,1.1725,1.1736,2284743.7000000002],[1637014800000,1.1735,1.1737,1.1701,1.1728,2143691.1000000001],[1637015100000,1.1728,1.1732,1.1715,1.1719,1255188.1000000001],[1637015400000,1.1719,1.1756,1.1719,1.1755,1242001.8],[1637015700000,1.1756,1.1773,1.1754,1.176,990468.2],[1637016000000,1.176,1.1777,1.1759,1.1775,498149.6],[1637016300000,1.1776,1.1793,1.1772,1.1775,750568.6],[1637016600000,1.1775,1.1804,1.1772,1.1803,941858.4],[1637016900000,1.1804,1.1824,1.179,1.1812,2075547.3],[1637017200000,1.1812,1.1812,1.1772,1.1778,1938884.0],[1637017500000,1.1777,1.1792,1.1774,1.1782,799165.2],[1637017800000,1.1782,1.1789,1.1777,1.1777,478035.0],[1637018100000,1.1778,1.1785,1.174,1.1782,4335357.7999999998],[1637018400000,1.1783,1.1784,1.1765,1.1767,697003.9],[1637018700000,1.1767,1.1768,1.1729,1.1734,1483791.0],[1637019000000,1.1733,1.1761,1.1726,1.1751,1632155.0],[1637019300000,1.1752,1.1763,1.1751,1.1756,618483.1],[1637019600000,1.1758,1.1767,1.1748,1.1764,551544.6],[1637019900000,1.1765,1.1767,1.1755,1.1761,769943.5],[1637020200000,1.1761,1.1766,1.175,1.1758,815763.7],[1637020500000,1.1758,1.1764,1.1707,1.1729,2601489.3999999999],[1637020800000,1.1728,1.1729,1.1626,1.1647,10370232.6999999993],[1637021100000,1.1647,1.1679,1.1574,1.1588,14674219.0999999996],[1637021400000,1.1588,1.1603,1.125,1.1505,51767444.6000000015],[1637021700000,1.1506,1.1562,1.1447,1.1485,12232299.4000000004],[1637022000000,1.1484,1.1527,1.1436,1.1519,6240786.5999999996],[1637022300000,1.152,1.1526,1.1458,1.1493,5898863.9000000004],[1637022600000,1.1493,1.1543,1.1453,1.1542,4023262.8999999999],[1637022900000,1.1542,1.1548,1.1503,1.1539,4072291.5],[1637023200000,1.1539,1.1548,1.1513,1.1526,2831077.2999999998],[1637023500000,1.1525,1.1573,1.1523,1.1525,3310198.0],[1637023800000,1.1524,1.1536,1.1482,1.1488,3801330.7000000002],[1637024100000,1.1486,1.1514,1.142,1.1432,8989381.1999999993],[1637024400000,1.1432,1.1472,1.13,1.1324,18542491.1999999993],[1637024700000,1.1322,1.139,1.105,1.137,49788431.8999999985],[1637025000000,1.1371,1.1391,1.1308,1.1388,16654546.9000000004],[1637025300000,1.1387,1.1412,1.1307,1.1356,14918494.0999999996],[1637025600000,1.1356,1.1414,1.1314,1.138,7098702.4000000004],[1637025900000,1.138,1.1416,1.1364,1.1393,5430829.7000000002],[1637026200000,1.1393,1.1401,1.13,1.1307,6803088.2000000002],[1637026500000,1.1307,1.1365,1.1261,1.1363,6164932.5],[1637026800000,1.1363,1.1459,1.136,1.1454,4365617.4000000004],[1637027100000,1.1453,1.1461,1.1419,1.145,4744308.5],[1637027400000,1.145,1.1471,1.1429,1.1453,3721814.3999999999],[1637027700000,1.1453,1.1458,1.1416,1.1424,2823682.3999999999],[1637028000000,1.1425,1.1438,1.1387,1.1402,3710527.2999999998],[1637028300000,1.1401,1.1418,1.1383,1.1411,3186377.5],[1637028600000,1.1411,1.1443,1.1405,1.143,3430024.2999999998],[1637028900000,1.1431,1.1437,1.1414,1.1429,2317514.3999999999],[1637029200000,1.1429,1.1435,1.1411,1.1429,2652508.5],[1637029500000,1.1429,1.1437,1.1415,1.1415,1811976.5],[1637029800000,1.1416,1.1422,1.14,1.1404,1639570.8],[1637030100000,1.1404,1.141,1.135,1.1374,5626771.4000000004],[1637030400000,1.1374,1.1388,1.1361,1.1367,1883461.3999999999],[1637030700000,1.1366,1.1396,1.1345,1.1354,2704401.7999999998],[1637031000000,1.1353,1.1368,1.1314,1.1314,3254363.8999999999],[1637031300000,1.1315,1.1319,1.1274,1.1302,6785507.5999999996],[1637031600000,1.1302,1.1303,1.1237,1.1302,7233618.5],[1637031900000,1.1303,1.1343,1.1296,1.1324,4118353.2999999998],[1637032200000,1.1324,1.1349,1.1321,1.1343,1859638.2],[1637032500000,1.1343,1.1351,1.1326,1.1345,1874930.3999999999],[1637032800000,1.1344,1.1354,1.1245,1.1268,6000321.0],[1637033100000,1.1268,1.1284,1.1121,1.1191,12805164.5999999996],[1637033400000,1.1192,1.1258,1.1164,1.1182,8744035.5999999996],[1637033700000,1.1182,1.1231,1.111,1.118,9232101.1999999993],[1637034000000,1.118,1.1239,1.1163,1.1165,6494642.2000000002],[1637034300000,1.1166,1.1232,1.1111,1.123,8552285.3000000007],[1637034600000,1.123,1.1286,1.121,1.1268,7567469.7999999998],[1637034900000,1.1268,1.1289,1.1211,1.1228,4671142.5999999996],[1637035200000,1.1228,1.1254,1.1159,1.1175,9853542.0],[1637035500000,1.1174,1.1239,1.1148,1.1238,6547575.7000000002],[1637035800000,1.1238,1.124,1.1122,1.1137,7136291.2000000002],[1637036100000,1.1138,1.1188,1.112,1.1128,6459000.0999999996],[1637036400000,1.1127,1.1195,1.1061,1.1195,15800732.3000000007],[1637036700000,1.1195,1.1289,1.1181,1.1273,7311133.7999999998],[1637037000000,1.1272,1.1299,1.1249,1.1287,6075163.2000000002],[1637037300000,1.1287,1.1318,1.1276,1.1309,3822050.1000000001],[1637037600000,1.1309,1.1324,1.1277,1.1314,4134442.7000000002],[1637037900000,1.1314,1.1314,1.1258,1.1289,3024553.7999999998],[1637038200000,1.1288,1.1328,1.1281,1.1324,3120336.0],[1637038500000,1.1323,1.1324,1.1286,1.1286,3527058.7999999998],[1637038800000,1.1285,1.1303,1.1275,1.1284,2208750.0],[1637039100000,1.1284,1.1285,1.1239,1.1283,2784313.2999999998],[1637039400000,1.1282,1.1284,1.1244,1.1249,2212214.7000000002],[1637039700000,1.125,1.1299,1.1248,1.1294,2706724.0],[1637040000000,1.1294,1.1326,1.1285,1.1323,2981264.8999999999],[1637040300000,1.1322,1.1327,1.1254,1.1289,5296197.7000000002],[1637040600000,1.1289,1.1312,1.1283,1.129,2207684.8999999999],[1637040900000,1.1289,1.129,1.1262,1.1262,1581778.5],[1637041200000,1.1264,1.1312,1.1228,1.1303,6245071.4000000004],[1637041500000,1.1302,1.1303,1.1264,1.1268,1430621.3999999999],[1637041800000,1.1268,1.1273,1.1242,1.1261,2663380.2000000002],[1637042100000,1.1262,1.1262,1.1216,1.1234,3088115.1000000001],[1637042400000,1.1235,1.1258,1.1215,1.1257,2607308.1000000001],[1637042700000,1.1257,1.1265,1.1204,1.1212,2930686.7999999998],[1637043000000,1.1213,1.1253,1.1212,1.125,1715592.8],[1637043300000,1.1249,1.1251,1.1213,1.1214,2267349.7000000002],[1637043600000,1.1213,1.1236,1.1208,1.1222,1124855.1000000001],[1637043900000,1.1223,1.1238,1.1155,1.1164,5530558.7999999998],[1637044200000,1.1166,1.1224,1.115,1.1224,5299299.0],[1637044500000,1.1224,1.1239,1.1186,1.1191,3826527.0],[1637044800000,1.1191,1.1214,1.1174,1.1199,2721175.3999999999],[1637045100000,1.1198,1.1244,1.1196,1.1226,3202701.1000000001],[1637045400000,1.1226,1.125,1.1223,1.1235,1864276.0],[1637045700000,1.1236,1.1267,1.122,1.1248,2202205.6000000001],[1637046000000,1.1247,1.1264,1.1197,1.12,3604061.2000000002],[1637046300000,1.1201,1.1277,1.12,1.127,3024670.2999999998],[1637046600000,1.127,1.127,1.1221,1.1228,2208623.7000000002],[1637046900000,1.1227,1.1266,1.1224,1.1228,2422007.5],[1637047200000,1.1228,1.1228,1.1198,1.1202,1741483.3],[1637047500000,1.1201,1.124,1.1197,1.1226,2176612.3999999999],[1637047800000,1.1226,1.1268,1.1208,1.1213,2963321.1000000001],[1637048100000,1.1215,1.1216,1.1187,1.1197,2621660.7999999998],[1637048400000,1.1198,1.122,1.1188,1.1217,1715248.7],[1637048700000,1.1216,1.1238,1.121,1.1237,1076378.6000000001],[1637049000000,1.1237,1.126,1.119,1.1242,2665782.8999999999],[1637049300000,1.1243,1.1258,1.1226,1.1255,2099191.7000000002],[1637049600000,1.1256,1.1274,1.1218,1.1258,4283096.0],[1637049900000,1.1259,1.1293,1.1257,1.1289,3450819.5],[1637050200000,1.129,1.1297,1.1247,1.1263,2658729.6000000001],[1637050500000,1.1263,1.1265,1.1216,1.1248,2353989.0],[1637050800000,1.1248,1.128,1.1235,1.1254,2667401.7999999998],[1637051100000,1.1255,1.1257,1.1224,1.1231,1663270.7],[1637051400000,1.1232,1.126,1.1228,1.1257,1504233.5],[1637051700000,1.1257,1.126,1.1235,1.1249,1636380.3],[1637052000000,1.1249,1.1287,1.1248,1.1286,2152550.8999999999],[1637052300000,1.1287,1.1291,1.1258,1.1258,1642710.6000000001],[1637052600000,1.1258,1.1299,1.1234,1.1295,2840899.0],[1637052900000,1.1294,1.1312,1.1292,1.1301,2753850.0],[1637053200000,1.13,1.1347,1.1275,1.1281,6623462.7000000002],[1637053500000,1.1282,1.1282,1.125,1.1252,3362681.8999999999],[1637053800000,1.1252,1.1281,1.1246,1.1264,1587342.8],[1637054100000,1.1264,1.1264,1.1209,1.121,2291705.7000000002],[1637054400000,1.121,1.1231,1.119,1.1206,4287524.7999999998],[1637054700000,1.1205,1.1211,1.1183,1.121,2149620.3999999999],[1637055000000,1.121,1.1211,1.1177,1.1198,1889836.2],[1637055300000,1.1198,1.1198,1.1109,1.1127,6507103.7000000002],[1637055600000,1.1127,1.1172,1.1125,1.1138,3022620.7999999998],[1637055900000,1.1138,1.1156,1.1101,1.1102,2856203.2000000002],[1637056200000,1.1101,1.1141,1.103,1.1124,13114838.6999999993],[1637056500000,1.1124,1.113,1.1027,1.1032,6424556.0999999996],[1637056800000,1.1031,1.1051,1.08,1.0959,39145521.200000003],[1637057100000,1.0959,1.0959,1.0392,1.0535,56581244.5],[1637057400000,1.0546,1.0729,1.0332,1.0439,42637203.3999999985],[1637057700000,1.0439,1.0661,1.0347,1.0657,38320115.5],[1637058000000,1.0658,1.0692,1.0616,1.064,17025610.8000000007],[1637058300000,1.0641,1.0721,1.057,1.0714,17492906.8000000007],[1637058600000,1.0714,1.0828,1.0676,1.0819,15396169.6999999993],[1637058900000,1.0818,1.089,1.0782,1.0821,15832077.6999999993],[1637059200000,1.0821,1.0877,1.08,1.0869,10945208.6999999993],[1637059500000,1.087,1.0871,1.0819,1.083,6231017.7000000002],[1637059800000,1.083,1.0868,1.0804,1.0858,5392462.9000000004],[1637060100000,1.0856,1.0947,1.0844,1.0927,8293781.2999999998],[1637060400000,1.0927,1.0991,1.0889,1.0948,14201629.4000000004],[1637060700000,1.0948,1.0956,1.092,1.0927,10489689.5999999996],[1637061000000,1.0928,1.0932,1.0893,1.092,5223379.2000000002],[1637061300000,1.092,1.0933,1.0892,1.0917,3130525.8999999999],[1637061600000,1.0917,1.0951,1.091,1.0924,4478758.0],[1637061900000,1.0922,1.0961,1.09,1.0961,4269518.2000000002],[1637062200000,1.0961,1.0965,1.0912,1.0944,4219889.2000000002],[1637062500000,1.0944,1.0963,1.092,1.0933,4445458.7999999998],[1637062800000,1.0932,1.0942,1.0893,1.0903,4145158.7000000002],[1637063100000,1.0904,1.0929,1.0898,1.0915,2970968.0],[1637063400000,1.0915,1.094,1.081,1.0869,14647309.9000000004],[1637063700000,1.0869,1.0912,1.0849,1.091,5089475.5999999996],[1637064000000,1.091,1.091,1.0854,1.0869,6876454.0999999996],[1637064300000,1.087,1.0936,1.0847,1.0915,6451835.0999999996],[1637064600000,1.0915,1.0936,1.0883,1.0935,5260521.0],[1637064900000,1.0936,1.0953,1.0917,1.0936,3561178.1000000001],[1637065200000,1.0936,1.0947,1.0919,1.092,5160451.7999999998],[1637065500000,1.092,1.0933,1.0875,1.0883,7458006.2999999998],[1637065800000,1.0883,1.0916,1.0864,1.0912,4436506.2000000002],[1637066100000,1.0912,1.0913,1.0865,1.0883,3664288.7999999998],[1637066400000,1.0883,1.0904,1.0876,1.0895,2131346.2000000002],[1637066700000,1.0896,1.0911,1.088,1.0891,1823000.0],[1637067000000,1.0891,1.0892,1.0858,1.0869,2434249.6000000001],[1637067300000,1.0869,1.0874,1.0781,1.0807,10353451.5999999996],[1637067600000,1.0807,1.0891,1.0807,1.0872,7115227.4000000004],[1637067900000,1.0872,1.0875,1.0831,1.0861,2835656.5],[1637068200000,1.0861,1.0871,1.0837,1.0862,1842530.0],[1637068500000,1.0863,1.0931,1.0861,1.0919,4535343.2000000002],[1637068800000,1.0919,1.0919,1.0896,1.0908,1767315.6000000001],[1637069100000,1.0909,1.0965,1.0908,1.0925,4127187.2999999998],[1637069400000,1.0925,1.0931,1.0874,1.0889,2829371.3999999999],[1637069700000,1.089,1.0941,1.0889,1.0933,2691450.5],[1637070000000,1.0933,1.0982,1.0933,1.0975,3449425.3999999999],[1637070300000,1.0976,1.0995,1.0949,1.0956,3111204.2000000002],[1637070600000,1.0955,1.0977,1.0922,1.097,3361311.6000000001],[1637070900000,1.0971,1.0978,1.0953,1.0955,1874257.1000000001],[1637071200000,1.0955,1.1002,1.0939,1.0996,2874238.1000000001],[1637071500000,1.0995,1.1072,1.0988,1.106,5584774.5999999996],[1637071800000,1.106,1.1063,1.1006,1.1021,6260439.5],[1637072100000,1.1021,1.1053,1.1007,1.1035,2629958.5],[1637072400000,1.1036,1.1071,1.1035,1.1063,2563542.7000000002],[1637072700000,1.1064,1.1074,1.1034,1.1058,2746573.6000000001],[1637073000000,1.1058,1.1088,1.104,1.1067,3563226.6000000001],[1637073300000,1.1067,1.1145,1.1067,1.1124,6518384.7999999998],[1637073600000,1.1125,1.1148,1.1122,1.1147,3836367.8999999999],[1637073900000,1.1147,1.1166,1.1131,1.1139,6381942.5999999996],[1637074200000,1.1138,1.1145,1.1099,1.1105,4349913.0999999996],[1637074500000,1.1105,1.1107,1.1071,1.1101,3994190.7999999998],[1637074800000,1.1101,1.1135,1.1076,1.1091,3753506.8999999999],[1637075100000,1.1091,1.1134,1.1089,1.1113,3603867.3999999999],[1637075400000,1.1112,1.1113,1.107,1.1083,4664129.0],[1637075700000,1.1083,1.1103,1.1064,1.1094,2488059.8999999999],[1637076000000,1.1093,1.1099,1.1039,1.1058,3100351.5],[1637076300000,1.1057,1.1066,1.1051,1.1065,1414436.3999999999],[1637076600000,1.1065,1.1078,1.1012,1.1028,3693132.0],[1637076900000,1.1027,1.1053,1.1026,1.1032,1753110.5],[1637077200000,1.1033,1.1041,1.1006,1.1018,1495171.1000000001],[1637077500000,1.1019,1.1028,1.0997,1.1002,2868409.6000000001],[1637077800000,1.1002,1.102,1.0994,1.1014,1944395.6000000001],[1637078100000,1.1014,1.1019,1.0958,1.0994,4411719.7000000002],[1637078400000,1.0995,1.1042,1.0993,1.1011,4274375.2000000002],[1637078700000,1.1011,1.1019,1.0976,1.1016,4437800.0],[1637079000000,1.1015,1.1062,1.101,1.1043,3558900.2999999998],[1637079300000,1.1042,1.1084,1.1042,1.1047,3116961.7000000002],[1637079600000,1.1047,1.1064,1.1028,1.1032,2383209.5],[1637079900000,1.1031,1.107,1.1019,1.1059,3174573.7000000002],[1637080200000,1.1059,1.1084,1.1052,1.1053,2027170.3999999999],[1637080500000,1.1054,1.1071,1.1028,1.1041,2097532.7999999998],[1637080800000,1.1039,1.1042,1.1009,1.1022,2384703.5],[1637081100000,1.1022,1.1042,1.1021,1.103,1090303.7],[1637081400000,1.1029,1.106,1.1026,1.1053,1679083.3],[1637081700000,1.1054,1.1062,1.1044,1.1047,1281072.5],[1637082000000,1.1047,1.1082,1.1046,1.1075,1870676.6000000001],[1637082300000,1.1075,1.1084,1.1055,1.106,1514063.3999999999],[1637082600000,1.1061,1.1074,1.1059,1.1066,1127931.8],[1637082900000,1.1067,1.1077,1.1052,1.106,2205945.3999999999],[1637083200000,1.106,1.106,1.1014,1.1032,2175136.6000000001],[1637083500000,1.1033,1.104,1.1026,1.1035,681357.6],[1637083800000,1.1035,1.1036,1.0965,1.0987,5090985.2999999998],[1637084100000,1.0988,1.1014,1.0985,1.1007,1185052.1000000001],[1637084400000,1.1007,1.1012,1.0986,1.1011,1336553.0],[1637084700000,1.1011,1.1022,1.0995,1.101,1619343.1000000001],[1637085000000,1.1011,1.1027,1.0995,1.1019,1152992.1000000001],[1637085300000,1.102,1.1024,1.0986,1.0988,1475514.2],[1637085600000,1.0988,1.1033,1.0987,1.1029,1140507.3],[1637085900000,1.1029,1.1055,1.1021,1.1028,2751272.6000000001],[1637086200000,1.1028,1.1034,1.1021,1.1029,870292.5],[1637086500000,1.1029,1.1039,1.1009,1.1014,856580.6],[1637086800000,1.1014,1.1027,1.1014,1.1018,616637.1],[1637087100000,1.1017,1.1019,1.0975,1.0979,1535581.5],[1637087400000,1.0979,1.1009,1.0977,1.0977,1669346.1000000001],[1637087700000,1.0978,1.1001,1.0924,1.0928,4071053.2999999998],[1637088000000,1.0928,1.0945,1.0886,1.0913,5158080.7000000002],[1637088300000,1.0912,1.0916,1.0875,1.0888,3913693.2000000002],[1637088600000,1.0888,1.092,1.0883,1.091,2824819.2000000002],[1637088900000,1.091,1.0922,1.0863,1.0863,1971506.7],[1637089200000,1.0862,1.0964,1.0849,1.095,5786081.9000000004],[1637089500000,1.0949,1.0994,1.0948,1.0988,2539197.7000000002],[1637089800000,1.0987,1.0998,1.0953,1.0959,2441709.2000000002],[1637090100000,1.096,1.0985,1.0931,1.0984,2598843.5],[1637090400000,1.0984,1.0995,1.0975,1.0986,1570715.7],[1637090700000,1.0985,1.0988,1.0956,1.098,1618041.8],[1637091000000,1.098,1.1013,1.0964,1.0985,2150798.7999999998],[1637091300000,1.0983,1.0998,1.0923,1.0933,3299815.6000000001],[1637091600000,1.0934,1.0947,1.093,1.093,1482874.0],[1637091900000,1.0931,1.0936,1.0814,1.0827,9204218.9000000004],[1637092200000,1.0827,1.0865,1.0817,1.0836,3364077.2000000002],[1637092500000,1.0836,1.0932,1.0835,1.0922,3895856.6000000001],[1637092800000,1.0922,1.0922,1.0854,1.0884,3260526.3999999999],[1637093100000,1.0883,1.0927,1.0883,1.089,2290681.6000000001],[1637093400000,1.0889,1.0906,1.0846,1.0864,3570163.0],[1637093700000,1.0863,1.0866,1.0805,1.0841,5326198.9000000004],[1637094000000,1.0841,1.0884,1.0835,1.0853,2398866.2999999998],[1637094300000,1.0852,1.0889,1.0809,1.0812,5647177.2999999998],[1637094600000,1.0812,1.0837,1.0764,1.0807,8712026.0999999996],[1637094900000,1.0808,1.0821,1.0705,1.0711,8140649.7999999998],[1637095200000,1.071,1.0758,1.0686,1.0717,8179432.7000000002],[1637095500000,1.0719,1.0783,1.0656,1.0768,8720833.5999999996],[1637095800000,1.0768,1.079,1.0711,1.0721,6371077.5],[1637096100000,1.0721,1.0811,1.0721,1.0807,6004000.5999999996],[1637096400000,1.0806,1.0901,1.0793,1.09,5236339.0],[1637096700000,1.09,1.0942,1.088,1.0939,7370866.0],[1637097000000,1.0939,1.0949,1.0906,1.0946,4293189.4000000004],[1637097300000,1.0944,1.0978,1.0933,1.0939,4202180.5999999996],[1637097600000,1.0938,1.0972,1.0922,1.0957,2739087.2000000002],[1637097900000,1.0958,1.096,1.0911,1.0925,2403520.3999999999],[1637098200000,1.0925,1.0972,1.0913,1.0947,2340053.2999999998],[1637098500000,1.0948,1.0964,1.0933,1.0951,2272554.7000000002],[1637098800000,1.0951,1.0966,1.0931,1.0941,3153594.7000000002],[1637099100000,1.094,1.096,1.0923,1.0956,2311184.7999999998],[1637099400000,1.0957,1.0966,1.0945,1.0963,1359327.6000000001],[1637099700000,1.0962,1.0969,1.0943,1.0955,1402210.6000000001],[1637100000000,1.0954,1.0999,1.0954,1.0999,2214508.5],[1637100300000,1.0999,1.1023,1.0971,1.0983,3369029.2999999998],[1637100600000,1.0984,1.1018,1.0983,1.1013,1713877.6000000001],[1637100900000,1.1014,1.1054,1.0995,1.1021,4033393.7999999998],[1637101200000,1.1021,1.1043,1.1017,1.1033,3141523.2000000002],[1637101500000,1.1033,1.1047,1.1005,1.1034,2721262.7000000002],[1637101800000,1.1034,1.104,1.1031,1.1038,907552.1],[1637102100000,1.1038,1.104,1.1005,1.1011,1635420.7],[1637102400000,1.1011,1.1013,1.1005,1.1011,828877.5],[1637102700000,1.1011,1.1014,1.0997,1.1007,1036611.5],[1637103000000,1.1008,1.1016,1.0992,1.1,755849.6],[1637103300000,1.1,1.1005,1.0991,1.0993,682736.6],[1637103600000,1.0994,1.102,1.0993,1.1009,1796997.3],[1637103900000,1.1009,1.1009,1.0976,1.0992,2076148.3],[1637104200000,1.0992,1.101,1.0958,1.0966,1887413.5],[1637104500000,1.0967,1.0976,1.0963,1.0968,1517664.7],[1637104800000,1.0967,1.0989,1.0956,1.0985,1420554.8999999999],[1637105100000,1.0984,1.0996,1.0966,1.0979,1159661.3],[1637105400000,1.098,1.0989,1.0946,1.0963,826631.7],[1637105700000,1.0962,1.0972,1.0936,1.0942,1012139.7],[1637106000000,1.0943,1.0965,1.0934,1.0952,1016698.3],[1637106300000,1.0953,1.0959,1.0914,1.0921,2394921.2999999998],[1637106600000,1.092,1.0932,1.0887,1.0924,1992608.7],[1637106900000,1.0923,1.0932,1.0875,1.0881,1619403.3],[1637107200000,1.0881,1.0923,1.0814,1.0819,7328761.2000000002],[1637107500000,1.0819,1.0949,1.0798,1.0933,7791120.0],[1637107800000,1.0933,1.0957,1.0894,1.0894,3203692.2000000002],[1637108100000,1.0893,1.0923,1.0854,1.0857,3370459.7999999998],[1637108400000,1.0856,1.0857,1.0773,1.0822,7263993.5999999996],[1637108700000,1.0821,1.0833,1.0803,1.0809,2084450.0],[1637109000000,1.0809,1.0869,1.0803,1.0845,2879224.5],[1637109300000,1.0845,1.088,1.0831,1.0854,2858814.3999999999],[1637109600000,1.0855,1.0873,1.0795,1.0819,4147523.7000000002],[1637109900000,1.0819,1.084,1.0765,1.0771,3351790.2999999998],[1637110200000,1.0771,1.0816,1.0768,1.08,2906774.5],[1637110500000,1.0799,1.083,1.0799,1.0802,2021854.0],[1637110800000,1.0803,1.0867,1.0773,1.0776,4514667.4000000004],[1637111100000,1.0776,1.0804,1.077,1.0781,2377557.0],[1637111400000,1.078,1.0852,1.0767,1.0845,2879961.7000000002],[1637111700000,1.0845,1.0857,1.0824,1.0834,1964225.8],[1637112000000,1.0833,1.0875,1.0827,1.0868,1728741.2],[1637112300000,1.0868,1.0954,1.0868,1.0949,4705829.0],[1637112600000,1.095,1.0984,1.0907,1.0968,3564621.7000000002],[1637112900000,1.0969,1.098,1.0937,1.094,3910508.6000000001],[1637113200000,1.0941,1.0956,1.0927,1.095,1694611.6000000001],[1637113500000,1.0949,1.0962,1.087,1.0871,3501061.2000000002],[1637113800000,1.0871,1.0889,1.0823,1.0835,3798244.5],[1637114100000,1.0835,1.0861,1.0775,1.0792,5097158.9000000004],[1637114400000,1.0791,1.0828,1.0757,1.0781,6593764.2999999998],[1637114700000,1.0782,1.0855,1.0777,1.085,4370758.5],[1637115000000,1.0849,1.0858,1.0815,1.0815,2163743.7000000002],[1637115300000,1.0814,1.0838,1.0785,1.0837,2472082.7000000002],[1637115600000,1.0837,1.0877,1.0837,1.086,2309508.2999999998],[1637115900000,1.086,1.0875,1.0854,1.0861,1587844.2],[1637116200000,1.086,1.088,1.0812,1.0815,2928244.2000000002],[1637116500000,1.0815,1.0869,1.0808,1.0859,2455434.7999999998],[1637116800000,1.0859,1.0864,1.0798,1.0803,1623658.6000000001],[1637117100000,1.0804,1.0827,1.079,1.0796,2038073.3999999999],[1637117400000,1.0796,1.0825,1.0733,1.0757,3769966.2999999998],[1637117700000,1.0757,1.0784,1.074,1.0763,2361069.2999999998],[1637118000000,1.0763,1.0821,1.0763,1.0778,3724170.2999999998],[1637118300000,1.0778,1.0782,1.0664,1.0695,9028147.0],[1637118600000,1.0694,1.0721,1.0629,1.0636,9485592.0999999996],[1637118900000,1.0636,1.0708,1.0584,1.0697,10075438.1999999993],[1637119200000,1.0696,1.0708,1.0669,1.0675,2935578.7000000002],[1637119500000,1.0675,1.0803,1.0667,1.0799,4704890.0999999996],[1637119800000,1.08,1.0859,1.0777,1.0822,7328433.0999999996],[1637120100000,1.0822,1.0824,1.0757,1.0786,3887194.3999999999],[1637120400000,1.0786,1.0794,1.0739,1.0767,2839375.5],[1637120700000,1.0768,1.0773,1.0723,1.0747,2334452.6000000001],[1637121000000,1.0748,1.0794,1.0725,1.0728,3459570.2999999998],[1637121300000,1.0727,1.0746,1.0674,1.0683,4035213.2999999998],[1637121600000,1.0684,1.0718,1.0638,1.0684,8054890.0],[1637121900000,1.0684,1.0726,1.0636,1.0638,3362220.7000000002],[1637122200000,1.0638,1.0664,1.0613,1.0614,2737673.2000000002],[1637122500000,1.0612,1.0698,1.0604,1.0679,6707714.5],[1637122800000,1.0678,1.0739,1.065,1.0694,5305425.5],[1637123100000,1.0694,1.0761,1.0689,1.0756,3789937.3999999999],[1637123400000,1.0756,1.079,1.0728,1.0767,4637235.0],[1637123700000,1.0767,1.0767,1.0717,1.0748,3380981.0],[1637124000000,1.0747,1.0782,1.0736,1.0738,2801660.3999999999],[1637124300000,1.0738,1.074,1.066,1.0663,3481897.7999999998],[1637124600000,1.0663,1.0689,1.0645,1.0678,2394145.7000000002],[1637124900000,1.0678,1.0768,1.0671,1.0766,3858423.2999999998],[1637125200000,1.0767,1.0817,1.073,1.0809,3924376.5],[1637125500000,1.0808,1.0833,1.0783,1.083,2728657.0],[1637125800000,1.083,1.0831,1.0795,1.0802,1779158.6000000001],[1637126100000,1.0802,1.0832,1.0786,1.0802,2990620.2999999998],[1637126400000,1.0802,1.0847,1.08,1.0846,2635455.2999999998],[1637126700000,1.0845,1.0845,1.0788,1.0797,4512611.7000000002],[1637127000000,1.0796,1.0837,1.0794,1.0822,1958104.1000000001],[1637127300000,1.0822,1.0857,1.082,1.0849,2294853.2000000002],[1637127600000,1.0849,1.0865,1.0844,1.0844,1880656.6000000001],[1637127900000,1.0844,1.0884,1.0832,1.0845,2602161.3999999999],[1637128200000,1.0846,1.0846,1.0816,1.0824,1432818.8999999999],[1637128500000,1.0824,1.0857,1.082,1.0842,1171212.2],[1637128800000,1.0843,1.086,1.0825,1.084,2035117.5],[1637129100000,1.0841,1.0848,1.0814,1.0819,1370075.7],[1637129400000,1.0819,1.082,1.0775,1.0789,2331354.0],[1637129700000,1.079,1.0801,1.0752,1.0759,1995356.3999999999],[1637130000000,1.0759,1.0798,1.0745,1.0797,2047187.6000000001],[1637130300000,1.0796,1.0796,1.0754,1.0779,2435020.2000000002],[1637130600000,1.078,1.0817,1.0779,1.0816,1979132.8999999999],[1637130900000,1.0817,1.0825,1.0802,1.0821,1801370.0],[1637131200000,1.0821,1.0821,1.0793,1.0801,1510297.2],[1637131500000,1.0802,1.081,1.0786,1.0809,1341184.1000000001],[1637131800000,1.0809,1.0811,1.0747,1.0767,3233574.1000000001],[1637132100000,1.0766,1.0819,1.0766,1.0801,3653328.0],[1637132400000,1.08,1.0841,1.08,1.0802,1885877.1000000001],[1637132700000,1.0801,1.0812,1.0762,1.0763,1922618.1000000001],[1637133000000,1.0762,1.0784,1.075,1.0754,2231747.1000000001],[1637133300000,1.0754,1.0771,1.074,1.0759,2723311.3999999999],[1637133600000,1.076,1.0782,1.0737,1.0775,2133324.0],[1637133900000,1.0775,1.0795,1.0766,1.0775,2760661.2000000002],[1637134200000,1.0775,1.0813,1.0773,1.0813,1752676.6000000001],[1637134500000,1.0812,1.0832,1.0803,1.0823,3506472.5],[1637134800000,1.0824,1.0911,1.0824,1.09,5288956.9000000004],[1637135100000,1.0899,1.0953,1.0876,1.0943,5344265.2000000002],[1637135400000,1.0942,1.0948,1.0916,1.0923,2699549.2000000002],[1637135700000,1.0922,1.0923,1.0865,1.0871,3138860.5],[1637136000000,1.0871,1.089,1.0844,1.0881,2924426.2000000002],[1637136300000,1.0881,1.0906,1.0874,1.0878,2051583.5],[1637136600000,1.0877,1.0901,1.0867,1.0899,1281969.5],[1637136900000,1.0898,1.0916,1.088,1.0903,2105461.6000000001],[1637137200000,1.0903,1.0922,1.0896,1.0897,1548503.8],[1637137500000,1.0898,1.0898,1.0858,1.0861,2406126.1000000001],[1637137800000,1.0862,1.0864,1.0808,1.0818,3634602.3999999999],[1637138100000,1.0818,1.0863,1.0818,1.0862,1386206.1000000001],[1637138400000,1.0863,1.0863,1.0836,1.0851,1375716.0],[1637138700000,1.0851,1.0884,1.0839,1.0859,2153031.5],[1637139000000,1.0859,1.0862,1.0811,1.0818,1906201.7],[1637139300000,1.0817,1.0827,1.0805,1.0806,1106265.3999999999],[1637139600000,1.0805,1.0807,1.0762,1.078,3489174.5],[1637139900000,1.078,1.0793,1.0762,1.0763,1696153.8],[1637140200000,1.0764,1.0773,1.0732,1.0742,3405487.5],[1637140500000,1.0742,1.0779,1.0725,1.0767,3377160.0],[1637140800000,1.0765,1.0797,1.0753,1.076,1986339.8],[1637141100000,1.076,1.0774,1.071,1.0718,4997953.5],[1637141400000,1.0716,1.074,1.07,1.0712,2219457.8999999999],[1637141700000,1.0712,1.0735,1.071,1.0724,1613672.6000000001],[1637142000000,1.0724,1.0736,1.0669,1.0726,4182243.6000000001],[1637142300000,1.0726,1.0753,1.0679,1.0707,5490107.2999999998],[1637142600000,1.0707,1.0744,1.0679,1.073,7715558.5999999996],[1637142900000,1.0731,1.0754,1.0684,1.0706,6229269.0999999996],[1637143200000,1.0707,1.0816,1.0706,1.0801,7898025.7000000002],[1637143500000,1.08,1.0815,1.0781,1.0803,3500217.6000000001],[1637143800000,1.0802,1.0805,1.0764,1.0782,2081784.7],[1637144100000,1.0782,1.0834,1.078,1.0831,2685664.8999999999],[1637144400000,1.083,1.0863,1.0823,1.0852,2647942.1000000001],[1637144700000,1.0852,1.0862,1.0838,1.0838,1861143.2],[1637145000000,1.0838,1.0845,1.076,1.076,4680665.9000000004],[1637145300000,1.076,1.0863,1.0703,1.0852,9234175.9000000004],[1637145600000,1.0853,1.095,1.0825,1.0899,12409553.6999999993],[1637145900000,1.0899,1.0964,1.0862,1.096,6436981.0999999996],[1637146200000,1.096,1.1068,1.096,1.106,11824100.3000000007],[1637146500000,1.106,1.1061,1.0996,1.1038,7977364.5999999996],[1637146800000,1.1039,1.106,1.0979,1.1009,7892673.9000000004],[1637147100000,1.101,1.1057,1.0986,1.1025,6771785.7999999998],[1637147400000,1.1025,1.1062,1.1018,1.1052,3735237.2000000002],[1637147700000,1.1053,1.1103,1.1028,1.1079,5009217.0],[1637148000000,1.1079,1.1084,1.1041,1.1064,3315650.8999999999],[1637148300000,1.1064,1.1069,1.1041,1.1047,3016959.2999999998],[1637148600000,1.1047,1.1058,1.1014,1.1018,3766007.3999999999],[1637148900000,1.1018,1.102,1.0981,1.1,3863771.5],[1637149200000,1.1001,1.1021,1.0994,1.1017,2386893.3999999999],[1637149500000,1.1017,1.1038,1.1007,1.1037,1990758.3999999999],[1637149800000,1.1038,1.1063,1.1032,1.1057,2846771.7000000002],[1637150100000,1.1058,1.1086,1.1048,1.1069,3226272.0],[1637150400000,1.1069,1.1081,1.1026,1.1036,3136059.2999999998],[1637150700000,1.1037,1.1062,1.1022,1.1055,2050220.6000000001],[1637151000000,1.1055,1.1074,1.1054,1.1063,1736577.5],[1637151300000,1.1063,1.1064,1.1035,1.1059,2622736.2999999998],[1637151600000,1.106,1.1068,1.1044,1.1046,2159126.8999999999],[1637151900000,1.1047,1.1059,1.1034,1.1038,1720883.5],[1637152200000,1.1037,1.1075,1.1037,1.1071,1897526.3999999999],[1637152500000,1.1071,1.1088,1.1061,1.1068,2402077.2999999998],[1637152800000,1.1069,1.107,1.1043,1.1061,2425579.7999999998],[1637153100000,1.106,1.1067,1.1039,1.1042,1281319.6000000001],[1637153400000,1.1043,1.1056,1.1042,1.1049,929455.9],[1637153700000,1.1048,1.1065,1.1048,1.1059,1360515.7],[1637154000000,1.1058,1.1133,1.1048,1.1096,6059693.5],[1637154300000,1.1096,1.1105,1.1045,1.1047,3046996.1000000001],[1637154600000,1.1048,1.1069,1.1045,1.1058,1648138.3999999999],[1637154900000,1.1059,1.1063,1.1012,1.1015,2568526.3999999999],[1637155200000,1.1015,1.1032,1.1,1.1006,2735189.7000000002],[1637155500000,1.1007,1.1033,1.1002,1.1029,1968598.8],[1637155800000,1.1028,1.1042,1.0989,1.1039,3753897.0],[1637156100000,1.1038,1.1044,1.1026,1.1038,1000207.1],[1637156400000,1.1038,1.1039,1.1001,1.1009,2153596.2999999998],[1637156700000,1.1009,1.1032,1.099,1.0995,3063064.7999999998],[1637157000000,1.0998,1.1003,1.0972,1.098,2697992.3999999999],[1637157300000,1.098,1.0992,1.096,1.096,2621387.0],[1637157600000,1.0961,1.1014,1.0961,1.1,2654646.5],[1637157900000,1.1001,1.1005,1.0981,1.0982,1341112.3999999999],[1637158200000,1.0982,1.0993,1.0965,1.0966,2182093.0],[1637158500000,1.0965,1.0992,1.0934,1.095,3821465.5],[1637158800000,1.095,1.0966,1.0936,1.095,1940575.5],[1637159100000,1.095,1.0984,1.0923,1.0977,2933823.8999999999],[1637159400000,1.0978,1.0978,1.0917,1.0923,2517615.2999999998],[1637159700000,1.0922,1.0956,1.0907,1.0914,4105409.0],[1637160000000,1.0913,1.0936,1.0906,1.0915,1618029.3999999999],[1637160300000,1.0915,1.0932,1.0886,1.0927,2769392.7999999998],[1637160600000,1.0926,1.0926,1.0847,1.0869,6282562.7999999998],[1637160900000,1.087,1.0875,1.0842,1.0846,2478907.8999999999],[1637161200000,1.0846,1.0879,1.0833,1.0874,3638166.1000000001],[1637161500000,1.0873,1.0896,1.0861,1.0868,2856420.7000000002],[1637161800000,1.0868,1.0882,1.0837,1.0838,2956741.2000000002],[1637162100000,1.0839,1.0865,1.0827,1.0845,2869705.3999999999],[1637162400000,1.0846,1.0867,1.0815,1.0827,3770542.6000000001],[1637162700000,1.0827,1.0839,1.0778,1.0804,4561579.5],[1637163000000,1.0805,1.0833,1.0756,1.0786,6138538.2999999998],[1637163300000,1.0787,1.0827,1.0783,1.0822,2007820.1000000001],[1637163600000,1.0823,1.0863,1.0816,1.085,5314252.5],[1637163900000,1.085,1.0872,1.0845,1.0871,1507044.3],[1637164200000,1.0871,1.0901,1.085,1.0855,2797640.3999999999],[1637164500000,1.0855,1.0875,1.0846,1.0861,1942630.8999999999],[1637164800000,1.0863,1.0866,1.0798,1.0808,3071536.1000000001],[1637165100000,1.0807,1.0856,1.0803,1.0854,1891225.3999999999],[1637165400000,1.0854,1.0901,1.0824,1.0901,3241084.6000000001],[1637165700000,1.0901,1.0919,1.0834,1.0834,4620817.5999999996],[1637166000000,1.0835,1.0896,1.0829,1.0875,2185543.7999999998],[1637166300000,1.0876,1.0912,1.0871,1.0906,1561475.5],[1637166600000,1.0906,1.095,1.09,1.0947,3319919.7000000002],[1637166900000,1.0947,1.0959,1.0915,1.0931,2493865.1000000001],[1637167200000,1.093,1.0943,1.0909,1.0943,2177410.2999999998],[1637167500000,1.0942,1.0963,1.0928,1.0961,1940089.1000000001],[1637167800000,1.0962,1.0963,1.0937,1.0945,1516195.5],[1637168100000,1.0946,1.0954,1.0933,1.095,1323452.1000000001],[1637168400000,1.095,1.096,1.0922,1.0927,1896410.2],[1637168700000,1.0926,1.093,1.0906,1.091,1236879.5],[1637169000000,1.0911,1.0912,1.0879,1.0888,1934815.5],[1637169300000,1.0887,1.0925,1.0879,1.0925,1552221.6000000001],[1637169600000,1.0925,1.0931,1.088,1.0903,1583392.8],[1637169900000,1.0903,1.0905,1.0882,1.0896,1510502.8999999999],[1637170200000,1.0896,1.0924,1.089,1.0923,1132094.8],[1637170500000,1.0923,1.0951,1.0919,1.0937,1582304.3],[1637170800000,1.0937,1.0941,1.0912,1.0929,1549678.0],[1637171100000,1.093,1.096,1.0925,1.0959,1505929.7],[1637171400000,1.0959,1.0984,1.0938,1.0948,2402150.2999999998],[1637171700000,1.095,1.0953,1.0928,1.0948,1127752.1000000001],[1637172000000,1.0948,1.097,1.094,1.0953,1735674.8],[1637172300000,1.0954,1.0974,1.0947,1.096,1491627.8999999999],[1637172600000,1.096,1.0969,1.0955,1.0965,664658.1],[1637172900000,1.0964,1.098,1.0959,1.0969,1453066.6000000001],[1637173200000,1.0969,1.0983,1.0967,1.0972,1340475.8],[1637173500000,1.0971,1.1006,1.0971,1.1002,1625938.8],[1637173800000,1.1001,1.1008,1.0994,1.0996,1679674.8999999999],[1637174100000,1.0997,1.0997,1.0979,1.0985,1132102.1000000001],[1637174400000,1.0985,1.0991,1.0969,1.0991,1373257.7],[1637174700000,1.099,1.1004,1.0982,1.0991,887280.9],[1637175000000,1.099,1.1023,1.099,1.1022,1543792.0],[1637175300000,1.1023,1.1032,1.0996,1.1,1377006.3],[1637175600000,1.0999,1.1031,1.0987,1.1007,2702878.7000000002],[1637175900000,1.1006,1.1012,1.0999,1.1011,799311.3],[1637176200000,1.1011,1.1015,1.0973,1.0979,2322776.1000000001],[1637176500000,1.0979,1.098,1.0959,1.0968,1159578.1000000001],[1637176800000,1.0968,1.0969,1.0947,1.095,1220533.8999999999],[1637177100000,1.0951,1.0985,1.0948,1.098,1157343.8999999999],[1637177400000,1.0979,1.098,1.0959,1.0964,929510.9],[1637177700000,1.0963,1.0986,1.0956,1.0969,1077697.0],[1637178000000,1.0968,1.0971,1.0946,1.0958,1033973.3],[1637178300000,1.0959,1.0977,1.0931,1.0934,1413592.3],[1637178600000,1.0933,1.0952,1.0926,1.0951,967092.4],[1637178900000,1.0951,1.0959,1.0942,1.0951,751371.1],[1637179200000,1.0951,1.0974,1.0933,1.0963,2208356.7999999998],[1637179500000,1.0962,1.0972,1.0945,1.0963,1179075.1000000001],[1637179800000,1.0964,1.097,1.0948,1.0949,1008579.0],[1637180100000,1.095,1.0952,1.0913,1.0917,1845474.7],[1637180400000,1.0917,1.0934,1.0906,1.0931,1408476.7],[1637180700000,1.0931,1.095,1.0931,1.0936,851841.7],[1637181000000,1.0936,1.0975,1.0927,1.0971,1295190.3999999999],[1637181300000,1.0971,1.1021,1.0971,1.1006,2684562.7000000002],[1637181600000,1.1005,1.1023,1.0997,1.102,1366607.1000000001],[1637181900000,1.102,1.1025,1.0976,1.0977,1451796.3999999999],[1637182200000,1.0976,1.1009,1.0973,1.1002,1050928.0],[1637182500000,1.1001,1.1006,1.0989,1.0999,1087095.8999999999],[1637182800000,1.1,1.1002,1.0966,1.0968,1062796.8],[1637183100000,1.0968,1.0969,1.0931,1.0936,1406189.6000000001],[1637183400000,1.0936,1.0971,1.0936,1.0959,908063.2],[1637183700000,1.096,1.0972,1.0928,1.0933,1567443.1000000001],[1637184000000,1.0933,1.0943,1.0914,1.0917,1478413.6000000001],[1637184300000,1.0916,1.0919,1.0877,1.0886,2730549.7999999998],[1637184600000,1.0885,1.0925,1.0885,1.0913,1442823.2],[1637184900000,1.0913,1.0922,1.09,1.0901,966258.9],[1637185200000,1.0902,1.0925,1.0901,1.0923,483252.6],[1637185500000,1.0923,1.0941,1.092,1.0921,760651.6],[1637185800000,1.092,1.0928,1.0904,1.091,859875.9],[1637186100000,1.091,1.0954,1.0908,1.0953,1327832.2],[1637186400000,1.0953,1.0956,1.0942,1.0943,828371.2],[1637186700000,1.0943,1.0945,1.0924,1.0932,1071065.3999999999],[1637187000000,1.0931,1.0953,1.0921,1.0949,753722.1],[1637187300000,1.0949,1.0951,1.0903,1.092,994191.6],[1637187600000,1.092,1.0926,1.0884,1.0896,1821173.5],[1637187900000,1.0896,1.0899,1.0853,1.0881,2776779.7000000002],[1637188200000,1.0882,1.089,1.0877,1.0887,673163.3],[1637188500000,1.0887,1.09,1.0887,1.09,485292.1],[1637188800000,1.0899,1.0934,1.0899,1.091,1079396.8999999999],[1637189100000,1.0909,1.0909,1.0888,1.0894,1290107.8999999999],[1637189400000,1.0894,1.0927,1.0891,1.0918,2200631.1000000001],[1637189700000,1.0916,1.093,1.0909,1.0928,564386.7],[1637190000000,1.0928,1.0948,1.0928,1.0945,747579.7],[1637190300000,1.0945,1.0948,1.0921,1.0921,969558.4],[1637190600000,1.0921,1.0921,1.0878,1.0886,1688184.8999999999],[1637190900000,1.0886,1.0909,1.0883,1.0903,844001.5],[1637191200000,1.0902,1.092,1.0902,1.0914,712580.3],[1637191500000,1.0915,1.0919,1.0903,1.0919,475440.6],[1637191800000,1.0918,1.0924,1.0902,1.0906,692121.2],[1637192100000,1.0907,1.091,1.0894,1.0895,570722.4],[1637192400000,1.0896,1.092,1.0895,1.0919,657315.2],[1637192700000,1.092,1.0975,1.0916,1.0974,1971930.8],[1637193000000,1.0975,1.0997,1.0962,1.0976,3437924.8999999999],[1637193300000,1.0977,1.0977,1.0944,1.0958,1948534.0],[1637193600000,1.0959,1.098,1.0907,1.0924,2614007.7000000002],[1637193900000,1.0922,1.1008,1.0919,1.0998,2948767.2000000002],[1637194200000,1.0997,1.1005,1.0971,1.099,2741193.2000000002],[1637194500000,1.099,1.102,1.0969,1.1005,4643687.9000000004],[1637194800000,1.1006,1.1028,1.0987,1.0998,2682431.3999999999],[1637195100000,1.0997,1.1009,1.0976,1.1001,1593940.1000000001],[1637195400000,1.1002,1.1013,1.0995,1.1011,619804.1],[1637195700000,1.1011,1.1045,1.101,1.1041,1441890.2],[1637196000000,1.1041,1.1056,1.1028,1.1041,2549423.7000000002],[1637196300000,1.1041,1.1061,1.103,1.1059,1393903.8999999999],[1637196600000,1.106,1.1072,1.1048,1.1067,1175572.8],[1637196900000,1.1068,1.1073,1.1049,1.105,1781210.8],[1637197200000,1.105,1.1061,1.1025,1.1039,2318627.7000000002],[1637197500000,1.1039,1.104,1.1027,1.1031,978156.0],[1637197800000,1.1031,1.1033,1.0992,1.1008,2558175.0],[1637198100000,1.1009,1.1019,1.0983,1.1002,3132340.3999999999],[1637198400000,1.1003,1.1013,1.0995,1.1008,788701.3],[1637198700000,1.1008,1.1043,1.1008,1.1041,1273241.0],[1637199000000,1.104,1.1377,1.104,1.1374,36479238.1000000015],[1637199300000,1.1375,1.162,1.131,1.16,37448787.799999997],[1637199600000,1.1603,1.1603,1.1405,1.1415,18739494.6999999993],[1637199900000,1.1415,1.1429,1.13,1.1348,12259697.5999999996],[1637200200000,1.1347,1.1353,1.1232,1.1252,11695103.5999999996],[1637200500000,1.1252,1.1312,1.1237,1.129,6841467.5],[1637200800000,1.129,1.1329,1.1286,1.1299,6573764.7999999998],[1637201100000,1.1298,1.1313,1.1251,1.1256,4100464.8999999999],[1637201400000,1.1256,1.1499,1.1243,1.1332,31686039.8000000007],[1637201700000,1.1331,1.1333,1.1277,1.128,4499818.2999999998],[1637202000000,1.1281,1.1294,1.1266,1.1292,2592096.3999999999],[1637202300000,1.1291,1.1311,1.1287,1.1311,1585982.8],[1637202600000,1.131,1.1393,1.1247,1.1339,11493173.5999999996],[1637202900000,1.1339,1.1364,1.1323,1.1333,3811665.3999999999],[1637203200000,1.1333,1.1342,1.1313,1.1336,2762649.7000000002],[1637203500000,1.1335,1.138,1.1324,1.1359,3023745.2000000002],[1637203800000,1.1359,1.1415,1.1357,1.1405,3071272.5],[1637204100000,1.1405,1.1405,1.1368,1.1385,2900170.0],[1637204400000,1.1385,1.1434,1.1372,1.1425,4306973.0999999996],[1637204700000,1.1424,1.1428,1.1346,1.1349,3390360.2999999998],[1637205000000,1.1348,1.1372,1.133,1.1335,3165410.2000000002],[1637205300000,1.1335,1.1375,1.1327,1.1338,1949274.1000000001],[1637205600000,1.1336,1.1356,1.1327,1.1338,1811876.2],[1637205900000,1.1338,1.1341,1.13,1.1307,4368692.7999999998],[1637206200000,1.1307,1.1325,1.1282,1.1292,3741574.2999999998],[1637206500000,1.1291,1.1322,1.1288,1.1318,2700658.2999999998],[1637206800000,1.1319,1.1321,1.1293,1.1293,1404040.3],[1637207100000,1.1293,1.1313,1.1262,1.1272,2801551.8999999999],[1637207400000,1.1271,1.1277,1.1238,1.1244,5518152.7999999998],[1637207700000,1.1245,1.1272,1.1241,1.1248,1519698.0],[1637208000000,1.1249,1.1321,1.1226,1.131,5786089.0999999996],[1637208300000,1.1309,1.133,1.1306,1.1307,1540875.6000000001],[1637208600000,1.1306,1.1322,1.1275,1.1279,2355058.6000000001],[1637208900000,1.128,1.1298,1.1261,1.1271,2771309.2999999998],[1637209200000,1.1271,1.1279,1.1254,1.1261,1854907.1000000001],[1637209500000,1.1262,1.1327,1.1169,1.1198,16188064.8000000007],[1637209800000,1.1198,1.1481,1.1165,1.1475,16896801.6000000015],[1637210100000,1.1475,1.1481,1.1322,1.1389,14173254.4000000004],[1637210400000,1.139,1.1407,1.1318,1.1364,13631417.6999999993],[1637210700000,1.1364,1.1404,1.1284,1.1294,11131764.9000000004],[1637211000000,1.1294,1.1309,1.1222,1.125,6321553.0],[1637211300000,1.125,1.1254,1.1136,1.115,11839636.9000000004],[1637211600000,1.1149,1.1176,1.1114,1.1155,6914612.5],[1637211900000,1.1153,1.1216,1.1134,1.1208,8321634.2999999998],[1637212200000,1.1208,1.1226,1.1187,1.121,5837211.4000000004],[1637212500000,1.121,1.1238,1.1181,1.1193,5989845.5999999996],[1637212800000,1.1193,1.1252,1.1169,1.1184,6576852.7999999998],[1637213100000,1.1184,1.123,1.1168,1.1219,3616199.8999999999],[1637213400000,1.1219,1.1269,1.1215,1.1219,5057255.5999999996],[1637213700000,1.1219,1.1243,1.1193,1.1198,4922280.5999999996],[1637214000000,1.1198,1.1226,1.1194,1.1194,3917341.2999999998],[1637214300000,1.1195,1.122,1.1137,1.1152,8680504.4000000004],[1637214600000,1.1153,1.1162,1.1118,1.1156,5167395.4000000004],[1637214900000,1.1156,1.1183,1.1117,1.1142,6087973.5],[1637215200000,1.1142,1.1153,1.1111,1.1131,4553846.2999999998],[1637215500000,1.1132,1.1134,1.1084,1.1087,4937834.5],[1637215800000,1.1087,1.1104,1.1064,1.1082,4350161.0],[1637216100000,1.1081,1.114,1.106,1.1139,4203990.5999999996],[1637216400000,1.114,1.1151,1.1102,1.1145,3909556.7000000002],[1637216700000,1.1145,1.1164,1.1123,1.1134,2783403.1000000001],[1637217000000,1.1133,1.1143,1.1104,1.1111,1793417.8],[1637217300000,1.1111,1.1175,1.111,1.1168,2683384.2000000002],[1637217600000,1.1168,1.1168,1.1129,1.1144,1596005.3],[1637217900000,1.1143,1.1143,1.1102,1.1124,1885052.7],[1637218200000,1.1121,1.1136,1.1086,1.1088,1878341.2],[1637218500000,1.1089,1.1145,1.1076,1.1142,2420014.8999999999],[1637218800000,1.1142,1.1147,1.1087,1.1096,3307754.7999999998],[1637219100000,1.1095,1.112,1.1086,1.1104,2543497.0],[1637219400000,1.1104,1.1104,1.1056,1.1059,2295635.2000000002],[1637219700000,1.1058,1.1079,1.1034,1.1073,2723064.3999999999],[1637220000000,1.1074,1.1078,1.103,1.1044,2910400.1000000001],[1637220300000,1.1043,1.1045,1.1022,1.103,2304491.7999999998],[1637220600000,1.1031,1.1052,1.099,1.1009,6195101.9000000004],[1637220900000,1.1009,1.1024,1.0966,1.1015,3942212.8999999999],[1637221200000,1.1015,1.1064,1.1004,1.1058,3304070.8999999999],[1637221500000,1.1057,1.1076,1.1043,1.1064,2473126.7000000002],[1637221800000,1.1065,1.1079,1.1044,1.105,2062578.0],[1637222100000,1.105,1.1078,1.1048,1.1074,1259992.1000000001],[1637222400000,1.1075,1.1104,1.1052,1.1056,3241738.8999999999],[1637222700000,1.1056,1.1082,1.1038,1.1055,2764367.7999999998],[1637223000000,1.1055,1.1065,1.103,1.1033,2205122.6000000001],[1637223300000,1.1034,1.1082,1.1022,1.1078,1854984.3999999999],[1637223600000,1.1077,1.1093,1.1062,1.1073,1405444.0],[1637223900000,1.1074,1.1097,1.107,1.109,1632723.5],[1637224200000,1.109,1.1103,1.1074,1.1078,2075103.8],[1637224500000,1.1079,1.1079,1.104,1.1045,1888507.0],[1637224800000,1.1045,1.1053,1.1033,1.1037,1495111.3999999999],[1637225100000,1.1038,1.1082,1.1028,1.1043,4119453.2999999998],[1637225400000,1.1043,1.107,1.1037,1.1042,1954533.8],[1637225700000,1.1043,1.1079,1.1038,1.1072,1478600.3999999999],[1637226000000,1.107,1.1077,1.1032,1.1035,3126430.7999999998],[1637226300000,1.1035,1.105,1.0976,1.0985,6405633.7000000002],[1637226600000,1.0986,1.0999,1.083,1.0906,12260258.1999999993],[1637226900000,1.0906,1.0923,1.0866,1.089,5197434.7999999998],[1637227200000,1.0891,1.0917,1.0814,1.0839,7086193.5],[1637227500000,1.0839,1.0857,1.0824,1.0853,3046616.2000000002],[1637227800000,1.0853,1.0882,1.079,1.0845,5761242.0999999996],[1637228100000,1.0845,1.0847,1.078,1.084,5052047.0999999996],[1637228400000,1.084,1.0874,1.0831,1.0846,3199587.5],[1637228700000,1.0845,1.0872,1.0815,1.0828,2354368.8999999999],[1637229000000,1.0828,1.0869,1.0811,1.0819,2610370.3999999999],[1637229300000,1.0819,1.0898,1.0773,1.0869,8080943.0],[1637229600000,1.0869,1.0929,1.086,1.0927,4635765.2999999998],[1637229900000,1.0927,1.0927,1.0864,1.0876,2974256.7000000002],[1637230200000,1.0877,1.0878,1.0831,1.0848,2237304.3999999999],[1637230500000,1.0847,1.0858,1.0811,1.0849,2963489.2999999998],[1637230800000,1.085,1.0913,1.081,1.0892,3821236.0],[1637231100000,1.0893,1.0901,1.0872,1.0894,2304758.1000000001],[1637231400000,1.0894,1.0948,1.0886,1.0946,2668053.0],[1637231700000,1.0945,1.095,1.0913,1.0918,2534872.2000000002],[1637232000000,1.0919,1.0944,1.091,1.0942,1711755.1000000001],[1637232300000,1.0941,1.0955,1.0917,1.0944,2627556.3999999999],[1637232600000,1.0944,1.0973,1.0929,1.0973,1769328.3],[1637232900000,1.0973,1.099,1.0954,1.0979,2591498.7000000002],[1637233200000,1.098,1.1027,1.0947,1.1025,5480946.7999999998],[1637233500000,1.1025,1.1025,1.0985,1.099,3196790.7999999998],[1637233800000,1.099,1.0999,1.0973,1.0993,1710833.5],[1637234100000,1.0994,1.0996,1.0954,1.096,2155253.1000000001],[1637234400000,1.096,1.0962,1.0944,1.0946,1713920.6000000001],[1637234700000,1.0947,1.0984,1.0942,1.0973,1729530.2],[1637235000000,1.0973,1.0973,1.0919,1.0926,3354500.5],[1637235300000,1.0925,1.0933,1.0907,1.0914,2148017.6000000001],[1637235600000,1.0914,1.0946,1.0904,1.0909,3060508.7999999998],[1637235900000,1.0909,1.0914,1.0871,1.0888,3127402.1000000001],[1637236200000,1.0886,1.0926,1.0883,1.089,2654773.6000000001],[1637236500000,1.0889,1.089,1.0837,1.085,3756011.2000000002],[1637236800000,1.085,1.0884,1.0818,1.0876,3740646.8999999999],[1637237100000,1.0875,1.0881,1.0813,1.0873,5464295.0],[1637237400000,1.0874,1.0915,1.086,1.0914,2984681.8999999999],[1637237700000,1.0915,1.0955,1.0862,1.0941,4439409.5],[1637238000000,1.0941,1.0954,1.0892,1.0892,4380673.9000000004],[1637238300000,1.0892,1.0897,1.0864,1.0888,2976525.6000000001],[1637238600000,1.0888,1.0913,1.0867,1.0867,1701390.8999999999],[1637238900000,1.0867,1.0877,1.0842,1.0851,2283647.6000000001],[1637239200000,1.0851,1.0866,1.0838,1.0862,1721140.5],[1637239500000,1.0862,1.0898,1.0859,1.0896,1310288.6000000001],[1637239800000,1.0896,1.09,1.0804,1.0807,4536972.0999999996],[1637240100000,1.0807,1.0853,1.0801,1.0838,4762274.5],[1637240400000,1.0836,1.0848,1.0792,1.0804,5064635.0],[1637240700000,1.0804,1.0831,1.08,1.0813,1537403.2],[1637241000000,1.0812,1.0815,1.0747,1.077,5156479.2999999998],[1637241300000,1.0771,1.0797,1.07,1.0747,7183726.9000000004],[1637241600000,1.0747,1.0757,1.0707,1.0731,4569661.2000000002],[1637241900000,1.073,1.0735,1.066,1.0711,6827627.2000000002],[1637242200000,1.0712,1.0744,1.0668,1.0736,4523276.2000000002],[1637242500000,1.0735,1.088,1.0732,1.087,10117740.1999999993],[1637242800000,1.087,1.0877,1.0814,1.083,6775660.9000000004],[1637243100000,1.0829,1.0851,1.081,1.0821,2642695.7000000002],[1637243400000,1.0821,1.0824,1.075,1.0761,4880387.2000000002],[1637243700000,1.0761,1.0778,1.0743,1.0772,1534373.2],[1637244000000,1.0771,1.0772,1.0716,1.0745,4327706.2000000002],[1637244300000,1.0744,1.0813,1.074,1.0803,3020688.8999999999],[1637244600000,1.0803,1.0806,1.0731,1.0736,3849244.6000000001],[1637244900000,1.0735,1.0753,1.0702,1.0725,2651872.2000000002],[1637245200000,1.0725,1.0759,1.0704,1.0754,2410886.6000000001],[1637245500000,1.0754,1.0761,1.0719,1.0719,1779660.3999999999],[1637245800000,1.0719,1.078,1.0715,1.0778,2666691.0],[1637246100000,1.0778,1.0779,1.0727,1.0743,2677487.3999999999],[1637246400000,1.0744,1.0755,1.0691,1.0694,2987468.6000000001],[1637246700000,1.0694,1.0744,1.0678,1.0681,4545253.0999999996],[1637247000000,1.0681,1.0718,1.0673,1.0689,3032031.3999999999],[1637247300000,1.0688,1.0771,1.0668,1.0713,4745771.5],[1637247600000,1.0713,1.077,1.0704,1.0714,5149637.0],[1637247900000,1.0714,1.0737,1.069,1.0698,2278352.5],[1637248200000,1.0698,1.0698,1.059,1.0638,12208164.5999999996],[1637248500000,1.0637,1.0642,1.0562,1.0603,10020211.0999999996],[1637248800000,1.0603,1.0631,1.0507,1.052,17936300.8999999985],[1637249100000,1.0516,1.0667,1.045,1.0659,26789320.8000000007],[1637249400000,1.0659,1.0753,1.0643,1.0722,15230670.6999999993],[1637249700000,1.0721,1.0784,1.0719,1.0756,7623911.2999999998],[1637250000000,1.0756,1.0769,1.0651,1.0654,8434091.4000000004],[1637250300000,1.0652,1.0701,1.0603,1.0618,9904451.5],[1637250600000,1.0618,1.0639,1.0547,1.056,9672806.5],[1637250900000,1.0558,1.0589,1.051,1.0563,7416348.5999999996],[1637251200000,1.0564,1.0607,1.0503,1.0544,9694105.0],[1637251500000,1.0545,1.0562,1.0499,1.0551,8325909.5],[1637251800000,1.055,1.0635,1.054,1.0619,7034183.5999999996],[1637252100000,1.0618,1.0635,1.0535,1.0551,4967031.9000000004],[1637252400000,1.0551,1.0551,1.0428,1.0489,12212691.6999999993],[1637252700000,1.0493,1.0531,1.0405,1.0499,12684642.0999999996],[1637253000000,1.05,1.0524,1.043,1.0442,9199165.8000000007],[1637253300000,1.0442,1.0521,1.0419,1.0483,7289009.9000000004],[1637253600000,1.0483,1.056,1.0461,1.0495,6475553.9000000004],[1637253900000,1.0495,1.0502,1.0434,1.0464,6323164.9000000004],[1637254200000,1.0465,1.0522,1.044,1.0513,4960452.7999999998],[1637254500000,1.0513,1.0515,1.0394,1.0407,6911517.2000000002],[1637254800000,1.0407,1.0444,1.0296,1.0399,23939978.1000000015],[1637255100000,1.0398,1.0405,1.0256,1.026,11352941.5999999996],[1637255400000,1.026,1.03,1.0145,1.0222,30418058.1999999993],[1637255700000,1.022,1.0407,1.0219,1.0405,14897561.9000000004],[1637256000000,1.0405,1.048,1.0354,1.0464,9762881.9000000004],[1637256300000,1.0467,1.0479,1.0434,1.0462,7487226.4000000004],[1637256600000,1.0463,1.0514,1.0445,1.0475,6550172.2000000002],[1637256900000,1.0474,1.0503,1.0425,1.05,6146483.4000000004],[1637257200000,1.0501,1.051,1.046,1.0487,3916486.5],[1637257500000,1.0487,1.0534,1.0428,1.0447,7068007.0],[1637257800000,1.0447,1.0452,1.0408,1.0437,3858984.3999999999],[1637258100000,1.0436,1.0466,1.0388,1.0421,8796545.6999999993],[1637258400000,1.042,1.0457,1.0415,1.0445,3286390.3999999999],[1637258700000,1.0445,1.0484,1.0414,1.0474,3499227.2000000002],[1637259000000,1.0475,1.0491,1.0441,1.0449,2073718.3999999999],[1637259300000,1.0449,1.0484,1.0443,1.0448,1992172.8999999999],[1637259600000,1.0447,1.0532,1.043,1.0517,7335197.7000000002],[1637259900000,1.0513,1.0527,1.0477,1.0481,2694719.1000000001],[1637260200000,1.0481,1.0546,1.0464,1.0535,2788362.8999999999],[1637260500000,1.0533,1.0546,1.048,1.0496,3148787.3999999999],[1637260800000,1.0495,1.0495,1.0471,1.0483,1636203.7],[1637261100000,1.0484,1.052,1.0478,1.0503,2142292.8999999999],[1637261400000,1.0503,1.0521,1.0474,1.052,1521865.5],[1637261700000,1.0521,1.0533,1.0502,1.052,1615455.0],[1637262000000,1.052,1.0534,1.0504,1.0511,2500315.7000000002],[1637262300000,1.0512,1.0533,1.0492,1.0525,1731929.8999999999],[1637262600000,1.0525,1.0526,1.0509,1.0525,1288238.6000000001],[1637262900000,1.0526,1.0534,1.0511,1.0521,1981181.3],[1637263200000,1.0522,1.0549,1.0517,1.0544,2082135.0],[1637263500000,1.0544,1.0589,1.0531,1.0538,4354132.7000000002],[1637263800000,1.0538,1.0592,1.0534,1.0591,3016289.7000000002],[1637264100000,1.0592,1.0597,1.0567,1.0582,2208937.5],[1637264400000,1.0582,1.0584,1.055,1.0559,1592049.6000000001],[1637264700000,1.0559,1.0559,1.05,1.0546,4724945.0999999996],[1637265000000,1.0545,1.0564,1.0541,1.0549,1248205.2],[1637265300000,1.055,1.0561,1.0529,1.0555,1044990.1],[1637265600000,1.0556,1.0562,1.051,1.0511,1374822.2],[1637265900000,1.0512,1.0529,1.0486,1.0503,2055764.1000000001],[1637266200000,1.0502,1.0536,1.0486,1.0523,2311715.2000000002],[1637266500000,1.0524,1.053,1.048,1.0529,1536118.8],[1637266800000,1.0529,1.0548,1.0523,1.0547,1741091.2],[1637267100000,1.0547,1.0549,1.0503,1.051,1699248.0],[1637267400000,1.0511,1.0522,1.0497,1.0499,1616389.8999999999],[1637267700000,1.0499,1.0546,1.0497,1.0542,1268396.3],[1637268000000,1.0543,1.0556,1.0519,1.0544,1719555.8],[1637268300000,1.0543,1.0595,1.054,1.0589,2433730.2000000002],[1637268600000,1.0589,1.0596,1.0554,1.0579,2604349.6000000001],[1637268900000,1.0579,1.0586,1.0473,1.0486,5917066.2999999998],[1637269200000,1.0486,1.0555,1.0482,1.0549,3221514.0],[1637269500000,1.0549,1.0558,1.0517,1.0517,1468725.8999999999],[1637269800000,1.0517,1.0565,1.0517,1.0542,1610096.8999999999],[1637270100000,1.0543,1.0548,1.0518,1.0519,848440.7],[1637270400000,1.052,1.0533,1.0486,1.049,1920701.8],[1637270700000,1.049,1.0504,1.0486,1.0488,784432.5],[1637271000000,1.0488,1.0495,1.042,1.048,7191645.5],[1637271300000,1.048,1.0493,1.0455,1.0458,1702880.2],[1637271600000,1.0457,1.0474,1.0451,1.0454,1642083.3],[1637271900000,1.0454,1.0473,1.0434,1.0465,1665604.3],[1637272200000,1.0464,1.0477,1.0415,1.0445,2543931.0],[1637272500000,1.0445,1.0463,1.0425,1.0455,3287773.8999999999],[1637272800000,1.0454,1.0468,1.0436,1.0437,2387173.8999999999],[1637273100000,1.0438,1.0454,1.0404,1.0422,2824927.5],[1637273400000,1.0421,1.0471,1.0337,1.0468,8781184.3000000007],[1637273700000,1.0467,1.0486,1.0425,1.0457,3452063.3999999999],[1637274000000,1.0458,1.0466,1.0421,1.046,1607743.3999999999],[1637274300000,1.046,1.0481,1.0459,1.0474,1390902.8999999999],[1637274600000,1.0473,1.0526,1.0459,1.0525,1985031.0],[1637274900000,1.0526,1.054,1.0464,1.0466,2085753.3],[1637275200000,1.0466,1.0466,1.0414,1.0439,1734988.8999999999],[1637275500000,1.044,1.0473,1.039,1.0423,2637924.2000000002],[1637275800000,1.0423,1.045,1.0403,1.041,1501560.1000000001],[1637276100000,1.041,1.0458,1.0364,1.0393,3287501.5],[1637276400000,1.0394,1.0408,1.0354,1.037,3141329.3999999999],[1637276700000,1.037,1.0437,1.0365,1.041,2409815.2999999998],[1637277000000,1.041,1.0412,1.0346,1.0362,2711584.7000000002],[1637277300000,1.0362,1.0383,1.0327,1.0334,2474262.7999999998],[1637277600000,1.0334,1.043,1.0329,1.0419,3130971.7999999998],[1637277900000,1.0419,1.0439,1.04,1.0434,3426939.5],[1637278200000,1.0434,1.0464,1.0363,1.0371,3060759.8999999999],[1637278500000,1.0371,1.0412,1.0333,1.0411,2772434.5],[1637278800000,1.0411,1.0411,1.033,1.0358,2457532.7000000002],[1637279100000,1.0359,1.0388,1.0286,1.038,5787787.9000000004],[1637279400000,1.0379,1.04,1.033,1.0345,2665939.3999999999],[1637279700000,1.0345,1.0438,1.034,1.041,4038551.6000000001],[1637280000000,1.0411,1.0464,1.0314,1.0345,9002812.8000000007],[1637280300000,1.0346,1.0416,1.0295,1.0415,5701463.4000000004],[1637280600000,1.0415,1.0479,1.038,1.0438,8495110.0999999996],[1637280900000,1.0438,1.0482,1.0422,1.0446,3843031.8999999999],[1637281200000,1.0446,1.0446,1.0379,1.0394,5906549.0999999996],[1637281500000,1.0395,1.0433,1.0382,1.0429,1947493.5],[1637281800000,1.0429,1.0489,1.0396,1.0475,4989048.5],[1637282100000,1.0475,1.053,1.0475,1.0512,4821880.0999999996],[1637282400000,1.0511,1.0572,1.0483,1.0564,4416235.7000000002],[1637282700000,1.0565,1.0568,1.0505,1.0509,3597824.1000000001],[1637283000000,1.051,1.0546,1.0496,1.0524,2647578.2999999998],[1637283300000,1.0525,1.0563,1.0514,1.0551,3312801.0],[1637283600000,1.055,1.0557,1.0499,1.0517,3101542.5],[1637283900000,1.0517,1.0526,1.0499,1.0524,2397938.1000000001],[1637284200000,1.0524,1.0526,1.0495,1.0512,2091210.3999999999],[1637284500000,1.0512,1.052,1.0475,1.0486,2411746.1000000001],[1637284800000,1.0484,1.0496,1.046,1.0482,2792944.1000000001],[1637285100000,1.0482,1.0483,1.0442,1.0443,1568003.0],[1637285400000,1.0443,1.0463,1.0439,1.0449,1622501.3999999999],[1637285700000,1.0449,1.0464,1.0442,1.0461,1144991.3999999999],[1637286000000,1.0461,1.0477,1.04,1.0405,3626138.2000000002],[1637286300000,1.0404,1.0423,1.0385,1.0405,3132361.7000000002],[1637286600000,1.0402,1.0416,1.0365,1.037,2028380.8],[1637286900000,1.037,1.0401,1.0356,1.0359,2847903.7999999998],[1637287200000,1.0358,1.0392,1.0345,1.0386,3284689.1000000001],[1637287500000,1.0384,1.0389,1.0357,1.037,1779480.5],[1637287800000,1.0371,1.0432,1.036,1.0428,2659037.3999999999],[1637288100000,1.0428,1.0442,1.0407,1.043,1587892.0],[1637288400000,1.043,1.0459,1.0429,1.045,1169724.5],[1637288700000,1.045,1.0452,1.0381,1.0387,3473844.7000000002],[1637289000000,1.0387,1.0407,1.0378,1.0403,1250291.6000000001],[1637289300000,1.0402,1.0416,1.038,1.038,1183740.0],[1637289600000,1.0381,1.039,1.03,1.0306,4775244.7999999998],[1637289900000,1.0306,1.0332,1.0256,1.028,5871642.9000000004],[1637290200000,1.028,1.0282,1.0211,1.0219,8272004.7999999998],[1637290500000,1.0221,1.0272,1.0201,1.0248,8520749.6999999993],[1637290800000,1.0248,1.0274,1.0232,1.0265,5266811.5999999996],[1637291100000,1.0265,1.0275,1.0221,1.0268,3088035.5],[1637291400000,1.0269,1.0294,1.0259,1.028,2541298.6000000001],[1637291700000,1.028,1.0285,1.0236,1.0241,2174009.6000000001],[1637292000000,1.0242,1.026,1.0229,1.0229,1710564.1000000001],[1637292300000,1.0229,1.0253,1.0216,1.0238,2250729.0],[1637292600000,1.0238,1.0252,1.0202,1.0251,5006980.7999999998],[1637292900000,1.025,1.0271,1.0234,1.0252,2973786.5],[1637293200000,1.0252,1.0252,1.0179,1.0191,4405564.2999999998],[1637293500000,1.019,1.0228,1.019,1.0224,2165756.7999999998],[1637293800000,1.0225,1.0272,1.0219,1.027,3005237.2000000002],[1637294100000,1.0269,1.029,1.0251,1.0289,2614775.7000000002],[1637294400000,1.0289,1.0336,1.0261,1.033,5683874.0],[1637294700000,1.033,1.0339,1.0302,1.0316,2516339.0],[1637295000000,1.0316,1.0338,1.0302,1.0335,2668964.7000000002],[1637295300000,1.0333,1.0388,1.0327,1.037,2691412.1000000001],[1637295600000,1.0369,1.0386,1.0359,1.0373,1374237.5],[1637295900000,1.0372,1.0387,1.0365,1.038,1478740.8],[1637296200000,1.038,1.0404,1.0366,1.0394,1943930.3999999999],[1637296500000,1.0395,1.0399,1.0378,1.0398,805676.1],[1637296800000,1.0399,1.0413,1.0382,1.0382,3092379.3999999999],[1637297100000,1.0383,1.0412,1.0377,1.0401,2541816.3999999999],[1637297400000,1.04,1.0413,1.0392,1.0408,1096755.3999999999],[1637297700000,1.0407,1.0451,1.0407,1.0432,4498930.5999999996],[1637298000000,1.0433,1.0443,1.042,1.0421,1396137.1000000001],[1637298300000,1.042,1.0449,1.042,1.0435,1937069.1000000001],[1637298600000,1.0436,1.0446,1.0428,1.0437,1266308.0],[1637298900000,1.0437,1.0444,1.0399,1.0401,2101957.1000000001],[1637299200000,1.0401,1.0413,1.0376,1.0382,2169149.0],[1637299500000,1.0382,1.0388,1.0371,1.0376,1569698.2],[1637299800000,1.0377,1.0439,1.0375,1.0435,2813737.7000000002],[1637300100000,1.0435,1.0466,1.0409,1.042,4241173.2000000002],[1637300400000,1.0421,1.0445,1.0421,1.0437,2477144.1000000001],[1637300700000,1.0437,1.0458,1.0436,1.0444,1621875.8999999999],[1637301000000,1.0444,1.0459,1.0441,1.0458,1097824.8999999999],[1637301300000,1.0459,1.0469,1.0446,1.045,1755199.3],[1637301600000,1.0451,1.0461,1.043,1.0444,1810849.2],[1637301900000,1.0444,1.0498,1.0439,1.0483,2074098.8],[1637302200000,1.0484,1.0495,1.0461,1.0464,1457180.2],[1637302500000,1.0464,1.0479,1.046,1.0466,1174520.3999999999],[1637302800000,1.0467,1.0468,1.0428,1.043,1564176.3],[1637303100000,1.0431,1.0467,1.0429,1.0454,2964933.3999999999],[1637303400000,1.0454,1.0459,1.0438,1.0454,766589.1],[1637303700000,1.0454,1.0484,1.0453,1.0475,1310481.5],[1637304000000,1.0476,1.0476,1.0423,1.0427,2213511.5],[1637304300000,1.0427,1.0456,1.0425,1.0438,1353233.3],[1637304600000,1.0437,1.0443,1.0411,1.043,1957829.1000000001],[1637304900000,1.0431,1.0459,1.0426,1.0448,1671180.0],[1637305200000,1.0448,1.0488,1.0447,1.0467,2016082.3999999999],[1637305500000,1.0467,1.0468,1.0416,1.0416,1787466.0],[1637305800000,1.0416,1.0433,1.0404,1.0405,1569913.6000000001],[1637306100000,1.0405,1.0411,1.0382,1.0393,1937543.5],[1637306400000,1.0392,1.042,1.0392,1.0413,1031926.7],[1637306700000,1.0413,1.0414,1.0381,1.0404,1714814.1000000001],[1637307000000,1.0404,1.0426,1.0392,1.0393,1783571.5],[1637307300000,1.0393,1.0404,1.0384,1.0403,1364430.2],[1637307600000,1.0402,1.0431,1.0389,1.0426,1227451.1000000001],[1637307900000,1.0426,1.0443,1.0397,1.04,1626605.7],[1637308200000,1.0401,1.0421,1.0387,1.0416,1494791.8999999999],[1637308500000,1.0417,1.0429,1.039,1.0421,1559077.3999999999],[1637308800000,1.042,1.0474,1.0418,1.0424,4172338.0],[1637309100000,1.0423,1.0473,1.0423,1.0467,2169063.3999999999],[1637309400000,1.0468,1.0486,1.0466,1.0484,1915057.7],[1637309700000,1.0483,1.0568,1.0483,1.0563,6329233.0999999996],[1637310000000,1.0563,1.0661,1.0544,1.0631,11705595.4000000004],[1637310300000,1.0632,1.0637,1.0589,1.0626,5223845.4000000004],[1637310600000,1.0625,1.063,1.0582,1.0592,3978271.3999999999],[1637310900000,1.0592,1.0621,1.0582,1.0612,2589196.5],[1637311200000,1.0612,1.0619,1.0589,1.0597,1740018.7],[1637311500000,1.0597,1.0631,1.0572,1.0577,2488892.8999999999],[1637311800000,1.0578,1.059,1.0564,1.0569,1876773.3],[1637312100000,1.0568,1.058,1.0555,1.057,2283765.7999999998],[1637312400000,1.0569,1.0589,1.0562,1.0572,2233281.2999999998],[1637312700000,1.0573,1.0608,1.057,1.0596,2130616.0],[1637313000000,1.0597,1.062,1.0596,1.0615,1626153.3],[1637313300000,1.0615,1.0649,1.0607,1.0631,3424118.8999999999],[1637313600000,1.0631,1.0646,1.0612,1.0623,2235360.2000000002],[1637313900000,1.0623,1.0624,1.0594,1.0609,2156914.3999999999],[1637314200000,1.061,1.0621,1.0596,1.0599,1578938.8],[1637314500000,1.0598,1.0619,1.0597,1.0611,1440036.3],[1637314800000,1.061,1.0627,1.061,1.0625,1264797.3999999999],[1637315100000,1.0626,1.0627,1.0598,1.06,1445057.8999999999],[1637315400000,1.0601,1.0621,1.0594,1.0597,1705156.6000000001],[1637315700000,1.0597,1.0603,1.0569,1.0583,2514239.6000000001],[1637316000000,1.0581,1.0592,1.0554,1.0554,1798072.6000000001],[1637316300000,1.0554,1.0566,1.0547,1.055,1512323.8],[1637316600000,1.055,1.0552,1.0532,1.0534,1732325.8999999999],[1637316900000,1.0534,1.0554,1.0518,1.0535,2882577.7000000002],[1637317200000,1.0536,1.0567,1.0536,1.0566,1118497.6000000001],[1637317500000,1.0565,1.057,1.0558,1.0566,1016241.9],[1637317800000,1.0566,1.0569,1.0547,1.0548,1407670.7],[1637318100000,1.0547,1.0553,1.0524,1.0524,2160236.7000000002],[1637318400000,1.0524,1.0543,1.0494,1.0505,8216318.2000000002],[1637318700000,1.0506,1.0538,1.0505,1.0535,2185536.2000000002],[1637319000000,1.0535,1.0538,1.0519,1.053,973366.5],[1637319300000,1.0529,1.055,1.0515,1.0549,1076603.3999999999],[1637319600000,1.0549,1.058,1.0516,1.0526,3025784.3999999999],[1637319900000,1.0528,1.0543,1.0526,1.0532,858447.4],[1637320200000,1.0532,1.0535,1.0464,1.0471,2844673.6000000001],[1637320500000,1.0471,1.0499,1.047,1.0486,1777340.6000000001],[1637320800000,1.0486,1.0499,1.0456,1.0494,2930679.3999999999],[1637321100000,1.0495,1.0512,1.0485,1.0489,1468135.5],[1637321400000,1.0489,1.0514,1.0476,1.0482,2117825.8999999999],[1637321700000,1.0482,1.0506,1.0469,1.05,1484764.5],[1637322000000,1.0499,1.0549,1.0492,1.0526,2848893.7999999998],[1637322300000,1.0526,1.0526,1.0492,1.0502,1876539.3999999999],[1637322600000,1.0503,1.0516,1.0502,1.0512,1289668.8999999999],[1637322900000,1.0512,1.0544,1.0512,1.0538,1193687.5],[1637323200000,1.0538,1.0557,1.0519,1.054,2278614.5],[1637323500000,1.054,1.055,1.0517,1.0538,1639711.8],[1637323800000,1.0539,1.0588,1.0538,1.0583,2866716.7999999998],[1637324100000,1.0582,1.0603,1.0567,1.0599,2282008.2000000002],[1637324400000,1.0598,1.0599,1.0568,1.0581,1824810.7],[1637324700000,1.058,1.061,1.0573,1.0607,2480658.6000000001],[1637325000000,1.0607,1.0608,1.0574,1.0588,1958265.1000000001],[1637325300000,1.0589,1.0601,1.0579,1.0582,1227657.2],[1637325600000,1.0583,1.0596,1.0564,1.0574,1629522.8999999999],[1637325900000,1.0574,1.0584,1.055,1.0572,1654087.0],[1637326200000,1.0572,1.0573,1.0537,1.0544,2593881.6000000001],[1637326500000,1.0545,1.0556,1.0523,1.0528,1929621.1000000001],[1637326800000,1.0528,1.055,1.0495,1.0516,2965527.8999999999],[1637327100000,1.0517,1.0558,1.0514,1.0542,2262686.0],[1637327400000,1.0542,1.0574,1.0532,1.0573,1695916.1000000001],[1637327700000,1.0572,1.0598,1.0552,1.0586,2219687.1000000001],[1637328000000,1.0586,1.0605,1.0571,1.0601,2067080.6000000001],[1637328300000,1.0602,1.0619,1.0585,1.0598,3917029.8999999999],[1637328600000,1.0599,1.0619,1.0591,1.0607,2356014.2999999998],[1637328900000,1.0607,1.0641,1.0602,1.0641,2933633.6000000001],[1637329200000,1.0641,1.0649,1.0608,1.0622,3647307.0],[1637329500000,1.0622,1.0652,1.0622,1.0645,2560422.5],[1637329800000,1.0646,1.065,1.0625,1.0642,1783036.3],[1637330100000,1.0643,1.0654,1.063,1.0651,1559591.0],[1637330400000,1.0652,1.0679,1.0652,1.0669,3404484.0],[1637330700000,1.0669,1.0693,1.0668,1.0679,2853599.2000000002],[1637331000000,1.0679,1.0702,1.0671,1.0697,2969501.7999999998],[1637331300000,1.0696,1.0704,1.0665,1.0685,2572050.3999999999],[1637331600000,1.0685,1.086,1.0685,1.075,14928506.0],[1637331900000,1.0751,1.0775,1.0704,1.0724,5195830.5],[1637332200000,1.0724,1.0729,1.0672,1.0674,3428569.8999999999],[1637332500000,1.0675,1.0702,1.067,1.068,1760836.1000000001],[1637332800000,1.068,1.0744,1.068,1.0738,2232547.3999999999],[1637333100000,1.0739,1.077,1.0726,1.077,2434194.2000000002],[1637333400000,1.077,1.1028,1.0742,1.0919,24851780.8999999985],[1637333700000,1.0919,1.1034,1.0905,1.095,17220289.8999999985],[1637334000000,1.0949,1.0993,1.0886,1.0937,10645506.5],[1637334300000,1.0936,1.0936,1.0857,1.0884,4950515.2999999998],[1637334600000,1.0884,1.0894,1.0832,1.0849,4678329.9000000004],[1637334900000,1.0847,1.0871,1.0815,1.0868,4151758.8999999999],[1637335200000,1.0868,1.0986,1.0856,1.09,9628256.9000000004],[1637335500000,1.0899,1.0907,1.0858,1.0864,2832302.7999999998],[1637335800000,1.0864,1.0913,1.0854,1.0864,4114308.1000000001],[1637336100000,1.0863,1.0996,1.0863,1.0913,12850899.4000000004],[1637336400000,1.0914,1.0923,1.0889,1.0903,2702810.0],[1637336700000,1.0902,1.0905,1.0867,1.0896,2937454.6000000001],[1637337000000,1.0897,1.0933,1.089,1.0914,3057155.3999999999],[1637337300000,1.0913,1.0915,1.0882,1.0891,1900239.8999999999],[1637337600000,1.0891,1.0934,1.0885,1.0918,3386471.8999999999],[1637337900000,1.0918,1.0949,1.0892,1.0943,2656613.2999999998],[1637338200000,1.0943,1.0944,1.0903,1.0907,2280753.5],[1637338500000,1.0906,1.0928,1.0886,1.0896,2880637.2999999998],[1637338800000,1.0896,1.0902,1.0748,1.0809,15229325.0999999996],[1637339100000,1.0809,1.0825,1.0801,1.0815,3759337.2999999998],[1637339400000,1.0815,1.0859,1.0815,1.0841,3276425.1000000001],[1637339700000,1.0842,1.0879,1.0831,1.0866,2705449.7999999998],[1637340000000,1.0867,1.0879,1.0851,1.0867,1940085.5],[1637340300000,1.0867,1.0877,1.0843,1.0857,1990591.6000000001],[1637340600000,1.0857,1.0901,1.0856,1.0899,1749199.3999999999],[1637340900000,1.0899,1.0914,1.0896,1.0909,2214512.1000000001],[1637341200000,1.0909,1.099,1.0904,1.0954,4852518.7000000002],[1637341500000,1.0954,1.0972,1.0931,1.0962,2662937.7000000002],[1637341800000,1.0961,1.0985,1.0956,1.0963,2422019.5],[1637342100000,1.0963,1.098,1.0953,1.0954,1835799.8],[1637342400000,1.0953,1.0963,1.0917,1.0953,2891458.0],[1637342700000,1.0951,1.0984,1.0945,1.0974,2600052.3999999999],[1637343000000,1.0973,1.0975,1.092,1.0943,1826843.7],[1637343300000,1.0942,1.0971,1.093,1.0951,2493674.7000000002],[1637343600000,1.0951,1.0952,1.0889,1.0921,3589679.0],[1637343900000,1.092,1.0934,1.0902,1.0906,2088592.0],[1637344200000,1.0907,1.0909,1.089,1.0908,1497654.0],[1637344500000,1.0907,1.0935,1.0903,1.0908,1551172.0],[1637344800000,1.0908,1.0919,1.0891,1.0908,1371659.8999999999],[1637345100000,1.0909,1.0923,1.0901,1.0912,1099405.2],[1637345400000,1.0912,1.0952,1.0912,1.0937,1544849.7],[1637345700000,1.0937,1.0939,1.0906,1.091,1028408.1],[1637346000000,1.0911,1.0919,1.088,1.0887,1541774.1000000001],[1637346300000,1.0887,1.0888,1.0861,1.0875,1889732.3999999999],[1637346600000,1.0876,1.088,1.0855,1.0879,1551550.0],[1637346900000,1.0879,1.0891,1.0869,1.0876,1318291.0],[1637347200000,1.0875,1.0946,1.0859,1.0929,4563689.9000000004],[1637347500000,1.0929,1.0939,1.0898,1.0915,1896728.6000000001],[1637347800000,1.0916,1.0923,1.0907,1.092,868193.3],[1637348100000,1.092,1.0921,1.0895,1.0911,881530.6],[1637348400000,1.091,1.0929,1.0904,1.0926,1430232.3999999999],[1637348700000,1.0925,1.0928,1.0909,1.0918,1058528.3999999999],[1637349000000,1.0918,1.0944,1.0904,1.0941,1438929.5],[1637349300000,1.094,1.0958,1.0933,1.0951,1214216.0],[1637349600000,1.095,1.0951,1.093,1.0937,1072236.0],[1637349900000,1.0936,1.0952,1.0926,1.0926,853420.7],[1637350200000,1.0926,1.093,1.0885,1.0906,2109807.7999999998],[1637350500000,1.0907,1.0916,1.0894,1.0903,777329.7],[1637350800000,1.0905,1.091,1.0881,1.0894,1155590.5],[1637351100000,1.0894,1.0928,1.0893,1.0909,1574971.2],[1637351400000,1.091,1.0941,1.0909,1.0924,1363640.2],[1637351700000,1.0924,1.0952,1.0917,1.0936,1362357.0],[1637352000000,1.0937,1.0949,1.0905,1.0916,1437675.3],[1637352300000,1.0915,1.0949,1.0909,1.0943,1157343.2],[1637352600000,1.0943,1.0955,1.0916,1.092,1653159.8],[1637352900000,1.0921,1.0927,1.0905,1.0918,945154.5],[1637353200000,1.0918,1.0946,1.0913,1.0926,1311882.8999999999],[1637353500000,1.0925,1.0927,1.086,1.0871,4312836.2000000002],[1637353800000,1.087,1.0885,1.0858,1.0877,1550918.6000000001],[1637354100000,1.0878,1.0878,1.0838,1.0859,2308438.5],[1637354400000,1.0859,1.0888,1.0853,1.0882,1855770.0],[1637354700000,1.0883,1.09,1.0867,1.0893,1192972.0],[1637355000000,1.0893,1.0894,1.0855,1.0864,1148445.5],[1637355300000,1.0866,1.0887,1.0855,1.0857,1099877.3999999999],[1637355600000,1.0856,1.0866,1.0837,1.0844,2039745.1000000001],[1637355900000,1.0844,1.0859,1.0801,1.0817,2892642.1000000001],[1637356200000,1.0816,1.0842,1.0813,1.083,2101040.1000000001],[1637356500000,1.0831,1.0854,1.0831,1.0851,1038172.5],[1637356800000,1.0851,1.0858,1.0836,1.0839,1119516.6000000001],[1637357100000,1.0839,1.0843,1.0817,1.0831,1538972.8],[1637357400000,1.0832,1.0856,1.0828,1.0854,1554488.0],[1637357700000,1.0854,1.0859,1.0832,1.0837,785075.1],[1637358000000,1.0838,1.0865,1.0837,1.0851,906393.9],[1637358300000,1.0851,1.0877,1.0847,1.0864,1111648.0],[1637358600000,1.0865,1.0872,1.0853,1.0862,662570.1],[1637358900000,1.0863,1.087,1.0845,1.087,651297.2],[1637359200000,1.087,1.089,1.0861,1.0863,1561620.3999999999],[1637359500000,1.0862,1.0897,1.0861,1.0896,690657.4],[1637359800000,1.0897,1.0906,1.0891,1.0893,1022069.4],[1637360100000,1.0893,1.0894,1.0872,1.0878,1387351.2],[1637360400000,1.0877,1.0885,1.087,1.0884,862012.8],[1637360700000,1.0885,1.0895,1.0879,1.089,647205.2],[1637361000000,1.089,1.0895,1.0876,1.0878,1066368.8],[1637361300000,1.0878,1.0881,1.0867,1.0879,858945.2],[1637361600000,1.0879,1.0879,1.0834,1.0847,1858069.5],[1637361900000,1.0848,1.0865,1.0845,1.0861,936997.9],[1637362200000,1.0861,1.0862,1.0825,1.0844,1495208.8999999999],[1637362500000,1.0844,1.0858,1.0829,1.0854,1352253.8],[1637362800000,1.0854,1.0871,1.0823,1.0849,1622230.3999999999],[1637363100000,1.0848,1.086,1.0828,1.0856,2417358.7999999998],[1637363400000,1.0855,1.088,1.0853,1.0867,1630532.2],[1637363700000,1.0867,1.0877,1.0848,1.085,760880.6],[1637364000000,1.085,1.0901,1.0848,1.0897,2069419.7],[1637364300000,1.0897,1.0911,1.0879,1.0879,1488516.5],[1637364600000,1.0879,1.0884,1.0856,1.0863,1533068.2],[1637364900000,1.0864,1.0875,1.0855,1.0874,722345.4],[1637365200000,1.0874,1.0874,1.0852,1.0857,822524.9],[1637365500000,1.0856,1.0902,1.0856,1.0902,1403417.8],[1637365800000,1.0902,1.0924,1.0901,1.0923,1636862.3999999999],[1637366100000,1.0923,1.0927,1.0895,1.0903,1399924.0],[1637366400000,1.0903,1.0962,1.0901,1.0914,4490673.2000000002],[1637366700000,1.0912,1.0941,1.0882,1.0941,3047626.5],[1637367000000,1.094,1.0977,1.0923,1.0971,3678381.5],[1637367300000,1.0972,1.1,1.0952,1.097,3997438.1000000001],[1637367600000,1.097,1.0977,1.0945,1.0972,2438163.0],[1637367900000,1.0972,1.0975,1.0956,1.0964,1098586.6000000001],[1637368200000,1.0964,1.0974,1.0897,1.0905,2539457.2999999998],[1637368500000,1.0905,1.0914,1.0865,1.0872,2320597.2000000002],[1637368800000,1.0872,1.0923,1.0864,1.0914,1631094.3],[1637369100000,1.0916,1.092,1.0877,1.0919,4289263.4000000004],[1637369400000,1.0919,1.094,1.091,1.0939,1055489.3],[1637369700000,1.0938,1.094,1.0901,1.0911,1184568.6000000001],[1637370000000,1.0912,1.0939,1.0903,1.0932,1212137.7],[1637370300000,1.0936,1.0955,1.0928,1.0951,1211542.5],[1637370600000,1.0952,1.0967,1.0945,1.096,1305328.2],[1637370900000,1.096,1.0961,1.0935,1.0947,1120283.7],[1637371200000,1.0947,1.0983,1.0939,1.0978,2445861.6000000001],[1637371500000,1.0979,1.0988,1.0969,1.098,1417139.0],[1637371800000,1.098,1.099,1.0967,1.098,1077261.6000000001],[1637372100000,1.0981,1.0986,1.0972,1.0981,674376.4],[1637372400000,1.0981,1.1005,1.0979,1.0983,2364323.5],[1637372700000,1.0982,1.0983,1.0967,1.0978,1247239.3999999999],[1637373000000,1.0978,1.099,1.0973,1.0981,1277629.1000000001],[1637373300000,1.0981,1.0999,1.0975,1.0985,1346729.3],[1637373600000,1.0985,1.0986,1.0944,1.0958,2723454.3999999999],[1637373900000,1.0958,1.0964,1.0929,1.093,1749144.7],[1637374200000,1.0929,1.0949,1.0914,1.0947,2049263.7],[1637374500000,1.0946,1.0956,1.0933,1.095,1205850.3],[1637374800000,1.095,1.0955,1.0898,1.0913,4338975.2000000002],[1637375100000,1.0913,1.0918,1.0894,1.0909,1560380.0],[1637375400000,1.0908,1.0918,1.0904,1.0906,972871.6],[1637375700000,1.0907,1.0913,1.0898,1.09,818448.0],[1637376000000,1.0899,1.0908,1.0894,1.0902,929097.9],[1637376300000,1.0902,1.0906,1.0891,1.0901,708380.7],[1637376600000,1.0901,1.0906,1.0897,1.0898,736159.1],[1637376900000,1.0898,1.0911,1.0896,1.0898,575795.6],[1637377200000,1.0897,1.0918,1.0892,1.0892,1190381.5],[1637377500000,1.0894,1.0921,1.0891,1.0908,765414.3],[1637377800000,1.0908,1.0908,1.0871,1.0878,1903675.5],[1637378100000,1.0879,1.0899,1.0876,1.0892,855392.0],[1637378400000,1.0892,1.0892,1.0864,1.0881,1257836.3999999999],[1637378700000,1.0882,1.0889,1.088,1.0883,536165.5],[1637379000000,1.0884,1.0899,1.088,1.0884,615970.0],[1637379300000,1.0885,1.0885,1.0861,1.0869,1734457.8],[1637379600000,1.0868,1.0871,1.0836,1.0867,2512820.2000000002],[1637379900000,1.0866,1.0868,1.0854,1.0858,859900.4],[1637380200000,1.0859,1.0868,1.0858,1.086,923713.7],[1637380500000,1.086,1.0865,1.0844,1.0856,858783.1],[1637380800000,1.0856,1.089,1.085,1.0859,3112801.1000000001],[1637381100000,1.0859,1.0867,1.0842,1.0845,893190.8],[1637381400000,1.0845,1.086,1.0844,1.0857,1771293.6000000001],[1637381700000,1.0857,1.087,1.0848,1.087,657313.5],[1637382000000,1.087,1.0874,1.0862,1.0871,500026.1],[1637382300000,1.0872,1.0875,1.0854,1.0861,611553.3],[1637382600000,1.086,1.0873,1.0856,1.0864,590790.3],[1637382900000,1.0865,1.0889,1.0864,1.0888,736771.6],[1637383200000,1.0887,1.0892,1.0875,1.0882,564684.6],[1637383500000,1.0883,1.0889,1.0867,1.0885,811903.8],[1637383800000,1.0884,1.0906,1.088,1.0888,1212980.8999999999],[1637384100000,1.0887,1.0893,1.0878,1.0882,464356.2],[1637384400000,1.0881,1.0901,1.0881,1.0899,669739.7],[1637384700000,1.0899,1.0899,1.0872,1.0883,533913.3],[1637385000000,1.0883,1.0896,1.0868,1.0868,2708301.2999999998],[1637385300000,1.0869,1.088,1.0843,1.0845,1120246.0],[1637385600000,1.0844,1.0857,1.0821,1.0855,1427580.0],[1637385900000,1.0854,1.0866,1.0851,1.0863,389398.7],[1637386200000,1.0862,1.0882,1.0855,1.0879,1024285.7],[1637386500000,1.0879,1.0883,1.0875,1.0876,497392.0],[1637386800000,1.0876,1.0878,1.0861,1.0873,511895.0],[1637387100000,1.0873,1.0874,1.0851,1.0856,1142755.2],[1637387400000,1.0855,1.0873,1.0852,1.0863,901715.7],[1637387700000,1.0862,1.0867,1.0842,1.0863,692900.3],[1637388000000,1.0864,1.0871,1.0847,1.0852,561651.4],[1637388300000,1.0853,1.0861,1.0843,1.0856,676985.3],[1637388600000,1.0855,1.0862,1.0848,1.0861,742870.5],[1637388900000,1.0862,1.0875,1.0854,1.0867,841786.8],[1637389200000,1.0868,1.092,1.0867,1.0915,2294600.3999999999],[1637389500000,1.0914,1.0917,1.0883,1.0893,1009314.8],[1637389800000,1.0894,1.0926,1.0892,1.0917,1368490.8999999999],[1637390100000,1.0916,1.0916,1.0886,1.0894,1084968.3],[1637390400000,1.0895,1.0896,1.0879,1.088,932017.3],[1637390700000,1.088,1.0883,1.0865,1.0871,767340.1],[1637391000000,1.0871,1.0897,1.0859,1.0889,1704183.8],[1637391300000,1.089,1.0897,1.0883,1.0892,455040.6],[1637391600000,1.0893,1.0895,1.0882,1.0884,393659.6],[1637391900000,1.0885,1.0895,1.0881,1.0893,567088.8],[1637392200000,1.0893,1.091,1.0892,1.0902,717566.6],[1637392500000,1.0903,1.0903,1.0883,1.0889,774337.1],[1637392800000,1.0888,1.0889,1.087,1.0871,449758.3],[1637393100000,1.0871,1.088,1.0863,1.087,933884.1],[1637393400000,1.0871,1.0879,1.0866,1.0866,596192.9],[1637393700000,1.0866,1.0886,1.086,1.0883,1050754.8],[1637394000000,1.0883,1.0886,1.0874,1.0881,509677.1],[1637394300000,1.0881,1.0882,1.0853,1.0863,1169936.7],[1637394600000,1.0863,1.0864,1.0847,1.0849,578612.8],[1637394900000,1.0849,1.086,1.0846,1.0856,1144627.1000000001],[1637395200000,1.0857,1.0866,1.085,1.0854,989275.4],[1637395500000,1.0855,1.0863,1.0779,1.0808,10505885.3000000007],[1637395800000,1.0808,1.0839,1.0807,1.0821,3208775.7000000002],[1637396100000,1.0821,1.0831,1.0806,1.083,1995404.0],[1637396400000,1.083,1.0846,1.0829,1.0841,681952.6],[1637396700000,1.084,1.0855,1.084,1.0845,794261.4],[1637397000000,1.0845,1.0862,1.0842,1.0855,888880.8],[1637397300000,1.0854,1.0864,1.0834,1.0862,1091271.2],[1637397600000,1.0863,1.0893,1.0858,1.0877,1279769.0],[1637397900000,1.0876,1.0881,1.0855,1.086,793110.0],[1637398200000,1.0859,1.0874,1.0859,1.0867,485470.1],[1637398500000,1.0866,1.0867,1.0837,1.0838,887626.4],[1637398800000,1.0838,1.0863,1.0838,1.0862,1245719.2],[1637399100000,1.0862,1.0884,1.0859,1.0883,974988.0],[1637399400000,1.0884,1.0888,1.0877,1.0886,1003591.0],[1637399700000,1.0885,1.0886,1.0861,1.0864,992947.0],[1637400000000,1.0864,1.0881,1.0863,1.087,779589.5],[1637400300000,1.087,1.0874,1.0844,1.0847,1269541.6000000001],[1637400600000,1.0846,1.0849,1.0831,1.0835,915033.7],[1637400900000,1.0835,1.0865,1.0834,1.0857,1087950.8999999999],[1637401200000,1.0857,1.0877,1.0856,1.0873,537262.9],[1637401500000,1.0873,1.0877,1.0862,1.0877,701827.7],[1637401800000,1.0876,1.0877,1.086,1.0863,755964.2],[1637402100000,1.0863,1.088,1.086,1.0864,926433.9],[1637402400000,1.0863,1.0864,1.084,1.0856,1366293.6000000001],[1637402700000,1.0855,1.0866,1.0843,1.086,796402.5],[1637403000000,1.086,1.0871,1.086,1.0868,381267.2],[1637403300000,1.0868,1.0887,1.0865,1.0879,1003275.7],[1637403600000,1.0878,1.0894,1.0877,1.0884,1017682.3],[1637403900000,1.0884,1.0896,1.0874,1.0895,879450.2],[1637404200000,1.0895,1.0907,1.0866,1.0875,1907528.3],[1637404500000,1.0874,1.0876,1.0861,1.0873,839201.7],[1637404800000,1.0872,1.089,1.0871,1.0878,682662.9],[1637405100000,1.0878,1.0886,1.0867,1.0868,559829.6],[1637405400000,1.0868,1.0871,1.0852,1.0865,1215875.8999999999],[1637405700000,1.0864,1.0879,1.0864,1.0873,937912.4],[1637406000000,1.0874,1.0892,1.0874,1.0878,944114.4],[1637406300000,1.0878,1.0903,1.0878,1.0902,979827.1],[1637406600000,1.0903,1.0904,1.0892,1.0898,805613.7],[1637406900000,1.0898,1.0901,1.0868,1.0881,1123460.1000000001],[1637407200000,1.0881,1.0904,1.0879,1.09,888838.0],[1637407500000,1.09,1.0905,1.0885,1.0897,750959.0],[1637407800000,1.0897,1.0901,1.0888,1.089,886774.2],[1637408100000,1.089,1.0969,1.089,1.0966,5718003.2999999998],[1637408400000,1.0967,1.0986,1.0956,1.0982,2973321.8999999999],[1637408700000,1.0982,1.0988,1.0968,1.0974,2032980.7],[1637409000000,1.0974,1.0976,1.0929,1.0966,2923037.3999999999],[1637409300000,1.0966,1.098,1.0954,1.0971,1428928.1000000001],[1637409600000,1.0971,1.1024,1.0967,1.1005,3556082.2999999998],[1637409900000,1.1004,1.1009,1.0937,1.095,3633304.7000000002],[1637410200000,1.095,1.0986,1.095,1.0969,2066445.8],[1637410500000,1.0968,1.0979,1.0949,1.0966,2075631.8999999999],[1637410800000,1.0965,1.0969,1.094,1.0948,1400437.5],[1637411100000,1.0949,1.0953,1.094,1.0947,723203.3],[1637411400000,1.0947,1.0964,1.0926,1.0946,1518842.8999999999],[1637411700000,1.0945,1.0951,1.0936,1.0938,702839.0],[1637412000000,1.0938,1.0938,1.091,1.0922,1820219.7],[1637412300000,1.0922,1.0929,1.09,1.0926,1242401.1000000001],[1637412600000,1.0926,1.0937,1.092,1.0932,945032.3],[1637412900000,1.0931,1.0941,1.0929,1.093,783040.7],[1637413200000,1.0931,1.0943,1.0928,1.0933,865950.4],[1637413500000,1.0933,1.0954,1.0928,1.0952,972369.5],[1637413800000,1.0952,1.0957,1.0934,1.0936,986854.5],[1637414100000,1.0936,1.0938,1.091,1.0915,1628016.7],[1637414400000,1.0916,1.0918,1.0886,1.0903,2689959.2000000002],[1637414700000,1.0902,1.0919,1.0901,1.091,873543.9],[1637415000000,1.091,1.0911,1.0896,1.09,1140434.0],[1637415300000,1.09,1.0901,1.0874,1.0877,1993566.8],[1637415600000,1.0877,1.0905,1.0874,1.0904,1408563.1000000001],[1637415900000,1.0904,1.0906,1.0877,1.088,1280882.3999999999],[1637416200000,1.088,1.0881,1.0862,1.0879,1721945.6000000001],[1637416500000,1.0879,1.0891,1.0875,1.088,878254.6],[1637416800000,1.0881,1.0903,1.0881,1.0884,1015559.4],[1637417100000,1.0883,1.0901,1.0867,1.0896,1573042.3],[1637417400000,1.0896,1.0915,1.0892,1.0901,1649532.8999999999],[1637417700000,1.0902,1.0921,1.0901,1.0918,780278.3],[1637418000000,1.0918,1.0929,1.0899,1.0909,1178830.8],[1637418300000,1.091,1.091,1.0871,1.0874,1673685.5],[1637418600000,1.0873,1.0878,1.0856,1.0876,1594742.1000000001],[1637418900000,1.0875,1.0903,1.0875,1.0882,1185215.8],[1637419200000,1.0882,1.0889,1.0873,1.0882,901834.1],[1637419500000,1.0881,1.0908,1.0881,1.0905,1190476.0],[1637419800000,1.0904,1.0909,1.088,1.0885,1333521.1000000001],[1637420100000,1.0885,1.0889,1.0868,1.0875,1204363.2],[1637420400000,1.0874,1.0882,1.0774,1.0774,6897278.2000000002],[1637420700000,1.0774,1.0798,1.0666,1.0734,18737028.1000000015],[1637421000000,1.0734,1.0744,1.0649,1.0653,8081248.0999999996],[1637421300000,1.0653,1.0713,1.0634,1.0682,6168610.9000000004],[1637421600000,1.0683,1.0738,1.0682,1.0723,3102912.2999999998],[1637421900000,1.0722,1.0724,1.0685,1.0696,3068162.8999999999],[1637422200000,1.0697,1.0742,1.0689,1.0726,3058278.2000000002],[1637422500000,1.0726,1.0727,1.068,1.0681,2896892.3999999999],[1637422800000,1.0682,1.069,1.06,1.0648,9484606.5],[1637423100000,1.0648,1.0683,1.0627,1.0658,6391215.2000000002],[1637423400000,1.0657,1.0662,1.0626,1.0636,2885611.7000000002],[1637423700000,1.0636,1.0687,1.0633,1.0657,3151402.8999999999],[1637424000000,1.0656,1.0731,1.0638,1.0703,7003005.7999999998],[1637424300000,1.0703,1.0714,1.0679,1.0682,2512787.7000000002],[1637424600000,1.0681,1.0698,1.067,1.0675,2116040.2999999998],[1637424900000,1.0675,1.0703,1.0622,1.0636,3607023.0],[1637425200000,1.0637,1.067,1.0619,1.0668,3870316.7999999998],[1637425500000,1.0667,1.0702,1.0661,1.0695,2504189.2000000002],[1637425800000,1.0695,1.0747,1.0684,1.0725,3386024.2000000002],[1637426100000,1.0724,1.0724,1.0703,1.0714,1934522.6000000001],[1637426400000,1.0715,1.0734,1.0709,1.0727,1171828.0],[1637426700000,1.0726,1.0744,1.0714,1.0737,1507495.8999999999],[1637427000000,1.0736,1.0737,1.0711,1.0714,1028025.1],[1637427300000,1.0715,1.0741,1.0714,1.0731,1073486.7],[1637427600000,1.0731,1.0749,1.0726,1.073,1826134.2],[1637427900000,1.073,1.0742,1.0712,1.0738,918052.8],[1637428200000,1.0738,1.0738,1.0719,1.0722,988718.0],[1637428500000,1.0723,1.0731,1.0703,1.0721,1311910.8],[1637428800000,1.0721,1.0723,1.0694,1.0699,1087906.5],[1637429100000,1.07,1.0711,1.0687,1.071,1325384.2],[1637429400000,1.071,1.0723,1.0698,1.0707,1655250.3],[1637429700000,1.0708,1.0709,1.0681,1.0691,1158388.3999999999],[1637430000000,1.0692,1.0713,1.0683,1.0711,1145710.2],[1637430300000,1.071,1.0734,1.0704,1.0705,1603998.2],[1637430600000,1.0705,1.0736,1.0704,1.0731,1422780.1000000001],[1637430900000,1.073,1.0733,1.0717,1.0729,804557.5],[1637431200000,1.0729,1.0733,1.0701,1.0711,2708513.8999999999],[1637431500000,1.0712,1.0724,1.0685,1.0696,2337731.0],[1637431800000,1.0696,1.0715,1.069,1.0712,1218239.6000000001],[1637432100000,1.0712,1.078,1.0709,1.077,3115678.5],[1637432400000,1.0771,1.0901,1.0765,1.089,10331195.0999999996],[1637432700000,1.089,1.0947,1.0885,1.0938,7902295.5999999996],[1637433000000,1.0939,1.0958,1.0874,1.0882,5300217.7999999998],[1637433300000,1.0882,1.0917,1.0865,1.0902,3014248.7000000002],[1637433600000,1.0901,1.0956,1.0895,1.0956,4186690.7999999998],[1637433900000,1.0956,1.0981,1.0931,1.0948,5519539.0999999996],[1637434200000,1.0948,1.0974,1.0927,1.0966,3683840.6000000001],[1637434500000,1.0965,1.0969,1.0928,1.094,1721444.3999999999],[1637434800000,1.0941,1.0959,1.092,1.0933,3065797.7999999998],[1637435100000,1.0933,1.0952,1.093,1.0933,2150903.7000000002],[1637435400000,1.0934,1.0955,1.0929,1.094,2857204.1000000001],[1637435700000,1.094,1.0953,1.0926,1.0932,2070352.5],[1637436000000,1.0933,1.0948,1.0924,1.0925,1837116.3999999999],[1637436300000,1.0925,1.0928,1.0894,1.0921,2155167.2000000002],[1637436600000,1.0921,1.0929,1.0906,1.0925,1278498.3],[1637436900000,1.0924,1.0939,1.0919,1.093,1043067.9],[1637437200000,1.0931,1.0933,1.0914,1.0921,912194.9],[1637437500000,1.0921,1.0921,1.0897,1.0907,1311876.8999999999],[1637437800000,1.0907,1.0913,1.0896,1.0897,1085619.1000000001],[1637438100000,1.0898,1.0913,1.0895,1.0913,1220068.3999999999],[1637438400000,1.0912,1.093,1.0901,1.0902,2883167.7000000002],[1637438700000,1.0902,1.0922,1.0901,1.0916,1082536.0],[1637439000000,1.0917,1.0922,1.0897,1.0898,1207431.3999999999],[1637439300000,1.0897,1.0908,1.0892,1.0894,818445.8],[1637439600000,1.0893,1.0904,1.0884,1.0902,963286.2],[1637439900000,1.0903,1.0915,1.0893,1.0902,1062387.6000000001],[1637440200000,1.0903,1.0909,1.089,1.0895,818111.2],[1637440500000,1.0895,1.0906,1.0894,1.0904,423345.4],[1637440800000,1.0905,1.0908,1.0899,1.0903,589835.3],[1637441100000,1.0904,1.091,1.0891,1.0908,1313067.3],[1637441400000,1.0908,1.0918,1.0905,1.0908,627179.8],[1637441700000,1.0909,1.0932,1.0908,1.0926,1093904.2],[1637442000000,1.0926,1.0927,1.09,1.0902,1134073.1000000001],[1637442300000,1.0902,1.0902,1.0886,1.0899,967459.1],[1637442600000,1.0899,1.0922,1.0897,1.0919,1200459.6000000001],[1637442900000,1.0919,1.0925,1.0902,1.0903,577084.6],[1637443200000,1.0904,1.0916,1.0901,1.0908,516103.0],[1637443500000,1.0907,1.0924,1.0907,1.0915,1033097.5],[1637443800000,1.0916,1.0937,1.0911,1.0924,1445591.8999999999],[1637444100000,1.0924,1.0939,1.0917,1.0939,730517.6],[1637444400000,1.0939,1.0949,1.0928,1.0934,1642349.3],[1637444700000,1.0934,1.0946,1.0934,1.0939,586339.8],[1637445000000,1.0939,1.095,1.0927,1.0927,597216.7],[1637445300000,1.0927,1.0936,1.0922,1.0929,1007741.2],[1637445600000,1.0929,1.0946,1.0927,1.0935,868797.3],[1637445900000,1.0937,1.0938,1.0916,1.0926,802146.7],[1637446200000,1.0925,1.0934,1.0916,1.0919,857952.7],[1637446500000,1.0919,1.0939,1.0919,1.0935,438778.0],[1637446800000,1.0935,1.0938,1.0917,1.0935,1225414.7],[1637447100000,1.0936,1.0947,1.0935,1.0939,586802.1],[1637447400000,1.0939,1.0941,1.0936,1.0941,349812.6],[1637447700000,1.094,1.0948,1.0936,1.0945,664782.5],[1637448000000,1.0946,1.0963,1.0945,1.0958,1088906.8999999999],[1637448300000,1.0958,1.0966,1.0951,1.0953,876719.8],[1637448600000,1.0953,1.0954,1.0945,1.0948,509822.1],[1637448900000,1.0948,1.0969,1.0942,1.0961,1505118.8999999999],[1637449200000,1.096,1.097,1.0957,1.0965,1148066.1000000001],[1637449500000,1.0966,1.098,1.0948,1.0976,1567379.7],[1637449800000,1.0976,1.098,1.095,1.0956,998647.3],[1637450100000,1.0956,1.0969,1.0952,1.0953,750595.9],[1637450400000,1.0954,1.0956,1.0927,1.0935,1621045.8],[1637450700000,1.0935,1.0952,1.0928,1.0937,925914.1],[1637451000000,1.0937,1.0961,1.0937,1.0953,695201.5],[1637451300000,1.0954,1.0972,1.0953,1.0968,676331.4],[1637451600000,1.0969,1.0977,1.0961,1.097,770746.1],[1637451900000,1.0971,1.098,1.0962,1.0971,784673.1],[1637452200000,1.097,1.0987,1.0961,1.0978,1375433.6000000001],[1637452500000,1.0978,1.0978,1.0956,1.0976,1412024.6000000001],[1637452800000,1.0975,1.0988,1.0951,1.0962,1990264.8999999999],[1637453100000,1.0962,1.0969,1.0946,1.095,780066.8],[1637453400000,1.095,1.0977,1.0937,1.0975,1258294.2],[1637453700000,1.0975,1.0981,1.0924,1.0931,1243792.3],[1637454000000,1.093,1.0956,1.0922,1.094,1261851.6000000001],[1637454300000,1.094,1.0941,1.0915,1.0924,999709.6],[1637454600000,1.0924,1.0926,1.0906,1.0917,1183609.0],[1637454900000,1.0917,1.0926,1.0906,1.0925,997068.5],[1637455200000,1.0924,1.094,1.0923,1.0929,969486.3],[1637455500000,1.0929,1.0935,1.0911,1.0917,781625.8],[1637455800000,1.0917,1.0924,1.0903,1.0912,721801.4],[1637456100000,1.0912,1.0918,1.0901,1.0903,1098562.5],[1637456400000,1.0903,1.0935,1.0903,1.0924,1184347.7],[1637456700000,1.0924,1.0927,1.0911,1.0911,581214.6],[1637457000000,1.0911,1.0932,1.0911,1.0926,726532.9],[1637457300000,1.0925,1.093,1.0911,1.0911,719980.4],[1637457600000,1.0911,1.0918,1.0904,1.0915,453159.2],[1637457900000,1.0914,1.0918,1.0909,1.0909,370430.5],[1637458200000,1.091,1.0911,1.0886,1.09,2121856.8999999999],[1637458500000,1.09,1.0915,1.0898,1.0904,700277.1],[1637458800000,1.0903,1.0907,1.0891,1.0903,473211.3],[1637459100000,1.0903,1.0921,1.087,1.0874,1230450.3],[1637459400000,1.0875,1.0888,1.086,1.0875,1717497.0],[1637459700000,1.0875,1.0894,1.0873,1.0888,784000.5],[1637460000000,1.0888,1.0894,1.0875,1.0891,767362.7],[1637460300000,1.0891,1.0898,1.0882,1.0889,409101.5],[1637460600000,1.089,1.089,1.0863,1.0865,799687.8],[1637460900000,1.0865,1.0875,1.0864,1.0875,478476.7],[1637461200000,1.0874,1.0876,1.0848,1.0852,1712651.7],[1637461500000,1.0852,1.0864,1.0833,1.0835,1532113.7],[1637461800000,1.0835,1.085,1.0783,1.0805,5003637.0999999996],[1637462100000,1.0805,1.0815,1.0732,1.0741,5105530.0],[1637462400000,1.0741,1.0777,1.074,1.0766,2968626.1000000001],[1637462700000,1.0766,1.0789,1.0764,1.0787,1551175.6000000001],[1637463000000,1.0788,1.0791,1.0777,1.0783,1160593.5],[1637463300000,1.0783,1.0811,1.0763,1.0802,1934711.2],[1637463600000,1.0803,1.0809,1.0774,1.0787,1737260.7],[1637463900000,1.0787,1.0824,1.0786,1.0811,1311801.0],[1637464200000,1.081,1.0835,1.0808,1.0819,1937098.3],[1637464500000,1.0819,1.0819,1.0793,1.0804,1190680.3999999999],[1637464800000,1.0803,1.0817,1.0795,1.0795,1084963.5],[1637465100000,1.0795,1.0809,1.0783,1.0796,1058532.3999999999],[1637465400000,1.0796,1.0803,1.0787,1.0791,653388.2],[1637465700000,1.0792,1.0808,1.0786,1.0786,934467.7],[1637466000000,1.0786,1.079,1.0771,1.0773,922674.1],[1637466300000,1.0773,1.078,1.0765,1.0775,748529.9],[1637466600000,1.0775,1.0781,1.0743,1.0776,1872877.2],[1637466900000,1.0776,1.0779,1.0751,1.077,910629.8],[1637467200000,1.0769,1.0791,1.0751,1.0791,1420191.3],[1637467500000,1.0791,1.0798,1.0777,1.0792,1197974.1000000001],[1637467800000,1.0792,1.0819,1.0792,1.0802,1130051.8],[1637468100000,1.0802,1.0825,1.0794,1.0803,1201338.2],[1637468400000,1.0803,1.0814,1.0799,1.0803,480717.8],[1637468700000,1.0804,1.081,1.0788,1.0788,1022164.1],[1637469000000,1.0788,1.0803,1.0783,1.0801,758983.6],[1637469300000,1.08,1.08,1.0775,1.0786,825612.3],[1637469600000,1.0785,1.0788,1.0775,1.0786,511487.8],[1637469900000,1.0786,1.0787,1.0767,1.0775,987343.4],[1637470200000,1.0776,1.0777,1.0759,1.0767,718581.7],[1637470500000,1.0767,1.0773,1.0758,1.0767,547054.9],[1637470800000,1.0768,1.078,1.0758,1.0771,547032.8],[1637471100000,1.0772,1.079,1.0765,1.077,660939.3],[1637471400000,1.0769,1.0786,1.0766,1.078,856206.1],[1637471700000,1.078,1.0792,1.0776,1.0777,476814.3],[1637472000000,1.0777,1.0786,1.0777,1.0781,335511.9],[1637472300000,1.078,1.079,1.0777,1.0784,391906.0],[1637472600000,1.0785,1.0823,1.0782,1.0821,1189955.7],[1637472900000,1.082,1.0825,1.081,1.0821,876731.4],[1637473200000,1.0822,1.0832,1.0809,1.0823,696226.2],[1637473500000,1.0822,1.0838,1.0819,1.0832,853775.1],[1637473800000,1.0832,1.0843,1.0832,1.0841,696519.2],[1637474100000,1.0841,1.0857,1.0825,1.0853,1808459.5],[1637474400000,1.0853,1.0854,1.0835,1.0837,1168583.8],[1637474700000,1.0837,1.0839,1.0821,1.0832,783244.2],[1637475000000,1.0832,1.0833,1.0821,1.0828,452212.4],[1637475300000,1.0828,1.0838,1.0825,1.0833,301469.1],[1637475600000,1.0834,1.0835,1.0812,1.0814,464090.7],[1637475900000,1.0815,1.0815,1.0802,1.0805,767040.1],[1637476200000,1.0805,1.0843,1.0805,1.0838,883357.9],[1637476500000,1.0838,1.0839,1.0804,1.0808,579035.1],[1637476800000,1.0808,1.0819,1.0795,1.0806,797439.9],[1637477100000,1.0805,1.0825,1.0801,1.0823,825426.5],[1637477400000,1.0822,1.0825,1.081,1.0812,547369.3],[1637477700000,1.0813,1.085,1.0812,1.0847,1108606.1000000001],[1637478000000,1.0847,1.0903,1.0831,1.0831,4807307.0],[1637478300000,1.0831,1.0847,1.0828,1.0843,650309.2],[1637478600000,1.0843,1.0844,1.0829,1.0834,771278.2],[1637478900000,1.0835,1.0835,1.0811,1.0824,793377.3],[1637479200000,1.0824,1.084,1.0822,1.0828,513116.3],[1637479500000,1.0828,1.0842,1.0821,1.0827,919236.9],[1637479800000,1.0827,1.0847,1.0827,1.0843,549662.5],[1637480100000,1.0842,1.0845,1.0825,1.0829,707142.8],[1637480400000,1.0829,1.0839,1.0818,1.0831,522142.3],[1637480700000,1.0832,1.0837,1.0813,1.0813,552156.2],[1637481000000,1.0813,1.0821,1.081,1.0813,532391.4],[1637481300000,1.0812,1.0813,1.0795,1.0803,834204.0],[1637481600000,1.0804,1.0813,1.079,1.0793,978148.0],[1637481900000,1.0793,1.0797,1.0765,1.077,1781373.8999999999],[1637482200000,1.077,1.0782,1.0742,1.0778,2554242.6000000001],[1637482500000,1.0778,1.0781,1.0743,1.075,1286432.1000000001],[1637482800000,1.0749,1.0774,1.0742,1.0769,1188115.7],[1637483100000,1.0769,1.0776,1.0744,1.0758,1387133.6000000001],[1637483400000,1.0759,1.0776,1.0748,1.0767,1571797.6000000001],[1637483700000,1.0768,1.0796,1.0767,1.0787,1558711.2],[1637484000000,1.0787,1.079,1.077,1.0776,1283710.6000000001],[1637484300000,1.0776,1.0776,1.0741,1.0742,1409473.3999999999],[1637484600000,1.0741,1.0753,1.0705,1.071,2226765.7999999998],[1637484900000,1.071,1.0738,1.07,1.0723,2707738.7000000002],[1637485200000,1.0722,1.0743,1.0711,1.074,1182262.2],[1637485500000,1.0741,1.0745,1.0728,1.0736,788009.3],[1637485800000,1.0736,1.0761,1.0733,1.0749,1058760.1000000001],[1637486100000,1.0749,1.0759,1.0745,1.0752,1119925.5],[1637486400000,1.0751,1.0762,1.0742,1.0749,910704.1],[1637486700000,1.0749,1.0765,1.0737,1.0738,1493216.8999999999],[1637487000000,1.0738,1.0756,1.0729,1.0741,1005417.0],[1637487300000,1.0741,1.0755,1.0728,1.0753,829939.0],[1637487600000,1.0752,1.0765,1.074,1.0744,809630.2],[1637487900000,1.0744,1.0759,1.0738,1.0746,717923.0],[1637488200000,1.0746,1.0765,1.0745,1.0756,820078.8],[1637488500000,1.0756,1.0783,1.0747,1.0779,1040966.2],[1637488800000,1.0779,1.0786,1.0775,1.0778,1053125.2],[1637489100000,1.0779,1.0783,1.0769,1.0779,811140.6],[1637489400000,1.0778,1.0779,1.0758,1.0762,650018.8],[1637489700000,1.0761,1.0793,1.0758,1.0788,1671629.0],[1637490000000,1.0788,1.0788,1.0768,1.0772,866999.2],[1637490300000,1.0773,1.0789,1.0768,1.0768,732410.1],[1637490600000,1.0768,1.0771,1.0737,1.0751,1686388.0],[1637490900000,1.075,1.0755,1.074,1.074,631987.9],[1637491200000,1.074,1.0743,1.0701,1.0724,2901798.5],[1637491500000,1.0724,1.0754,1.0715,1.0747,1143065.3],[1637491800000,1.0746,1.0766,1.0744,1.076,1246851.5],[1637492100000,1.076,1.0762,1.0745,1.0756,800906.1],[1637492400000,1.0756,1.0809,1.0745,1.0783,4955742.4000000004],[1637492700000,1.0782,1.0809,1.0774,1.079,2248110.1000000001],[1637493000000,1.079,1.0792,1.0767,1.0769,1823132.5],[1637493300000,1.077,1.0771,1.0708,1.0715,3368298.1000000001],[1637493600000,1.0715,1.0716,1.0652,1.071,6452206.2999999998],[1637493900000,1.0709,1.0711,1.0678,1.0694,1547093.3],[1637494200000,1.0694,1.0719,1.0685,1.0713,1943760.0],[1637494500000,1.0712,1.073,1.0704,1.0714,995341.1],[1637494800000,1.0714,1.0715,1.069,1.0714,1160709.3],[1637495100000,1.0714,1.073,1.0709,1.0721,1085871.3999999999],[1637495400000,1.0721,1.0731,1.0716,1.0723,958377.4],[1637495700000,1.0724,1.0734,1.0722,1.0726,442414.5],[1637496000000,1.0727,1.0727,1.07,1.0713,1616334.3999999999],[1637496300000,1.0713,1.0721,1.0711,1.0721,590388.2],[1637496600000,1.0721,1.0765,1.0721,1.0759,2206257.2000000002],[1637496900000,1.0759,1.0776,1.0743,1.0759,1760184.6000000001],[1637497200000,1.0759,1.0767,1.0749,1.0753,997043.0],[1637497500000,1.0754,1.0763,1.0748,1.0759,945988.8],[1637497800000,1.0759,1.0771,1.0737,1.074,1312225.7],[1637498100000,1.0741,1.0745,1.0724,1.0733,896465.1],[1637498400000,1.0734,1.0734,1.0714,1.0731,1280526.7],[1637498700000,1.073,1.0752,1.0727,1.0729,1084723.7],[1637499000000,1.073,1.0755,1.0729,1.0752,948844.9],[1637499300000,1.0751,1.0752,1.0732,1.0736,761256.9],[1637499600000,1.0736,1.0745,1.0728,1.073,724334.7],[1637499900000,1.0729,1.074,1.0724,1.0725,410581.6],[1637500200000,1.0725,1.0738,1.0714,1.0723,825709.7],[1637500500000,1.0724,1.0741,1.0722,1.0731,541109.7],[1637500800000,1.0731,1.0741,1.0729,1.0736,602113.7],[1637501100000,1.0736,1.0738,1.0718,1.072,772796.4],[1637501400000,1.072,1.0728,1.0706,1.0707,639585.1],[1637501700000,1.0708,1.0712,1.0672,1.0699,3931510.2999999998],[1637502000000,1.0699,1.0701,1.0681,1.0694,846705.8],[1637502300000,1.0693,1.0715,1.0688,1.0702,1041782.8],[1637502600000,1.0702,1.071,1.0685,1.069,1044235.0],[1637502900000,1.069,1.0695,1.0663,1.0678,2842689.8999999999],[1637503200000,1.0678,1.0679,1.0638,1.0676,3331142.2000000002],[1637503500000,1.0677,1.0677,1.0658,1.0661,1509472.6000000001],[1637503800000,1.066,1.0694,1.066,1.0686,1594643.8999999999],[1637504100000,1.0686,1.0694,1.0671,1.0673,934328.6],[1637504400000,1.0673,1.0698,1.0673,1.0696,907421.8],[1637504700000,1.0697,1.0698,1.0678,1.0685,700061.7],[1637505000000,1.0685,1.0712,1.0669,1.0709,1578725.6000000001],[1637505300000,1.0709,1.0729,1.0705,1.0724,3502201.0],[1637505600000,1.0724,1.074,1.0716,1.0733,1390219.3],[1637505900000,1.0735,1.0745,1.0717,1.0722,1348645.0],[1637506200000,1.0721,1.0741,1.0711,1.0736,1267274.8999999999],[1637506500000,1.0736,1.0741,1.07,1.0701,2498196.3999999999],[1637506800000,1.07,1.0705,1.0685,1.0697,1205914.8999999999],[1637507100000,1.0696,1.0728,1.0696,1.0728,996615.6],[1637507400000,1.0728,1.0728,1.0704,1.0713,863754.8],[1637507700000,1.0713,1.0734,1.0709,1.0734,1053392.6000000001],[1637508000000,1.0734,1.074,1.0723,1.074,733229.2],[1637508300000,1.0739,1.0794,1.0739,1.079,3367813.3999999999],[1637508600000,1.079,1.0793,1.0768,1.0782,1781674.3999999999],[1637508900000,1.0783,1.0788,1.0775,1.0783,1179503.3999999999],[1637509200000,1.0783,1.0818,1.0782,1.08,2515741.7999999998],[1637509500000,1.0801,1.0805,1.0786,1.0795,1321868.2],[1637509800000,1.0795,1.0807,1.0791,1.0801,1287931.0],[1637510100000,1.0801,1.0804,1.0787,1.0788,1565686.1000000001],[1637510400000,1.0787,1.0814,1.0786,1.0805,1763473.7],[1637510700000,1.0806,1.0838,1.0805,1.0823,2995209.7999999998],[1637511000000,1.0824,1.0826,1.0807,1.0809,1521309.6000000001],[1637511300000,1.081,1.0812,1.0772,1.0793,1840075.8],[1637511600000,1.0792,1.0798,1.0765,1.0776,1690043.6000000001],[1637511900000,1.0775,1.078,1.0754,1.0755,1063176.8999999999],[1637512200000,1.0756,1.077,1.0754,1.0769,1187972.8],[1637512500000,1.0769,1.0769,1.0749,1.0762,1593978.7],[1637512800000,1.0763,1.079,1.0762,1.0786,1059333.8999999999],[1637513100000,1.0786,1.083,1.0784,1.0823,3005583.8999999999],[1637513400000,1.0823,1.0853,1.0811,1.0848,3877599.2999999998],[1637513700000,1.0849,1.0864,1.0839,1.0854,3246257.0],[1637514000000,1.0854,1.0867,1.0818,1.0824,5822200.0999999996],[1637514300000,1.0825,1.084,1.08,1.0817,3095709.1000000001],[1637514600000,1.0818,1.0839,1.0813,1.0828,1452589.8],[1637514900000,1.0829,1.0847,1.0824,1.084,973392.1],[1637515200000,1.0841,1.0855,1.0832,1.0842,1350230.5],[1637515500000,1.0843,1.0855,1.0839,1.0839,1418790.7],[1637515800000,1.084,1.0849,1.082,1.0831,1278012.6000000001],[1637516100000,1.083,1.0845,1.0809,1.0812,1221282.8999999999],[1637516400000,1.0811,1.0828,1.081,1.0814,946701.2],[1637516700000,1.0813,1.0816,1.0799,1.08,1185232.1000000001],[1637517000000,1.0801,1.0811,1.0797,1.0805,814544.5],[1637517300000,1.0804,1.081,1.0797,1.0802,743002.3],[1637517600000,1.0804,1.081,1.0783,1.0784,1149454.1000000001],[1637517900000,1.0783,1.0805,1.0771,1.0796,1361561.5],[1637518200000,1.0797,1.0807,1.0791,1.0806,835282.1],[1637518500000,1.0807,1.0809,1.0793,1.0799,712053.8],[1637518800000,1.0799,1.0808,1.0778,1.0779,664907.9],[1637519100000,1.0779,1.0792,1.0765,1.0779,1317777.8],[1637519400000,1.078,1.0784,1.077,1.0783,414788.8],[1637519700000,1.0783,1.0799,1.0783,1.0786,447598.1],[1637520000000,1.0786,1.0794,1.0785,1.0792,348289.5],[1637520300000,1.0791,1.081,1.0781,1.0785,1278199.5],[1637520600000,1.0786,1.0802,1.0785,1.0801,636711.5],[1637520900000,1.0801,1.0808,1.0789,1.0801,701731.7],[1637521200000,1.0801,1.0817,1.08,1.0813,845379.6],[1637521500000,1.0812,1.0815,1.0778,1.0778,887534.6],[1637521800000,1.0777,1.0792,1.0775,1.0776,598421.4],[1637522100000,1.0776,1.0786,1.0744,1.0748,2436814.7000000002],[1637522400000,1.0748,1.0755,1.0627,1.0673,11657709.5999999996],[1637522700000,1.0674,1.0714,1.0674,1.0711,2419596.8999999999],[1637523000000,1.0712,1.0724,1.0709,1.0711,1822021.5],[1637523300000,1.071,1.0717,1.0692,1.0705,1204982.3999999999],[1637523600000,1.0706,1.0709,1.0688,1.0701,947123.0],[1637523900000,1.0701,1.0722,1.0678,1.0681,1683728.5],[1637524200000,1.0682,1.0691,1.0661,1.0682,1654263.7],[1637524500000,1.0683,1.07,1.0675,1.068,814100.6],[1637524800000,1.0681,1.071,1.068,1.0697,1127817.3],[1637525100000,1.0696,1.0714,1.0691,1.0708,1297767.2],[1637525400000,1.0707,1.0711,1.0695,1.0699,880530.2],[1637525700000,1.07,1.071,1.0696,1.0706,639251.1],[1637526000000,1.0706,1.0722,1.07,1.0711,1272377.8999999999],[1637526300000,1.071,1.0715,1.07,1.0715,766472.4],[1637526600000,1.0714,1.0723,1.0704,1.0719,912265.7],[1637526900000,1.0719,1.0742,1.0719,1.0727,1148654.3999999999],[1637527200000,1.0728,1.0741,1.0726,1.0734,1033655.7],[1637527500000,1.0734,1.0739,1.0727,1.0735,580060.4],[1637527800000,1.0734,1.0764,1.0734,1.0759,956301.3],[1637528100000,1.0759,1.0774,1.0755,1.076,1718106.0],[1637528400000,1.0759,1.0772,1.0743,1.0746,1695191.3999999999],[1637528700000,1.0747,1.076,1.0744,1.0753,754169.2],[1637529000000,1.0753,1.0753,1.0728,1.074,1454014.0],[1637529300000,1.074,1.0761,1.0738,1.0754,789771.2],[1637529600000,1.0753,1.077,1.0751,1.0768,708803.5],[1637529900000,1.0767,1.0781,1.0761,1.0775,953198.1],[1637530200000,1.0775,1.0784,1.0765,1.0771,1015064.0],[1637530500000,1.077,1.0777,1.0744,1.0751,1236336.5],[1637530800000,1.0752,1.0776,1.0751,1.0773,596424.3],[1637531100000,1.0773,1.0773,1.0753,1.0755,883756.5],[1637531400000,1.0755,1.0763,1.0736,1.0739,1046835.3],[1637531700000,1.0739,1.0753,1.0738,1.0752,485188.2],[1637532000000,1.0751,1.0759,1.073,1.074,1138527.0],[1637532300000,1.0741,1.0744,1.0732,1.0735,749520.8],[1637532600000,1.0736,1.0756,1.0735,1.0752,763636.5],[1637532900000,1.0753,1.0762,1.0753,1.0758,369235.1],[1637533200000,1.0759,1.0762,1.0736,1.0742,820142.4],[1637533500000,1.0742,1.0745,1.0721,1.0734,876413.1],[1637533800000,1.0733,1.0737,1.0711,1.0713,765844.7]] \ No newline at end of file diff --git a/tests/testdata/futures/XRP_USDT-8h-funding_rate.json b/tests/testdata/futures/XRP_USDT_USDT-8h-funding_rate.json similarity index 100% rename from tests/testdata/futures/XRP_USDT-8h-funding_rate.json rename to tests/testdata/futures/XRP_USDT_USDT-8h-funding_rate.json diff --git a/tests/testdata/futures/XRP_USDT-8h-mark.json b/tests/testdata/futures/XRP_USDT_USDT-8h-mark.json similarity index 100% rename from tests/testdata/futures/XRP_USDT-8h-mark.json rename to tests/testdata/futures/XRP_USDT_USDT-8h-mark.json