diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5024a34fe..2e0e682dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -276,14 +276,23 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Pip cache (Windows) - uses: actions/cache@v4 + - name: Install uv + uses: astral-sh/setup-uv@v4 with: - path: ~\AppData\Local\pip\Cache - key: pip-${{ matrix.os }}-${{ matrix.python-version }} + enable-cache: true + cache-dependency-glob: "requirements**.txt" + cache-suffix: "${{ matrix.python-version }}" + prune-cache: false - name: Installation run: | + uv venv + .venv\Scripts\activate + # persist the venv path for future steps + "$(pwd)/.venv/Scripts" >> $env:GITHUB_PATH + + function uvpipFunction { uv pip $args } + Set-Alias -name pip -value uvpipFunction ./build_helpers/install_windows.ps1 - name: Tests @@ -517,13 +526,40 @@ jobs: ft_client/dist retention-days: 10 - deploy-pypi: - name: "Deploy to PyPI" + deploy-test-pypi: + name: "Publish Python 🐍 distribution 📦 to TestPyPI" needs: [ build ] runs-on: ubuntu-22.04 if: (github.event_name == 'release') environment: - name: release + name: testpypi + url: https://test.pypi.org/p/freqtrade + permissions: + id-token: write + + steps: + - uses: actions/checkout@v4 + + - name: Download artifact 📦 + uses: actions/download-artifact@v4 + with: + pattern: freqtrade*-build + path: dist + merge-multiple: true + + - name: Publish to PyPI (Test) + uses: pypa/gh-action-pypi-publish@v1.12.3 + with: + repository-url: https://test.pypi.org/legacy/ + + + deploy-pypi: + name: "Publish Python 🐍 distribution 📦 to PyPI" + needs: [ build ] + runs-on: ubuntu-22.04 + if: (github.event_name == 'release') + environment: + name: pypi url: https://pypi.org/p/freqtrade permissions: id-token: write @@ -538,14 +574,8 @@ jobs: path: dist merge-multiple: true - - - name: Publish to PyPI (Test) - uses: pypa/gh-action-pypi-publish@v1.12.2 - with: - repository-url: https://test.pypi.org/legacy/ - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@v1.12.2 + uses: pypa/gh-action-pypi-publish@v1.12.3 deploy-docker: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dbc627c33..037234fb2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,8 +17,8 @@ repos: - types-cachetools==5.5.0.20240820 - types-filelock==3.2.7 - types-requests==2.32.0.20241016 - - types-tabulate==0.9.0.20240106 - - types-python-dateutil==2.9.0.20241003 + - types-tabulate==0.9.0.20241207 + - types-python-dateutil==2.9.0.20241206 - SQLAlchemy==2.0.36 # stages: [push] @@ -31,7 +31,7 @@ repos: - repo: https://github.com/charliermarsh/ruff-pre-commit # Ruff version. - rev: 'v0.8.0' + rev: 'v0.8.3' hooks: - id: ruff - id: ruff-format @@ -56,6 +56,11 @@ repos: .*\.md )$ + - repo: https://github.com/stefmolin/exif-stripper + rev: 0.6.1 + hooks: + - id: strip-exif + - repo: https://github.com/codespell-project/codespell rev: v2.3.0 hooks: diff --git a/build_helpers/TA_Lib-0.4.32-cp310-cp310-win_amd64.whl b/build_helpers/TA_Lib-0.4.32-cp310-cp310-win_amd64.whl deleted file mode 100644 index d31d63db8..000000000 Binary files a/build_helpers/TA_Lib-0.4.32-cp310-cp310-win_amd64.whl and /dev/null differ diff --git a/build_helpers/TA_Lib-0.4.32-cp311-cp311-linux_armv7l.whl b/build_helpers/TA_Lib-0.4.32-cp311-cp311-linux_armv7l.whl deleted file mode 100644 index e69bdd97d..000000000 Binary files a/build_helpers/TA_Lib-0.4.32-cp311-cp311-linux_armv7l.whl and /dev/null differ diff --git a/build_helpers/TA_Lib-0.4.32-cp311-cp311-win_amd64.whl b/build_helpers/TA_Lib-0.4.32-cp311-cp311-win_amd64.whl deleted file mode 100644 index e992ece01..000000000 Binary files a/build_helpers/TA_Lib-0.4.32-cp311-cp311-win_amd64.whl and /dev/null differ diff --git a/build_helpers/TA_Lib-0.4.32-cp312-cp312-win_amd64.whl b/build_helpers/TA_Lib-0.4.32-cp312-cp312-win_amd64.whl deleted file mode 100644 index 98845c409..000000000 Binary files a/build_helpers/TA_Lib-0.4.32-cp312-cp312-win_amd64.whl and /dev/null differ diff --git a/build_helpers/install_windows.ps1 b/build_helpers/install_windows.ps1 index 4aa070992..919d8b7da 100644 --- a/build_helpers/install_windows.ps1 +++ b/build_helpers/install_windows.ps1 @@ -1,11 +1,10 @@ # vendored Wheels compiled via https://github.com/xmatthias/ta-lib-python/tree/ta_bundled_040 -python -m pip install --upgrade pip wheel +python -m pip install --upgrade pip +python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" -$pyv = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" - - -pip install --find-links=build_helpers\ --prefer-binary TA-Lib +pip install -U wheel "numpy<2" +pip install --only-binary ta-lib --find-links=build_helpers\ ta-lib pip install -r requirements-dev.txt pip install -e . diff --git a/build_helpers/pyarrow-18.0.0-cp311-cp311-linux_armv7l.whl b/build_helpers/pyarrow-18.1.0-cp311-cp311-linux_armv7l.whl similarity index 66% rename from build_helpers/pyarrow-18.0.0-cp311-cp311-linux_armv7l.whl rename to build_helpers/pyarrow-18.1.0-cp311-cp311-linux_armv7l.whl index adb13b65f..d40603a5f 100644 Binary files a/build_helpers/pyarrow-18.0.0-cp311-cp311-linux_armv7l.whl and b/build_helpers/pyarrow-18.1.0-cp311-cp311-linux_armv7l.whl differ diff --git a/build_helpers/schema.json b/build_helpers/schema.json index e12b0bf0d..73c06ba46 100644 --- a/build_helpers/schema.json +++ b/build_helpers/schema.json @@ -102,8 +102,17 @@ }, "dry_run_wallet": { "description": "Initial wallet balance for dry run mode.", - "type": "number", - "default": 1000 + "type": [ + "number", + "object" + ], + "default": 1000, + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "number" + } + }, + "additionalProperties": false }, "cancel_open_orders_on_exit": { "description": "Cancel open orders when exiting.", diff --git a/build_helpers/ta_lib-0.4.34-cp310-cp310-win_amd64.whl b/build_helpers/ta_lib-0.4.34-cp310-cp310-win_amd64.whl new file mode 100644 index 000000000..32bb10e4f Binary files /dev/null and b/build_helpers/ta_lib-0.4.34-cp310-cp310-win_amd64.whl differ diff --git a/build_helpers/ta_lib-0.4.34-cp311-cp311-linux_armv7l.whl b/build_helpers/ta_lib-0.4.34-cp311-cp311-linux_armv7l.whl new file mode 100644 index 000000000..581361925 Binary files /dev/null and b/build_helpers/ta_lib-0.4.34-cp311-cp311-linux_armv7l.whl differ diff --git a/build_helpers/ta_lib-0.4.34-cp311-cp311-win_amd64.whl b/build_helpers/ta_lib-0.4.34-cp311-cp311-win_amd64.whl new file mode 100644 index 000000000..3513df4ba Binary files /dev/null and b/build_helpers/ta_lib-0.4.34-cp311-cp311-win_amd64.whl differ diff --git a/build_helpers/ta_lib-0.4.34-cp312-cp312-win_amd64.whl b/build_helpers/ta_lib-0.4.34-cp312-cp312-win_amd64.whl new file mode 100644 index 000000000..212668e58 Binary files /dev/null and b/build_helpers/ta_lib-0.4.34-cp312-cp312-win_amd64.whl differ diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index 480b20daf..b12d8f5b6 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -39,6 +39,7 @@ class SuperDuperHyperOptLoss(IHyperOptLoss): config: Config, processed: dict[str, DataFrame], backtest_stats: dict[str, Any], + starting_balance: float, **kwargs, ) -> float: """ @@ -70,6 +71,7 @@ Currently, the arguments are: * `config`: Config object used (Note: Not all strategy-related parameters will be updated here if they are part of a hyperopt space). * `processed`: Dict of Dataframes with the pair as keys containing the data used for backtesting. * `backtest_stats`: Backtesting statistics using the same format as the backtesting file "strategy" substructure. Available fields can be seen in `generate_strategy_stats()` in `optimize_reports.py`. +* `starting_balance`: Starting balance used for backtesting. This function needs to return a floating point number (`float`). Smaller numbers will be interpreted as better results. The parameters and balancing for this is up to you. diff --git a/docs/advanced-orderflow.md b/docs/advanced-orderflow.md index 22a28fe87..9769b8e92 100644 --- a/docs/advanced-orderflow.md +++ b/docs/advanced-orderflow.md @@ -4,6 +4,7 @@ This guide walks you through utilizing public trade data for advanced orderflow !!! Warning "Experimental Feature" The orderflow feature is currently in beta and may be subject to changes in future releases. Please report any issues or feedback on the [Freqtrade GitHub repository](https://github.com/freqtrade/freqtrade/issues). + It's also currently not been tested with freqAI - and combining these two features is considered out of scope at this point. !!! Warning "Performance" Orderflow requires raw trades data. This data is rather large, and can cause a slow initial startup, when freqtrade needs to download the trades data for the last X candles. Additionally, enabling this feature will cause increased memory usage. Please ensure to have sufficient resources available. diff --git a/docs/assets/frequi-login-CORS-light.png b/docs/assets/frequi-login-CORS-light.png index 019ae4e8c..cf6d7a700 100644 Binary files a/docs/assets/frequi-login-CORS-light.png and b/docs/assets/frequi-login-CORS-light.png differ diff --git a/docs/assets/telegram_forcebuy.png b/docs/assets/telegram_forcebuy.png index b0592bff3..a75db99b0 100644 Binary files a/docs/assets/telegram_forcebuy.png and b/docs/assets/telegram_forcebuy.png differ diff --git a/docs/configuration.md b/docs/configuration.md index 9c46b7546..fdddf7cda 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -39,13 +39,19 @@ Please note that Environment variables will overwrite corresponding settings in Common example: -``` +``` bash FREQTRADE__TELEGRAM__CHAT_ID= FREQTRADE__TELEGRAM__TOKEN= FREQTRADE__EXCHANGE__KEY= FREQTRADE__EXCHANGE__SECRET= ``` +Json lists are parsed as json - so you can use the following to set a list of pairs: + +``` bash +export FREQTRADE__EXCHANGE__PAIR_WHITELIST='["BTC/USDT", "ETH/USDT"]' +``` + !!! Note Environment variables detected are logged at startup - so if you can't find why a value is not what you think it should be based on the configuration, make sure it's not loaded from an environment variable. @@ -54,7 +60,7 @@ FREQTRADE__EXCHANGE__SECRET= ??? Warning "Loading sequence" Environment variables are loaded after the initial configuration. As such, you cannot provide the path to the configuration through environment variables. Please use `--config path/to/config.json` for that. - This also applies to user_dir to some degree. while the user directory can be set through environment variables - the configuration will **not** be loaded from that location. + This also applies to `user_dir` to some degree. while the user directory can be set through environment variables - the configuration will **not** be loaded from that location. ### Multiple configuration files @@ -168,7 +174,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `timeframe` | The timeframe to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). Usually missing in configuration, and specified in the strategy. [Strategy Override](#parameters-in-the-strategy).
**Datatype:** String | `fiat_display_currency` | Fiat currency used to show your profits. [More information below](#what-values-can-be-used-for-fiat_display_currency).
**Datatype:** String | `dry_run` | **Required.** Define if the bot must be in Dry Run or production mode.
*Defaults to `true`.*
**Datatype:** Boolean -| `dry_run_wallet` | Define the starting amount in stake currency for the simulated wallet used by the bot running in Dry Run mode.
*Defaults to `1000`.*
**Datatype:** Float +| `dry_run_wallet` | Define the starting amount in stake currency for the simulated wallet used by the bot running in Dry Run mode. [More information below](#dry-run-wallet)
*Defaults to `1000`.*
**Datatype:** Float or Dict | `cancel_open_orders_on_exit` | Cancel open orders when the `/stop` RPC command is issued, `Ctrl+C` is pressed or the bot dies unexpectedly. When set to `true`, this allows you to use `/stop` to cancel unfilled and partially filled orders in the event of a market crash. It does not impact open positions.
*Defaults to `false`.*
**Datatype:** Boolean | `process_only_new_candles` | Enable processing of indicators only when new candles arrive. If false each loop populates the indicators, this will mean the same candle is processed many times creating system load but can be useful of your strategy depends on tick data not only candle. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `true`.*
**Datatype:** Boolean | `minimal_roi` | **Required.** Set the threshold as ratio the bot will use to exit a trade. [More information below](#understand-minimal_roi). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** Dict @@ -225,6 +231,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `exchange.skip_open_order_update` | Skips open order updates on startup should the exchange cause problems. Only relevant in live conditions.
*Defaults to `false`*
**Datatype:** Boolean | `exchange.unknown_fee_rate` | Fallback value to use when calculating trading fees. This can be useful for exchanges which have fees in non-tradable currencies. The value provided here will be multiplied with the "fee cost".
*Defaults to `None`
**Datatype:** float | `exchange.log_responses` | Log relevant exchange responses. For debug mode only - use with care.
*Defaults to `false`*
**Datatype:** Boolean +| `exchange.only_from_ccxt` | Prevent data-download from data.binance.vision. Leaving this as false can greatly speed up downloads, but may be problematic if the site is not available.
*Defaults to `false`*
**Datatype:** Boolean | `experimental.block_bad_exchanges` | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now.
*Defaults to `true`.*
**Datatype:** Boolean | | **Plugins** | `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation of all possible configuration options. @@ -323,6 +330,25 @@ To limit this calculation in case of large stoploss values, the calculated minim !!! Warning Since the limits on exchanges are usually stable and are not updated often, some pairs can show pretty high minimum limits, simply because the price increased a lot since the last limit adjustment by the exchange. Freqtrade adjusts the stake-amount to this value, unless it's > 30% more than the calculated/desired stake-amount - in which case the trade is rejected. +#### Dry-run wallet + +When running in dry-run mode, the bot will use a simulated wallet to execute trades. The starting balance of this wallet is defined by `dry_run_wallet` (defaults to 1000). +For more complex scenarios, you can also assign a dictionary to `dry_run_wallet` to define the starting balance for each currency. + +```json +"dry_run_wallet": { + "BTC": 0.01, + "ETH": 2, + "USDT": 1000 +} +``` + +Command line options (`--dry-run-wallet`) can be used to override the configuration value, but only for the float value, not for the dictionary. If you'd like to use the dictionary, please adjust the configuration file. + +!!! Note + Balances not in stake-currency will not be used for trading, but are shown as part of the wallet balance. + On Cross-margin exchanges, the wallet balance may be used to calculate the available collateral for trading. + #### Tradable balance By default, the bot assumes that the `complete amount - 1%` is at it's disposal, and when using [dynamic stake amount](#dynamic-stake-amount), it will split the complete balance into `max_open_trades` buckets per trade. diff --git a/docs/faq.md b/docs/faq.md index 98b106899..a41e641f6 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -40,6 +40,10 @@ This could be caused by the following reasons: * The installation did not complete successfully. * Please check the [Installation documentation](installation.md). +### The bot starts, but in STOPPED mode + +Make sure you set the `initial_state` config option to `"running"` in your config.json + ### I have waited 5 minutes, why hasn't the bot made any trades yet? * Depending on the buy strategy, the amount of whitelisted coins, the diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 066a10766..f342680e2 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,6 +1,6 @@ markdown==3.7 mkdocs==1.6.1 -mkdocs-material==9.5.45 +mkdocs-material==9.5.48 mdx_truly_sane_lists==1.3 pymdown-extensions==10.12 jinja2==3.1.4 diff --git a/docs/rest-api.md b/docs/rest-api.md index 8c927d5d7..b958c0927 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -88,8 +88,9 @@ Make sure that the following 2 lines are available in your docker-compose file: ### Consuming the API -You can consume the API by using `freqtrade-client` (also available as `scripts/rest_client.py`). -This command can be installed independent of the bot by using `pip install freqtrade-client`. +We advise consuming the API by using the supported `freqtrade-client` package (also available as `scripts/rest_client.py`). + +This command can be installed independent of any running freqtrade bot by using `pip install freqtrade-client`. This module is designed to be lightweight, and only depends on the `requests` and `python-rapidjson` modules, skipping all heavy dependencies freqtrade otherwise needs. @@ -144,57 +145,6 @@ This method will work for all arguments - check the "show" command for a list of For a full list of available commands, please refer to the list below. -### Available endpoints - -| Command | Description | -|----------|-------------| -| `ping` | Simple command testing the API Readiness - requires no authentication. -| `start` | Starts the trader. -| `stop` | Stops the trader. -| `stopbuy` | Stops the trader from opening new trades. Gracefully closes open trades according to their rules. -| `reload_config` | Reloads the configuration file. -| `trades` | List last trades. Limited to 500 trades per call. -| `trade/` | Get specific trade. -| `trades/` | DELETE - Remove trade from the database. Tries to close open orders. Requires manual handling of this trade on the exchange. -| `trades//open-order` | DELETE - Cancel open order for this trade. -| `trades//reload` | GET - Reload a trade from the Exchange. Only works in live, and can potentially help recover a trade that was manually sold on the exchange. -| `show_config` | Shows part of the current configuration with relevant settings to operation. -| `logs` | Shows last log messages. -| `status` | Lists all open trades. -| `count` | Displays number of trades used and available. -| `entries [pair]` | Shows profit statistics for each enter tags for given pair (or all pairs if pair isn't given). Pair is optional. -| `exits [pair]` | Shows profit statistics for each exit reasons for given pair (or all pairs if pair isn't given). Pair is optional. -| `mix_tags [pair]` | Shows profit statistics for each combinations of enter tag + exit reasons for given pair (or all pairs if pair isn't given). Pair is optional. -| `locks` | Displays currently locked pairs. -| `delete_lock ` | Deletes (disables) the lock by id. -| `locks add , , [side], [reason]` | Locks a pair until "until". (Until will be rounded up to the nearest timeframe). -| `profit` | Display a summary of your profit/loss from close trades and some stats about your performance. -| `forceexit [order_type] [amount]` | Instantly exits the given trade (ignoring `minimum_roi`), using the given order type ("market" or "limit", uses your config setting if not specified), and the chosen amount (full sell if not specified). -| `forceexit all` | Instantly exits all open trades (Ignoring `minimum_roi`). -| `forceenter [rate]` | Instantly enters the given pair. Rate is optional. (`force_entry_enable` must be set to True) -| `forceenter [rate]` | Instantly longs or shorts the given pair. Rate is optional. (`force_entry_enable` must be set to True) -| `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). -| `weekly ` | Shows profit or loss per week, over the last n days (n defaults to 4). -| `monthly ` | Shows profit or loss per month, over the last n days (n defaults to 3). -| `stats` | Display a summary of profit / loss reasons as well as average holding times. -| `whitelist` | Show the current whitelist. -| `blacklist [pair]` | Show the current blacklist, or adds a pair to the blacklist. -| `edge` | Show validated pairs by Edge if it is enabled. -| `pair_candles` | Returns dataframe for a pair / timeframe combination while the bot is running. **Alpha** -| `pair_history` | Returns an analyzed dataframe for a given timerange, analyzed by a given strategy. **Alpha** -| `plot_config` | Get plot config from the strategy (or nothing if not configured). **Alpha** -| `strategies` | List strategies in strategy directory. **Alpha** -| `strategy ` | Get specific Strategy content. **Alpha** -| `available_pairs` | List available backtest data. **Alpha** -| `version` | Show version. -| `sysinfo` | Show information about the system load. -| `health` | Show bot health (last bot loop). - -!!! Warning "Alpha status" - Endpoints labeled with *Alpha status* above may change at any time without notice. - Possible commands can be listed from the rest-client script using the `help` command. ``` bash @@ -266,6 +216,14 @@ forceexit health Provides a quick health check of the running bot. +lock_add + Manually lock a specific pair + + :param pair: Pair to lock + :param until: Lock until this date (format "2024-03-30 16:00:00Z") + :param side: Side to lock (long, short, *) + :param reason: Reason for the lock + locks Return current locks @@ -353,6 +311,62 @@ whitelist ``` +### Available endpoints + +If you wish to call the REST API manually via another route, e.g. directly via `curl`, the table below shows the relevant URL endpoints and parameters. +All endpoints in the below table need to be prefixed with the base URL of the API, e.g. `http://127.0.0.1:8080/api/v1/` - so the command becomes `http://127.0.0.1:8080/api/v1/`. + +| Endpoint | Method | Description / Parameters | +|-----------|--------|--------------------------| +| `/ping` | GET | Simple command testing the API Readiness - requires no authentication. +| `/start` | POST | Starts the trader. +| `/stop` | POST | Stops the trader. +| `/stopbuy` | POST | Stops the trader from opening new trades. Gracefully closes open trades according to their rules. +| `/reload_config` | POST | Reloads the configuration file. +| `/trades` | GET | List last trades. Limited to 500 trades per call. +| `/trade/` | GET | Get specific trade.
*Params:*
- `tradeid` (`int`) +| `/trades/` | DELETE | Remove trade from the database. Tries to close open orders. Requires manual handling of this trade on the exchange.
*Params:*
- `tradeid` (`int`) +| `/trades//open-order` | DELETE | Cancel open order for this trade.
*Params:*
- `tradeid` (`int`) +| `/trades//reload` | POST | Reload a trade from the Exchange. Only works in live, and can potentially help recover a trade that was manually sold on the exchange.
*Params:*
- `tradeid` (`int`) +| `/show_config` | GET | Shows part of the current configuration with relevant settings to operation. +| `/logs` | GET | Shows last log messages. +| `/status` | GET | Lists all open trades. +| `/count` | GET | Displays number of trades used and available. +| `/entries` | GET | Shows profit statistics for each enter tags for given pair (or all pairs if pair isn't given). Pair is optional.
*Params:*
- `pair` (`str`) +| `/exits` | GET | Shows profit statistics for each exit reasons for given pair (or all pairs if pair isn't given). Pair is optional.
*Params:*
- `pair` (`str`) +| `/mix_tags` | GET | Shows profit statistics for each combinations of enter tag + exit reasons for given pair (or all pairs if pair isn't given). Pair is optional.
*Params:*
- `pair` (`str`) +| `/locks` | GET | Displays currently locked pairs. +| `/locks` | POST | Locks a pair until "until". (Until will be rounded up to the nearest timeframe). Side is optional and is either `long` or `short` (default is `long`). Reason is optional.
*Params:*
- `` (`str`)
- `` (`datetime`)
- `[side]` (`str`)
- `[reason]` (`str`) +| `/locks/` | DELETE | Deletes (disables) the lock by id.
*Params:*
- `lockid` (`int`) +| `/profit` | GET | Display a summary of your profit/loss from close trades and some stats about your performance. +| `/forceexit` | POST | Instantly exits the given trade (ignoring `minimum_roi`), using the given order type ("market" or "limit", uses your config setting if not specified), and the chosen amount (full sell if not specified). If `all` is supplied as the `tradeid`, then all currently open trades will be forced to exit.
*Params:*
- `` (`int` or `str`)
- `` (`str`)
- `[amount]` (`float`) +| `/forceenter` | POST | Instantly enters the given pair. Side is optional and is either `long` or `short` (default is `long`). Rate is optional. (`force_entry_enable` must be set to True)
*Params:*
- `` (`str`)
- `` (`str`)
- `[rate]` (`float`) +| `/performance` | GET | Show performance of each finished trade grouped by pair. +| `/balance` | GET | Show account balance per currency. +| `/daily` | GET | Shows profit or loss per day, over the last n days (n defaults to 7).
*Params:*
- `` (`int`) +| `/weekly` | GET | Shows profit or loss per week, over the last n days (n defaults to 4).
*Params:*
- `` (`int`) +| `/monthly` | GET | Shows profit or loss per month, over the last n days (n defaults to 3).
*Params:*
- `` (`int`) +| `/stats` | GET | Display a summary of profit / loss reasons as well as average holding times. +| `/whitelist` | GET | Show the current whitelist. +| `/blacklist` | GET | Show the current blacklist. +| `/blacklist` | POST | Adds the specified pair to the blacklist.
*Params:*
- `pair` (`str`) +| `/blacklist` | DELETE | Deletes the specified list of pairs from the blacklist.
*Params:*
- `[pair,pair]` (`list[str]`) +| `/edge` | GET | Show validated pairs by Edge if it is enabled. +| `/pair_candles` | GET | Returns dataframe for a pair / timeframe combination while the bot is running. **Alpha** +| `/pair_candles` | POST | Returns dataframe for a pair / timeframe combination while the bot is running, filtered by a provided list of columns to return. **Alpha**
*Params:*
- `` (`list[str]`) +| `/pair_history` | GET | Returns an analyzed dataframe for a given timerange, analyzed by a given strategy. **Alpha** +| `/pair_history` | POST | Returns an analyzed dataframe for a given timerange, analyzed by a given strategy, filtered by a provided list of columns to return. **Alpha**
*Params:*
- `` (`list[str]`) +| `/plot_config` | GET | Get plot config from the strategy (or nothing if not configured). **Alpha** +| `/strategies` | GET | List strategies in strategy directory. **Alpha** +| `/strategy/` | GET | Get specific Strategy content by strategy class name. **Alpha**
*Params:*
- `` (`str`) +| `/available_pairs` | GET | List available backtest data. **Alpha** +| `/version` | GET | Show version. +| `/sysinfo` | GET | Show information about the system load. +| `/health` | GET | Show bot health (last bot loop). + +!!! Warning "Alpha status" + Endpoints labeled with *Alpha status* above may change at any time without notice. + ### Message WebSocket The API Server includes a websocket endpoint for subscribing to RPC messages from the freqtrade Bot. diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 44d675055..14e39a447 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -767,6 +767,15 @@ Adjustment orders can be assigned with a tag by returning a 2 element Tuple, wit Modifications to leverage are not possible, and the stake-amount returned is assumed to be before applying leverage. +!!! Danger "Loose Logic" + On dry and live run, this function will be called every `throttle_process_secs` (default to 5s). If you have a loose logic, for example your logic for extra entry is only to check RSI of last candle is below 30, then when such condition fulfilled, your bot will do extra re-entry every 5 secs until either it run out of money, it hit the `max_position_adjustment` limit, or a new candle with RSI more than 30 arrived. + + Same thing also can happen with partial exit. So be sure to have a strict logic and/or check for the last filled order. + +!!! 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. + ### Increase position The strategy is expected to return a positive **stake_amount** (in stake currency) between `min_stake` and `max_stake` if and when an additional entry order should be made (position is increased -> buy order for long trades, sell order for short trades). @@ -776,16 +785,22 @@ If there are not enough funds in the wallet (the return value is above `max_stak Additional entries are ignored once you have reached the maximum amount of extra entries that you have set on `max_entry_position_adjustment`, but the callback is called anyway looking for partial exits. +!!! Note "About stake size" + Using fixed stake size means it will be the amount used for the first order, just like without position adjustment. + If you wish to buy additional orders with DCA, then make sure to leave enough funds in the wallet for that. + Using `"unlimited"` stake amount with DCA orders requires you to also implement the `custom_stake_amount()` callback to avoid allocating all funds to the initial order. + ### Decrease position The strategy is expected to return a negative stake_amount (in stake currency) for a partial exit. Returning the full owned stake at that point (`-trade.stake_amount`) results in a full exit. Returning a value more than the above (so remaining stake_amount would become negative) will result in the bot ignoring the signal. -!!! Note "About stake size" - Using fixed stake size means it will be the amount used for the first order, just like without position adjustment. - If you wish to buy additional orders with DCA, then make sure to leave enough funds in the wallet for that. - Using `"unlimited"` stake amount with DCA orders requires you to also implement the `custom_stake_amount()` callback to avoid allocating all funds to the initial order. +For a partial exit, it's important to know that the formula used to calculate the amount of the coin for the partial exit order is `amount to be exited partially = negative_stake_amount * trade.amount / trade.stake_amount`, where `negative_stake_amount` is the value returned from the `adjust_trade_position` function. As seen in the formula, the formula doesn't care about current profit/loss of the position. It only cares about `trade.amount` and `trade.stake_amount` which aren't affected by the price movement at all. + +For example, let's say you buy 2 SHITCOIN/USDT at open rate of 50, which means the trade's stake amount is 100 USDT. Now the price raises to 200 and you want to sell half of it. In that case, you have to return -50% of `trade.stake_amount` (0.5 * 100 USDT) which equals to -50. The bot will calculate the amount it needed to sell, which is `50 * 2 / 100` which equals 1 SHITCOIN/USDT. If you return -200 (50% of 2 * 200), the bot will ignore it since `trade.stake_amount` is only 100 USDT but you asked to sell 200 USDT which means you are asking to sell 4 SHITCOIN/USDT. + +Back to the example above, since current rate is 200, the current USDT value of your trade is now 400 USDT. Let's say you want to partially sell 100 USDT to take out the initial investment and leave the profit in the trade hoping that the price keeps rising. In that case, you have to do a different approach. First, you need to calculate the exact amount you needed to sell. In this case, since you want to sell 100 USDT worth based of current rate, the exact amount you need to partially sell is `100 * 2 / 400` which equals 0.5 SHITCOIN/USDT. Since we know now the exact amount we want to sell (0.5), the value you need to return in the `adjust_trade_position` function is `-amount to be exited partially * trade.stake_amount / trade.amount`, which equals -25. The bot will sell 0.5 SHITCOIN/USDT, keeping 1.5 in trade. You will receive 100 USDT from the partial exit. !!! Warning "Stoploss calculation" Stoploss is still calculated from the initial opening price, not averaged price. @@ -793,10 +808,6 @@ Returning a value more than the above (so remaining stake_amount would become ne While `/stopentry` command stops the bot from entering new trades, the position adjustment feature will continue buying new orders on existing trades. -!!! 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. - !!! Warning "Performance with many position adjustments" Position adjustments can be a good approach to increase a strategy's output - but it can also have drawbacks if using this feature extensively. Each of the orders will be attached to the trade object for the duration of the trade - hence increasing memory usage. diff --git a/docs/strategy_analysis_example.md b/docs/strategy_analysis_example.md index a1c74162e..814531c2d 100644 --- a/docs/strategy_analysis_example.md +++ b/docs/strategy_analysis_example.md @@ -152,7 +152,7 @@ print(stats["strategy"][strategy]["pairlist"]) # Get market change (average change of all pairs from start to end of the backtest period) print(stats["strategy"][strategy]["market_change"]) # Maximum drawdown () -print(stats["strategy"][strategy]["max_drawdown"]) +print(stats["strategy"][strategy]["max_drawdown_abs"]) # Maximum drawdown start and end print(stats["strategy"][strategy]["drawdown_start"]) print(stats["strategy"][strategy]["drawdown_end"]) diff --git a/docs/stylesheets/ft.extra.css b/docs/stylesheets/ft.extra.css index 18985baf0..930463ca8 100644 --- a/docs/stylesheets/ft.extra.css +++ b/docs/stylesheets/ft.extra.css @@ -15,3 +15,7 @@ .md-version__list { font-weight: 500 !important; } + +#available-endpoints ~ .md-typeset__scrollwrap .md-typeset__table th:first-of-type { + width: 35% !important; +} diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index 3f7ecaa22..8688aa917 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -1,6 +1,6 @@ """Freqtrade bot""" -__version__ = "2024.11-dev" +__version__ = "2024.12-dev" if "dev" in __version__: from pathlib import Path diff --git a/freqtrade/commands/optimize_commands.py b/freqtrade/commands/optimize_commands.py index ea75f3bd1..9695a313b 100644 --- a/freqtrade/commands/optimize_commands.py +++ b/freqtrade/commands/optimize_commands.py @@ -17,7 +17,7 @@ def setup_optimize_configuration(args: dict[str, Any], method: RunMode) -> dict[ :return: Configuration """ from freqtrade.configuration import setup_utils_configuration - from freqtrade.util import fmt_coin + from freqtrade.util import fmt_coin, get_dry_run_wallet config = setup_utils_configuration(args, method) @@ -26,7 +26,7 @@ def setup_optimize_configuration(args: dict[str, Any], method: RunMode) -> dict[ RunMode.HYPEROPT: "hyperoptimization", } if method in no_unlimited_runmodes.keys(): - wallet_size = config["dry_run_wallet"] * config["tradable_balance_ratio"] + wallet_size = get_dry_run_wallet(config) * config["tradable_balance_ratio"] # tradable_balance_ratio if ( config["stake_amount"] != constants.UNLIMITED_STAKE_AMOUNT diff --git a/freqtrade/configuration/config_schema.py b/freqtrade/configuration/config_schema.py index 30f1f6f28..d31069e7b 100644 --- a/freqtrade/configuration/config_schema.py +++ b/freqtrade/configuration/config_schema.py @@ -85,8 +85,10 @@ CONF_SCHEMA = { }, "dry_run_wallet": { "description": "Initial wallet balance for dry run mode.", - "type": "number", + "type": ["number", "object"], "default": DRY_RUN_WALLET, + "patternProperties": {r"^[a-zA-Z0-9]+$": {"type": "number"}}, + "additionalProperties": False, }, "cancel_open_orders_on_exit": { "description": "Cancel open orders when exiting.", diff --git a/freqtrade/configuration/environment_vars.py b/freqtrade/configuration/environment_vars.py index 37445538d..8a825f59b 100644 --- a/freqtrade/configuration/environment_vars.py +++ b/freqtrade/configuration/environment_vars.py @@ -2,6 +2,8 @@ import logging import os from typing import Any +import rapidjson + from freqtrade.constants import ENV_VAR_PREFIX from freqtrade.misc import deep_merge_dicts @@ -20,6 +22,14 @@ def _get_var_typed(val): return True elif val.lower() in ("f", "false"): return False + # try to convert from json + try: + value = rapidjson.loads(val) + # Limited to lists for now + if isinstance(value, list): + return value + except rapidjson.JSONDecodeError: + pass # keep as string return val diff --git a/freqtrade/data/converter/orderflow.py b/freqtrade/data/converter/orderflow.py index e64caa88b..a51394ce9 100644 --- a/freqtrade/data/converter/orderflow.py +++ b/freqtrade/data/converter/orderflow.py @@ -4,20 +4,31 @@ Functions to convert orderflow data from public_trades import logging import time -import typing -from collections import OrderedDict from datetime import datetime import numpy as np import pandas as pd from freqtrade.constants import DEFAULT_ORDERFLOW_COLUMNS, Config -from freqtrade.enums import RunMode from freqtrade.exceptions import DependencyException logger = logging.getLogger(__name__) +ORDERFLOW_ADDED_COLUMNS = [ + "trades", + "orderflow", + "imbalances", + "stacked_imbalances_bid", + "stacked_imbalances_ask", + "max_delta", + "min_delta", + "bid", + "ask", + "delta", + "total_trades", +] + def _init_dataframe_with_trades_columns(dataframe: pd.DataFrame): """ @@ -25,53 +36,73 @@ def _init_dataframe_with_trades_columns(dataframe: pd.DataFrame): :param dataframe: Dataframe to populate """ # Initialize columns with appropriate dtypes - dataframe["trades"] = np.nan - dataframe["orderflow"] = np.nan - dataframe["imbalances"] = np.nan - dataframe["stacked_imbalances_bid"] = np.nan - dataframe["stacked_imbalances_ask"] = np.nan - dataframe["max_delta"] = np.nan - dataframe["min_delta"] = np.nan - dataframe["bid"] = np.nan - dataframe["ask"] = np.nan - dataframe["delta"] = np.nan - dataframe["total_trades"] = np.nan + for column in ORDERFLOW_ADDED_COLUMNS: + dataframe[column] = np.nan - # Ensure the 'trades' column is of object type - dataframe["trades"] = dataframe["trades"].astype(object) - dataframe["orderflow"] = dataframe["orderflow"].astype(object) - dataframe["imbalances"] = dataframe["imbalances"].astype(object) - dataframe["stacked_imbalances_bid"] = dataframe["stacked_imbalances_bid"].astype(object) - dataframe["stacked_imbalances_ask"] = dataframe["stacked_imbalances_ask"].astype(object) + # Set columns to object type + for column in ( + "trades", + "orderflow", + "imbalances", + "stacked_imbalances_bid", + "stacked_imbalances_ask", + ): + dataframe[column] = dataframe[column].astype(object) + + +def timeframe_to_DateOffset(timeframe: str) -> pd.DateOffset: + """ + Translates the timeframe interval value written in the human readable + form ('1m', '5m', '1h', '1d', '1w', etc.) to the number + of seconds for one timeframe interval. + """ + from freqtrade.exchange import timeframe_to_seconds + + timeframe_seconds = timeframe_to_seconds(timeframe) + timeframe_minutes = timeframe_seconds // 60 + if timeframe_minutes < 1: + return pd.DateOffset(seconds=timeframe_seconds) + elif 59 < timeframe_minutes < 1440: + return pd.DateOffset(hours=timeframe_minutes // 60) + elif 1440 <= timeframe_minutes < 10080: + return pd.DateOffset(days=timeframe_minutes // 1440) + elif 10000 < timeframe_minutes < 43200: + return pd.DateOffset(weeks=1) + elif timeframe_minutes >= 43200 and timeframe_minutes < 525600: + return pd.DateOffset(months=1) + elif timeframe == "1y": + return pd.DateOffset(years=1) + else: + return pd.DateOffset(minutes=timeframe_minutes) def _calculate_ohlcv_candle_start_and_end(df: pd.DataFrame, timeframe: str): - from freqtrade.exchange import timeframe_to_next_date, timeframe_to_resample_freq + from freqtrade.exchange import timeframe_to_resample_freq - timeframe_frequency = timeframe_to_resample_freq(timeframe) - # calculate ohlcv candle start and end if df is not None and not df.empty: + timeframe_frequency = timeframe_to_resample_freq(timeframe) + dofs = timeframe_to_DateOffset(timeframe) + # calculate ohlcv candle start and end df["datetime"] = pd.to_datetime(df["date"], unit="ms") df["candle_start"] = df["datetime"].dt.floor(timeframe_frequency) # used in _now_is_time_to_refresh_trades - df["candle_end"] = df["candle_start"].apply( - lambda candle_start: timeframe_to_next_date(timeframe, candle_start) - ) + df["candle_end"] = df["candle_start"] + dofs df.drop(columns=["datetime"], inplace=True) def populate_dataframe_with_trades( - cached_grouped_trades: OrderedDict[tuple[datetime, datetime], pd.DataFrame], + cached_grouped_trades: pd.DataFrame | None, config: Config, dataframe: pd.DataFrame, trades: pd.DataFrame, -) -> tuple[pd.DataFrame, OrderedDict[tuple[datetime, datetime], pd.DataFrame]]: +) -> tuple[pd.DataFrame, pd.DataFrame]: """ Populates a dataframe with trades :param dataframe: Dataframe to populate :param trades: Trades to populate with :return: Dataframe with trades populated """ + timeframe = config["timeframe"] config_orderflow = config["orderflow"] @@ -94,71 +125,52 @@ def populate_dataframe_with_trades( # group trades by candle start trades_grouped_by_candle_start = trades.groupby("candle_start", group_keys=False) - # Create Series to hold complex data - trades_series = pd.Series(index=dataframe.index, dtype=object) - orderflow_series = pd.Series(index=dataframe.index, dtype=object) - imbalances_series = pd.Series(index=dataframe.index, dtype=object) - stacked_imbalances_bid_series = pd.Series(index=dataframe.index, dtype=object) - stacked_imbalances_ask_series = pd.Series(index=dataframe.index, dtype=object) - trades_grouped_by_candle_start = trades.groupby("candle_start", group_keys=False) + candle_start: datetime for candle_start, trades_grouped_df in trades_grouped_by_candle_start: is_between = candle_start == dataframe["date"] if is_between.any(): - from freqtrade.exchange import timeframe_to_next_date + # there can only be one row with the same date + index = dataframe.index[is_between][0] - candle_next = timeframe_to_next_date(timeframe, typing.cast(datetime, candle_start)) - if candle_next not in trades_grouped_by_candle_start.groups: - logger.warning( - f"candle at {candle_start} with {len(trades_grouped_df)} trades " - f"might be unfinished, because no finished trades at {candle_next}" - ) - - indices = dataframe.index[is_between].tolist() - # Add trades to each candle - trades_series.loc[indices] = [ - trades_grouped_df.drop(columns=["candle_start", "candle_end"]).to_dict( - orient="records" - ) - ] - # Use caching mechanism - if (candle_start, candle_next) in cached_grouped_trades: - cache_entry = cached_grouped_trades[ - (typing.cast(datetime, candle_start), candle_next) - ] - # dataframe.loc[is_between] = cache_entry # doesn't take, so we need workaround: - # Create a dictionary of the column values to be assigned - update_dict = {c: cache_entry[c].iat[0] for c in cache_entry.columns} - # Assign the values using the update_dict - dataframe.loc[is_between, update_dict.keys()] = pd.DataFrame( - [update_dict], index=dataframe.loc[is_between].index - ) + if ( + cached_grouped_trades is not None + and (candle_start == cached_grouped_trades["date"]).any() + ): + # Check if the trades are already in the cache + cache_idx = cached_grouped_trades.index[ + cached_grouped_trades["date"] == candle_start + ][0] + for col in ORDERFLOW_ADDED_COLUMNS: + dataframe.at[index, col] = cached_grouped_trades.at[cache_idx, col] continue + dataframe.at[index, "trades"] = trades_grouped_df.drop( + columns=["candle_start", "candle_end"] + ).to_dict(orient="records") + # Calculate orderflow for each candle orderflow = trades_to_volumeprofile_with_total_delta_bid_ask( trades_grouped_df, scale=config_orderflow["scale"] ) - orderflow_series.loc[indices] = [orderflow.to_dict(orient="index")] + dataframe.at[index, "orderflow"] = orderflow.to_dict(orient="index") + # orderflow_series.loc[[index]] = [orderflow.to_dict(orient="index")] # Calculate imbalances for each candle's orderflow imbalances = trades_orderflow_to_imbalances( orderflow, imbalance_ratio=config_orderflow["imbalance_ratio"], imbalance_volume=config_orderflow["imbalance_volume"], ) - imbalances_series.loc[indices] = [imbalances.to_dict(orient="index")] + dataframe.at[index, "imbalances"] = imbalances.to_dict(orient="index") stacked_imbalance_range = config_orderflow["stacked_imbalance_range"] - stacked_imbalances_bid_series.loc[indices] = [ - stacked_imbalance_bid( - imbalances, stacked_imbalance_range=stacked_imbalance_range - ) - ] - stacked_imbalances_ask_series.loc[indices] = [ - stacked_imbalance_ask( - imbalances, stacked_imbalance_range=stacked_imbalance_range - ) - ] + dataframe.at[index, "stacked_imbalances_bid"] = stacked_imbalance_bid( + imbalances, stacked_imbalance_range=stacked_imbalance_range + ) + + dataframe.at[index, "stacked_imbalances_ask"] = stacked_imbalance_ask( + imbalances, stacked_imbalance_range=stacked_imbalance_range + ) bid = np.where( trades_grouped_df["side"].str.contains("sell"), trades_grouped_df["amount"], 0 @@ -168,39 +180,20 @@ def populate_dataframe_with_trades( trades_grouped_df["side"].str.contains("buy"), trades_grouped_df["amount"], 0 ) deltas_per_trade = ask - bid - min_delta = deltas_per_trade.cumsum().min() - max_delta = deltas_per_trade.cumsum().max() - dataframe.loc[indices, "max_delta"] = max_delta - dataframe.loc[indices, "min_delta"] = min_delta + dataframe.at[index, "max_delta"] = deltas_per_trade.cumsum().max() + dataframe.at[index, "min_delta"] = deltas_per_trade.cumsum().min() - dataframe.loc[indices, "bid"] = bid.sum() - dataframe.loc[indices, "ask"] = ask.sum() - dataframe.loc[indices, "delta"] = ( - dataframe.loc[indices, "ask"] - dataframe.loc[indices, "bid"] + dataframe.at[index, "bid"] = bid.sum() + dataframe.at[index, "ask"] = ask.sum() + dataframe.at[index, "delta"] = ( + dataframe.at[index, "ask"] - dataframe.at[index, "bid"] ) - dataframe.loc[indices, "total_trades"] = len(trades_grouped_df) + dataframe.at[index, "total_trades"] = len(trades_grouped_df) - # Cache the result - cached_grouped_trades[(typing.cast(datetime, candle_start), candle_next)] = ( - dataframe.loc[is_between].copy() - ) - - # Maintain cache size - if ( - config.get("runmode") in (RunMode.DRY_RUN, RunMode.LIVE) - and len(cached_grouped_trades) > config_orderflow["cache_size"] - ): - cached_grouped_trades.popitem(last=False) - else: - logger.debug(f"Found NO candles for trades starting with {candle_start}") logger.debug(f"trades.groups_keys in {time.time() - start_time} seconds") - # Merge the complex data Series back into the DataFrame - dataframe["trades"] = trades_series - dataframe["orderflow"] = orderflow_series - dataframe["imbalances"] = imbalances_series - dataframe["stacked_imbalances_bid"] = stacked_imbalances_bid_series - dataframe["stacked_imbalances_ask"] = stacked_imbalances_ask_series + # Cache the entire dataframe + cached_grouped_trades = dataframe.tail(config_orderflow["cache_size"]).copy() except Exception as e: logger.exception("Error populating dataframe with trades") diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index fd4a5c5ee..eb93f3ad5 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -285,6 +285,7 @@ def _download_pair_history( candle_type=candle_type, until_ms=until_ms if until_ms else None, ) + logger.info(f"Downloaded data for {pair} with length {len(new_dataframe)}.") if data.empty: data = new_dataframe else: @@ -603,7 +604,7 @@ def download_data( Download data function. Used from both cli and API. """ timerange = TimeRange() - if "days" in config: + if "days" in config and config["days"] is not None: time_since = (datetime.now() - timedelta(days=config["days"])).strftime("%Y%m%d") timerange = TimeRange.parse_timerange(f"{time_since}-") diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 64b597fe8..74a37b4f6 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -5,13 +5,18 @@ from datetime import datetime, timezone from pathlib import Path import ccxt +from pandas import DataFrame +from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS from freqtrade.enums import CandleType, MarginMode, PriceType, TradingMode from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError from freqtrade.exchange import Exchange +from freqtrade.exchange.binance_public_data import concat_safe, download_archive_ohlcv from freqtrade.exchange.common import retrier -from freqtrade.exchange.exchange_types import FtHas, OHLCVResponse, Tickers +from freqtrade.exchange.exchange_types import FtHas, Tickers +from freqtrade.exchange.exchange_utils_timeframe import timeframe_to_msecs from freqtrade.misc import deep_merge_dicts, json_load +from freqtrade.util.datetime_helpers import dt_from_ts, dt_ts logger = logging.getLogger(__name__) @@ -52,8 +57,14 @@ class Binance(Exchange): (TradingMode.FUTURES, MarginMode.ISOLATED) ] - def get_tickers(self, symbols: list[str] | None = None, *, cached: bool = False) -> Tickers: - tickers = super().get_tickers(symbols=symbols, cached=cached) + def get_tickers( + self, + symbols: list[str] | None = None, + *, + cached: bool = False, + market_type: TradingMode | None = None, + ) -> Tickers: + tickers = super().get_tickers(symbols=symbols, cached=cached, market_type=market_type) if self.trading_mode == TradingMode.FUTURES: # Binance's future result has no bid/ask values. # Therefore we must fetch that from fetch_bids_asks and combine the two results. @@ -80,7 +91,10 @@ class Binance(Exchange): "\nHedge Mode is not supported by freqtrade. " "Please change 'Position Mode' on your binance futures account." ) - if assets_margin.get("multiAssetsMargin") is True: + if ( + assets_margin.get("multiAssetsMargin") is True + and self.margin_mode != MarginMode.CROSS + ): msg += ( "\nMulti-Asset Mode is not supported by freqtrade. " "Please change 'Asset Mode' on your binance futures account." @@ -97,23 +111,24 @@ class Binance(Exchange): except ccxt.BaseError as e: raise OperationalException(e) from e - async def _async_get_historic_ohlcv( + def get_historic_ohlcv( self, pair: str, timeframe: str, since_ms: int, candle_type: CandleType, is_new_pair: bool = False, - raise_: bool = False, until_ms: int | None = None, - ) -> OHLCVResponse: + ) -> DataFrame: """ 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" :param candle_type: Any of the enum CandleType (must match trading mode!) """ if is_new_pair: - x = await self._async_get_candle_history(pair, timeframe, candle_type, 0) + x = self.loop.run_until_complete( + self._async_get_candle_history(pair, timeframe, candle_type, 0) + ) if x and x[3] and x[3][0] and x[3][0][0] > since_ms: # Set starting date to first available candle. since_ms = x[3][0][0] @@ -121,17 +136,89 @@ class Binance(Exchange): f"Candle-data for {pair} available starting with " f"{datetime.fromtimestamp(since_ms // 1000, tz=timezone.utc).isoformat()}." ) + if until_ms and since_ms >= until_ms: + logger.warning( + f"No available candle-data for {pair} before " + f"{dt_from_ts(until_ms).isoformat()}" + ) + return DataFrame(columns=DEFAULT_DATAFRAME_COLUMNS) - return await super()._async_get_historic_ohlcv( - pair=pair, - timeframe=timeframe, - since_ms=since_ms, - is_new_pair=is_new_pair, - raise_=raise_, - candle_type=candle_type, - until_ms=until_ms, + if ( + self._config["exchange"].get("only_from_ccxt", False) + or + # only download timeframes with significant improvements, + # otherwise fall back to rest API + not ( + (candle_type == CandleType.SPOT and timeframe in ["1s", "1m", "3m", "5m"]) + or ( + candle_type == CandleType.FUTURES + and timeframe in ["1m", "3m", "5m", "15m", "30m"] + ) + ) + ): + return super().get_historic_ohlcv( + pair=pair, + timeframe=timeframe, + since_ms=since_ms, + candle_type=candle_type, + is_new_pair=is_new_pair, + until_ms=until_ms, + ) + else: + # Download from data.binance.vision + return self.get_historic_ohlcv_fast( + pair=pair, + timeframe=timeframe, + since_ms=since_ms, + candle_type=candle_type, + is_new_pair=is_new_pair, + until_ms=until_ms, + ) + + def get_historic_ohlcv_fast( + self, + pair: str, + timeframe: str, + since_ms: int, + candle_type: CandleType, + is_new_pair: bool = False, + until_ms: int | None = None, + ) -> DataFrame: + """ + Fastly fetch OHLCV data by leveraging https://data.binance.vision. + """ + df = self.loop.run_until_complete( + download_archive_ohlcv( + candle_type=candle_type, + pair=pair, + timeframe=timeframe, + since_ms=since_ms, + until_ms=until_ms, + markets=self.markets, + ) ) + # download the remaining data from rest API + if df.empty: + rest_since_ms = since_ms + else: + rest_since_ms = dt_ts(df.iloc[-1].date) + timeframe_to_msecs(timeframe) + + # make sure since <= until + if until_ms and rest_since_ms > until_ms: + rest_df = DataFrame() + else: + rest_df = super().get_historic_ohlcv( + pair=pair, + timeframe=timeframe, + since_ms=rest_since_ms, + candle_type=candle_type, + is_new_pair=is_new_pair, + until_ms=until_ms, + ) + all_df = concat_safe([df, rest_df]) + return all_df + def funding_fee_cutoff(self, open_date: datetime): """ Funding fees are only charged at full hours (usually every 4-8h). diff --git a/freqtrade/exchange/binance_leverage_tiers.json b/freqtrade/exchange/binance_leverage_tiers.json index 4bcdab66d..f66095591 100644 --- a/freqtrade/exchange/binance_leverage_tiers.json +++ b/freqtrade/exchange/binance_leverage_tiers.json @@ -315,13 +315,13 @@ "symbol": "1000BONK/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 60000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "60000", + "notionalCap": "100000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -331,119 +331,119 @@ "tier": 3.0, "symbol": "1000BONK/USDT:USDT", "currency": "USDT", - "minNotional": 60000.0, - "maxNotional": 300000.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "300000", - "notionalFloor": "60000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.02", - "cum": "350.0" + "cum": "550.0" } }, { "tier": 4.0, "symbol": "1000BONK/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 600000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "600000", - "notionalFloor": "300000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.025", - "cum": "1850.0" + "cum": "3050.0" } }, { "tier": 5.0, "symbol": "1000BONK/USDT:USDT", "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 3000000.0, + "minNotional": 1000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "3000000", - "notionalFloor": "600000", + "notionalCap": "5000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.05", - "cum": "16850.0" + "cum": "28050.0" } }, { "tier": 6.0, "symbol": "1000BONK/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 6000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "6000000", - "notionalFloor": "3000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1", - "cum": "166850.0" + "cum": "278050.0" } }, { "tier": 7.0, "symbol": "1000BONK/USDT:USDT", "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 7500000.0, + "minNotional": 10000000.0, + "maxNotional": 12500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "7500000", - "notionalFloor": "6000000", + "notionalCap": "12500000", + "notionalFloor": "10000000", "maintMarginRatio": "0.125", - "cum": "316850.0" + "cum": "528050.0" } }, { "tier": 8.0, "symbol": "1000BONK/USDT:USDT", "currency": "USDT", - "minNotional": 7500000.0, - "maxNotional": 15000000.0, + "minNotional": 12500000.0, + "maxNotional": 25000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "15000000", - "notionalFloor": "7500000", + "notionalCap": "25000000", + "notionalFloor": "12500000", "maintMarginRatio": "0.25", - "cum": "1254350.0" + "cum": "2090550.0" } }, { "tier": 9.0, "symbol": "1000BONK/USDT:USDT", "currency": "USDT", - "minNotional": 15000000.0, - "maxNotional": 30000000.0, + "minNotional": 25000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "15000000", + "notionalCap": "50000000", + "notionalFloor": "25000000", "maintMarginRatio": "0.5", - "cum": "5004350.0" + "cum": "8340550.0" } } ], @@ -1814,13 +1814,13 @@ "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 10000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.0065, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "10000", + "notionalCap": "25000", "notionalFloor": "0", "maintMarginRatio": "0.0065", "cum": "0.0" @@ -1830,153 +1830,153 @@ "tier": 2.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.0075, + "minNotional": 25000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.01, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "25000", - "notionalFloor": "10000", - "maintMarginRatio": "0.0075", - "cum": "10.0" + "notionalCap": "150000", + "notionalFloor": "25000", + "maintMarginRatio": "0.01", + "cum": "87.5" } }, { "tier": 3.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.01, + "minNotional": 150000.0, + "maxNotional": 200000.0, + "maintenanceMarginRate": 0.015, "maxLeverage": 40.0, "info": { "bracket": "3", "initialLeverage": "40", - "notionalCap": "150000", - "notionalFloor": "25000", - "maintMarginRatio": "0.01", - "cum": "72.5" + "notionalCap": "200000", + "notionalFloor": "150000", + "maintMarginRatio": "0.015", + "cum": "837.5" } }, { "tier": 4.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 500000.0, + "minNotional": 200000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "notionalCap": "500000", - "notionalFloor": "150000", + "notionalCap": "800000", + "notionalFloor": "200000", "maintMarginRatio": "0.02", - "cum": "1572.5" + "cum": "1837.5" } }, { "tier": 5.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "1000000", - "notionalFloor": "500000", + "notionalCap": "1600000", + "notionalFloor": "800000", "maintMarginRatio": "0.025", - "cum": "4072.5" + "cum": "5837.5" } }, { "tier": 6.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 1600000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.05", - "cum": "29072.5" + "cum": "45837.5" } }, { "tier": 7.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 8000000.0, + "maxNotional": 16000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "16000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.1", - "cum": "279072.5" + "cum": "445837.5" } }, { "tier": 8.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 12500000.0, + "minNotional": 16000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "8", "initialLeverage": "4", - "notionalCap": "12500000", - "notionalFloor": "10000000", + "notionalCap": "20000000", + "notionalFloor": "16000000", "maintMarginRatio": "0.125", - "cum": "529072.5" + "cum": "845837.5" } }, { "tier": 9.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 12500000.0, - "maxNotional": 25000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "25000000", - "notionalFloor": "12500000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "2091572.5" + "cum": "3345837.5" } }, { "tier": 10.0, "symbol": "1000SHIB/USDT:USDT", "currency": "USDT", - "minNotional": 25000000.0, - "maxNotional": 50000000.0, + "minNotional": 40000000.0, + "maxNotional": 80000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "25000000", + "notionalCap": "80000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.5", - "cum": "8341572.5" + "cum": "13345837.5" } } ], @@ -3209,13 +3209,13 @@ "symbol": "ACT/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 40000.0, + "maxNotional": 80000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "40000", + "notionalCap": "80000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -3225,119 +3225,274 @@ "tier": 3.0, "symbol": "ACT/USDT:USDT", "currency": "USDT", - "minNotional": 40000.0, - "maxNotional": 200000.0, + "minNotional": 80000.0, + "maxNotional": 400000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "200000", - "notionalFloor": "40000", + "notionalCap": "400000", + "notionalFloor": "80000", "maintMarginRatio": "0.02", - "cum": "250.0" + "cum": "450.0" } }, { "tier": 4.0, "symbol": "ACT/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, + "minNotional": 400000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "400000", - "notionalFloor": "200000", + "notionalCap": "800000", + "notionalFloor": "400000", "maintMarginRatio": "0.025", - "cum": "1250.0" + "cum": "2450.0" } }, { "tier": 5.0, "symbol": "ACT/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 2000000.0, + "minNotional": 800000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "2000000", - "notionalFloor": "400000", + "notionalCap": "4000000", + "notionalFloor": "800000", "maintMarginRatio": "0.05", - "cum": "11250.0" + "cum": "22450.0" } }, { "tier": 6.0, "symbol": "ACT/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, + "minNotional": 4000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "4000000", - "notionalFloor": "2000000", + "notionalCap": "8000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.1", - "cum": "111250.0" + "cum": "222450.0" } }, { "tier": 7.0, "symbol": "ACT/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 5000000.0, + "minNotional": 8000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "4000000", + "notionalCap": "10000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.125", - "cum": "211250.0" + "cum": "422450.0" } }, { "tier": 8.0, "symbol": "ACT/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", - "cum": "836250.0" + "cum": "1672450.0" } }, { "tier": 9.0, "symbol": "ACT/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", - "cum": "3336250.0" + "cum": "6672450.0" + } + } + ], + "ACX/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 20000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "20000", + "notionalFloor": "10000", + "maintMarginRatio": "0.015", + "cum": "50.0" + } + }, + { + "tier": 3.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 20000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "100000", + "notionalFloor": "20000", + "maintMarginRatio": "0.02", + "cum": "150.0" + } + }, + { + "tier": 4.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 200000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "200000", + "notionalFloor": "100000", + "maintMarginRatio": "0.025", + "cum": "650.0" + } + }, + { + "tier": 5.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 200000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "200000", + "maintMarginRatio": "0.05", + "cum": "5650.0" + } + }, + { + "tier": 6.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "55650.0" + } + }, + { + "tier": 7.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 2500000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "2500000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "105650.0" + } + }, + { + "tier": 8.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 2500000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "5000000", + "notionalFloor": "2500000", + "maintMarginRatio": "0.25", + "cum": "418150.0" + } + }, + { + "tier": 9.0, + "symbol": "ACX/USDT:USDT", + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.5", + "cum": "1668150.0" } } ], @@ -3668,6 +3823,161 @@ } } ], + "AERO/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "AERO/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "AEVO/USDT:USDT": [ { "tier": 1.0, @@ -4347,15 +4657,15 @@ "symbol": "ALGO/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, - "maintenanceMarginRate": 0.015, - "maxLeverage": 50.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", + "initialLeverage": "75", + "notionalCap": "10000", "notionalFloor": "0", - "maintMarginRatio": "0.015", + "maintMarginRatio": "0.01", "cum": "0.0" } }, @@ -4363,16 +4673,16 @@ "tier": 2.0, "symbol": "ALGO/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "minNotional": 10000.0, + "maxNotional": 40000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.025", + "initialLeverage": "50", + "notionalCap": "40000", + "notionalFloor": "10000", + "maintMarginRatio": "0.015", "cum": "50.0" } }, @@ -4380,85 +4690,119 @@ "tier": 3.0, "symbol": "ALGO/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 40000.0, + "maxNotional": 200000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "675.0" + "initialLeverage": "25", + "notionalCap": "200000", + "notionalFloor": "40000", + "maintMarginRatio": "0.02", + "cum": "250.0" } }, { "tier": 4.0, "symbol": "ALGO/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 200000.0, + "maxNotional": 400000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5675.0" + "initialLeverage": "20", + "notionalCap": "400000", + "notionalFloor": "200000", + "maintMarginRatio": "0.025", + "cum": "1250.0" } }, { "tier": 5.0, "symbol": "ALGO/USDT:USDT", "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 400000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11925.0" + "initialLeverage": "10", + "notionalCap": "2000000", + "notionalFloor": "400000", + "maintMarginRatio": "0.05", + "cum": "11250.0" } }, { "tier": 6.0, "symbol": "ALGO/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 2000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "6", - "initialLeverage": "2", - "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "136925.0" + "initialLeverage": "5", + "notionalCap": "4000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.1", + "cum": "111250.0" } }, { "tier": 7.0, "symbol": "ALGO/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, + "minNotional": 4000000.0, "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.125", + "cum": "211250.0" + } + }, + { + "tier": 8.0, + "symbol": "ALGO/USDT:USDT", + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.25", + "cum": "836250.0" + } + }, + { + "tier": 9.0, + "symbol": "ALGO/USDT:USDT", + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "7", + "bracket": "9", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "636925.0" + "cum": "3336250.0" } } ], @@ -6088,13 +6432,13 @@ "symbol": "ARB/USDT:USDT", "currency": "USDT", "minNotional": 50000.0, - "maxNotional": 80000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 40.0, "info": { "bracket": "3", "initialLeverage": "40", - "notionalCap": "80000", + "notionalCap": "100000", "notionalFloor": "50000", "maintMarginRatio": "0.015", "cum": "270.0" @@ -6104,119 +6448,119 @@ "tier": 4.0, "symbol": "ARB/USDT:USDT", "currency": "USDT", - "minNotional": 80000.0, - "maxNotional": 300000.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "notionalCap": "300000", - "notionalFloor": "80000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.02", - "cum": "670.0" + "cum": "770.0" } }, { "tier": 5.0, "symbol": "ARB/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 600000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "600000", - "notionalFloor": "300000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.025", - "cum": "2170.0" + "cum": "3270.0" } }, { "tier": 6.0, "symbol": "ARB/USDT:USDT", "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 3000000.0, + "minNotional": 1000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "3000000", - "notionalFloor": "600000", + "notionalCap": "5000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.05", - "cum": "17170.0" + "cum": "28270.0" } }, { "tier": 7.0, "symbol": "ARB/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 6000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "6000000", - "notionalFloor": "3000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1", - "cum": "167170.0" + "cum": "278270.0" } }, { "tier": 8.0, "symbol": "ARB/USDT:USDT", "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 7500000.0, + "minNotional": 10000000.0, + "maxNotional": 12500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "8", "initialLeverage": "4", - "notionalCap": "7500000", - "notionalFloor": "6000000", + "notionalCap": "12500000", + "notionalFloor": "10000000", "maintMarginRatio": "0.125", - "cum": "317170.0" + "cum": "528270.0" } }, { "tier": 9.0, "symbol": "ARB/USDT:USDT", "currency": "USDT", - "minNotional": 7500000.0, - "maxNotional": 15000000.0, + "minNotional": 12500000.0, + "maxNotional": 25000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "15000000", - "notionalFloor": "7500000", + "notionalCap": "25000000", + "notionalFloor": "12500000", "maintMarginRatio": "0.25", - "cum": "1254670.0" + "cum": "2090770.0" } }, { "tier": 10.0, "symbol": "ARB/USDT:USDT", "currency": "USDT", - "minNotional": 15000000.0, - "maxNotional": 30000000.0, + "minNotional": 25000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "15000000", + "notionalCap": "50000000", + "notionalFloor": "25000000", "maintMarginRatio": "0.5", - "cum": "5004670.0" + "cum": "8340770.0" } } ], @@ -7203,6 +7547,161 @@ } } ], + "AVA/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "AVA/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "AVAX/USDC:USDC": [ { "tier": 1.0, @@ -7381,13 +7880,13 @@ "symbol": "AVAX/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.005, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "5000", + "notionalCap": "25000", "notionalFloor": "0", "maintMarginRatio": "0.005", "cum": "0.0" @@ -7397,153 +7896,153 @@ "tier": 2.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.0065, + "minNotional": 25000.0, + "maxNotional": 80000.0, + "maintenanceMarginRate": 0.01, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "notionalCap": "80000", + "notionalFloor": "25000", + "maintMarginRatio": "0.01", + "cum": "125.0" } }, { "tier": 3.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 80000.0, - "maintenanceMarginRate": 0.01, + "minNotional": 80000.0, + "maxNotional": 160000.0, + "maintenanceMarginRate": 0.015, "maxLeverage": 40.0, "info": { "bracket": "3", "initialLeverage": "40", - "notionalCap": "80000", - "notionalFloor": "25000", - "maintMarginRatio": "0.01", - "cum": "95.0" + "notionalCap": "160000", + "notionalFloor": "80000", + "maintMarginRatio": "0.015", + "cum": "525.0" } }, { "tier": 4.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 80000.0, - "maxNotional": 400000.0, + "minNotional": 160000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "notionalCap": "400000", - "notionalFloor": "80000", + "notionalCap": "800000", + "notionalFloor": "160000", "maintMarginRatio": "0.02", - "cum": "895.0" + "cum": "1325.0" } }, { "tier": 5.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 800000.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "800000", - "notionalFloor": "400000", + "notionalCap": "1600000", + "notionalFloor": "800000", "maintMarginRatio": "0.025", - "cum": "2895.0" + "cum": "5325.0" } }, { "tier": 6.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 4000000.0, + "minNotional": 1600000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "4000000", - "notionalFloor": "800000", + "notionalCap": "8000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.05", - "cum": "22895.0" + "cum": "45325.0" } }, { "tier": 7.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 8000000.0, + "minNotional": 8000000.0, + "maxNotional": 16000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "8000000", - "notionalFloor": "4000000", + "notionalCap": "16000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.1", - "cum": "222895.0" + "cum": "445325.0" } }, { "tier": 8.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 8000000.0, - "maxNotional": 10000000.0, + "minNotional": 16000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "8", "initialLeverage": "4", - "notionalCap": "10000000", - "notionalFloor": "8000000", + "notionalCap": "20000000", + "notionalFloor": "16000000", "maintMarginRatio": "0.125", - "cum": "422895.0" + "cum": "845325.0" } }, { "tier": 9.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "1672895.0" + "cum": "3345325.0" } }, { "tier": 10.0, "symbol": "AVAX/USDT:USDT", "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 50000000.0, + "minNotional": 40000000.0, + "maxNotional": 80000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "20000000", + "notionalCap": "80000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.5", - "cum": "6672895.0" + "cum": "13345325.0" } } ], @@ -8226,13 +8725,13 @@ "symbol": "BAN/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "5000", + "notionalCap": "10000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -8242,136 +8741,136 @@ "tier": 2.0, "symbol": "BAN/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 10000.0, + "minNotional": 10000.0, + "maxNotional": 30000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "10000", - "notionalFloor": "5000", + "notionalCap": "30000", + "notionalFloor": "10000", "maintMarginRatio": "0.015", - "cum": "25.0" + "cum": "50.0" } }, { "tier": 3.0, "symbol": "BAN/USDT:USDT", "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 30000.0, + "minNotional": 30000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "30000", - "notionalFloor": "10000", + "notionalCap": "150000", + "notionalFloor": "30000", "maintMarginRatio": "0.02", - "cum": "75.0" + "cum": "200.0" } }, { "tier": 4.0, "symbol": "BAN/USDT:USDT", "currency": "USDT", - "minNotional": 30000.0, - "maxNotional": 60000.0, + "minNotional": 150000.0, + "maxNotional": 300000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "60000", - "notionalFloor": "30000", + "notionalCap": "300000", + "notionalFloor": "150000", "maintMarginRatio": "0.025", - "cum": "225.0" + "cum": "950.0" } }, { "tier": 5.0, "symbol": "BAN/USDT:USDT", "currency": "USDT", - "minNotional": 60000.0, - "maxNotional": 300000.0, + "minNotional": 300000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "300000", - "notionalFloor": "60000", + "notionalCap": "1500000", + "notionalFloor": "300000", "maintMarginRatio": "0.05", - "cum": "1725.0" + "cum": "8450.0" } }, { "tier": 6.0, "symbol": "BAN/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 600000.0, + "minNotional": 1500000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "600000", - "notionalFloor": "300000", + "notionalCap": "3000000", + "notionalFloor": "1500000", "maintMarginRatio": "0.1", - "cum": "16725.0" + "cum": "83450.0" } }, { "tier": 7.0, "symbol": "BAN/USDT:USDT", "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 750000.0, + "minNotional": 3000000.0, + "maxNotional": 3750000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "750000", - "notionalFloor": "600000", + "notionalCap": "3750000", + "notionalFloor": "3000000", "maintMarginRatio": "0.125", - "cum": "31725.0" + "cum": "158450.0" } }, { "tier": 8.0, "symbol": "BAN/USDT:USDT", "currency": "USDT", - "minNotional": 750000.0, - "maxNotional": 1500000.0, + "minNotional": 3750000.0, + "maxNotional": 7500000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "1500000", - "notionalFloor": "750000", + "notionalCap": "7500000", + "notionalFloor": "3750000", "maintMarginRatio": "0.25", - "cum": "125475.0" + "cum": "627200.0" } }, { "tier": 9.0, "symbol": "BAN/USDT:USDT", "currency": "USDT", - "minNotional": 1500000.0, - "maxNotional": 3000000.0, + "minNotional": 7500000.0, + "maxNotional": 15000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1500000", + "notionalCap": "15000000", + "notionalFloor": "7500000", "maintMarginRatio": "0.5", - "cum": "500475.0" + "cum": "2502200.0" } } ], @@ -9122,13 +9621,13 @@ "symbol": "BCH/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.005, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "5000", + "notionalCap": "10000", "notionalFloor": "0", "maintMarginRatio": "0.005", "cum": "0.0" @@ -9138,153 +9637,153 @@ "tier": 2.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 10000.0, - "maintenanceMarginRate": 0.0065, + "minNotional": 10000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.01, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "10000", - "notionalFloor": "5000", - "maintMarginRatio": "0.0065", - "cum": "7.5" + "notionalCap": "100000", + "notionalFloor": "10000", + "maintMarginRatio": "0.01", + "cum": "50.0" } }, { "tier": 3.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.01, + "minNotional": 100000.0, + "maxNotional": 160000.0, + "maintenanceMarginRate": 0.015, "maxLeverage": 40.0, "info": { "bracket": "3", "initialLeverage": "40", - "notionalCap": "100000", - "notionalFloor": "10000", - "maintMarginRatio": "0.01", - "cum": "42.5" + "notionalCap": "160000", + "notionalFloor": "100000", + "maintMarginRatio": "0.015", + "cum": "550.0" } }, { "tier": 4.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 500000.0, + "minNotional": 160000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "notionalCap": "500000", - "notionalFloor": "100000", + "notionalCap": "800000", + "notionalFloor": "160000", "maintMarginRatio": "0.02", - "cum": "1042.5" + "cum": "1350.0" } }, { "tier": 5.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "1000000", - "notionalFloor": "500000", + "notionalCap": "1600000", + "notionalFloor": "800000", "maintMarginRatio": "0.025", - "cum": "3542.5" + "cum": "5350.0" } }, { "tier": 6.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 1600000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.05", - "cum": "28542.5" + "cum": "45350.0" } }, { "tier": 7.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 8000000.0, + "maxNotional": 16000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "16000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.1", - "cum": "278542.5" + "cum": "445350.0" } }, { "tier": 8.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 15000000.0, + "minNotional": 16000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "8", "initialLeverage": "4", - "notionalCap": "15000000", - "notionalFloor": "10000000", + "notionalCap": "20000000", + "notionalFloor": "16000000", "maintMarginRatio": "0.125", - "cum": "528542.5" + "cum": "845350.0" } }, { "tier": 9.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 15000000.0, - "maxNotional": 25000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "25000000", - "notionalFloor": "15000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "2403542.5" + "cum": "3345350.0" } }, { "tier": 10.0, "symbol": "BCH/USDT:USDT", "currency": "USDT", - "minNotional": 25000000.0, - "maxNotional": 50000000.0, + "minNotional": 40000000.0, + "maxNotional": 80000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "25000000", + "notionalCap": "80000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.5", - "cum": "8653542.5" + "cum": "13345350.0" } } ], @@ -10020,10 +10519,10 @@ "minNotional": 0.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "0", "maintMarginRatio": "0.025", @@ -10037,10 +10536,10 @@ "minNotional": 25000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 6.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "6", "notionalCap": "100000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -10086,13 +10585,13 @@ "symbol": "BLZ/USDT:USDT", "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 1500000.0, + "maxNotional": 1300000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "notionalCap": "1500000", + "notionalCap": "1300000", "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "136875.0" @@ -10102,17 +10601,17 @@ "tier": 6.0, "symbol": "BLZ/USDT:USDT", "currency": "USDT", - "minNotional": 1500000.0, - "maxNotional": 3000000.0, + "minNotional": 1300000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1500000", + "notionalCap": "1500000", + "notionalFloor": "1300000", "maintMarginRatio": "0.5", - "cum": "511875.0" + "cum": "461875.0" } } ], @@ -11037,10 +11536,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.015, - "maxLeverage": 21.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "21", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.015", @@ -11054,10 +11553,10 @@ "minNotional": 5000.0, "maxNotional": 10000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 8.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "8", "notionalCap": "10000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -11071,10 +11570,10 @@ "minNotional": 10000.0, "maxNotional": 100000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "6", "notionalCap": "100000", "notionalFloor": "10000", "maintMarginRatio": "0.05", @@ -11156,13 +11655,13 @@ "symbol": "BRETT/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "5000", + "notionalCap": "10000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -11172,136 +11671,136 @@ "tier": 2.0, "symbol": "BRETT/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 10000.0, + "minNotional": 10000.0, + "maxNotional": 20000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "10000", - "notionalFloor": "5000", + "notionalCap": "20000", + "notionalFloor": "10000", "maintMarginRatio": "0.015", - "cum": "25.0" + "cum": "50.0" } }, { "tier": 3.0, "symbol": "BRETT/USDT:USDT", "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 30000.0, + "minNotional": 20000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "30000", - "notionalFloor": "10000", + "notionalCap": "100000", + "notionalFloor": "20000", "maintMarginRatio": "0.02", - "cum": "75.0" + "cum": "150.0" } }, { "tier": 4.0, "symbol": "BRETT/USDT:USDT", "currency": "USDT", - "minNotional": 30000.0, - "maxNotional": 60000.0, + "minNotional": 100000.0, + "maxNotional": 200000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "60000", - "notionalFloor": "30000", + "notionalCap": "200000", + "notionalFloor": "100000", "maintMarginRatio": "0.025", - "cum": "225.0" + "cum": "650.0" } }, { "tier": 5.0, "symbol": "BRETT/USDT:USDT", "currency": "USDT", - "minNotional": 60000.0, - "maxNotional": 300000.0, + "minNotional": 200000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "300000", - "notionalFloor": "60000", + "notionalCap": "1000000", + "notionalFloor": "200000", "maintMarginRatio": "0.05", - "cum": "1725.0" + "cum": "5650.0" } }, { "tier": 6.0, "symbol": "BRETT/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 600000.0, + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "600000", - "notionalFloor": "300000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.1", - "cum": "16725.0" + "cum": "55650.0" } }, { "tier": 7.0, "symbol": "BRETT/USDT:USDT", "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 750000.0, + "minNotional": 2000000.0, + "maxNotional": 2500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "750000", - "notionalFloor": "600000", + "notionalCap": "2500000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", - "cum": "31725.0" + "cum": "105650.0" } }, { "tier": 8.0, "symbol": "BRETT/USDT:USDT", "currency": "USDT", - "minNotional": 750000.0, - "maxNotional": 1500000.0, + "minNotional": 2500000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "1500000", - "notionalFloor": "750000", + "notionalCap": "5000000", + "notionalFloor": "2500000", "maintMarginRatio": "0.25", - "cum": "125475.0" + "cum": "418150.0" } }, { "tier": 9.0, "symbol": "BRETT/USDT:USDT", "currency": "USDT", - "minNotional": 1500000.0, - "maxNotional": 3000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1500000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.5", - "cum": "500475.0" + "cum": "1668150.0" } } ], @@ -13621,6 +14120,161 @@ "symbol": "CHILLGUY/USDT:USDT", "currency": "USDT", "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "CHILLGUY/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 20000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "20000", + "notionalFloor": "10000", + "maintMarginRatio": "0.015", + "cum": "50.0" + } + }, + { + "tier": 3.0, + "symbol": "CHILLGUY/USDT:USDT", + "currency": "USDT", + "minNotional": 20000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "100000", + "notionalFloor": "20000", + "maintMarginRatio": "0.02", + "cum": "150.0" + } + }, + { + "tier": 4.0, + "symbol": "CHILLGUY/USDT:USDT", + "currency": "USDT", + "minNotional": 100000.0, + "maxNotional": 200000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "200000", + "notionalFloor": "100000", + "maintMarginRatio": "0.025", + "cum": "650.0" + } + }, + { + "tier": 5.0, + "symbol": "CHILLGUY/USDT:USDT", + "currency": "USDT", + "minNotional": 200000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "1000000", + "notionalFloor": "200000", + "maintMarginRatio": "0.05", + "cum": "5650.0" + } + }, + { + "tier": 6.0, + "symbol": "CHILLGUY/USDT:USDT", + "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "2000000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.1", + "cum": "55650.0" + } + }, + { + "tier": 7.0, + "symbol": "CHILLGUY/USDT:USDT", + "currency": "USDT", + "minNotional": 2000000.0, + "maxNotional": 2500000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "2500000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.125", + "cum": "105650.0" + } + }, + { + "tier": 8.0, + "symbol": "CHILLGUY/USDT:USDT", + "currency": "USDT", + "minNotional": 2500000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "5000000", + "notionalFloor": "2500000", + "maintMarginRatio": "0.25", + "cum": "418150.0" + } + }, + { + "tier": 9.0, + "symbol": "CHILLGUY/USDT:USDT", + "currency": "USDT", + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.5", + "cum": "1668150.0" + } + } + ], + "CHR/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "CHR/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 75.0, @@ -13635,7 +14289,7 @@ }, { "tier": 2.0, - "symbol": "CHILLGUY/USDT:USDT", + "symbol": "CHR/USDT:USDT", "currency": "USDT", "minNotional": 5000.0, "maxNotional": 10000.0, @@ -13652,16 +14306,16 @@ }, { "tier": 3.0, - "symbol": "CHILLGUY/USDT:USDT", + "symbol": "CHR/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 30000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "30000", + "notionalCap": "50000", "notionalFloor": "10000", "maintMarginRatio": "0.02", "cum": "75.0" @@ -13669,208 +14323,104 @@ }, { "tier": 4.0, - "symbol": "CHILLGUY/USDT:USDT", + "symbol": "CHR/USDT:USDT", "currency": "USDT", - "minNotional": 30000.0, - "maxNotional": 60000.0, + "minNotional": 50000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "60000", - "notionalFloor": "30000", + "notionalCap": "100000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", - "cum": "225.0" + "cum": "325.0" } }, { "tier": 5.0, - "symbol": "CHILLGUY/USDT:USDT", + "symbol": "CHR/USDT:USDT", "currency": "USDT", - "minNotional": 60000.0, - "maxNotional": 300000.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "300000", - "notionalFloor": "60000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.05", - "cum": "1725.0" + "cum": "2825.0" } }, { "tier": 6.0, - "symbol": "CHILLGUY/USDT:USDT", + "symbol": "CHR/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 600000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "600000", - "notionalFloor": "300000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.1", - "cum": "16725.0" + "cum": "27825.0" } }, { "tier": 7.0, - "symbol": "CHILLGUY/USDT:USDT", + "symbol": "CHR/USDT:USDT", "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 750000.0, + "minNotional": 1000000.0, + "maxNotional": 1250000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "750000", - "notionalFloor": "600000", + "notionalCap": "1250000", + "notionalFloor": "1000000", "maintMarginRatio": "0.125", - "cum": "31725.0" + "cum": "52825.0" } }, { "tier": 8.0, - "symbol": "CHILLGUY/USDT:USDT", + "symbol": "CHR/USDT:USDT", "currency": "USDT", - "minNotional": 750000.0, - "maxNotional": 1500000.0, + "minNotional": 1250000.0, + "maxNotional": 2500000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "1500000", - "notionalFloor": "750000", + "notionalCap": "2500000", + "notionalFloor": "1250000", "maintMarginRatio": "0.25", - "cum": "125475.0" + "cum": "209075.0" } }, { "tier": 9.0, - "symbol": "CHILLGUY/USDT:USDT", + "symbol": "CHR/USDT:USDT", "currency": "USDT", - "minNotional": 1500000.0, - "maxNotional": 3000000.0, + "minNotional": 2500000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1500000", - "maintMarginRatio": "0.5", - "cum": "500475.0" - } - } - ], - "CHR/USDT:USDT": [ - { - "tier": 1.0, - "symbol": "CHR/USDT:USDT", - "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, - "symbol": "CHR/USDT:USDT", - "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, - "symbol": "CHR/USDT:USDT", - "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, - "info": { - "bracket": "3", - "initialLeverage": "10", - "notionalCap": "200000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "650.0" - } - }, - { - "tier": 4.0, - "symbol": "CHR/USDT:USDT", - "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, - "info": { - "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "200000", - "maintMarginRatio": "0.1", - "cum": "10650.0" - } - }, - { - "tier": 5.0, - "symbol": "CHR/USDT:USDT", - "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, - "info": { - "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "23150.0" - } - }, - { - "tier": 6.0, - "symbol": "CHR/USDT:USDT", - "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.5, - "maxLeverage": 1.0, - "info": { - "bracket": "6", - "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalFloor": "2500000", "maintMarginRatio": "0.5", - "cum": "398150.0" + "cum": "834075.0" } } ], @@ -15069,118 +15619,135 @@ "symbol": "CRV/USDT:USDT", "currency": "USDT", "minNotional": 50000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maxNotional": 80000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 40.0, "info": { "bracket": "3", - "initialLeverage": "25", - "notionalCap": "200000", + "initialLeverage": "40", + "notionalCap": "80000", "notionalFloor": "50000", - "maintMarginRatio": "0.02", - "cum": "535.0" + "maintMarginRatio": "0.015", + "cum": "285.0" } }, { "tier": 4.0, "symbol": "CRV/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "minNotional": 80000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "4", - "initialLeverage": "20", - "notionalCap": "400000", - "notionalFloor": "200000", - "maintMarginRatio": "0.025", - "cum": "1535.0" + "initialLeverage": "25", + "notionalCap": "300000", + "notionalFloor": "80000", + "maintMarginRatio": "0.02", + "cum": "685.0" } }, { "tier": 5.0, "symbol": "CRV/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "5", - "initialLeverage": "10", - "notionalCap": "2000000", - "notionalFloor": "400000", - "maintMarginRatio": "0.05", - "cum": "11535.0" + "initialLeverage": "20", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.025", + "cum": "2185.0" } }, { "tier": 6.0, "symbol": "CRV/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 600000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "6", - "initialLeverage": "5", - "notionalCap": "4000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.1", - "cum": "111535.0" + "initialLeverage": "10", + "notionalCap": "3000000", + "notionalFloor": "600000", + "maintMarginRatio": "0.05", + "cum": "17185.0" } }, { "tier": 7.0, "symbol": "CRV/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 3000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "7", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "4000000", - "maintMarginRatio": "0.125", - "cum": "211535.0" + "initialLeverage": "5", + "notionalCap": "6000000", + "notionalFloor": "3000000", + "maintMarginRatio": "0.1", + "cum": "167185.0" } }, { "tier": 8.0, "symbol": "CRV/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 6000000.0, + "maxNotional": 7500000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "8", - "initialLeverage": "2", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.25", - "cum": "836535.0" + "initialLeverage": "4", + "notionalCap": "7500000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.125", + "cum": "317185.0" } }, { "tier": 9.0, "symbol": "CRV/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 7500000.0, + "maxNotional": 15000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "9", + "initialLeverage": "2", + "notionalCap": "15000000", + "notionalFloor": "7500000", + "maintMarginRatio": "0.25", + "cum": "1254685.0" + } + }, + { + "tier": 10.0, + "symbol": "CRV/USDT:USDT", + "currency": "USDT", + "minNotional": 15000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "9", + "bracket": "10", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "30000000", + "notionalFloor": "15000000", "maintMarginRatio": "0.5", - "cum": "3336535.0" + "cum": "5004685.0" } } ], @@ -15900,14 +16467,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.015, - "maxLeverage": 50.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "75", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.015", + "maintMarginRatio": "0.01", "cum": "0.0" } }, @@ -15916,15 +16483,15 @@ "symbol": "DASH/USDT:USDT", "currency": "USDT", "minNotional": 5000.0, - "maxNotional": 20000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "25", - "notionalCap": "20000", + "initialLeverage": "50", + "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.02", + "maintMarginRatio": "0.015", "cum": "25.0" } }, @@ -15932,102 +16499,119 @@ "tier": 3.0, "symbol": "DASH/USDT:USDT", "currency": "USDT", - "minNotional": 20000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "20000", - "maintMarginRatio": "0.025", - "cum": "125.0" + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" } }, { "tier": 4.0, "symbol": "DASH/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 50000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "4", - "initialLeverage": "10", - "notionalCap": "200000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "750.0" + "initialLeverage": "20", + "notionalCap": "100000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "325.0" } }, { "tier": 5.0, "symbol": "DASH/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "5", - "initialLeverage": "5", - "notionalCap": "400000", - "notionalFloor": "200000", - "maintMarginRatio": "0.1", - "cum": "10750.0" + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2825.0" } }, { "tier": 6.0, "symbol": "DASH/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "6", - "initialLeverage": "4", - "notionalCap": "500000", - "notionalFloor": "400000", - "maintMarginRatio": "0.125", - "cum": "20750.0" + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27825.0" } }, { "tier": 7.0, "symbol": "DASH/USDT:USDT", "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 1000000.0, + "maxNotional": 1250000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "7", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.25", - "cum": "83250.0" + "initialLeverage": "4", + "notionalCap": "1250000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.125", + "cum": "52825.0" } }, { "tier": 8.0, "symbol": "DASH/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 1250000.0, + "maxNotional": 2500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "2500000", + "notionalFloor": "1250000", + "maintMarginRatio": "0.25", + "cum": "209075.0" + } + }, + { + "tier": 9.0, + "symbol": "DASH/USDT:USDT", + "currency": "USDT", + "minNotional": 2500000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "8", + "bracket": "9", "initialLeverage": "1", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "5000000", + "notionalFloor": "2500000", "maintMarginRatio": "0.5", - "cum": "333250.0" + "cum": "834075.0" } } ], @@ -16290,6 +16874,161 @@ } } ], + "DEGO/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "DEGO/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "DENT/USDT:USDT": [ { "tier": 1.0, @@ -18933,13 +19672,13 @@ "symbol": "ENS/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "5000", + "notionalCap": "10000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -18949,136 +19688,136 @@ "tier": 2.0, "symbol": "ENS/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 16000.0, + "minNotional": 10000.0, + "maxNotional": 40000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "16000", - "notionalFloor": "5000", + "notionalCap": "40000", + "notionalFloor": "10000", "maintMarginRatio": "0.015", - "cum": "25.0" + "cum": "50.0" } }, { "tier": 3.0, "symbol": "ENS/USDT:USDT", "currency": "USDT", - "minNotional": 16000.0, - "maxNotional": 80000.0, + "minNotional": 40000.0, + "maxNotional": 200000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "80000", - "notionalFloor": "16000", + "notionalCap": "200000", + "notionalFloor": "40000", "maintMarginRatio": "0.02", - "cum": "105.0" + "cum": "250.0" } }, { "tier": 4.0, "symbol": "ENS/USDT:USDT", "currency": "USDT", - "minNotional": 80000.0, - "maxNotional": 160000.0, + "minNotional": 200000.0, + "maxNotional": 400000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "160000", - "notionalFloor": "80000", + "notionalCap": "400000", + "notionalFloor": "200000", "maintMarginRatio": "0.025", - "cum": "505.0" + "cum": "1250.0" } }, { "tier": 5.0, "symbol": "ENS/USDT:USDT", "currency": "USDT", - "minNotional": 160000.0, - "maxNotional": 800000.0, + "minNotional": 400000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "800000", - "notionalFloor": "160000", + "notionalCap": "2000000", + "notionalFloor": "400000", "maintMarginRatio": "0.05", - "cum": "4505.0" + "cum": "11250.0" } }, { "tier": 6.0, "symbol": "ENS/USDT:USDT", "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 1600000.0, + "minNotional": 2000000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "1600000", - "notionalFloor": "800000", + "notionalCap": "4000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.1", - "cum": "44505.0" + "cum": "111250.0" } }, { "tier": 7.0, "symbol": "ENS/USDT:USDT", "currency": "USDT", - "minNotional": 1600000.0, - "maxNotional": 2000000.0, + "minNotional": 4000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "2000000", - "notionalFloor": "1600000", + "notionalCap": "5000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.125", - "cum": "84505.0" + "cum": "211250.0" } }, { "tier": 8.0, "symbol": "ENS/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "4000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.25", - "cum": "334505.0" + "cum": "836250.0" } }, { "tier": 9.0, "symbol": "ENS/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 8000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "8000000", - "notionalFloor": "4000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "1334505.0" + "cum": "3336250.0" } } ], @@ -20430,13 +21169,13 @@ "symbol": "ETHFI/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 20000.0, + "maxNotional": 40000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "20000", + "notionalCap": "40000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -20446,119 +21185,119 @@ "tier": 3.0, "symbol": "ETHFI/USDT:USDT", "currency": "USDT", - "minNotional": 20000.0, - "maxNotional": 100000.0, + "minNotional": 40000.0, + "maxNotional": 200000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "100000", - "notionalFloor": "20000", + "notionalCap": "200000", + "notionalFloor": "40000", "maintMarginRatio": "0.02", - "cum": "150.0" + "cum": "250.0" } }, { "tier": 4.0, "symbol": "ETHFI/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 200000.0, + "minNotional": 200000.0, + "maxNotional": 400000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "200000", - "notionalFloor": "100000", + "notionalCap": "400000", + "notionalFloor": "200000", "maintMarginRatio": "0.025", - "cum": "650.0" + "cum": "1250.0" } }, { "tier": 5.0, "symbol": "ETHFI/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 1000000.0, + "minNotional": 400000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "200000", + "notionalCap": "2000000", + "notionalFloor": "400000", "maintMarginRatio": "0.05", - "cum": "5650.0" + "cum": "11250.0" } }, { "tier": 6.0, "symbol": "ETHFI/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 2000000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "4000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.1", - "cum": "55650.0" + "cum": "111250.0" } }, { "tier": 7.0, "symbol": "ETHFI/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 2500000.0, + "minNotional": 4000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "2500000", - "notionalFloor": "2000000", + "notionalCap": "5000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.125", - "cum": "105650.0" + "cum": "211250.0" } }, { "tier": 8.0, "symbol": "ETHFI/USDT:USDT", "currency": "USDT", - "minNotional": 2500000.0, - "maxNotional": 5000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "5000000", - "notionalFloor": "2500000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.25", - "cum": "418150.0" + "cum": "836250.0" } }, { "tier": 9.0, "symbol": "ETHFI/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "1668150.0" + "cum": "3336250.0" } } ], @@ -20740,13 +21479,13 @@ "symbol": "FET/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 60000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "60000", + "notionalCap": "100000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -20756,119 +21495,119 @@ "tier": 3.0, "symbol": "FET/USDT:USDT", "currency": "USDT", - "minNotional": 60000.0, - "maxNotional": 300000.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "300000", - "notionalFloor": "60000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.02", - "cum": "350.0" + "cum": "550.0" } }, { "tier": 4.0, "symbol": "FET/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 600000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "600000", - "notionalFloor": "300000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.025", - "cum": "1850.0" + "cum": "3050.0" } }, { "tier": 5.0, "symbol": "FET/USDT:USDT", "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 3000000.0, + "minNotional": 1000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "3000000", - "notionalFloor": "600000", + "notionalCap": "5000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.05", - "cum": "16850.0" + "cum": "28050.0" } }, { "tier": 6.0, "symbol": "FET/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 6000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "6000000", - "notionalFloor": "3000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1", - "cum": "166850.0" + "cum": "278050.0" } }, { "tier": 7.0, "symbol": "FET/USDT:USDT", "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 7500000.0, + "minNotional": 10000000.0, + "maxNotional": 12500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "7500000", - "notionalFloor": "6000000", + "notionalCap": "12500000", + "notionalFloor": "10000000", "maintMarginRatio": "0.125", - "cum": "316850.0" + "cum": "528050.0" } }, { "tier": 8.0, "symbol": "FET/USDT:USDT", "currency": "USDT", - "minNotional": 7500000.0, - "maxNotional": 15000000.0, + "minNotional": 12500000.0, + "maxNotional": 25000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "15000000", - "notionalFloor": "7500000", + "notionalCap": "25000000", + "notionalFloor": "12500000", "maintMarginRatio": "0.25", - "cum": "1254350.0" + "cum": "2090550.0" } }, { "tier": 9.0, "symbol": "FET/USDT:USDT", "currency": "USDT", - "minNotional": 15000000.0, - "maxNotional": 30000000.0, + "minNotional": 25000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "15000000", + "notionalCap": "50000000", + "notionalFloor": "25000000", "maintMarginRatio": "0.5", - "cum": "5004350.0" + "cum": "8340550.0" } } ], @@ -21256,13 +21995,13 @@ "symbol": "FIL/USDT:USDT", "currency": "USDT", "minNotional": 600000.0, - "maxNotional": 800000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "800000", + "notionalCap": "1000000", "notionalFloor": "600000", "maintMarginRatio": "0.025", "cum": "6200.0" @@ -21272,85 +22011,85 @@ "tier": 6.0, "symbol": "FIL/USDT:USDT", "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 3000000.0, + "minNotional": 1000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "3000000", - "notionalFloor": "800000", + "notionalCap": "5000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.05", - "cum": "26200.0" + "cum": "31200.0" } }, { "tier": 7.0, "symbol": "FIL/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 6000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "6000000", - "notionalFloor": "3000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1", - "cum": "176200.0" + "cum": "281200.0" } }, { "tier": 8.0, "symbol": "FIL/USDT:USDT", "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 12500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "8", "initialLeverage": "4", - "notionalCap": "10000000", - "notionalFloor": "6000000", + "notionalCap": "12500000", + "notionalFloor": "10000000", "maintMarginRatio": "0.125", - "cum": "326200.0" + "cum": "531200.0" } }, { "tier": 9.0, "symbol": "FIL/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 12500000.0, + "maxNotional": 25000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "25000000", + "notionalFloor": "12500000", "maintMarginRatio": "0.25", - "cum": "1576200.0" + "cum": "2093700.0" } }, { "tier": 10.0, "symbol": "FIL/USDT:USDT", "currency": "USDT", - "minNotional": 20000000.0, - "maxNotional": 30000000.0, + "minNotional": 25000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "20000000", + "notionalCap": "50000000", + "notionalFloor": "25000000", "maintMarginRatio": "0.5", - "cum": "6576200.0" + "cum": "8343700.0" } } ], @@ -21965,10 +22704,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.006, - "maxLeverage": 75.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "75", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.006", @@ -21982,10 +22721,10 @@ "minNotional": 5000.0, "maxNotional": 50000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 50.0, + "maxLeverage": 9.0, "info": { "bracket": "2", - "initialLeverage": "50", + "initialLeverage": "9", "notionalCap": "50000", "notionalFloor": "5000", "maintMarginRatio": "0.01", @@ -21999,10 +22738,10 @@ "minNotional": 50000.0, "maxNotional": 80000.0, "maintenanceMarginRate": 0.015, - "maxLeverage": 40.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "40", + "initialLeverage": "8", "notionalCap": "80000", "notionalFloor": "50000", "maintMarginRatio": "0.015", @@ -22016,10 +22755,10 @@ "minNotional": 80000.0, "maxNotional": 300000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maxLeverage": 7.0, "info": { "bracket": "4", - "initialLeverage": "25", + "initialLeverage": "7", "notionalCap": "300000", "notionalFloor": "80000", "maintMarginRatio": "0.02", @@ -22033,10 +22772,10 @@ "minNotional": 300000.0, "maxNotional": 600000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 6.0, "info": { "bracket": "5", - "initialLeverage": "20", + "initialLeverage": "6", "notionalCap": "600000", "notionalFloor": "300000", "maintMarginRatio": "0.025", @@ -22050,10 +22789,10 @@ "minNotional": 600000.0, "maxNotional": 3000000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 5.0, "info": { "bracket": "6", - "initialLeverage": "10", + "initialLeverage": "5", "notionalCap": "3000000", "notionalFloor": "600000", "maintMarginRatio": "0.05", @@ -22067,10 +22806,10 @@ "minNotional": 3000000.0, "maxNotional": 6000000.0, "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "maxLeverage": 4.0, "info": { "bracket": "7", - "initialLeverage": "5", + "initialLeverage": "4", "notionalCap": "6000000", "notionalFloor": "3000000", "maintMarginRatio": "0.1", @@ -22082,13 +22821,13 @@ "symbol": "FTM/USDT:USDT", "currency": "USDT", "minNotional": 6000000.0, - "maxNotional": 7500000.0, + "maxNotional": 7000000.0, "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "maxLeverage": 3.0, "info": { "bracket": "8", - "initialLeverage": "4", - "notionalCap": "7500000", + "initialLeverage": "3", + "notionalCap": "7000000", "notionalFloor": "6000000", "maintMarginRatio": "0.125", "cum": "317170.0" @@ -22098,34 +22837,34 @@ "tier": 9.0, "symbol": "FTM/USDT:USDT", "currency": "USDT", - "minNotional": 7500000.0, - "maxNotional": 15000000.0, + "minNotional": 7000000.0, + "maxNotional": 7200000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "15000000", - "notionalFloor": "7500000", + "notionalCap": "7200000", + "notionalFloor": "7000000", "maintMarginRatio": "0.25", - "cum": "1254670.0" + "cum": "1192170.0" } }, { "tier": 10.0, "symbol": "FTM/USDT:USDT", "currency": "USDT", - "minNotional": 15000000.0, - "maxNotional": 30000000.0, + "minNotional": 7200000.0, + "maxNotional": 7500000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "15000000", + "notionalCap": "7500000", + "notionalFloor": "7200000", "maintMarginRatio": "0.5", - "cum": "5004670.0" + "cum": "2992170.0" } } ], @@ -23585,13 +24324,13 @@ "symbol": "GRASS/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "5000", + "notionalCap": "10000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -23601,136 +24340,136 @@ "tier": 2.0, "symbol": "GRASS/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 16000.0, + "minNotional": 10000.0, + "maxNotional": 30000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "16000", - "notionalFloor": "5000", + "notionalCap": "30000", + "notionalFloor": "10000", "maintMarginRatio": "0.015", - "cum": "25.0" + "cum": "50.0" } }, { "tier": 3.0, "symbol": "GRASS/USDT:USDT", "currency": "USDT", - "minNotional": 16000.0, - "maxNotional": 80000.0, + "minNotional": 30000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "80000", - "notionalFloor": "16000", + "notionalCap": "150000", + "notionalFloor": "30000", "maintMarginRatio": "0.02", - "cum": "105.0" + "cum": "200.0" } }, { "tier": 4.0, "symbol": "GRASS/USDT:USDT", "currency": "USDT", - "minNotional": 80000.0, - "maxNotional": 160000.0, + "minNotional": 150000.0, + "maxNotional": 300000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "160000", - "notionalFloor": "80000", + "notionalCap": "300000", + "notionalFloor": "150000", "maintMarginRatio": "0.025", - "cum": "505.0" + "cum": "950.0" } }, { "tier": 5.0, "symbol": "GRASS/USDT:USDT", "currency": "USDT", - "minNotional": 160000.0, - "maxNotional": 800000.0, + "minNotional": 300000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "800000", - "notionalFloor": "160000", + "notionalCap": "1500000", + "notionalFloor": "300000", "maintMarginRatio": "0.05", - "cum": "4505.0" + "cum": "8450.0" } }, { "tier": 6.0, "symbol": "GRASS/USDT:USDT", "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 1600000.0, + "minNotional": 1500000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "1600000", - "notionalFloor": "800000", + "notionalCap": "3000000", + "notionalFloor": "1500000", "maintMarginRatio": "0.1", - "cum": "44505.0" + "cum": "83450.0" } }, { "tier": 7.0, "symbol": "GRASS/USDT:USDT", "currency": "USDT", - "minNotional": 1600000.0, - "maxNotional": 2000000.0, + "minNotional": 3000000.0, + "maxNotional": 3750000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "2000000", - "notionalFloor": "1600000", + "notionalCap": "3750000", + "notionalFloor": "3000000", "maintMarginRatio": "0.125", - "cum": "84505.0" + "cum": "158450.0" } }, { "tier": 8.0, "symbol": "GRASS/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, + "minNotional": 3750000.0, + "maxNotional": 7500000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "4000000", - "notionalFloor": "2000000", + "notionalCap": "7500000", + "notionalFloor": "3750000", "maintMarginRatio": "0.25", - "cum": "334505.0" + "cum": "627200.0" } }, { "tier": 9.0, "symbol": "GRASS/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 8000000.0, + "minNotional": 7500000.0, + "maxNotional": 15000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "8000000", - "notionalFloor": "4000000", + "notionalCap": "15000000", + "notionalFloor": "7500000", "maintMarginRatio": "0.5", - "cum": "1334505.0" + "cum": "2502200.0" } } ], @@ -24033,13 +24772,13 @@ "symbol": "HBAR/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 20000.0, + "maxNotional": 80000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "20000", + "notionalCap": "80000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -24049,119 +24788,119 @@ "tier": 3.0, "symbol": "HBAR/USDT:USDT", "currency": "USDT", - "minNotional": 20000.0, - "maxNotional": 100000.0, + "minNotional": 80000.0, + "maxNotional": 400000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "100000", - "notionalFloor": "20000", + "notionalCap": "400000", + "notionalFloor": "80000", "maintMarginRatio": "0.02", - "cum": "150.0" + "cum": "450.0" } }, { "tier": 4.0, "symbol": "HBAR/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 200000.0, + "minNotional": 400000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "200000", - "notionalFloor": "100000", + "notionalCap": "800000", + "notionalFloor": "400000", "maintMarginRatio": "0.025", - "cum": "650.0" + "cum": "2450.0" } }, { "tier": 5.0, "symbol": "HBAR/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 1000000.0, + "minNotional": 800000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "1000000", - "notionalFloor": "200000", + "notionalCap": "4000000", + "notionalFloor": "800000", "maintMarginRatio": "0.05", - "cum": "5650.0" + "cum": "22450.0" } }, { "tier": 6.0, "symbol": "HBAR/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 4000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.1", - "cum": "55650.0" + "cum": "222450.0" } }, { "tier": 7.0, "symbol": "HBAR/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 2500000.0, + "minNotional": 8000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "2500000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.125", - "cum": "105650.0" + "cum": "422450.0" } }, { "tier": 8.0, "symbol": "HBAR/USDT:USDT", "currency": "USDT", - "minNotional": 2500000.0, - "maxNotional": 5000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "5000000", - "notionalFloor": "2500000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", - "cum": "418150.0" + "cum": "1672450.0" } }, { "tier": 9.0, "symbol": "HBAR/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", - "cum": "1668150.0" + "cum": "6672450.0" } } ], @@ -25931,13 +26670,13 @@ "symbol": "INJ/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 40000.0, + "maxNotional": 80000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "40000", + "notionalCap": "80000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -25947,119 +26686,119 @@ "tier": 3.0, "symbol": "INJ/USDT:USDT", "currency": "USDT", - "minNotional": 40000.0, - "maxNotional": 200000.0, + "minNotional": 80000.0, + "maxNotional": 400000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "200000", - "notionalFloor": "40000", + "notionalCap": "400000", + "notionalFloor": "80000", "maintMarginRatio": "0.02", - "cum": "250.0" + "cum": "450.0" } }, { "tier": 4.0, "symbol": "INJ/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, + "minNotional": 400000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "400000", - "notionalFloor": "200000", + "notionalCap": "800000", + "notionalFloor": "400000", "maintMarginRatio": "0.025", - "cum": "1250.0" + "cum": "2450.0" } }, { "tier": 5.0, "symbol": "INJ/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 2000000.0, + "minNotional": 800000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "2000000", - "notionalFloor": "400000", + "notionalCap": "4000000", + "notionalFloor": "800000", "maintMarginRatio": "0.05", - "cum": "11250.0" + "cum": "22450.0" } }, { "tier": 6.0, "symbol": "INJ/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, + "minNotional": 4000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "4000000", - "notionalFloor": "2000000", + "notionalCap": "8000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.1", - "cum": "111250.0" + "cum": "222450.0" } }, { "tier": 7.0, "symbol": "INJ/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 5000000.0, + "minNotional": 8000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "4000000", + "notionalCap": "10000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.125", - "cum": "211250.0" + "cum": "422450.0" } }, { "tier": 8.0, "symbol": "INJ/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 12000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "12000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", - "cum": "836250.0" + "cum": "1672450.0" } }, { "tier": 9.0, "symbol": "INJ/USDT:USDT", "currency": "USDT", - "minNotional": 12000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "12000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", - "cum": "3836250.0" + "cum": "6672450.0" } } ], @@ -26760,14 +27499,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "75", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.02", + "maintMarginRatio": "0.01", "cum": "0.0" } }, @@ -26776,15 +27515,15 @@ "symbol": "JOE/USDT:USDT", "currency": "USDT", "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 15.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "15", - "notionalCap": "25000", + "initialLeverage": "50", + "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.015", "cum": "25.0" } }, @@ -26792,85 +27531,119 @@ "tier": 3.0, "symbol": "JOE/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "200000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "650.0" + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" } }, { "tier": 4.0, "symbol": "JOE/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 50000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "200000", - "maintMarginRatio": "0.1", - "cum": "10650.0" + "initialLeverage": "20", + "notionalCap": "100000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "325.0" } }, { "tier": 5.0, "symbol": "JOE/USDT:USDT", "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "23150.0" + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2825.0" } }, { "tier": 6.0, "symbol": "JOE/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "6", - "initialLeverage": "2", - "notionalCap": "3000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "148150.0" + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27825.0" } }, { "tier": 7.0, "symbol": "JOE/USDT:USDT", "currency": "USDT", + "minNotional": 1000000.0, + "maxNotional": 1250000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "1250000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.125", + "cum": "52825.0" + } + }, + { + "tier": 8.0, + "symbol": "JOE/USDT:USDT", + "currency": "USDT", + "minNotional": 1250000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "3000000", + "notionalFloor": "1250000", + "maintMarginRatio": "0.25", + "cum": "209075.0" + } + }, + { + "tier": 9.0, + "symbol": "JOE/USDT:USDT", + "currency": "USDT", "minNotional": 3000000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "7", + "bracket": "9", "initialLeverage": "1", "notionalCap": "5000000", "notionalFloor": "3000000", "maintMarginRatio": "0.5", - "cum": "898150.0" + "cum": "959075.0" } } ], @@ -27184,6 +27957,161 @@ } } ], + "KAIA/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "KAIA/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "KAS/USDT:USDT": [ { "tier": 1.0, @@ -28012,6 +28940,161 @@ } } ], + "KOMA/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "KOMA/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "KSM/USDT:USDT": [ { "tier": 1.0, @@ -28776,13 +29859,13 @@ "symbol": "LINK/USDT:USDT", "currency": "USDT", "minNotional": 50000.0, - "maxNotional": 80000.0, + "maxNotional": 160000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 40.0, "info": { "bracket": "3", "initialLeverage": "40", - "notionalCap": "80000", + "notionalCap": "160000", "notionalFloor": "50000", "maintMarginRatio": "0.015", "cum": "300.0" @@ -28792,75 +29875,75 @@ "tier": 4.0, "symbol": "LINK/USDT:USDT", "currency": "USDT", - "minNotional": 80000.0, - "maxNotional": 400000.0, + "minNotional": 160000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "notionalCap": "400000", - "notionalFloor": "80000", + "notionalCap": "800000", + "notionalFloor": "160000", "maintMarginRatio": "0.02", - "cum": "700.0" + "cum": "1100.0" } }, { "tier": 5.0, "symbol": "LINK/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 800000.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "800000", - "notionalFloor": "400000", + "notionalCap": "1600000", + "notionalFloor": "800000", "maintMarginRatio": "0.025", - "cum": "2700.0" + "cum": "5100.0" } }, { "tier": 6.0, "symbol": "LINK/USDT:USDT", "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 4000000.0, + "minNotional": 1600000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "4000000", - "notionalFloor": "800000", + "notionalCap": "8000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.05", - "cum": "22700.0" + "cum": "45100.0" } }, { "tier": 7.0, "symbol": "LINK/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 8000000.0, + "minNotional": 8000000.0, + "maxNotional": 16000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "8000000", - "notionalFloor": "4000000", + "notionalCap": "16000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.1", - "cum": "222700.0" + "cum": "445100.0" } }, { "tier": 8.0, "symbol": "LINK/USDT:USDT", "currency": "USDT", - "minNotional": 8000000.0, + "minNotional": 16000000.0, "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, @@ -28868,9 +29951,9 @@ "bracket": "8", "initialLeverage": "4", "notionalCap": "20000000", - "notionalFloor": "8000000", + "notionalFloor": "16000000", "maintMarginRatio": "0.125", - "cum": "422700.0" + "cum": "845100.0" } }, { @@ -28878,33 +29961,33 @@ "symbol": "LINK/USDT:USDT", "currency": "USDT", "minNotional": 20000000.0, - "maxNotional": 30000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "30000000", + "notionalCap": "40000000", "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "2922700.0" + "cum": "3345100.0" } }, { "tier": 10.0, "symbol": "LINK/USDT:USDT", "currency": "USDT", - "minNotional": 30000000.0, - "maxNotional": 50000000.0, + "minNotional": 40000000.0, + "maxNotional": 80000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "30000000", + "notionalCap": "80000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.5", - "cum": "10422700.0" + "cum": "13345100.0" } } ], @@ -29347,10 +30430,10 @@ "minNotional": 0.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.03, - "maxLeverage": 20.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "10", "notionalCap": "25000", "notionalFloor": "0", "maintMarginRatio": "0.03", @@ -29364,10 +30447,10 @@ "minNotional": 25000.0, "maxNotional": 200000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 8.0, "info": { "bracket": "2", - "initialLeverage": "10", + "initialLeverage": "8", "notionalCap": "200000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -29413,13 +30496,13 @@ "symbol": "LOOM/USDT:USDT", "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 3000000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "5", "initialLeverage": "2", - "notionalCap": "3000000", + "notionalCap": "1500000", "notionalFloor": "1000000", "maintMarginRatio": "0.25", "cum": "148000.0" @@ -29429,17 +30512,17 @@ "tier": 6.0, "symbol": "LOOM/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 3500000.0, + "minNotional": 1500000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "6", "initialLeverage": "1", - "notionalCap": "3500000", - "notionalFloor": "3000000", + "notionalCap": "2000000", + "notionalFloor": "1500000", "maintMarginRatio": "0.5", - "cum": "898000.0" + "cum": "523000.0" } } ], @@ -30105,13 +31188,13 @@ "symbol": "LTC/USDT:USDT", "currency": "USDT", "minNotional": 50000.0, - "maxNotional": 100000.0, + "maxNotional": 160000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 40.0, "info": { "bracket": "3", "initialLeverage": "40", - "notionalCap": "100000", + "notionalCap": "160000", "notionalFloor": "50000", "maintMarginRatio": "0.015", "cum": "300.0" @@ -30121,75 +31204,75 @@ "tier": 4.0, "symbol": "LTC/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 750000.0, + "minNotional": 160000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "notionalCap": "750000", - "notionalFloor": "100000", + "notionalCap": "800000", + "notionalFloor": "160000", "maintMarginRatio": "0.02", - "cum": "800.0" + "cum": "1100.0" } }, { "tier": 5.0, "symbol": "LTC/USDT:USDT", "currency": "USDT", - "minNotional": 750000.0, - "maxNotional": 1000000.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "1000000", - "notionalFloor": "750000", + "notionalCap": "1600000", + "notionalFloor": "800000", "maintMarginRatio": "0.025", - "cum": "4550.0" + "cum": "5100.0" } }, { "tier": 6.0, "symbol": "LTC/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 1600000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.05", - "cum": "29550.0" + "cum": "45100.0" } }, { "tier": 7.0, "symbol": "LTC/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 8000000.0, + "maxNotional": 16000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "16000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.1", - "cum": "279550.0" + "cum": "445100.0" } }, { "tier": 8.0, "symbol": "LTC/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, + "minNotional": 16000000.0, "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, @@ -30197,9 +31280,9 @@ "bracket": "8", "initialLeverage": "4", "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalFloor": "16000000", "maintMarginRatio": "0.125", - "cum": "529550.0" + "cum": "845100.0" } }, { @@ -30207,33 +31290,188 @@ "symbol": "LTC/USDT:USDT", "currency": "USDT", "minNotional": 20000000.0, - "maxNotional": 30000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "30000000", + "notionalCap": "40000000", "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "3029550.0" + "cum": "3345100.0" } }, { "tier": 10.0, "symbol": "LTC/USDT:USDT", "currency": "USDT", - "minNotional": 30000000.0, - "maxNotional": 50000000.0, + "minNotional": 40000000.0, + "maxNotional": 80000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "30000000", + "notionalCap": "80000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.5", - "cum": "10529550.0" + "cum": "13345100.0" + } + } + ], + "LUMIA/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "LUMIA/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" } } ], @@ -30244,14 +31482,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.015, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "75", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.015", + "maintMarginRatio": "0.01", "cum": "0.0" } }, @@ -30260,84 +31498,135 @@ "symbol": "LUNA2/USDT:USDT", "currency": "USDT", "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "10", - "notionalCap": "25000", + "initialLeverage": "50", + "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "50.0" + "maintMarginRatio": "0.015", + "cum": "25.0" } }, { "tier": 3.0, "symbol": "LUNA2/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "675.0" + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" } }, { "tier": 4.0, "symbol": "LUNA2/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 50000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5675.0" + "initialLeverage": "20", + "notionalCap": "100000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "325.0" } }, { "tier": 5.0, "symbol": "LUNA2/USDT:USDT", "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11925.0" + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2825.0" } }, { "tier": 6.0, "symbol": "LUNA2/USDT:USDT", "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27825.0" + } + }, + { + "tier": 7.0, + "symbol": "LUNA2/USDT:USDT", + "currency": "USDT", "minNotional": 1000000.0, + "maxNotional": 1250000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "1250000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.125", + "cum": "52825.0" + } + }, + { + "tier": 8.0, + "symbol": "LUNA2/USDT:USDT", + "currency": "USDT", + "minNotional": 1250000.0, + "maxNotional": 2500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "2500000", + "notionalFloor": "1250000", + "maintMarginRatio": "0.25", + "cum": "209075.0" + } + }, + { + "tier": 9.0, + "symbol": "LUNA2/USDT:USDT", + "currency": "USDT", + "minNotional": 2500000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "9", "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalFloor": "2500000", "maintMarginRatio": "0.5", - "cum": "386925.0" + "cum": "834075.0" } } ], @@ -31090,10 +32379,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.015, - "maxLeverage": 50.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.015", @@ -31107,10 +32396,10 @@ "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", @@ -31124,10 +32413,10 @@ "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", @@ -31479,6 +32768,161 @@ } } ], + "ME/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "ME/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "MEME/USDT:USDT": [ { "tier": 1.0, @@ -32203,6 +33647,161 @@ } } ], + "MOCA/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "MOCA/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "MOODENG/USDT:USDT": [ { "tier": 1.0, @@ -32513,6 +34112,161 @@ } } ], + "MOVE/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.015", + "cum": "50.0" + } + }, + { + "tier": 3.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 150000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "150000", + "notionalFloor": "30000", + "maintMarginRatio": "0.02", + "cum": "200.0" + } + }, + { + "tier": 4.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 150000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "300000", + "notionalFloor": "150000", + "maintMarginRatio": "0.025", + "cum": "950.0" + } + }, + { + "tier": 5.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "1500000", + "notionalFloor": "300000", + "maintMarginRatio": "0.05", + "cum": "8450.0" + } + }, + { + "tier": 6.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.1", + "cum": "83450.0" + } + }, + { + "tier": 7.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 3000000.0, + "maxNotional": 3750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "3750000", + "notionalFloor": "3000000", + "maintMarginRatio": "0.125", + "cum": "158450.0" + } + }, + { + "tier": 8.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 3750000.0, + "maxNotional": 7500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "7500000", + "notionalFloor": "3750000", + "maintMarginRatio": "0.25", + "cum": "627200.0" + } + }, + { + "tier": 9.0, + "symbol": "MOVE/USDT:USDT", + "currency": "USDT", + "minNotional": 7500000.0, + "maxNotional": 15000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "15000000", + "notionalFloor": "7500000", + "maintMarginRatio": "0.5", + "cum": "2502200.0" + } + } + ], "MOVR/USDT:USDT": [ { "tier": 1.0, @@ -33054,13 +34808,13 @@ "symbol": "NEAR/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 10000.0, + "maxNotional": 20000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "10000", + "notionalCap": "20000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -33070,136 +34824,136 @@ "tier": 2.0, "symbol": "NEAR/USDT:USDT", "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 100000.0, + "minNotional": 20000.0, + "maxNotional": 200000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "100000", - "notionalFloor": "10000", + "notionalCap": "200000", + "notionalFloor": "20000", "maintMarginRatio": "0.015", - "cum": "50.0" + "cum": "100.0" } }, { "tier": 3.0, "symbol": "NEAR/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 500000.0, + "minNotional": 200000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "500000", - "notionalFloor": "100000", + "notionalCap": "1000000", + "notionalFloor": "200000", "maintMarginRatio": "0.02", - "cum": "550.0" + "cum": "1100.0" } }, { "tier": 4.0, "symbol": "NEAR/USDT:USDT", "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, + "minNotional": 1000000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "1000000", - "notionalFloor": "500000", + "notionalCap": "2000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.025", - "cum": "3050.0" + "cum": "6100.0" } }, { "tier": 5.0, "symbol": "NEAR/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 2000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "10000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.05", - "cum": "28050.0" + "cum": "56100.0" } }, { "tier": 6.0, "symbol": "NEAR/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.1", - "cum": "278050.0" + "cum": "556100.0" } }, { "tier": 7.0, "symbol": "NEAR/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 12500000.0, + "minNotional": 20000000.0, + "maxNotional": 25000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "12500000", - "notionalFloor": "10000000", + "notionalCap": "25000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.125", - "cum": "528050.0" + "cum": "1056100.0" } }, { "tier": 8.0, "symbol": "NEAR/USDT:USDT", "currency": "USDT", - "minNotional": 12500000.0, - "maxNotional": 25000000.0, + "minNotional": 25000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "25000000", - "notionalFloor": "12500000", + "notionalCap": "50000000", + "notionalFloor": "25000000", "maintMarginRatio": "0.25", - "cum": "2090550.0" + "cum": "4181100.0" } }, { "tier": 9.0, "symbol": "NEAR/USDT:USDT", "currency": "USDT", - "minNotional": 25000000.0, - "maxNotional": 50000000.0, + "minNotional": 50000000.0, + "maxNotional": 100000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "25000000", + "notionalCap": "100000000", + "notionalFloor": "50000000", "maintMarginRatio": "0.5", - "cum": "8340550.0" + "cum": "16681100.0" } } ], @@ -34988,10 +36742,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.015, - "maxLeverage": 50.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.015", @@ -35005,10 +36759,10 @@ "minNotional": 5000.0, "maxNotional": 50000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 8.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "8", "notionalCap": "50000", "notionalFloor": "5000", "maintMarginRatio": "0.025", @@ -35022,10 +36776,10 @@ "minNotional": 50000.0, "maxNotional": 900000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "6", "notionalCap": "900000", "notionalFloor": "50000", "maintMarginRatio": "0.05", @@ -35037,13 +36791,13 @@ "symbol": "OMG/USDT:USDT", "currency": "USDT", "minNotional": 900000.0, - "maxNotional": 2400000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "4", "initialLeverage": "5", - "notionalCap": "2400000", + "notionalCap": "2000000", "notionalFloor": "900000", "maintMarginRatio": "0.1", "cum": "46300.0" @@ -35053,51 +36807,51 @@ "tier": 5.0, "symbol": "OMG/USDT:USDT", "currency": "USDT", - "minNotional": 2400000.0, - "maxNotional": 3000000.0, + "minNotional": 2000000.0, + "maxNotional": 2100000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "5", "initialLeverage": "4", - "notionalCap": "3000000", - "notionalFloor": "2400000", + "notionalCap": "2100000", + "notionalFloor": "2000000", "maintMarginRatio": "0.125", - "cum": "106300.0" + "cum": "96300.0" } }, { "tier": 6.0, "symbol": "OMG/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 9000000.0, + "minNotional": 2100000.0, + "maxNotional": 2200000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "notionalCap": "9000000", - "notionalFloor": "3000000", + "notionalCap": "2200000", + "notionalFloor": "2100000", "maintMarginRatio": "0.25", - "cum": "481300.0" + "cum": "358800.0" } }, { "tier": 7.0, "symbol": "OMG/USDT:USDT", "currency": "USDT", - "minNotional": 9000000.0, - "maxNotional": 15000000.0, + "minNotional": 2200000.0, + "maxNotional": 2300000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "15000000", - "notionalFloor": "9000000", + "notionalCap": "2300000", + "notionalFloor": "2200000", "maintMarginRatio": "0.5", - "cum": "2731300.0" + "cum": "908800.0" } } ], @@ -35262,13 +37016,13 @@ "symbol": "ONDO/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 40000.0, + "maxNotional": 80000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "40000", + "notionalCap": "80000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -35278,119 +37032,119 @@ "tier": 3.0, "symbol": "ONDO/USDT:USDT", "currency": "USDT", - "minNotional": 40000.0, - "maxNotional": 200000.0, + "minNotional": 80000.0, + "maxNotional": 400000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "200000", - "notionalFloor": "40000", + "notionalCap": "400000", + "notionalFloor": "80000", "maintMarginRatio": "0.02", - "cum": "250.0" + "cum": "450.0" } }, { "tier": 4.0, "symbol": "ONDO/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, + "minNotional": 400000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "400000", - "notionalFloor": "200000", + "notionalCap": "800000", + "notionalFloor": "400000", "maintMarginRatio": "0.025", - "cum": "1250.0" + "cum": "2450.0" } }, { "tier": 5.0, "symbol": "ONDO/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 2000000.0, + "minNotional": 800000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "2000000", - "notionalFloor": "400000", + "notionalCap": "4000000", + "notionalFloor": "800000", "maintMarginRatio": "0.05", - "cum": "11250.0" + "cum": "22450.0" } }, { "tier": 6.0, "symbol": "ONDO/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, + "minNotional": 4000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "4000000", - "notionalFloor": "2000000", + "notionalCap": "8000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.1", - "cum": "111250.0" + "cum": "222450.0" } }, { "tier": 7.0, "symbol": "ONDO/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 5000000.0, + "minNotional": 8000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "4000000", + "notionalCap": "10000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.125", - "cum": "211250.0" + "cum": "422450.0" } }, { "tier": 8.0, "symbol": "ONDO/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.25", - "cum": "836250.0" + "cum": "1672450.0" } }, { "tier": 9.0, "symbol": "ONDO/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.5", - "cum": "3336250.0" + "cum": "6672450.0" } } ], @@ -35954,10 +37708,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 75.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "75", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -35971,10 +37725,10 @@ "minNotional": 5000.0, "maxNotional": 10000.0, "maintenanceMarginRate": 0.015, - "maxLeverage": 50.0, + "maxLeverage": 9.0, "info": { "bracket": "2", - "initialLeverage": "50", + "initialLeverage": "9", "notionalCap": "10000", "notionalFloor": "5000", "maintMarginRatio": "0.015", @@ -35988,10 +37742,10 @@ "minNotional": 10000.0, "maxNotional": 30000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maxLeverage": 8.0, "info": { "bracket": "3", - "initialLeverage": "25", + "initialLeverage": "8", "notionalCap": "30000", "notionalFloor": "10000", "maintMarginRatio": "0.02", @@ -36005,10 +37759,10 @@ "minNotional": 30000.0, "maxNotional": 60000.0, "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxLeverage": 7.0, "info": { "bracket": "4", - "initialLeverage": "20", + "initialLeverage": "7", "notionalCap": "60000", "notionalFloor": "30000", "maintMarginRatio": "0.025", @@ -36022,10 +37776,10 @@ "minNotional": 60000.0, "maxNotional": 300000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 6.0, "info": { "bracket": "5", - "initialLeverage": "10", + "initialLeverage": "6", "notionalCap": "300000", "notionalFloor": "60000", "maintMarginRatio": "0.05", @@ -36071,6 +37825,161 @@ "symbol": "ORBS/USDT:USDT", "currency": "USDT", "minNotional": 750000.0, + "maxNotional": 900000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "900000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "ORBS/USDT:USDT", + "currency": "USDT", + "minNotional": 900000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "1000000", + "notionalFloor": "900000", + "maintMarginRatio": "0.5", + "cum": "350475.0" + } + } + ], + "ORCA/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "ORCA/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "ORCA/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "ORCA/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "ORCA/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "ORCA/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "ORCA/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "ORCA/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "ORCA/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, "maxNotional": 1500000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, @@ -36085,7 +37994,7 @@ }, { "tier": 9.0, - "symbol": "ORBS/USDT:USDT", + "symbol": "ORCA/USDT:USDT", "currency": "USDT", "minNotional": 1500000.0, "maxNotional": 3000000.0, @@ -36721,6 +38630,161 @@ } } ], + "PENGU/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "PENGU/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "PEOPLE/USDT:USDT": [ { "tier": 1.0, @@ -37262,13 +39326,13 @@ "symbol": "PNUT/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 10000.0, + "maxNotional": 20000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "10000", + "notionalCap": "20000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -37278,136 +39342,136 @@ "tier": 2.0, "symbol": "PNUT/USDT:USDT", "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 40000.0, + "minNotional": 20000.0, + "maxNotional": 160000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "40000", - "notionalFloor": "10000", + "notionalCap": "160000", + "notionalFloor": "20000", "maintMarginRatio": "0.015", - "cum": "50.0" + "cum": "100.0" } }, { "tier": 3.0, "symbol": "PNUT/USDT:USDT", "currency": "USDT", - "minNotional": 40000.0, - "maxNotional": 200000.0, + "minNotional": 160000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "200000", - "notionalFloor": "40000", + "notionalCap": "800000", + "notionalFloor": "160000", "maintMarginRatio": "0.02", - "cum": "250.0" + "cum": "900.0" } }, { "tier": 4.0, "symbol": "PNUT/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "400000", - "notionalFloor": "200000", + "notionalCap": "1600000", + "notionalFloor": "800000", "maintMarginRatio": "0.025", - "cum": "1250.0" + "cum": "4900.0" } }, { "tier": 5.0, "symbol": "PNUT/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 2000000.0, + "minNotional": 1600000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "2000000", - "notionalFloor": "400000", + "notionalCap": "8000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.05", - "cum": "11250.0" + "cum": "44900.0" } }, { "tier": 6.0, "symbol": "PNUT/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, + "minNotional": 8000000.0, + "maxNotional": 16000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "4000000", - "notionalFloor": "2000000", + "notionalCap": "16000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.1", - "cum": "111250.0" + "cum": "444900.0" } }, { "tier": 7.0, "symbol": "PNUT/USDT:USDT", "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 5000000.0, + "minNotional": 16000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "4000000", + "notionalCap": "20000000", + "notionalFloor": "16000000", "maintMarginRatio": "0.125", - "cum": "211250.0" + "cum": "844900.0" } }, { "tier": 8.0, "symbol": "PNUT/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "836250.0" + "cum": "3344900.0" } }, { "tier": 9.0, "symbol": "PNUT/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 40000000.0, + "maxNotional": 80000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "80000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.5", - "cum": "3336250.0" + "cum": "13344900.0" } } ], @@ -38419,10 +40483,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 20.0, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "75", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.01", @@ -38434,84 +40498,135 @@ "symbol": "QNT/USDT:USDT", "currency": "USDT", "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 10.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "10", - "notionalCap": "25000", + "initialLeverage": "50", + "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "75.0" + "maintMarginRatio": "0.015", + "cum": "25.0" } }, { "tier": 3.0, "symbol": "QNT/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 8.0, + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "8", - "notionalCap": "100000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "700.0" + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" } }, { "tier": 4.0, "symbol": "QNT/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 50000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "250000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5700.0" + "initialLeverage": "20", + "notionalCap": "100000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "325.0" } }, { "tier": 5.0, "symbol": "QNT/USDT:USDT", "currency": "USDT", - "minNotional": 250000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 2.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "5", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.125", - "cum": "11950.0" + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2825.0" } }, { "tier": 6.0, "symbol": "QNT/USDT:USDT", "currency": "USDT", + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27825.0" + } + }, + { + "tier": 7.0, + "symbol": "QNT/USDT:USDT", + "currency": "USDT", "minNotional": 1000000.0, + "maxNotional": 1250000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "1250000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.125", + "cum": "52825.0" + } + }, + { + "tier": 8.0, + "symbol": "QNT/USDT:USDT", + "currency": "USDT", + "minNotional": 1250000.0, + "maxNotional": 2500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "2500000", + "notionalFloor": "1250000", + "maintMarginRatio": "0.25", + "cum": "209075.0" + } + }, + { + "tier": 9.0, + "symbol": "QNT/USDT:USDT", + "currency": "USDT", + "minNotional": 2500000.0, "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "6", + "bracket": "9", "initialLeverage": "1", "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalFloor": "2500000", "maintMarginRatio": "0.5", - "cum": "386950.0" + "cum": "834075.0" } } ], @@ -39171,6 +41286,161 @@ } } ], + "RAYSOL/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "RAYSOL/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "RDNT/USDT:USDT": [ { "tier": 1.0, @@ -41453,13 +43723,13 @@ "symbol": "SAND/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 25000.0, "maintenanceMarginRate": 0.006, - "maxLeverage": 50.0, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "50", - "notionalCap": "5000", + "initialLeverage": "75", + "notionalCap": "25000", "notionalFloor": "0", "maintMarginRatio": "0.006", "cum": "0.0" @@ -41469,136 +43739,153 @@ "tier": 2.0, "symbol": "SAND/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.007, - "maxLeverage": 40.0, + "minNotional": 25000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "40", - "notionalCap": "25000", - "notionalFloor": "5000", - "maintMarginRatio": "0.007", - "cum": "5.0" + "initialLeverage": "50", + "notionalCap": "50000", + "notionalFloor": "25000", + "maintMarginRatio": "0.01", + "cum": "100.0" } }, { "tier": 3.0, "symbol": "SAND/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "minNotional": 50000.0, + "maxNotional": 80000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 40.0, "info": { "bracket": "3", - "initialLeverage": "25", - "notionalCap": "50000", - "notionalFloor": "25000", - "maintMarginRatio": "0.01", - "cum": "80.0" + "initialLeverage": "40", + "notionalCap": "80000", + "notionalFloor": "50000", + "maintMarginRatio": "0.015", + "cum": "350.0" } }, { "tier": 4.0, "symbol": "SAND/USDT:USDT", "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 400000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "minNotional": 80000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "4", - "initialLeverage": "20", - "notionalCap": "400000", - "notionalFloor": "50000", - "maintMarginRatio": "0.025", - "cum": "830.0" + "initialLeverage": "25", + "notionalCap": "300000", + "notionalFloor": "80000", + "maintMarginRatio": "0.02", + "cum": "750.0" } }, { "tier": 5.0, "symbol": "SAND/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 800000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "5", - "initialLeverage": "10", - "notionalCap": "800000", - "notionalFloor": "400000", - "maintMarginRatio": "0.05", - "cum": "10830.0" + "initialLeverage": "20", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.025", + "cum": "2250.0" } }, { "tier": 6.0, "symbol": "SAND/USDT:USDT", "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 600000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "6", - "initialLeverage": "5", - "notionalCap": "2000000", - "notionalFloor": "800000", - "maintMarginRatio": "0.1", - "cum": "50830.0" + "initialLeverage": "10", + "notionalCap": "3000000", + "notionalFloor": "600000", + "maintMarginRatio": "0.05", + "cum": "17250.0" } }, { "tier": 7.0, "symbol": "SAND/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 3000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "7", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "100830.0" + "initialLeverage": "5", + "notionalCap": "6000000", + "notionalFloor": "3000000", + "maintMarginRatio": "0.1", + "cum": "167250.0" } }, { "tier": 8.0, "symbol": "SAND/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 12000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 6000000.0, + "maxNotional": 7500000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "8", - "initialLeverage": "2", - "notionalCap": "12000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.25", - "cum": "725830.0" + "initialLeverage": "4", + "notionalCap": "7500000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.125", + "cum": "317250.0" } }, { "tier": 9.0, "symbol": "SAND/USDT:USDT", "currency": "USDT", - "minNotional": 12000000.0, - "maxNotional": 20000000.0, + "minNotional": 7500000.0, + "maxNotional": 15000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "9", + "initialLeverage": "2", + "notionalCap": "15000000", + "notionalFloor": "7500000", + "maintMarginRatio": "0.25", + "cum": "1254750.0" + } + }, + { + "tier": 10.0, + "symbol": "SAND/USDT:USDT", + "currency": "USDT", + "minNotional": 15000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "9", + "bracket": "10", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "12000000", + "notionalCap": "30000000", + "notionalFloor": "15000000", "maintMarginRatio": "0.5", - "cum": "3725830.0" + "cum": "5004750.0" } } ], @@ -42194,13 +44481,13 @@ "symbol": "SEI/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 60000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "60000", + "notionalCap": "100000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -42210,119 +44497,119 @@ "tier": 3.0, "symbol": "SEI/USDT:USDT", "currency": "USDT", - "minNotional": 60000.0, - "maxNotional": 300000.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "300000", - "notionalFloor": "60000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.02", - "cum": "350.0" + "cum": "550.0" } }, { "tier": 4.0, "symbol": "SEI/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 600000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "600000", - "notionalFloor": "300000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.025", - "cum": "1850.0" + "cum": "3050.0" } }, { "tier": 5.0, "symbol": "SEI/USDT:USDT", "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 3000000.0, + "minNotional": 1000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "3000000", - "notionalFloor": "600000", + "notionalCap": "5000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.05", - "cum": "16850.0" + "cum": "28050.0" } }, { "tier": 6.0, "symbol": "SEI/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 6000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "6000000", - "notionalFloor": "3000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1", - "cum": "166850.0" + "cum": "278050.0" } }, { "tier": 7.0, "symbol": "SEI/USDT:USDT", "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 7500000.0, + "minNotional": 10000000.0, + "maxNotional": 12500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "7500000", - "notionalFloor": "6000000", + "notionalCap": "12500000", + "notionalFloor": "10000000", "maintMarginRatio": "0.125", - "cum": "316850.0" + "cum": "528050.0" } }, { "tier": 8.0, "symbol": "SEI/USDT:USDT", "currency": "USDT", - "minNotional": 7500000.0, - "maxNotional": 15000000.0, + "minNotional": 12500000.0, + "maxNotional": 25000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "15000000", - "notionalFloor": "7500000", + "notionalCap": "25000000", + "notionalFloor": "12500000", "maintMarginRatio": "0.25", - "cum": "1254350.0" + "cum": "2090550.0" } }, { "tier": 9.0, "symbol": "SEI/USDT:USDT", "currency": "USDT", - "minNotional": 15000000.0, - "maxNotional": 30000000.0, + "minNotional": 25000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "15000000", + "notionalCap": "50000000", + "notionalFloor": "25000000", "maintMarginRatio": "0.5", - "cum": "5004350.0" + "cum": "8340550.0" } } ], @@ -43602,6 +45889,161 @@ } } ], + "SPX/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "SPX/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "SSV/USDT:USDT": [ { "tier": 1.0, @@ -44627,13 +47069,13 @@ "symbol": "STX/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 30000.0, + "maxNotional": 60000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "30000", + "notionalCap": "60000", "notionalFloor": "10000", "maintMarginRatio": "0.015", "cum": "50.0" @@ -44643,119 +47085,119 @@ "tier": 3.0, "symbol": "STX/USDT:USDT", "currency": "USDT", - "minNotional": 30000.0, - "maxNotional": 150000.0, + "minNotional": 60000.0, + "maxNotional": 300000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "150000", - "notionalFloor": "30000", + "notionalCap": "300000", + "notionalFloor": "60000", "maintMarginRatio": "0.02", - "cum": "200.0" + "cum": "350.0" } }, { "tier": 4.0, "symbol": "STX/USDT:USDT", "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 300000.0, + "minNotional": 300000.0, + "maxNotional": 600000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "300000", - "notionalFloor": "150000", + "notionalCap": "600000", + "notionalFloor": "300000", "maintMarginRatio": "0.025", - "cum": "950.0" + "cum": "1850.0" } }, { "tier": 5.0, "symbol": "STX/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 1500000.0, + "minNotional": 600000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "1500000", - "notionalFloor": "300000", + "notionalCap": "3000000", + "notionalFloor": "600000", "maintMarginRatio": "0.05", - "cum": "8450.0" + "cum": "16850.0" } }, { "tier": 6.0, "symbol": "STX/USDT:USDT", "currency": "USDT", - "minNotional": 1500000.0, - "maxNotional": 3000000.0, + "minNotional": 3000000.0, + "maxNotional": 6000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "3000000", - "notionalFloor": "1500000", + "notionalCap": "6000000", + "notionalFloor": "3000000", "maintMarginRatio": "0.1", - "cum": "83450.0" + "cum": "166850.0" } }, { "tier": 7.0, "symbol": "STX/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 3750000.0, + "minNotional": 6000000.0, + "maxNotional": 7500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "3750000", - "notionalFloor": "3000000", + "notionalCap": "7500000", + "notionalFloor": "6000000", "maintMarginRatio": "0.125", - "cum": "158450.0" + "cum": "316850.0" } }, { "tier": 8.0, "symbol": "STX/USDT:USDT", "currency": "USDT", - "minNotional": 3750000.0, - "maxNotional": 7500000.0, + "minNotional": 7500000.0, + "maxNotional": 15000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "7500000", - "notionalFloor": "3750000", + "notionalCap": "15000000", + "notionalFloor": "7500000", "maintMarginRatio": "0.25", - "cum": "627200.0" + "cum": "1254350.0" } }, { "tier": 9.0, "symbol": "STX/USDT:USDT", "currency": "USDT", - "minNotional": 7500000.0, - "maxNotional": 15000000.0, + "minNotional": 15000000.0, + "maxNotional": 30000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "15000000", - "notionalFloor": "7500000", + "notionalCap": "30000000", + "notionalFloor": "15000000", "maintMarginRatio": "0.5", - "cum": "2502200.0" + "cum": "5004350.0" } } ], @@ -46368,13 +48810,13 @@ "symbol": "THE/USDT:USDT", "currency": "USDT", "minNotional": 0.0, - "maxNotional": 5000.0, + "maxNotional": 10000.0, "maintenanceMarginRate": 0.01, "maxLeverage": 75.0, "info": { "bracket": "1", "initialLeverage": "75", - "notionalCap": "5000", + "notionalCap": "10000", "notionalFloor": "0", "maintMarginRatio": "0.01", "cum": "0.0" @@ -46384,136 +48826,136 @@ "tier": 2.0, "symbol": "THE/USDT:USDT", "currency": "USDT", - "minNotional": 5000.0, - "maxNotional": 10000.0, + "minNotional": 10000.0, + "maxNotional": 40000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 50.0, "info": { "bracket": "2", "initialLeverage": "50", - "notionalCap": "10000", - "notionalFloor": "5000", + "notionalCap": "40000", + "notionalFloor": "10000", "maintMarginRatio": "0.015", - "cum": "25.0" + "cum": "50.0" } }, { "tier": 3.0, "symbol": "THE/USDT:USDT", "currency": "USDT", - "minNotional": 10000.0, - "maxNotional": 30000.0, + "minNotional": 40000.0, + "maxNotional": 200000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "3", "initialLeverage": "25", - "notionalCap": "30000", - "notionalFloor": "10000", + "notionalCap": "200000", + "notionalFloor": "40000", "maintMarginRatio": "0.02", - "cum": "75.0" + "cum": "250.0" } }, { "tier": 4.0, "symbol": "THE/USDT:USDT", "currency": "USDT", - "minNotional": 30000.0, - "maxNotional": 60000.0, + "minNotional": 200000.0, + "maxNotional": 400000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "4", "initialLeverage": "20", - "notionalCap": "60000", - "notionalFloor": "30000", + "notionalCap": "400000", + "notionalFloor": "200000", "maintMarginRatio": "0.025", - "cum": "225.0" + "cum": "1250.0" } }, { "tier": 5.0, "symbol": "THE/USDT:USDT", "currency": "USDT", - "minNotional": 60000.0, - "maxNotional": 300000.0, + "minNotional": 400000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "5", "initialLeverage": "10", - "notionalCap": "300000", - "notionalFloor": "60000", + "notionalCap": "2000000", + "notionalFloor": "400000", "maintMarginRatio": "0.05", - "cum": "1725.0" + "cum": "11250.0" } }, { "tier": 6.0, "symbol": "THE/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 600000.0, + "minNotional": 2000000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "6", "initialLeverage": "5", - "notionalCap": "600000", - "notionalFloor": "300000", + "notionalCap": "4000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.1", - "cum": "16725.0" + "cum": "111250.0" } }, { "tier": 7.0, "symbol": "THE/USDT:USDT", "currency": "USDT", - "minNotional": 600000.0, - "maxNotional": 750000.0, + "minNotional": 4000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "7", "initialLeverage": "4", - "notionalCap": "750000", - "notionalFloor": "600000", + "notionalCap": "5000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.125", - "cum": "31725.0" + "cum": "211250.0" } }, { "tier": 8.0, "symbol": "THE/USDT:USDT", "currency": "USDT", - "minNotional": 750000.0, - "maxNotional": 1500000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "8", "initialLeverage": "2", - "notionalCap": "1500000", - "notionalFloor": "750000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.25", - "cum": "125475.0" + "cum": "836250.0" } }, { "tier": 9.0, "symbol": "THE/USDT:USDT", "currency": "USDT", - "minNotional": 1500000.0, - "maxNotional": 3000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "9", "initialLeverage": "1", - "notionalCap": "3000000", - "notionalFloor": "1500000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "500475.0" + "cum": "3336250.0" } } ], @@ -48695,13 +51137,13 @@ "symbol": "UNI/USDT:USDT", "currency": "USDT", "minNotional": 50000.0, - "maxNotional": 80000.0, + "maxNotional": 100000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 40.0, "info": { "bracket": "3", "initialLeverage": "40", - "notionalCap": "80000", + "notionalCap": "100000", "notionalFloor": "50000", "maintMarginRatio": "0.015", "cum": "290.0" @@ -48711,119 +51153,119 @@ "tier": 4.0, "symbol": "UNI/USDT:USDT", "currency": "USDT", - "minNotional": 80000.0, - "maxNotional": 300000.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "notionalCap": "300000", - "notionalFloor": "80000", + "notionalCap": "500000", + "notionalFloor": "100000", "maintMarginRatio": "0.02", - "cum": "690.0" + "cum": "790.0" } }, { "tier": 5.0, "symbol": "UNI/USDT:USDT", "currency": "USDT", - "minNotional": 300000.0, - "maxNotional": 900000.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "900000", - "notionalFloor": "300000", + "notionalCap": "1000000", + "notionalFloor": "500000", "maintMarginRatio": "0.025", - "cum": "2190.0" + "cum": "3290.0" } }, { "tier": 6.0, "symbol": "UNI/USDT:USDT", "currency": "USDT", - "minNotional": 900000.0, - "maxNotional": 3000000.0, + "minNotional": 1000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "3000000", - "notionalFloor": "900000", + "notionalCap": "5000000", + "notionalFloor": "1000000", "maintMarginRatio": "0.05", - "cum": "24690.0" + "cum": "28290.0" } }, { "tier": 7.0, "symbol": "UNI/USDT:USDT", "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 6000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "6000000", - "notionalFloor": "3000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.1", - "cum": "174690.0" + "cum": "278290.0" } }, { "tier": 8.0, "symbol": "UNI/USDT:USDT", "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 7500000.0, + "minNotional": 10000000.0, + "maxNotional": 12500000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "8", "initialLeverage": "4", - "notionalCap": "7500000", - "notionalFloor": "6000000", + "notionalCap": "12500000", + "notionalFloor": "10000000", "maintMarginRatio": "0.125", - "cum": "324690.0" + "cum": "528290.0" } }, { "tier": 9.0, "symbol": "UNI/USDT:USDT", "currency": "USDT", - "minNotional": 7500000.0, - "maxNotional": 18000000.0, + "minNotional": 12500000.0, + "maxNotional": 25000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "18000000", - "notionalFloor": "7500000", + "notionalCap": "25000000", + "notionalFloor": "12500000", "maintMarginRatio": "0.25", - "cum": "1262190.0" + "cum": "2090790.0" } }, { "tier": 10.0, "symbol": "UNI/USDT:USDT", "currency": "USDT", - "minNotional": 18000000.0, - "maxNotional": 30000000.0, + "minNotional": 25000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "30000000", - "notionalFloor": "18000000", + "notionalCap": "50000000", + "notionalFloor": "25000000", "maintMarginRatio": "0.5", - "cum": "5762190.0" + "cum": "8340790.0" } } ], @@ -49086,6 +51528,161 @@ } } ], + "USUAL/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "USUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "UXLINK/USDT:USDT": [ { "tier": 1.0, @@ -49241,6 +51838,161 @@ } } ], + "VANA/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "VANA/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "VANRY/USDT:USDT": [ { "tier": 1.0, @@ -49362,6 +52114,161 @@ } } ], + "VELODROME/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "VELODROME/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "VET/USDT:USDT": [ { "tier": 1.0, @@ -49370,10 +52277,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.006, - "maxLeverage": 50.0, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "75", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.006", @@ -49387,10 +52294,10 @@ "minNotional": 5000.0, "maxNotional": 25000.0, "maintenanceMarginRate": 0.01, - "maxLeverage": 25.0, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "25", + "initialLeverage": "50", "notionalCap": "25000", "notionalFloor": "5000", "maintMarginRatio": "0.01", @@ -49402,101 +52309,135 @@ "symbol": "VET/USDT:USDT", "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxNotional": 40000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 40.0, "info": { "bracket": "3", - "initialLeverage": "20", - "notionalCap": "200000", + "initialLeverage": "40", + "notionalCap": "40000", "notionalFloor": "25000", - "maintMarginRatio": "0.025", - "cum": "395.0" + "maintMarginRatio": "0.015", + "cum": "145.0" } }, { "tier": 4.0, "symbol": "VET/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 40000.0, + "maxNotional": 200000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "4", - "initialLeverage": "10", - "notionalCap": "400000", - "notionalFloor": "200000", - "maintMarginRatio": "0.05", - "cum": "5395.0" + "initialLeverage": "25", + "notionalCap": "200000", + "notionalFloor": "40000", + "maintMarginRatio": "0.02", + "cum": "345.0" } }, { "tier": 5.0, "symbol": "VET/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 200000.0, + "maxNotional": 400000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "5", - "initialLeverage": "5", - "notionalCap": "1000000", - "notionalFloor": "400000", - "maintMarginRatio": "0.1", - "cum": "25395.0" + "initialLeverage": "20", + "notionalCap": "400000", + "notionalFloor": "200000", + "maintMarginRatio": "0.025", + "cum": "1345.0" } }, { "tier": 6.0, "symbol": "VET/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 400000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.125", - "cum": "50395.0" + "initialLeverage": "10", + "notionalCap": "2000000", + "notionalFloor": "400000", + "maintMarginRatio": "0.05", + "cum": "11345.0" } }, { "tier": 7.0, "symbol": "VET/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 6000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 2000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "7", - "initialLeverage": "2", - "notionalCap": "6000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.25", - "cum": "675395.0" + "initialLeverage": "5", + "notionalCap": "4000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.1", + "cum": "111345.0" } }, { "tier": 8.0, "symbol": "VET/USDT:USDT", "currency": "USDT", - "minNotional": 6000000.0, + "minNotional": 4000000.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "8", + "initialLeverage": "4", + "notionalCap": "5000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.125", + "cum": "211345.0" + } + }, + { + "tier": 9.0, + "symbol": "VET/USDT:USDT", + "currency": "USDT", + "minNotional": 5000000.0, "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "9", + "initialLeverage": "2", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.25", + "cum": "836345.0" + } + }, + { + "tier": 10.0, + "symbol": "VET/USDT:USDT", + "currency": "USDT", + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "8", + "bracket": "10", "initialLeverage": "1", - "notionalCap": "10000000", - "notionalFloor": "6000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "2175395.0" + "cum": "3336345.0" } } ], @@ -49655,6 +52596,161 @@ } } ], + "VIRTUAL/USDT:USDT": [ + { + "tier": 1.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 5000.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "10000", + "notionalFloor": "5000", + "maintMarginRatio": "0.015", + "cum": "25.0" + } + }, + { + "tier": 3.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 10000.0, + "maxNotional": 30000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "30000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" + } + }, + { + "tier": 4.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 30000.0, + "maxNotional": 60000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "60000", + "notionalFloor": "30000", + "maintMarginRatio": "0.025", + "cum": "225.0" + } + }, + { + "tier": 5.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 60000.0, + "maxNotional": 300000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "300000", + "notionalFloor": "60000", + "maintMarginRatio": "0.05", + "cum": "1725.0" + } + }, + { + "tier": 6.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 300000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "600000", + "notionalFloor": "300000", + "maintMarginRatio": "0.1", + "cum": "16725.0" + } + }, + { + "tier": 7.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 600000.0, + "maxNotional": 750000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "750000", + "notionalFloor": "600000", + "maintMarginRatio": "0.125", + "cum": "31725.0" + } + }, + { + "tier": 8.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 750000.0, + "maxNotional": 1500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "1500000", + "notionalFloor": "750000", + "maintMarginRatio": "0.25", + "cum": "125475.0" + } + }, + { + "tier": 9.0, + "symbol": "VIRTUAL/USDT:USDT", + "currency": "USDT", + "minNotional": 1500000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "3000000", + "notionalFloor": "1500000", + "maintMarginRatio": "0.5", + "cum": "500475.0" + } + } + ], "VOXEL/USDT:USDT": [ { "tier": 1.0, @@ -50678,13 +53774,13 @@ "symbol": "WLD/USDT:USDT", "currency": "USDT", "minNotional": 60000.0, - "maxNotional": 100000.0, + "maxNotional": 160000.0, "maintenanceMarginRate": 0.015, "maxLeverage": 40.0, "info": { "bracket": "3", "initialLeverage": "40", - "notionalCap": "100000", + "notionalCap": "160000", "notionalFloor": "60000", "maintMarginRatio": "0.015", "cum": "320.0" @@ -50694,119 +53790,119 @@ "tier": 4.0, "symbol": "WLD/USDT:USDT", "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 500000.0, + "minNotional": 160000.0, + "maxNotional": 800000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "4", "initialLeverage": "25", - "notionalCap": "500000", - "notionalFloor": "100000", + "notionalCap": "800000", + "notionalFloor": "160000", "maintMarginRatio": "0.02", - "cum": "820.0" + "cum": "1120.0" } }, { "tier": 5.0, "symbol": "WLD/USDT:USDT", "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "5", "initialLeverage": "20", - "notionalCap": "1000000", - "notionalFloor": "500000", + "notionalCap": "1600000", + "notionalFloor": "800000", "maintMarginRatio": "0.025", - "cum": "3320.0" + "cum": "5120.0" } }, { "tier": 6.0, "symbol": "WLD/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 5000000.0, + "minNotional": 1600000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "6", "initialLeverage": "10", - "notionalCap": "5000000", - "notionalFloor": "1000000", + "notionalCap": "8000000", + "notionalFloor": "1600000", "maintMarginRatio": "0.05", - "cum": "28320.0" + "cum": "45120.0" } }, { "tier": 7.0, "symbol": "WLD/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, + "minNotional": 8000000.0, + "maxNotional": 16000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "7", "initialLeverage": "5", - "notionalCap": "10000000", - "notionalFloor": "5000000", + "notionalCap": "16000000", + "notionalFloor": "8000000", "maintMarginRatio": "0.1", - "cum": "278320.0" + "cum": "445120.0" } }, { "tier": 8.0, "symbol": "WLD/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 12500000.0, + "minNotional": 16000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "8", "initialLeverage": "4", - "notionalCap": "12500000", - "notionalFloor": "10000000", + "notionalCap": "20000000", + "notionalFloor": "16000000", "maintMarginRatio": "0.125", - "cum": "528320.0" + "cum": "845120.0" } }, { "tier": 9.0, "symbol": "WLD/USDT:USDT", "currency": "USDT", - "minNotional": 12500000.0, - "maxNotional": 25000000.0, + "minNotional": 20000000.0, + "maxNotional": 40000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "9", "initialLeverage": "2", - "notionalCap": "25000000", - "notionalFloor": "12500000", + "notionalCap": "40000000", + "notionalFloor": "20000000", "maintMarginRatio": "0.25", - "cum": "2090820.0" + "cum": "3345120.0" } }, { "tier": 10.0, "symbol": "WLD/USDT:USDT", "currency": "USDT", - "minNotional": 25000000.0, - "maxNotional": 50000000.0, + "minNotional": 40000000.0, + "maxNotional": 80000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "10", "initialLeverage": "1", - "notionalCap": "50000000", - "notionalFloor": "25000000", + "notionalCap": "80000000", + "notionalFloor": "40000000", "maintMarginRatio": "0.5", - "cum": "8340820.0" + "cum": "13345120.0" } } ], @@ -51060,10 +54156,10 @@ "minNotional": 0.0, "maxNotional": 5000.0, "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maxLeverage": 10.0, "info": { "bracket": "1", - "initialLeverage": "25", + "initialLeverage": "10", "notionalCap": "5000", "notionalFloor": "0", "maintMarginRatio": "0.02", @@ -51077,10 +54173,10 @@ "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", @@ -51094,10 +54190,10 @@ "minNotional": 25000.0, "maxNotional": 400000.0, "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxLeverage": 6.0, "info": { "bracket": "3", - "initialLeverage": "10", + "initialLeverage": "6", "notionalCap": "400000", "notionalFloor": "25000", "maintMarginRatio": "0.05", @@ -51143,13 +54239,13 @@ "symbol": "XEM/USDT:USDT", "currency": "USDT", "minNotional": 2000000.0, - "maxNotional": 6000000.0, + "maxNotional": 2100000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "6", "initialLeverage": "2", - "notionalCap": "6000000", + "notionalCap": "2100000", "notionalFloor": "2000000", "maintMarginRatio": "0.25", "cum": "295650.0" @@ -51159,17 +54255,17 @@ "tier": 7.0, "symbol": "XEM/USDT:USDT", "currency": "USDT", - "minNotional": 6000000.0, - "maxNotional": 10000000.0, + "minNotional": 2100000.0, + "maxNotional": 2200000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "7", "initialLeverage": "1", - "notionalCap": "10000000", - "notionalFloor": "6000000", + "notionalCap": "2200000", + "notionalFloor": "2100000", "maintMarginRatio": "0.5", - "cum": "1795650.0" + "cum": "820650.0" } } ], @@ -51180,14 +54276,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 10000.0, - "maintenanceMarginRate": 0.015, - "maxLeverage": 50.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "75", "notionalCap": "10000", "notionalFloor": "0", - "maintMarginRatio": "0.015", + "maintMarginRatio": "0.01", "cum": "0.0" } }, @@ -51196,50 +54292,50 @@ "symbol": "XLM/USDT:USDT", "currency": "USDT", "minNotional": 10000.0, - "maxNotional": 150000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "20", - "notionalCap": "150000", + "initialLeverage": "50", + "notionalCap": "100000", "notionalFloor": "10000", - "maintMarginRatio": "0.025", - "cum": "100.0" + "maintMarginRatio": "0.015", + "cum": "50.0" } }, { "tier": 3.0, "symbol": "XLM/USDT:USDT", "currency": "USDT", - "minNotional": 150000.0, - "maxNotional": 250000.0, - "maintenanceMarginRate": 0.03, - "maxLeverage": 15.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "15", - "notionalCap": "250000", - "notionalFloor": "150000", - "maintMarginRatio": "0.03", - "cum": "850.0" + "initialLeverage": "25", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.02", + "cum": "550.0" } }, { "tier": 4.0, "symbol": "XLM/USDT:USDT", "currency": "USDT", - "minNotional": 250000.0, + "minNotional": 500000.0, "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "4", - "initialLeverage": "10", + "initialLeverage": "20", "notionalCap": "1000000", - "notionalFloor": "250000", - "maintMarginRatio": "0.05", - "cum": "5850.0" + "notionalFloor": "500000", + "maintMarginRatio": "0.025", + "cum": "3050.0" } }, { @@ -51247,67 +54343,84 @@ "symbol": "XLM/USDT:USDT", "currency": "USDT", "minNotional": 1000000.0, - "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "maxNotional": 5000000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "5", - "initialLeverage": "5", - "notionalCap": "2000000", + "initialLeverage": "10", + "notionalCap": "5000000", "notionalFloor": "1000000", - "maintMarginRatio": "0.1", - "cum": "55850.0" + "maintMarginRatio": "0.05", + "cum": "28050.0" } }, { "tier": 6.0, "symbol": "XLM/USDT:USDT", "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 5000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "6", - "initialLeverage": "4", - "notionalCap": "5000000", - "notionalFloor": "2000000", - "maintMarginRatio": "0.125", - "cum": "105850.0" + "initialLeverage": "5", + "notionalCap": "10000000", + "notionalFloor": "5000000", + "maintMarginRatio": "0.1", + "cum": "278050.0" } }, { "tier": 7.0, "symbol": "XLM/USDT:USDT", "currency": "USDT", - "minNotional": 5000000.0, - "maxNotional": 10000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 10000000.0, + "maxNotional": 12500000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "7", - "initialLeverage": "2", - "notionalCap": "10000000", - "notionalFloor": "5000000", - "maintMarginRatio": "0.25", - "cum": "730850.0" + "initialLeverage": "4", + "notionalCap": "12500000", + "notionalFloor": "10000000", + "maintMarginRatio": "0.125", + "cum": "528050.0" } }, { "tier": 8.0, "symbol": "XLM/USDT:USDT", "currency": "USDT", - "minNotional": 10000000.0, - "maxNotional": 20000000.0, + "minNotional": 12500000.0, + "maxNotional": 25000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "25000000", + "notionalFloor": "12500000", + "maintMarginRatio": "0.25", + "cum": "2090550.0" + } + }, + { + "tier": 9.0, + "symbol": "XLM/USDT:USDT", + "currency": "USDT", + "minNotional": 25000000.0, + "maxNotional": 50000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "8", + "bracket": "9", "initialLeverage": "1", - "notionalCap": "20000000", - "notionalFloor": "10000000", + "notionalCap": "50000000", + "notionalFloor": "25000000", "maintMarginRatio": "0.5", - "cum": "3230850.0" + "cum": "8340550.0" } } ], @@ -53284,14 +56397,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.015, - "maxLeverage": 50.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 75.0, "info": { "bracket": "1", - "initialLeverage": "50", + "initialLeverage": "75", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.015", + "maintMarginRatio": "0.01", "cum": "0.0" } }, @@ -53300,15 +56413,15 @@ "symbol": "ZRX/USDT:USDT", "currency": "USDT", "minNotional": 5000.0, - "maxNotional": 20000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 25.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "2", - "initialLeverage": "25", - "notionalCap": "20000", + "initialLeverage": "50", + "notionalCap": "10000", "notionalFloor": "5000", - "maintMarginRatio": "0.02", + "maintMarginRatio": "0.015", "cum": "25.0" } }, @@ -53316,102 +56429,119 @@ "tier": 3.0, "symbol": "ZRX/USDT:USDT", "currency": "USDT", - "minNotional": 20000.0, - "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "minNotional": 10000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "3", - "initialLeverage": "20", - "notionalCap": "25000", - "notionalFloor": "20000", - "maintMarginRatio": "0.025", - "cum": "125.0" + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "10000", + "maintMarginRatio": "0.02", + "cum": "75.0" } }, { "tier": 4.0, "symbol": "ZRX/USDT:USDT", "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 50000.0, + "maxNotional": 100000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "4", - "initialLeverage": "10", - "notionalCap": "200000", - "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "750.0" + "initialLeverage": "20", + "notionalCap": "100000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "325.0" } }, { "tier": 5.0, "symbol": "ZRX/USDT:USDT", "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 400000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 100000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "5", - "initialLeverage": "5", - "notionalCap": "400000", - "notionalFloor": "200000", - "maintMarginRatio": "0.1", - "cum": "10750.0" + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "100000", + "maintMarginRatio": "0.05", + "cum": "2825.0" } }, { "tier": 6.0, "symbol": "ZRX/USDT:USDT", "currency": "USDT", - "minNotional": 400000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "6", - "initialLeverage": "4", - "notionalCap": "500000", - "notionalFloor": "400000", - "maintMarginRatio": "0.125", - "cum": "20750.0" + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "27825.0" } }, { "tier": 7.0, "symbol": "ZRX/USDT:USDT", "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 1000000.0, + "maxNotional": 1250000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "7", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.25", - "cum": "83250.0" + "initialLeverage": "4", + "notionalCap": "1250000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.125", + "cum": "52825.0" } }, { "tier": 8.0, "symbol": "ZRX/USDT:USDT", "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 1250000.0, + "maxNotional": 2500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "2500000", + "notionalFloor": "1250000", + "maintMarginRatio": "0.25", + "cum": "209075.0" + } + }, + { + "tier": 9.0, + "symbol": "ZRX/USDT:USDT", + "currency": "USDT", + "minNotional": 2500000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "8", + "bracket": "9", "initialLeverage": "1", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "5000000", + "notionalFloor": "2500000", "maintMarginRatio": "0.5", - "cum": "333250.0" + "cum": "834075.0" } } ] diff --git a/freqtrade/exchange/binance_public_data.py b/freqtrade/exchange/binance_public_data.py new file mode 100644 index 000000000..fdc9a993d --- /dev/null +++ b/freqtrade/exchange/binance_public_data.py @@ -0,0 +1,281 @@ +""" +Fetch daily-archived OHLCV data from https://data.binance.vision/ +""" + +import asyncio +import logging +import zipfile +from datetime import date, timedelta +from io import BytesIO +from typing import Any + +import aiohttp +import pandas as pd +from pandas import DataFrame + +from freqtrade.enums import CandleType +from freqtrade.misc import chunks +from freqtrade.util.datetime_helpers import dt_from_ts, dt_now + + +logger = logging.getLogger(__name__) + + +class Http404(Exception): + def __init__(self, msg, date, url): + super().__init__(msg) + self.date = date + self.url = url + + +class BadHttpStatus(Exception): + """Not 200/404""" + + pass + + +async def download_archive_ohlcv( + candle_type: CandleType, + pair: str, + timeframe: str, + *, + since_ms: int, + until_ms: int | None, + markets: dict[str, Any], + stop_on_404: bool = True, +) -> DataFrame: + """ + Fetch OHLCV data from https://data.binance.vision + The function makes its best effort to download data within the time range + [`since_ms`, `until_ms`] -- including `since_ms`, but excluding `until_ms`. + If `stop_one_404` is True, this returned DataFrame is guaranteed to start from `since_ms` + with no gaps in the data. + + :candle_type: Currently only spot and futures are supported + :pair: symbol name in CCXT convention + :since_ms: the start timestamp of data, including itself + :until_ms: the end timestamp of data, excluding itself + :param until_ms: `None` indicates the timestamp of the latest available data + :markets: the CCXT markets dict, when it's None, the function will load the markets data + from a new `ccxt.binance` instance + :param stop_on_404: Stop to download the following data when a 404 returned + :return: the date range is between [since_ms, until_ms), return an empty DataFrame if no data + available in the time range + """ + try: + if candle_type == CandleType.SPOT: + asset_type_url_segment = "spot" + elif candle_type == CandleType.FUTURES: + asset_type_url_segment = "futures/um" + else: + raise ValueError(f"Unsupported CandleType: {candle_type}") + + symbol = markets[pair]["id"] + + start = dt_from_ts(since_ms) + end = dt_from_ts(until_ms) if until_ms else dt_now() + + # We use two days ago as the last available day because the daily archives are daily + # uploaded and have several hours delay + last_available_date = dt_now() - timedelta(days=2) + end = min(end, last_available_date) + if start >= end: + return DataFrame() + df = await _download_archive_ohlcv( + asset_type_url_segment, symbol, pair, timeframe, start, end, stop_on_404 + ) + logger.debug( + f"Downloaded data for {pair} from https://data.binance.vision with length {len(df)}." + ) + except Exception as e: + logger.warning( + "An exception occurred during fast download from Binance, falling back to " + "the slower REST API, this can take more time.", + exc_info=e, + ) + df = DataFrame() + + if not df.empty: + # only return the data within the requested time range + return df.loc[(df["date"] >= start) & (df["date"] < end)] + else: + return df + + +def concat_safe(dfs) -> DataFrame: + if all(df is None for df in dfs): + return DataFrame() + else: + return pd.concat(dfs) + + +async def _download_archive_ohlcv( + asset_type_url_segment: str, + symbol: str, + pair: str, + timeframe: str, + start: date, + end: date, + stop_on_404: bool, +) -> DataFrame: + # daily dataframes, `None` indicates missing data in that day (when `stop_on_404` is False) + dfs: list[DataFrame | None] = [] + # the current day being processing, starting at 1. + current_day = 0 + + connector = aiohttp.TCPConnector(limit=100) + async with aiohttp.ClientSession(connector=connector, trust_env=True) as session: + # the HTTP connections has been throttled by TCPConnector + for dates in chunks(list(date_range(start, end)), 1000): + tasks = [ + asyncio.create_task( + get_daily_ohlcv(asset_type_url_segment, symbol, timeframe, date, session) + ) + for date in dates + ] + for task in tasks: + current_day += 1 + try: + df = await task + except Http404 as e: + if stop_on_404: + logger.debug(f"Failed to download {e.url} due to 404.") + + # A 404 error on the first day indicates missing data + # on https://data.binance.vision, we provide the warning and the advice. + # https://github.com/freqtrade/freqtrade/blob/acc53065e5fa7ab5197073276306dc9dc3adbfa3/tests/exchange_online/test_binance_compare_ohlcv.py#L7 + if current_day == 1: + logger.warning( + f"Fast download is unavailable due to missing data: " + f"{e.url}. Falling back to the slower REST API, " + "which may take more time." + ) + if pair in ["BTC/USDT:USDT", "ETH/USDT:USDT", "BCH/USDT:USDT"]: + logger.warning( + f"To avoid the delay, you can first download {pair} using " + "`--timerange -20200101`, and then download the " + "remaining data with `--timerange 20200101-`." + ) + else: + logger.warning( + f"Binance fast download for {pair} stopped at {e.date} due to " + f"missing data: {e.url}, falling back to rest API for the " + "remaining data, this can take more time." + ) + await cancel_and_await_tasks(tasks[tasks.index(task) + 1 :]) + return concat_safe(dfs) + else: + dfs.append(None) + except BaseException as e: + logger.warning(f"An exception raised: : {e}") + # Directly return the existing data, do not allow the gap within the data + await cancel_and_await_tasks(tasks[tasks.index(task) + 1 :]) + return concat_safe(dfs) + else: + dfs.append(df) + return concat_safe(dfs) + + +async def cancel_and_await_tasks(unawaited_tasks): + """Cancel and await the tasks""" + logger.debug("Try to cancel uncompleted download tasks.") + for task in unawaited_tasks: + task.cancel() + await asyncio.gather(*unawaited_tasks, return_exceptions=True) + logger.debug("All download tasks were awaited.") + + +def date_range(start: date, end: date): + date = start + while date <= end: + yield date + date += timedelta(days=1) + + +def binance_vision_zip_name(symbol: str, timeframe: str, date: date) -> str: + return f"{symbol}-{timeframe}-{date.strftime('%Y-%m-%d')}.zip" + + +def binance_vision_zip_url( + asset_type_url_segment: str, symbol: str, timeframe: str, date: date +) -> str: + """ + example urls: + https://data.binance.vision/data/spot/daily/klines/BTCUSDT/1s/BTCUSDT-1s-2023-10-27.zip + https://data.binance.vision/data/futures/um/daily/klines/BTCUSDT/1h/BTCUSDT-1h-2023-10-27.zip + """ + url = ( + f"https://data.binance.vision/data/{asset_type_url_segment}/daily/klines/{symbol}" + f"/{timeframe}/{binance_vision_zip_name(symbol, timeframe, date)}" + ) + return url + + +async def get_daily_ohlcv( + asset_type_url_segment: str, + symbol: str, + timeframe: str, + date: date, + session: aiohttp.ClientSession, + retry_count: int = 3, + retry_delay: float = 0.0, +) -> DataFrame: + """ + Get daily OHLCV from https://data.binance.vision + See https://github.com/binance/binance-public-data + + :asset_type_url_segment: `spot` or `futures/um` + :symbol: binance symbol name, e.g. BTCUSDT + :timeframe: e.g. 1m, 1h + :date: the returned DataFrame will cover the entire day of `date` in UTC + :session: an aiohttp.ClientSession instance + :retry_count: times to retry before returning the exceptions + :retry_delay: the time to wait before every retry + :return: A dataframe containing columns date,open,high,low,close,volume + """ + + url = binance_vision_zip_url(asset_type_url_segment, symbol, timeframe, date) + + logger.debug(f"download data from binance: {url}") + + retry = 0 + while True: + if retry > 0: + sleep_secs = retry * retry_delay + logger.debug( + f"[{retry}/{retry_count}] retry to download {url} after {sleep_secs} seconds" + ) + await asyncio.sleep(sleep_secs) + try: + async with session.get(url) as resp: + if resp.status == 200: + content = await resp.read() + logger.debug(f"Successfully downloaded {url}") + with zipfile.ZipFile(BytesIO(content)) as zipf: + with zipf.open(zipf.namelist()[0]) as csvf: + # https://github.com/binance/binance-public-data/issues/283 + first_byte = csvf.read(1)[0] + if chr(first_byte).isdigit(): + header = None + else: + header = 0 + csvf.seek(0) + + df = pd.read_csv( + csvf, + usecols=[0, 1, 2, 3, 4, 5], + names=["date", "open", "high", "low", "close", "volume"], + header=header, + ) + df["date"] = pd.to_datetime(df["date"], unit="ms", utc=True) + return df + elif resp.status == 404: + logger.debug(f"Failed to download {url}") + raise Http404(f"404: {url}", date, url) + else: + raise BadHttpStatus(f"{resp.status} - {resp.reason}") + except Exception as e: + retry += 1 + if isinstance(e, Http404) or retry > retry_count: + logger.debug(f"Failed to get data from {url}: {e}") + raise diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index a3006c99b..bba6c5aaf 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -7,7 +7,7 @@ import asyncio import inspect import logging import signal -from collections.abc import Coroutine +from collections.abc import Coroutine, Generator from copy import deepcopy from datetime import datetime, timedelta, timezone from math import floor, isnan @@ -201,7 +201,7 @@ class Exchange: self._cache_lock = Lock() # Cache for 10 minutes ... - self._fetch_tickers_cache: TTLCache = TTLCache(maxsize=2, ttl=60 * 10) + self._fetch_tickers_cache: TTLCache = TTLCache(maxsize=4, ttl=60 * 10) # Cache values for 300 to avoid frequent polling of the exchange for prices # Caching only applies to RPC methods, so prices for open trades are still # refreshed once every iteration. @@ -705,14 +705,22 @@ class Exchange: f"Available currencies are: {', '.join(quote_currencies)}" ) - def get_valid_pair_combination(self, curr_1: str, curr_2: str) -> str: + def get_valid_pair_combination(self, curr_1: str, curr_2: str) -> Generator[str, None, None]: """ Get valid pair combination of curr_1 and curr_2 by trying both combinations. """ - for pair in [f"{curr_1}/{curr_2}", f"{curr_2}/{curr_1}"]: + yielded = False + for pair in ( + f"{curr_1}/{curr_2}", + f"{curr_2}/{curr_1}", + f"{curr_1}/{curr_2}:{curr_2}", + f"{curr_2}/{curr_1}:{curr_1}", + ): if pair in self.markets and self.markets[pair].get("active"): - return pair - raise ValueError(f"Could not combine {curr_1} and {curr_2} to get a valid pair.") + yielded = True + yield pair + if not yielded: + raise ValueError(f"Could not combine {curr_1} and {curr_2} to get a valid pair.") def validate_timeframes(self, timeframe: str | None) -> None: """ @@ -1801,24 +1809,37 @@ class Exchange: raise OperationalException(e) from e @retrier - def get_tickers(self, symbols: list[str] | None = None, *, cached: bool = False) -> Tickers: + def get_tickers( + self, + symbols: list[str] | None = None, + *, + cached: bool = False, + market_type: TradingMode | None = None, + ) -> Tickers: """ :param symbols: List of symbols to fetch :param cached: Allow cached result + :param market_type: Market type to fetch - either spot or futures. :return: fetch_tickers result """ tickers: Tickers if not self.exchange_has("fetchTickers"): return {} + cache_key = f"fetch_tickers_{market_type}" if market_type else "fetch_tickers" if cached: with self._cache_lock: - tickers = self._fetch_tickers_cache.get("fetch_tickers") # type: ignore + tickers = self._fetch_tickers_cache.get(cache_key) # type: ignore if tickers: return tickers try: - tickers = self._api.fetch_tickers(symbols) + # Re-map futures to swap + market_types = { + TradingMode.FUTURES: "swap", + } + params = {"type": market_types.get(market_type, market_type)} if market_type else {} + tickers = self._api.fetch_tickers(symbols, params) with self._cache_lock: - self._fetch_tickers_cache["fetch_tickers"] = tickers + self._fetch_tickers_cache[cache_key] = tickers return tickers except ccxt.NotSupported as e: raise OperationalException( @@ -1842,7 +1863,39 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - # Pricing info + def get_conversion_rate(self, coin: str, currency: str) -> float | None: + """ + Quick and cached way to get conversion rate one currency to the other. + Can then be used as "rate * amount" to convert between currencies. + :param coin: Coin to convert + :param currency: Currency to convert to + :returns: Conversion rate from coin to currency + :raises: ExchangeErrors + """ + if coin == currency: + return 1.0 + tickers = self.get_tickers(cached=True) + try: + for pair in self.get_valid_pair_combination(coin, currency): + ticker: Ticker | None = tickers.get(pair, None) + if not ticker: + tickers_other: Tickers = self.get_tickers( + cached=True, + market_type=( + TradingMode.SPOT + if self.trading_mode != TradingMode.SPOT + else TradingMode.FUTURES + ), + ) + ticker = tickers_other.get(pair, None) + if ticker: + rate: float | None = ticker.get("last", None) + if rate and pair.startswith(currency) and not pair.endswith(currency): + rate = 1.0 / rate + return rate + except ValueError: + return None + return None @retrier def fetch_ticker(self, pair: str) -> Ticker: @@ -2198,10 +2251,13 @@ class Exchange: # If cost is None or 0.0 -> falsy, return None return None try: - comb = self.get_valid_pair_combination(fee_curr, self._config["stake_currency"]) - tick = self.fetch_ticker(comb) - - fee_to_quote_rate = safe_value_fallback2(tick, tick, "last", "ask") + for comb in self.get_valid_pair_combination( + fee_curr, self._config["stake_currency"] + ): + tick = self.fetch_ticker(comb) + fee_to_quote_rate = safe_value_fallback2(tick, tick, "last", "ask") + if tick: + break except (ValueError, ExchangeError): fee_to_quote_rate = self._config["exchange"].get("unknown_fee_rate", None) if not fee_to_quote_rate: @@ -2244,8 +2300,9 @@ class Exchange: :param pair: Pair to download :param timeframe: Timeframe to get data for :param since_ms: Timestamp in milliseconds to get history from - :param until_ms: Timestamp in milliseconds to get history up to :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param is_new_pair: used by binance subclass to allow "fast" new pair downloading + :param until_ms: Timestamp in milliseconds to get history up to :return: Dataframe with candle (OHLCV) data """ pair, _, _, data, _ = self.loop.run_until_complete( @@ -2254,11 +2311,10 @@ class Exchange: 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)}.") + logger.debug(f"Downloaded data for {pair} from ccxt with length {len(data)}.") return ohlcv_to_dataframe(data, timeframe, pair, fill_missing=False, drop_incomplete=True) async def _async_get_historic_ohlcv( @@ -2267,13 +2323,11 @@ class Exchange: timeframe: str, since_ms: int, candle_type: CandleType, - is_new_pair: bool = False, raise_: bool = False, until_ms: int | None = None, ) -> OHLCVResponse: """ Download historic ohlcv - :param is_new_pair: used by binance subclass to allow "fast" new pair downloading :param candle_type: Any of the enum CandleType (must match trading mode!) """ diff --git a/freqtrade/exchange/exchange_utils.py b/freqtrade/exchange/exchange_utils.py index 1c8a30001..1c9894242 100644 --- a/freqtrade/exchange/exchange_utils.py +++ b/freqtrade/exchange/exchange_utils.py @@ -308,7 +308,9 @@ def price_to_precision( decimal_to_precision( price, rounding_mode=rounding_mode, - precision=price_precision, + precision=int(price_precision) + if precisionMode != TICK_SIZE + else price_precision, counting_mode=precisionMode, ) ) diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 75e2bcbd3..8573d611d 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -50,11 +50,17 @@ class Kraken(Exchange): return parent_check and market.get("darkpool", False) is False - def get_tickers(self, symbols: list[str] | None = None, *, cached: bool = False) -> Tickers: + def get_tickers( + self, + symbols: list[str] | None = None, + *, + cached: bool = False, + market_type: TradingMode | None = None, + ) -> Tickers: # Only fetch tickers for current stake currency # Otherwise the request for kraken becomes too large. symbols = list(self.get_markets(quote_currencies=[self._config["stake_currency"]])) - return super().get_tickers(symbols=symbols, cached=cached) + return super().get_tickers(symbols=symbols, cached=cached, market_type=market_type) def consolidate_balances(self, balances: CcxtBalances) -> CcxtBalances: """ diff --git a/freqtrade/freqai/data_kitchen.py b/freqtrade/freqai/data_kitchen.py index 5292dc0af..cac76ece5 100644 --- a/freqtrade/freqai/data_kitchen.py +++ b/freqtrade/freqai/data_kitchen.py @@ -849,7 +849,7 @@ class FreqaiDataKitchen: dataframe = strategy.set_freqai_targets(dataframe.copy(), metadata=metadata) dataframe = self.remove_special_chars_from_feature_names(dataframe) - self.get_unique_classes_from_labels(dataframe) + self.get_unique_classes_from_labels(dataframe) if self.config.get("reduce_df_footprint", False): dataframe = reduce_dataframe_footprint(dataframe) diff --git a/freqtrade/freqai/prediction_models/XGBoostRFRegressor.py b/freqtrade/freqai/prediction_models/XGBoostRFRegressor.py index 12231ed13..140186075 100644 --- a/freqtrade/freqai/prediction_models/XGBoostRFRegressor.py +++ b/freqtrade/freqai/prediction_models/XGBoostRFRegressor.py @@ -5,7 +5,6 @@ from xgboost import XGBRFRegressor from freqtrade.freqai.base_models.BaseRegressionModel import BaseRegressionModel from freqtrade.freqai.data_kitchen import FreqaiDataKitchen -from freqtrade.freqai.tensorboard import TBCallback logger = logging.getLogger(__name__) @@ -45,7 +44,12 @@ class XGBoostRFRegressor(BaseRegressionModel): model = XGBRFRegressor(**self.model_training_parameters) - model.set_params(callbacks=[TBCallback(dk.data_path)]) + # Callbacks are not supported for XGBRFRegressor, and version 2.1.x started to throw + # the following error: + # NotImplementedError: `early_stopping_rounds` and `callbacks` are not implemented + # for random forest. + + # model.set_params(callbacks=[TBCallback(dk.data_path)]) model.fit( X=X, y=y, @@ -55,6 +59,6 @@ class XGBoostRFRegressor(BaseRegressionModel): xgb_model=xgb_model, ) # set the callbacks to empty so that we can serialize to disk later - model.set_params(callbacks=[]) + # model.set_params(callbacks=[]) return model diff --git a/freqtrade/leverage/liquidation_price.py b/freqtrade/leverage/liquidation_price.py index aed8c9160..b48190d84 100644 --- a/freqtrade/leverage/liquidation_price.py +++ b/freqtrade/leverage/liquidation_price.py @@ -27,10 +27,13 @@ def update_liquidation_prices( total_wallet_stake = 0.0 if dry_run: # Parameters only needed for cross margin - total_wallet_stake = wallets.get_total(stake_currency) + total_wallet_stake = wallets.get_collateral() - logger.info("Updating liquidation price for all open trades.") - open_trades = Trade.get_open_trades() + logger.info( + "Updating liquidation price for all open trades. " + f"Collateral {total_wallet_stake} {stake_currency}." + ) + open_trades: list[Trade] = Trade.get_open_trades() for t in open_trades: # TODO: This should be done in a batch update t.set_liquidation_price( diff --git a/freqtrade/optimize/analysis/lookahead_helpers.py b/freqtrade/optimize/analysis/lookahead_helpers.py index d664f9635..631a9549f 100644 --- a/freqtrade/optimize/analysis/lookahead_helpers.py +++ b/freqtrade/optimize/analysis/lookahead_helpers.py @@ -10,7 +10,7 @@ from freqtrade.constants import Config from freqtrade.exceptions import OperationalException from freqtrade.optimize.analysis.lookahead import LookaheadAnalysis from freqtrade.resolvers import StrategyResolver -from freqtrade.util import print_rich_table +from freqtrade.util import get_dry_run_wallet, print_rich_table logger = logging.getLogger(__name__) @@ -163,7 +163,7 @@ class LookaheadAnalysisSubFunctions: config["max_open_trades"] = len(config["pairs"]) min_dry_run_wallet = 1000000000 - if config["dry_run_wallet"] < min_dry_run_wallet: + if get_dry_run_wallet(config) < min_dry_run_wallet: logger.info( "Dry run wallet was not set to 1 billion, pushing it up there " "just to avoid false positives" diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 8cccae02d..e77e69fc8 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -47,8 +47,7 @@ from freqtrade.optimize.optimize_reports import ( generate_rejected_signals, generate_trade_signal_candles, show_backtest_results, - store_backtest_analysis_results, - store_backtest_stats, + store_backtest_results, ) from freqtrade.persistence import ( CustomDataWrapper, @@ -121,10 +120,12 @@ class Backtesting: self.run_ids: dict[str, str] = {} self.strategylist: list[IStrategy] = [] self.all_results: dict[str, dict] = {} - self.processed_dfs: dict[str, dict] = {} + self.analysis_results: dict[str, dict[str, DataFrame]] = { + "signals": {}, + "rejected": {}, + "exited": {}, + } self.rejected_dict: dict[str, list] = {} - self.rejected_df: dict[str, dict] = {} - self.exited_dfs: dict[str, dict] = {} self._exchange_name = self.config["exchange"]["name"] if not exchange: @@ -1629,15 +1630,13 @@ class Backtesting: self.config.get("export", "none") == "signals" and self.dataprovider.runmode == RunMode.BACKTEST ): - self.processed_dfs[strategy_name] = generate_trade_signal_candles( - preprocessed_tmp, results, "open_date" - ) - self.rejected_df[strategy_name] = generate_rejected_signals( - preprocessed_tmp, self.rejected_dict - ) - self.exited_dfs[strategy_name] = generate_trade_signal_candles( - preprocessed_tmp, results, "close_date" - ) + signals = generate_trade_signal_candles(preprocessed_tmp, results, "open_date") + rejected = generate_rejected_signals(preprocessed_tmp, self.rejected_dict) + exited = generate_trade_signal_candles(preprocessed_tmp, results, "close_date") + + self.analysis_results["signals"][strategy_name] = signals + self.analysis_results["rejected"][strategy_name] = rejected + self.analysis_results["exited"][strategy_name] = exited return min_date, max_date @@ -1701,23 +1700,12 @@ class Backtesting: dt_appendix = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") if self.config.get("export", "none") in ("trades", "signals"): combined_res = combined_dataframes_with_rel_mean(data, min_date, max_date) - store_backtest_stats( - self.config["exportfilename"], + store_backtest_results( + self.config, self.results, dt_appendix, market_change_data=combined_res, - ) - - if ( - self.config.get("export", "none") == "signals" - and self.dataprovider.runmode == RunMode.BACKTEST - ): - store_backtest_analysis_results( - self.config["exportfilename"], - self.processed_dfs, - self.rejected_df, - self.exited_dfs, - dt_appendix, + analysis_results=self.analysis_results, ) # Results may be mixed up now. Sort them so they follow --strategy-list order. diff --git a/freqtrade/optimize/hyperopt/hyperopt_optimizer.py b/freqtrade/optimize/hyperopt/hyperopt_optimizer.py index bd234aa57..c8d18d224 100644 --- a/freqtrade/optimize/hyperopt/hyperopt_optimizer.py +++ b/freqtrade/optimize/hyperopt/hyperopt_optimizer.py @@ -28,6 +28,7 @@ from freqtrade.optimize.hyperopt_loss.hyperopt_loss_interface import IHyperOptLo from freqtrade.optimize.hyperopt_tools import HyperoptStateContainer, HyperoptTools from freqtrade.optimize.optimize_reports import generate_strategy_stats from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver +from freqtrade.util.dry_run_wallet import get_dry_run_wallet # Suppress scikit-learn FutureWarnings from skopt @@ -363,6 +364,7 @@ class HyperOptimizer: config=self.config, processed=processed, backtest_stats=strat_stats, + starting_balance=get_dry_run_wallet(self.config), ) return { "loss": loss, diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_calmar.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_calmar.py index f22d59e50..4f1a82e1e 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_calmar.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_calmar.py @@ -9,7 +9,6 @@ from datetime import datetime from pandas import DataFrame -from freqtrade.constants import Config from freqtrade.data.metrics import calculate_calmar from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -24,10 +23,9 @@ class CalmarHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function( results: DataFrame, - trade_count: int, min_date: datetime, max_date: datetime, - config: Config, + starting_balance: float, *args, **kwargs, ) -> float: @@ -36,7 +34,6 @@ class CalmarHyperOptLoss(IHyperOptLoss): Uses Calmar Ratio calculation. """ - 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_interface.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_interface.py index a48fee731..ddc96d6a0 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_interface.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_interface.py @@ -31,6 +31,7 @@ class IHyperOptLoss(ABC): config: Config, processed: dict[str, DataFrame], backtest_stats: dict[str, Any], + starting_balance: float, **kwargs, ) -> float: """ diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_max_drawdown_relative.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_max_drawdown_relative.py index ee7088d75..3cd578cb4 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_max_drawdown_relative.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_max_drawdown_relative.py @@ -7,7 +7,6 @@ Hyperoptimization. from pandas import DataFrame -from freqtrade.constants import Config from freqtrade.data.metrics import calculate_underwater from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -21,7 +20,9 @@ class MaxDrawDownRelativeHyperOptLoss(IHyperOptLoss): """ @staticmethod - def hyperopt_loss_function(results: DataFrame, config: Config, *args, **kwargs) -> float: + def hyperopt_loss_function( + results: DataFrame, starting_balance: float, *args, **kwargs + ) -> float: """ Objective function. @@ -31,7 +32,7 @@ class MaxDrawDownRelativeHyperOptLoss(IHyperOptLoss): total_profit = results["profit_abs"].sum() try: drawdown_df = calculate_underwater( - results, value_col="profit_abs", starting_balance=config["dry_run_wallet"] + results, value_col="profit_abs", starting_balance=starting_balance ) max_drawdown = abs(min(drawdown_df["drawdown"])) relative_drawdown = max(drawdown_df["drawdown_relative"]) diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_multi_metric.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_multi_metric.py index de8d117d6..adffdfb0b 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_multi_metric.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_multi_metric.py @@ -33,7 +33,6 @@ TARGET_TRADE_AMOUNT variable sets the minimum number of trades required to avoid import numpy as np from pandas import DataFrame -from freqtrade.constants import Config from freqtrade.data.metrics import calculate_expectancy, calculate_max_drawdown from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -57,7 +56,7 @@ class MultiMetricHyperOptLoss(IHyperOptLoss): def hyperopt_loss_function( results: DataFrame, trade_count: int, - config: Config, + starting_balance: float, **kwargs, ) -> float: total_profit = results["profit_abs"].sum() @@ -83,7 +82,7 @@ class MultiMetricHyperOptLoss(IHyperOptLoss): # Calculate drawdown try: drawdown = calculate_max_drawdown( - results, starting_balance=config["dry_run_wallet"], value_col="profit_abs" + results, starting_balance=starting_balance, value_col="profit_abs" ) relative_account_drawdown = drawdown.relative_account_drawdown except ValueError: diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_profit_drawdown.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_profit_drawdown.py index 61e2a6d32..af1b33dfb 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_profit_drawdown.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_profit_drawdown.py @@ -10,7 +10,6 @@ individual needs. from pandas import DataFrame -from freqtrade.constants import Config from freqtrade.data.metrics import calculate_max_drawdown from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -21,12 +20,14 @@ DRAWDOWN_MULT = 0.075 class ProfitDrawDownHyperOptLoss(IHyperOptLoss): @staticmethod - def hyperopt_loss_function(results: DataFrame, config: Config, *args, **kwargs) -> float: + def hyperopt_loss_function( + results: DataFrame, starting_balance: float, *args, **kwargs + ) -> float: total_profit = results["profit_abs"].sum() try: drawdown = calculate_max_drawdown( - results, starting_balance=config["dry_run_wallet"], value_col="profit_abs" + results, starting_balance=starting_balance, value_col="profit_abs" ) relative_account_drawdown = drawdown.relative_account_drawdown except ValueError: diff --git a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe.py index 2c7042a8a..20e4ee2b6 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sharpe.py @@ -9,7 +9,6 @@ from datetime import datetime from pandas import DataFrame -from freqtrade.constants import Config from freqtrade.data.metrics import calculate_sharpe from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -24,10 +23,9 @@ class SharpeHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function( results: DataFrame, - trade_count: int, min_date: datetime, max_date: datetime, - config: Config, + starting_balance: float, *args, **kwargs, ) -> float: @@ -36,7 +34,6 @@ class SharpeHyperOptLoss(IHyperOptLoss): Uses Sharpe Ratio calculation. """ - 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_sortino.py b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino.py index 32ff0c73f..935d038e5 100644 --- a/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino.py +++ b/freqtrade/optimize/hyperopt_loss/hyperopt_loss_sortino.py @@ -9,7 +9,6 @@ from datetime import datetime from pandas import DataFrame -from freqtrade.constants import Config from freqtrade.data.metrics import calculate_sortino from freqtrade.optimize.hyperopt import IHyperOptLoss @@ -24,10 +23,9 @@ class SortinoHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function( results: DataFrame, - trade_count: int, min_date: datetime, max_date: datetime, - config: Config, + starting_balance: float, *args, **kwargs, ) -> float: @@ -36,7 +34,6 @@ class SortinoHyperOptLoss(IHyperOptLoss): Uses Sortino Ratio calculation. """ - 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/optimize_reports/__init__.py b/freqtrade/optimize/optimize_reports/__init__.py index 6f3278a1c..c08bae4be 100644 --- a/freqtrade/optimize/optimize_reports/__init__.py +++ b/freqtrade/optimize/optimize_reports/__init__.py @@ -11,10 +11,7 @@ from freqtrade.optimize.optimize_reports.bt_output import ( text_table_strategy, text_table_tags, ) -from freqtrade.optimize.optimize_reports.bt_storage import ( - store_backtest_analysis_results, - store_backtest_stats, -) +from freqtrade.optimize.optimize_reports.bt_storage import store_backtest_results from freqtrade.optimize.optimize_reports.optimize_reports import ( generate_all_periodic_breakdown_stats, generate_backtest_stats, diff --git a/freqtrade/optimize/optimize_reports/bt_storage.py b/freqtrade/optimize/optimize_reports/bt_storage.py index 21532d4d2..cd47aab18 100644 --- a/freqtrade/optimize/optimize_reports/bt_storage.py +++ b/freqtrade/optimize/optimize_reports/bt_storage.py @@ -4,6 +4,7 @@ from pathlib import Path from pandas import DataFrame from freqtrade.constants import LAST_BT_RESULT_FN +from freqtrade.enums.runmode import RunMode from freqtrade.ft_types import BacktestResultType from freqtrade.misc import file_dump_joblib, file_dump_json from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename @@ -29,21 +30,27 @@ def _generate_filename(recordfilename: Path, appendix: str, suffix: str) -> Path return filename -def store_backtest_stats( - recordfilename: Path, +def store_backtest_results( + config: dict, stats: BacktestResultType, dtappendix: str, *, market_change_data: DataFrame | None = None, + analysis_results: dict[str, dict[str, DataFrame]] | None = None, ) -> Path: """ - Stores backtest results - :param recordfilename: Path object, which can either be a filename or a directory. - Filenames will be appended with a timestamp right before the suffix - while for directories, /backtest-result-.json will be used as filename + Stores backtest results and analysis data + :param config: Configuration dictionary :param stats: Dataframe containing the backtesting statistics :param dtappendix: Datetime to use for the filename + :param market_change_data: Dataframe containing market change data + :param analysis_results: Dictionary containing analysis results """ + + # Path object, which can either be a filename or a directory. + # Filenames will be appended with a timestamp right before the suffix + # while for directories, /backtest-result-.json will be used as filename + recordfilename: Path = config["exportfilename"] filename = _generate_filename(recordfilename, dtappendix, ".json") # Store metadata separately. @@ -65,6 +72,21 @@ def store_backtest_stats( filename_mc, compression_level=9, compression="lz4" ) + if ( + config.get("export", "none") == "signals" + and analysis_results is not None + and config.get("runmode", RunMode.OTHER) == RunMode.BACKTEST + ): + _store_backtest_analysis_data( + recordfilename, analysis_results["signals"], dtappendix, "signals" + ) + _store_backtest_analysis_data( + recordfilename, analysis_results["rejected"], dtappendix, "rejected" + ) + _store_backtest_analysis_data( + recordfilename, analysis_results["exited"], dtappendix, "exited" + ) + return filename @@ -86,15 +108,3 @@ def _store_backtest_analysis_data( file_dump_joblib(filename, data) return filename - - -def store_backtest_analysis_results( - recordfilename: Path, - candles: dict[str, dict], - trades: dict[str, dict], - exited: dict[str, dict], - dtappendix: str, -) -> None: - _store_backtest_analysis_data(recordfilename, candles, dtappendix, "signals") - _store_backtest_analysis_data(recordfilename, trades, dtappendix, "rejected") - _store_backtest_analysis_data(recordfilename, exited, dtappendix, "exited") diff --git a/freqtrade/optimize/optimize_reports/optimize_reports.py b/freqtrade/optimize/optimize_reports/optimize_reports.py index 8f1f0140a..23119077b 100644 --- a/freqtrade/optimize/optimize_reports/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports/optimize_reports.py @@ -18,7 +18,7 @@ from freqtrade.data.metrics import ( calculate_sortino, ) from freqtrade.ft_types import BacktestResultType -from freqtrade.util import decimals_per_coin, fmt_coin +from freqtrade.util import decimals_per_coin, fmt_coin, get_dry_run_wallet logger = logging.getLogger(__name__) @@ -69,7 +69,7 @@ def generate_rejected_signals( def _generate_result_line( - result: DataFrame, starting_balance: int, first_column: str | list[str] + result: DataFrame, starting_balance: float, first_column: str | list[str] ) -> dict: """ Generate one result dict, with "first_column" as key. @@ -111,7 +111,7 @@ def _generate_result_line( def generate_pair_metrics( pairlist: list[str], stake_currency: str, - starting_balance: int, + starting_balance: float, results: DataFrame, skip_nan: bool = False, ) -> list[dict]: @@ -144,7 +144,7 @@ def generate_pair_metrics( def generate_tag_metrics( tag_type: Literal["enter_tag", "exit_reason"] | list[Literal["enter_tag", "exit_reason"]], - starting_balance: int, + starting_balance: float, results: DataFrame, skip_nan: bool = False, ) -> list[dict]: @@ -373,7 +373,7 @@ def generate_strategy_stats( return {} config = content["config"] max_open_trades = min(config["max_open_trades"], len(pairlist)) - start_balance = config["dry_run_wallet"] + start_balance = get_dry_run_wallet(config) stake_currency = config["stake_currency"] pair_results = generate_pair_metrics( diff --git a/freqtrade/persistence/pairlock.py b/freqtrade/persistence/pairlock.py index 01549fb63..6c98a607d 100644 --- a/freqtrade/persistence/pairlock.py +++ b/freqtrade/persistence/pairlock.py @@ -39,7 +39,7 @@ class PairLock(ModelBase): @staticmethod def query_pair_locks( - pair: str | None, now: datetime, side: str = "*" + pair: str | None, now: datetime, side: str | None = None ) -> ScalarResult["PairLock"]: """ Get all currently active locks for this pair @@ -53,9 +53,9 @@ class PairLock(ModelBase): ] if pair: filters.append(PairLock.pair == pair) - if side != "*": + if side is not None and side != "*": filters.append(or_(PairLock.side == side, PairLock.side == "*")) - else: + elif side is not None: filters.append(PairLock.side == "*") return PairLock.session.scalars(select(PairLock).filter(*filters)) diff --git a/freqtrade/persistence/pairlock_middleware.py b/freqtrade/persistence/pairlock_middleware.py index c182cf534..0adbcc8be 100644 --- a/freqtrade/persistence/pairlock_middleware.py +++ b/freqtrade/persistence/pairlock_middleware.py @@ -67,13 +67,14 @@ class PairLocks: @staticmethod def get_pair_locks( - pair: str | None, now: datetime | None = None, side: str = "*" + pair: str | None, now: datetime | None = None, side: str | None = None ) -> Sequence[PairLock]: """ Get all currently active locks for this pair :param pair: Pair to check for. Returns all current locks if pair is empty :param now: Datetime object (generated via datetime.now(timezone.utc)). defaults to datetime.now(timezone.utc) + :param side: Side get locks for, can be 'long', 'short', '*' or None """ if not now: now = datetime.now(timezone.utc) @@ -88,7 +89,7 @@ class PairLocks: lock.lock_end_time >= now and lock.active is True and (pair is None or lock.pair == pair) - and (lock.side == "*" or lock.side == side) + and (side is None or lock.side == "*" or lock.side == side) ) ] return locks diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index dffede11b..973aef1a6 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -172,12 +172,20 @@ class Order(ModelBase): @property def stake_amount(self) -> float: """Amount in stake currency used for this order""" - return self.safe_amount * self.safe_price / self.trade.leverage + return float( + FtPrecise(self.safe_amount) + * FtPrecise(self.safe_price) + / FtPrecise(self.trade.leverage) + ) @property def stake_amount_filled(self) -> float: """Filled Amount in stake currency used for this order""" - return self.safe_filled * self.safe_price / self.trade.leverage + return float( + FtPrecise(self.safe_filled) + * FtPrecise(self.safe_price) + / FtPrecise(self.trade.leverage) + ) def __repr__(self): return ( @@ -777,7 +785,9 @@ class LocalTrade: """ if liquidation_price is None: return - self.liquidation_price = liquidation_price + self.liquidation_price = price_to_precision( + liquidation_price, self.price_precision, self.precision_mode_price + ) def set_funding_fees(self, funding_fee: float) -> None: """ diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index cf86f070d..8ec7c7bae 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -28,6 +28,7 @@ from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.strategy import IStrategy from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper +from freqtrade.util import get_dry_run_wallet logger = logging.getLogger(__name__) @@ -706,7 +707,7 @@ def plot_profit(config: Config) -> None: trades, config["timeframe"], config.get("stake_currency", ""), - config.get("available_capital", config["dry_run_wallet"]), + config.get("available_capital", get_dry_run_wallet(config)), ) store_plot_file( fig, diff --git a/freqtrade/plugins/pairlist/PercentChangePairList.py b/freqtrade/plugins/pairlist/PercentChangePairList.py index cbc86f259..4f91a47d1 100644 --- a/freqtrade/plugins/pairlist/PercentChangePairList.py +++ b/freqtrade/plugins/pairlist/PercentChangePairList.py @@ -8,7 +8,7 @@ defined period or as coming from ticker import logging from datetime import timedelta -from typing import Any +from typing import TypedDict from cachetools import TTLCache from pandas import DataFrame @@ -24,6 +24,11 @@ from freqtrade.util import dt_now, format_ms_time logger = logging.getLogger(__name__) +class SymbolWithPercentage(TypedDict): + symbol: str + percentage: float | None + + class PercentChangePairList(IPairList): is_pairlist_generator = True supports_backtesting = SupportsBacktesting.NO @@ -191,7 +196,6 @@ class PercentChangePairList(IPairList): for k, v in tickers.items() if ( self._exchange.get_pair_quote_currency(k) == self._stake_currency - and (self._use_range or v.get("percentage") is not None) and v["symbol"] in _pairlist ) ] @@ -212,13 +216,15 @@ class PercentChangePairList(IPairList): :param tickers: Tickers (from exchange.get_tickers). May be cached. :return: new whitelist """ - filtered_tickers: list[dict[str, Any]] = [{"symbol": k} for k in pairlist] + filtered_tickers: list[SymbolWithPercentage] = [ + {"symbol": k, "percentage": None} for k in pairlist + ] if self._use_range: # calculating using lookback_period - self.fetch_percent_change_from_lookback_period(filtered_tickers) + filtered_tickers = self.fetch_percent_change_from_lookback_period(filtered_tickers) else: # Fetching 24h change by default from supported exchange tickers - self.fetch_percent_change_from_tickers(filtered_tickers, tickers) + filtered_tickers = self.fetch_percent_change_from_tickers(filtered_tickers, tickers) if self._min_value is not None: filtered_tickers = [v for v in filtered_tickers if v["percentage"] > self._min_value] @@ -228,7 +234,7 @@ class PercentChangePairList(IPairList): sorted_tickers = sorted( filtered_tickers, reverse=self._sort_direction == "desc", - key=lambda t: t["percentage"], + key=lambda t: t["percentage"], # type: ignore ) # Validate whitelist to only have active market pairs @@ -240,7 +246,7 @@ class PercentChangePairList(IPairList): return pairs def fetch_candles_for_lookback_period( - self, filtered_tickers: list[dict[str, str]] + self, filtered_tickers: list[SymbolWithPercentage] ) -> dict[PairWithTimeframe, DataFrame]: since_ms = ( int( @@ -262,7 +268,6 @@ class PercentChangePairList(IPairList): ) * 1000 ) - # todo: utc date output for starting date self.log_once( f"Using change range of {self._lookback_period} candles, timeframe: " f"{self._lookback_timeframe}, starting from {format_ms_time(since_ms)} " @@ -277,7 +282,9 @@ class PercentChangePairList(IPairList): candles = self._exchange.refresh_ohlcv_with_cache(needed_pairs, since_ms) return candles - def fetch_percent_change_from_lookback_period(self, filtered_tickers: list[dict[str, Any]]): + def fetch_percent_change_from_lookback_period( + self, filtered_tickers: list[SymbolWithPercentage] + ) -> list[SymbolWithPercentage]: # get lookback period in ms, for exchange ohlcv fetch candles = self.fetch_candles_for_lookback_period(filtered_tickers) @@ -302,16 +309,23 @@ class PercentChangePairList(IPairList): filtered_tickers[i]["percentage"] = pct_change else: filtered_tickers[i]["percentage"] = 0 + return filtered_tickers - def fetch_percent_change_from_tickers(self, filtered_tickers: list[dict[str, Any]], tickers): - for i, p in enumerate(filtered_tickers): + def fetch_percent_change_from_tickers( + self, filtered_tickers: list[SymbolWithPercentage], tickers + ) -> list[SymbolWithPercentage]: + valid_tickers: list[SymbolWithPercentage] = [] + for p in filtered_tickers: # Filter out assets - if not self._validate_pair( - p["symbol"], tickers[p["symbol"]] if p["symbol"] in tickers else None + if ( + self._validate_pair( + p["symbol"], tickers[p["symbol"]] if p["symbol"] in tickers else None + ) + and p["symbol"] != "UNI/USDT" ): - filtered_tickers.remove(p) - else: - filtered_tickers[i]["percentage"] = tickers[p["symbol"]]["percentage"] + p["percentage"] = tickers[p["symbol"]]["percentage"] + valid_tickers.append(p) + return valid_tickers def _validate_pair(self, pair: str, ticker: Ticker | None) -> bool: """ diff --git a/freqtrade/rpc/api_server/api_backtest.py b/freqtrade/rpc/api_server/api_backtest.py index 1386109b8..65631add6 100644 --- a/freqtrade/rpc/api_server/api_backtest.py +++ b/freqtrade/rpc/api_server/api_backtest.py @@ -43,7 +43,7 @@ router = APIRouter() def __run_backtest_bg(btconfig: Config): from freqtrade.data.metrics import combined_dataframes_with_rel_mean - from freqtrade.optimize.optimize_reports import generate_backtest_stats, store_backtest_stats + from freqtrade.optimize.optimize_reports import generate_backtest_stats, store_backtest_results from freqtrade.resolvers import StrategyResolver asyncio.set_event_loop(asyncio.new_event_loop()) @@ -101,8 +101,8 @@ def __run_backtest_bg(btconfig: Config): if btconfig.get("export", "none") == "trades": combined_res = combined_dataframes_with_rel_mean(ApiBG.bt["data"], min_date, max_date) - fn = store_backtest_stats( - btconfig["exportfilename"], + fn = store_backtest_results( + btconfig, ApiBG.bt["bt"].results, datetime.now().strftime("%Y-%m-%d_%H-%M-%S"), market_change_data=combined_res, diff --git a/freqtrade/rpc/api_server/api_download_data.py b/freqtrade/rpc/api_server/api_download_data.py index 161655725..b8c14ea13 100644 --- a/freqtrade/rpc/api_server/api_download_data.py +++ b/freqtrade/rpc/api_server/api_download_data.py @@ -57,7 +57,7 @@ def pairlists_evaluate( config_loc = deepcopy(config) config_loc["stake_currency"] = "" config_loc["pairs"] = payload.pairs - config_loc["timeframe"] = payload.timeframes + config_loc["timerange"] = payload.timerange config_loc["days"] = payload.days config_loc["timeframes"] = payload.timeframes config_loc["erase"] = payload.erase diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index 5722ad157..25fd12efd 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -6,7 +6,7 @@ from fastapi.exceptions import HTTPException from freqtrade import __version__ from freqtrade.data.history import get_datahandler -from freqtrade.enums import CandleType, TradingMode +from freqtrade.enums import CandleType, State, TradingMode from freqtrade.exceptions import OperationalException from freqtrade.rpc import RPC from freqtrade.rpc.api_server.api_schemas import ( @@ -217,7 +217,7 @@ def edge(rpc: RPC = Depends(get_rpc)): @router.get("/show_config", response_model=ShowConfig, tags=["info"]) def show_config(rpc: RPC | None = Depends(get_rpc_optional), config=Depends(get_config)): - state = "" + state: State | str = "" strategy_version = None if rpc: state = rpc._freqtrade.state @@ -357,6 +357,7 @@ def pair_history( config = deepcopy(config) config.update( { + "timeframe": timeframe, "strategy": strategy, "timerange": timerange, "freqaimodel": freqaimodel if freqaimodel else config.get("freqaimodel"), @@ -377,6 +378,7 @@ def pair_history_filtered( config = deepcopy(config) config.update( { + "timeframe": payload.timeframe, "strategy": payload.strategy, "timerange": payload.timerange, "freqaimodel": ( diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index afa8baea2..0e492be86 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -7,7 +7,7 @@ from abc import abstractmethod from collections.abc import Generator, Sequence from datetime import date, datetime, timedelta, timezone from math import isnan -from typing import Any, cast +from typing import TYPE_CHECKING, Any import psutil from dateutil.relativedelta import relativedelta @@ -32,7 +32,7 @@ from freqtrade.enums import ( ) from freqtrade.exceptions import ExchangeError, PricingError from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs -from freqtrade.exchange.exchange_types import Ticker, Tickers +from freqtrade.exchange.exchange_utils import price_to_precision from freqtrade.loggers import bufferHandler from freqtrade.persistence import KeyStoreKeys, KeyValueStore, PairLocks, Trade from freqtrade.persistence.models import PairLock @@ -98,6 +98,10 @@ class RPC: # Bind _fiat_converter if needed _fiat_converter: CryptoToFiatConverter | None = None + if TYPE_CHECKING: + from freqtrade.freqtradebot import FreqtradeBot + + _freqtrade: FreqtradeBot def __init__(self, freqtrade) -> None: """ @@ -201,7 +205,7 @@ class RPC: # calculate profit and send message to user if trade.is_open: try: - current_rate = self._freqtrade.exchange.get_rate( + current_rate: float = self._freqtrade.exchange.get_rate( trade.pair, side="exit", is_short=trade.is_short, refresh=False ) except (ExchangeError, PricingError): @@ -219,7 +223,7 @@ class RPC: else: # Closed trade ... - current_rate = trade.close_rate + current_rate = trade.close_rate or 0.0 current_profit = trade.close_profit or 0.0 current_profit_abs = trade.close_profit_abs or 0.0 @@ -243,7 +247,11 @@ class RPC: stoploss_entry_dist_ratio = stop_entry.profit_ratio # calculate distance to stoploss - stoploss_current_dist = trade.stop_loss - current_rate + stoploss_current_dist = price_to_precision( + trade.stop_loss - current_rate, + trade.price_precision, + trade.precision_mode_price, + ) stoploss_current_dist_ratio = stoploss_current_dist / current_rate trade_dict = trade.to_json() @@ -572,8 +580,8 @@ class RPC: # Doing the sum is not right - overall profit needs to be based on initial capital profit_all_ratio_sum = sum(profit_all_ratio) if profit_all_ratio else 0.0 starting_balance = self._freqtrade.wallets.get_starting_balance() - profit_closed_ratio_fromstart = 0 - profit_all_ratio_fromstart = 0 + profit_closed_ratio_fromstart = 0.0 + profit_all_ratio_fromstart = 0.0 if starting_balance: profit_closed_ratio_fromstart = profit_closed_coin_sum / starting_balance profit_all_ratio_fromstart = profit_all_coin_sum / starting_balance @@ -670,7 +678,7 @@ class RPC: } def __balance_get_est_stake( - self, coin: str, stake_currency: str, amount: float, balance: Wallet, tickers: Tickers + self, coin: str, stake_currency: str, amount: float, balance: Wallet ) -> tuple[float, float]: est_stake = 0.0 est_bot_stake = 0.0 @@ -681,14 +689,18 @@ class RPC: est_stake = balance.free est_bot_stake = amount else: - pair = self._freqtrade.exchange.get_valid_pair_combination(coin, stake_currency) - rate: float | None = cast(Ticker, tickers.get(pair, {})).get("last", None) - if rate: - if pair.startswith(stake_currency) and not pair.endswith(stake_currency): - rate = 1.0 / rate - est_stake = rate * balance.total - est_bot_stake = rate * amount + try: + rate: float | None = self._freqtrade.exchange.get_conversion_rate( + coin, stake_currency + ) + if rate: + est_stake = rate * balance.total + est_bot_stake = rate * amount + return est_stake, est_bot_stake + except (ExchangeError, PricingError) as e: + logger.warning(f"Error {e} getting rate for {coin}") + pass return est_stake, est_bot_stake def _rpc_balance(self, stake_currency: str, fiat_display_currency: str) -> dict: @@ -696,10 +708,6 @@ class RPC: currencies: list[dict] = [] total = 0.0 total_bot = 0.0 - try: - tickers: Tickers = self._freqtrade.exchange.get_tickers(cached=True) - except ExchangeError: - raise RPCException("Error getting current tickers.") open_trades: list[Trade] = Trade.get_open_trades() open_assets: dict[str, Trade] = {t.safe_base_currency: t for t in open_trades} @@ -715,7 +723,7 @@ class RPC: coin: str balance: Wallet for coin, balance in self._freqtrade.wallets.get_all_balances().items(): - if not balance.total: + if not balance.total and not balance.free: continue trade = open_assets.get(coin, None) @@ -726,7 +734,7 @@ class RPC: try: est_stake, est_stake_bot = self.__balance_get_est_stake( - coin, stake_currency, trade_amount, balance, tickers + coin, stake_currency, trade_amount, balance ) except ValueError: continue @@ -886,10 +894,10 @@ class RPC: if amount and amount < trade.amount: # Partial exit ... min_exit_stake = self._freqtrade.exchange.get_min_pair_stake_amount( - trade.pair, current_rate, trade.stop_loss_pct + trade.pair, current_rate, trade.stop_loss_pct or 0.0 ) remaining = (trade.amount - amount) * current_rate - if remaining < min_exit_stake: + if min_exit_stake and remaining < min_exit_stake: raise RPCException(f"Remaining amount of {remaining} would be too small.") sub_amount = amount @@ -1229,7 +1237,7 @@ class RPC: for pair in add: if pair not in self._freqtrade.pairlists.blacklist: try: - expand_pairlist([pair], self._freqtrade.exchange.get_markets().keys()) + expand_pairlist([pair], list(self._freqtrade.exchange.get_markets().keys())) self._freqtrade.pairlists.blacklist.append(pair) except ValueError: diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 1e415e9fc..73d3acfa9 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -5,7 +5,6 @@ This module defines the interface to apply for strategies import logging from abc import ABC, abstractmethod -from collections import OrderedDict from datetime import datetime, timedelta, timezone from math import isinf, isnan @@ -141,9 +140,7 @@ class IStrategy(ABC, HyperStrategyMixin): market_direction: MarketDirection = MarketDirection.NONE # Global cache dictionary - _cached_grouped_trades_per_pair: dict[ - str, OrderedDict[tuple[datetime, datetime], DataFrame] - ] = {} + _cached_grouped_trades_per_pair: dict[str, DataFrame] = {} def __init__(self, config: Config) -> None: self.config = config @@ -1163,10 +1160,10 @@ class IStrategy(ABC, HyperStrategyMixin): logger.warning(f"Empty candle (OHLCV) data for pair {pair}") return None, None - latest_date = dataframe["date"].max() - latest = dataframe.loc[dataframe["date"] == latest_date].iloc[-1] + latest_date_pd = dataframe["date"].max() + latest = dataframe.loc[dataframe["date"] == latest_date_pd].iloc[-1] # Explicitly convert to datetime object to ensure the below comparison does not fail - latest_date = latest_date.to_pydatetime() + latest_date: datetime = latest_date_pd.to_pydatetime() # Check if dataframe is out of date timeframe_minutes = timeframe_to_minutes(timeframe) @@ -1604,15 +1601,11 @@ class IStrategy(ABC, HyperStrategyMixin): if use_public_trades: trades = self.dp.trades(pair=metadata["pair"], copy=False) - config = self.config - config["timeframe"] = self.timeframe pair = metadata["pair"] # TODO: slice trades to size of dataframe for faster backtesting - cached_grouped_trades: OrderedDict[tuple[datetime, datetime], DataFrame] = ( - self._cached_grouped_trades_per_pair.get(pair, OrderedDict()) - ) + cached_grouped_trades: DataFrame | None = self._cached_grouped_trades_per_pair.get(pair) dataframe, cached_grouped_trades = populate_dataframe_with_trades( - cached_grouped_trades, config, dataframe, trades + cached_grouped_trades, self.config, dataframe, trades ) # dereference old cache diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index 2510b38b9..c81a76f72 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -216,7 +216,7 @@ "# Get market change (average change of all pairs from start to end of the backtest period)\n", "print(stats[\"strategy\"][strategy][\"market_change\"])\n", "# Maximum drawdown ()\n", - "print(stats[\"strategy\"][strategy][\"max_drawdown\"])\n", + "print(stats[\"strategy\"][strategy][\"max_drawdown_abs\"])\n", "# Maximum drawdown start and end\n", "print(stats[\"strategy\"][strategy][\"drawdown_start\"])\n", "print(stats[\"strategy\"][strategy][\"drawdown_end\"])\n", diff --git a/freqtrade/util/__init__.py b/freqtrade/util/__init__.py index 7a4d4d119..a0b618b11 100644 --- a/freqtrade/util/__init__.py +++ b/freqtrade/util/__init__.py @@ -11,6 +11,7 @@ from freqtrade.util.datetime_helpers import ( format_ms_time, shorten_date, ) +from freqtrade.util.dry_run_wallet import get_dry_run_wallet from freqtrade.util.formatters import decimals_per_coin, fmt_coin, fmt_coin2, round_value from freqtrade.util.ft_precise import FtPrecise from freqtrade.util.measure_time import MeasureTime @@ -35,6 +36,7 @@ __all__ = [ "dt_utc", "format_date", "format_ms_time", + "get_dry_run_wallet", "FtPrecise", "PeriodicCache", "shorten_date", diff --git a/freqtrade/util/dry_run_wallet.py b/freqtrade/util/dry_run_wallet.py new file mode 100644 index 000000000..c904db6b3 --- /dev/null +++ b/freqtrade/util/dry_run_wallet.py @@ -0,0 +1,12 @@ +from freqtrade.constants import Config + + +def get_dry_run_wallet(config: Config) -> int | float: + """ + Return dry-run wallet balance in stake currency from configuration. + This setup also supports dictionary mode for dry-run-wallet. + """ + if isinstance(_start_cap := config["dry_run_wallet"], float | int): + return _start_cap + else: + return _start_cap.get("stake_currency") diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 2b26fb8b6..e0fb1f556 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -2,7 +2,6 @@ """Wallet""" import logging -from copy import deepcopy from datetime import datetime, timedelta from typing import NamedTuple @@ -41,7 +40,14 @@ class Wallets: self._exchange = exchange self._wallets: dict[str, Wallet] = {} self._positions: dict[str, PositionWallet] = {} - self._start_cap = config["dry_run_wallet"] + self._start_cap: dict[str, float] = {} + self._stake_currency = config["stake_currency"] + + if isinstance(_start_cap := config["dry_run_wallet"], float | int): + self._start_cap[self._stake_currency] = _start_cap + else: + self._start_cap = _start_cap + self._last_wallet_refresh: datetime | None = None self.update() @@ -66,6 +72,18 @@ class Wallets: else: return 0 + def get_collateral(self) -> float: + """ + Get total collateral for liquidation price calculation. + """ + if self._config.get("margin_mode") == "cross": + # free includes all balances and, combined with position collateral, + # is used as "wallet balance". + return self.get_free(self._stake_currency) + sum( + pos.collateral for pos in self._positions.values() + ) + return self.get_total(self._stake_currency) + def get_owned(self, pair: str, base_currency: str) -> float: """ Get currently owned value. @@ -109,54 +127,66 @@ class Wallets: for o in trade.open_orders if o.amount and o.ft_order_side == trade.exit_side ) + curr_wallet_bal = self._start_cap.get(curr, 0) - _wallets[curr] = Wallet(curr, trade.amount - pending, pending, trade.amount) - - current_stake = self._start_cap + tot_profit - tot_in_trades - total_stake = current_stake + used_stake + _wallets[curr] = Wallet( + curr, + curr_wallet_bal + trade.amount - pending, + pending, + trade.amount + curr_wallet_bal, + ) else: - tot_in_trades = 0 for position in open_trades: - # size = self._exchange._contracts_to_amount(position.pair, position['contracts']) - size = position.amount - collateral = position.stake_amount - leverage = position.leverage - tot_in_trades += collateral _positions[position.pair] = PositionWallet( position.pair, - position=size, - leverage=leverage, - collateral=collateral, + position=position.amount, + leverage=position.leverage, + collateral=position.stake_amount, side=position.trade_direction, ) - current_stake = self._start_cap + tot_profit - tot_in_trades - used_stake = tot_in_trades - total_stake = current_stake + tot_in_trades - _wallets[self._config["stake_currency"]] = Wallet( - currency=self._config["stake_currency"], - free=current_stake, + used_stake = tot_in_trades + + cross_margin = 0.0 + if self._config.get("margin_mode") == "cross": + # In cross-margin mode, the total balance is used as collateral. + # This is moved as "free" into the stake currency balance. + # strongly tied to the get_collateral() implementation. + for curr, bal in self._start_cap.items(): + if curr == self._stake_currency: + continue + rate = self._exchange.get_conversion_rate(curr, self._stake_currency) + if rate: + cross_margin += bal * rate + + current_stake = self._start_cap.get(self._stake_currency, 0) + tot_profit - tot_in_trades + total_stake = current_stake + used_stake + + _wallets[self._stake_currency] = Wallet( + currency=self._stake_currency, + free=current_stake + cross_margin, used=used_stake, total=total_stake, ) + for currency, bal in self._start_cap.items(): + if currency not in _wallets: + _wallets[currency] = Wallet(currency, bal, 0, bal) + self._wallets = _wallets self._positions = _positions def _update_live(self) -> None: balances = self._exchange.get_balances() + _wallets = {} for currency in balances: if isinstance(balances[currency], dict): - self._wallets[currency] = Wallet( + _wallets[currency] = Wallet( currency, balances[currency].get("free", 0), balances[currency].get("used", 0), balances[currency].get("total", 0), ) - # Remove currencies no longer in get_balances output - for currency in deepcopy(self._wallets): - if currency not in balances: - del self._wallets[currency] positions = self._exchange.fetch_positions() _parsed_positions = {} @@ -176,6 +206,7 @@ class Wallets: side=position["side"], ) self._positions = _parsed_positions + self._wallets = _wallets def update(self, require_update: bool = True) -> None: """ @@ -244,8 +275,10 @@ class Wallets: else: tot_profit = Trade.get_total_closed_profit() open_stakes = Trade.total_open_trades_stakes() - available_balance = self.get_free(self._config["stake_currency"]) - return available_balance - tot_profit + open_stakes + available_balance = self.get_free(self._stake_currency) + return (available_balance - tot_profit + open_stakes) * self._config[ + "tradable_balance_ratio" + ] def get_total_stake_amount(self): """ @@ -264,9 +297,9 @@ class Wallets: # Ensure % is used from the overall balance # Otherwise we'd risk lowering stakes with each open trade. # (tied up + current free) * ratio) - tied up - available_amount = ( - val_tied_up + self.get_free(self._config["stake_currency"]) - ) * self._config["tradable_balance_ratio"] + available_amount = (val_tied_up + self.get_free(self._stake_currency)) * self._config[ + "tradable_balance_ratio" + ] return available_amount def get_available_stake_amount(self) -> float: @@ -277,7 +310,7 @@ class Wallets: ( + free amount) * tradable_balance_ratio - """ - free = self.get_free(self._config["stake_currency"]) + free = self.get_free(self._stake_currency) return min(self.get_total_stake_amount() - Trade.total_open_trades_stakes(), free) def _calculate_unlimited_stake_amount( @@ -316,7 +349,7 @@ class Wallets: f"lower than stake amount ({stake_amount} {self._config['stake_currency']})" ) - return stake_amount + return max(stake_amount, 0) def get_trade_stake_amount( self, pair: str, max_open_trades: IntOrInf, edge=None, update: bool = True @@ -336,8 +369,8 @@ class Wallets: if edge: stake_amount = edge.stake_amount( pair, - self.get_free(self._config["stake_currency"]), - self.get_total(self._config["stake_currency"]), + self.get_free(self._stake_currency), + self.get_total(self._stake_currency), val_tied_up, ) else: diff --git a/ft_client/freqtrade_client/__init__.py b/ft_client/freqtrade_client/__init__.py index d01708a70..d17eec2a7 100644 --- a/ft_client/freqtrade_client/__init__.py +++ b/ft_client/freqtrade_client/__init__.py @@ -1,7 +1,7 @@ from freqtrade_client.ft_rest_client import FtRestClient -__version__ = "2024.11-dev" +__version__ = "2024.12-dev" if "dev" in __version__: from pathlib import Path diff --git a/pyproject.toml b/pyproject.toml index bb4575553..cc88c9131 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,6 +111,8 @@ develop = [ "pytest-cov", "pytest-mock", "pytest-random-order", + "pytest-timeout", + "pytest-xdist", "pytest", "ruff", "time-machine", @@ -215,7 +217,6 @@ exclude = [ "build_helpers/*.py", "ft_client/build/*", "build/*", - "tests/*", ] ignore = ["freqtrade/vendor/**"] pythonPlatform = "All" diff --git a/requirements-dev.txt b/requirements-dev.txt index 5cdea9ba1..f0a72aed6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,11 +7,11 @@ -r docs/requirements-docs.txt coveralls==4.0.1 -ruff==0.8.0 +ruff==0.8.3 mypy==1.13.0 pre-commit==4.0.1 -pytest==8.3.3 -pytest-asyncio==0.24.0 +pytest==8.3.4 +pytest-asyncio==0.25.0 pytest-cov==6.0.0 pytest-mock==3.14.0 pytest-random-order==1.1.1 @@ -28,5 +28,5 @@ nbconvert==7.16.4 types-cachetools==5.5.0.20240820 types-filelock==3.2.7 types-requests==2.32.0.20241016 -types-tabulate==0.9.0.20240106 -types-python-dateutil==2.9.0.20241003 +types-tabulate==0.9.0.20241207 +types-python-dateutil==2.9.0.20241206 diff --git a/requirements-freqai.txt b/requirements-freqai.txt index a09eadbb3..4b7e04c15 100644 --- a/requirements-freqai.txt +++ b/requirements-freqai.txt @@ -3,13 +3,13 @@ -r requirements-plot.txt # Required for freqai -scikit-learn==1.5.2 +scikit-learn==1.6.0 joblib==1.4.2 catboost==1.2.7; 'arm' not in platform_machine # Pin Matplotlib - it's depended on by catboost # Temporary downgrade of matplotlib due to https://github.com/matplotlib/matplotlib/issues/28551 -matplotlib==3.9.2 +matplotlib==3.10.0 lightgbm==4.5.0 -xgboost==2.0.3 +xgboost==2.1.3 tensorboard==2.18.0 datasieve==0.1.7 diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 7f60c8299..024eeecf8 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -3,6 +3,6 @@ # Required for hyperopt scipy==1.14.1 -scikit-learn==1.5.2 +scikit-learn==1.6.0 ft-scikit-optimize==0.9.2 filelock==3.16.1 diff --git a/requirements.txt b/requirements.txt index 5691b42d1..4b8b784ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,12 +4,12 @@ bottleneck==1.4.2 numexpr==2.10.2 pandas-ta==0.3.14b -ccxt==4.4.35 +ccxt==4.4.40 cryptography==42.0.8; platform_machine == 'armv7l' -cryptography==43.0.3; platform_machine != 'armv7l' +cryptography==44.0.0; platform_machine != 'armv7l' aiohttp==3.10.11 SQLAlchemy==2.0.36 -python-telegram-bot==21.7 +python-telegram-bot==21.9 # can't be hard-pinned due to telegram-bot pinning httpx with ~ httpx>=0.24.1 humanize==4.11.0 @@ -17,15 +17,18 @@ cachetools==5.5.0 requests==2.32.3 urllib3==2.2.3 jsonschema==4.23.0 -TA-Lib==0.4.32 +TA-Lib==0.4.34 technical==1.4.4 tabulate==0.9.0 pycoingecko==3.2.0 jinja2==3.1.4 tables==3.10.1 +# Pin blosc2 to < 3.0 until piwheel has wheels for 3.x +blosc2==2.7.1; platform_machine == 'armv7l' or python_version < '3.11' +blosc2==3.0.0; platform_machine != 'armv7l' and python_version >= '3.11' joblib==1.4.2 rich==13.9.4 -pyarrow==18.0.0; platform_machine != 'armv7l' +pyarrow==18.1.0; platform_machine != 'armv7l' # find first, C search in arrays py_find_1st==1.1.6 @@ -39,10 +42,10 @@ orjson==3.10.12 sdnotify==0.3.2 # API Server -fastapi==0.115.5 -pydantic==2.10.1 -uvicorn==0.32.1 -pyjwt==2.10.0 +fastapi==0.115.6 +pydantic==2.10.3 +uvicorn==0.34.0 +pyjwt==2.10.1 aiofiles==24.1.0 psutil==6.1.0 @@ -58,7 +61,7 @@ schedule==1.2.2 #WS Messages websockets==14.1 -janus==1.1.0 +janus==2.0.0 ast-comments==1.2.2 packaging==24.2 diff --git a/tests/conftest.py b/tests/conftest.py index 0a71a8a77..a6958ccb4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,7 @@ # pragma pylint: disable=missing-docstring import json import logging +import platform import re from copy import deepcopy from datetime import datetime, timedelta, timezone @@ -517,6 +518,30 @@ def patch_gc(mocker) -> None: mocker.patch("freqtrade.main.gc_set_threshold") +def is_arm() -> bool: + machine = platform.machine() + return "arm" in machine or "aarch64" in machine + + +def is_mac() -> bool: + machine = platform.system() + return "Darwin" in machine + + +@pytest.fixture(autouse=True) +def patch_torch_initlogs(mocker) -> None: + if is_mac(): + # Mock torch import completely + import sys + import types + + module_name = "torch" + mocked_module = types.ModuleType(module_name) + sys.modules[module_name] = mocked_module + else: + mocker.patch("torch._logging._init_logs") + + @pytest.fixture(autouse=True) def user_dir(mocker, tmp_path) -> Path: user_dir = tmp_path / "user_data" @@ -2235,7 +2260,7 @@ def tickers(): "first": None, "last": 8603.67, "change": -0.879, - "percentage": None, + "percentage": -8.95, "average": None, "baseVolume": 30414.604298, "quoteVolume": 259629896.48584127, @@ -2279,7 +2304,7 @@ def tickers(): "first": None, "last": 129.28, "change": 1.795, - "percentage": None, + "percentage": -2.5, "average": None, "baseVolume": 59698.79897, "quoteVolume": 29132399.743954, diff --git a/tests/data/test_converter_orderflow.py b/tests/data/test_converter_orderflow.py index 9a337da91..656c1eab3 100644 --- a/tests/data/test_converter_orderflow.py +++ b/tests/data/test_converter_orderflow.py @@ -1,13 +1,17 @@ -from collections import OrderedDict - import numpy as np import pandas as pd import pytest from freqtrade.constants import DEFAULT_TRADES_COLUMNS from freqtrade.data.converter import populate_dataframe_with_trades -from freqtrade.data.converter.orderflow import trades_to_volumeprofile_with_total_delta_bid_ask +from freqtrade.data.converter.orderflow import ( + ORDERFLOW_ADDED_COLUMNS, + timeframe_to_DateOffset, + trades_to_volumeprofile_with_total_delta_bid_ask, +) from freqtrade.data.converter.trade_converter import trades_list_to_df +from freqtrade.data.dataprovider import DataProvider +from tests.strategy.strats.strategy_test_v3 import StrategyTestV3 BIN_SIZE_SCALE = 0.5 @@ -37,6 +41,7 @@ def populate_dataframe_with_trades_trades(testdatadir): @pytest.fixture def candles(testdatadir): + # TODO: this fixture isn't really necessary and could be removed return pd.read_json(testdatadir / "orderflow/candles.json").copy() @@ -102,7 +107,7 @@ def test_public_trades_mock_populate_dataframe_with_trades__check_orderflow( }, } # Apply the function to populate the data frame with order flow data - df, _ = populate_dataframe_with_trades(OrderedDict(), config, dataframe, trades) + df, _ = populate_dataframe_with_trades(None, config, dataframe, trades) # Extract results from the first row of the DataFrame results = df.iloc[0] t = results["trades"] @@ -243,7 +248,7 @@ def test_public_trades_trades_mock_populate_dataframe_with_trades__check_trades( } # Populate the DataFrame with trades and order flow data - df, _ = populate_dataframe_with_trades(OrderedDict(), config, dataframe, trades) + df, _ = populate_dataframe_with_trades(None, config, dataframe, trades) # --- DataFrame and Trade Data Validation --- @@ -401,9 +406,7 @@ def test_public_trades_config_max_trades( }, } - df, _ = populate_dataframe_with_trades( - OrderedDict(), default_conf | orderflow_config, dataframe, trades - ) + df, _ = populate_dataframe_with_trades(None, default_conf | orderflow_config, dataframe, trades) assert df.delta.count() == 1 @@ -482,3 +485,94 @@ def test_public_trades_testdata_sanity( "cost", "date", ] + + +def test_analyze_with_orderflow( + default_conf_usdt, + mocker, + populate_dataframe_with_trades_dataframe, + populate_dataframe_with_trades_trades, +): + ohlcv_history = populate_dataframe_with_trades_dataframe + # call without orderflow + strategy = StrategyTestV3(config=default_conf_usdt) + strategy.dp = DataProvider(default_conf_usdt, None, None) + + mocker.patch.object(strategy.dp, "trades", return_value=populate_dataframe_with_trades_trades) + import freqtrade.data.converter.orderflow as orderflow_module + + spy = mocker.spy(orderflow_module, "trades_to_volumeprofile_with_total_delta_bid_ask") + + pair = "ETH/BTC" + df = strategy.advise_indicators(ohlcv_history, {"pair:": pair}) + assert len(df) == len(ohlcv_history) + assert "open" in df.columns + assert spy.call_count == 0 + + # Not expected to run - shouldn't have added orderflow columns + for col in ORDERFLOW_ADDED_COLUMNS: + assert col not in df.columns, f"Column {col} found in df.columns" + + default_conf_usdt["exchange"]["use_public_trades"] = True + default_conf_usdt["orderflow"] = { + "cache_size": 5, + "max_candles": 5, + "scale": 0.005, + "imbalance_volume": 0, + "imbalance_ratio": 3, + "stacked_imbalance_range": 3, + } + + strategy.config = default_conf_usdt + # First round - builds cache + df1 = strategy.advise_indicators(ohlcv_history, {"pair": pair}) + assert len(df1) == len(ohlcv_history) + assert "open" in df1.columns + assert spy.call_count == 5 + + for col in ORDERFLOW_ADDED_COLUMNS: + assert col in df1.columns, f"Column {col} not found in df.columns" + + if col not in ("stacked_imbalances_bid", "stacked_imbalances_ask"): + assert df1[col].count() == 5, f"Column {col} has {df1[col].count()} non-NaN values" + + assert len(strategy._cached_grouped_trades_per_pair[pair]) == 5 + + lastval_trades = df1.at[len(df1) - 1, "trades"] + assert isinstance(lastval_trades, list) + assert len(lastval_trades) == 122 + + lastval_of = df1.at[len(df1) - 1, "orderflow"] + assert isinstance(lastval_of, dict) + + spy.reset_mock() + # Ensure caching works - call the same logic again. + df2 = strategy.advise_indicators(ohlcv_history, {"pair": pair}) + assert len(df2) == len(ohlcv_history) + assert "open" in df2.columns + assert spy.call_count == 0 + for col in ORDERFLOW_ADDED_COLUMNS: + assert col in df2.columns, f"Round2: Column {col} not found in df.columns" + + if col not in ("stacked_imbalances_bid", "stacked_imbalances_ask"): + assert ( + df2[col].count() == 5 + ), f"Round2: Column {col} has {df2[col].count()} non-NaN values" + + lastval_trade2 = df2.at[len(df2) - 1, "trades"] + assert isinstance(lastval_trade2, list) + assert len(lastval_trade2) == 122 + + lastval_of2 = df2.at[len(df2) - 1, "orderflow"] + assert isinstance(lastval_of2, dict) + + +def test_timeframe_to_DateOffset(): + assert timeframe_to_DateOffset("1s") == pd.DateOffset(seconds=1) + assert timeframe_to_DateOffset("1m") == pd.DateOffset(minutes=1) + assert timeframe_to_DateOffset("5m") == pd.DateOffset(minutes=5) + assert timeframe_to_DateOffset("1h") == pd.DateOffset(hours=1) + assert timeframe_to_DateOffset("1d") == pd.DateOffset(days=1) + assert timeframe_to_DateOffset("1w") == pd.DateOffset(weeks=1) + assert timeframe_to_DateOffset("1M") == pd.DateOffset(months=1) + assert timeframe_to_DateOffset("1y") == pd.DateOffset(years=1) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 2549ff65d..1b865c963 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -128,8 +128,8 @@ def test_load_data_with_new_pair_1min( """ Test load_pair_history() with 1 min timeframe """ - mocker.patch(f"{EXMS}.get_historic_ohlcv", return_value=ohlcv_history) exchange = get_patched_exchange(mocker, default_conf) + mocker.patch.object(exchange, "get_historic_ohlcv", return_value=ohlcv_history) file = tmp_path / "MEME_BTC-1m.feather" # do not download a new pair if refresh_pairs isn't set @@ -306,8 +306,8 @@ def test_load_cached_data_for_updating(testdatadir) -> None: def test_download_pair_history( ohlcv_history, mocker, default_conf, tmp_path, candle_type, subdir, file_tail ) -> None: - mocker.patch(f"{EXMS}.get_historic_ohlcv", return_value=ohlcv_history) exchange = get_patched_exchange(mocker, default_conf) + mocker.patch.object(exchange, "get_historic_ohlcv", return_value=ohlcv_history) file1_1 = tmp_path / f"{subdir}MEME_BTC-1m{file_tail}.feather" file1_5 = tmp_path / f"{subdir}MEME_BTC-5m{file_tail}.feather" file2_1 = tmp_path / f"{subdir}CFI_BTC-1m{file_tail}.feather" @@ -357,8 +357,8 @@ def test_download_pair_history2(mocker, default_conf, testdatadir, ohlcv_history "freqtrade.data.history.datahandlers.featherdatahandler.FeatherDataHandler.ohlcv_store", return_value=None, ) - mocker.patch(f"{EXMS}.get_historic_ohlcv", return_value=ohlcv_history) exchange = get_patched_exchange(mocker, default_conf) + mocker.patch.object(exchange, "get_historic_ohlcv", return_value=ohlcv_history) _download_pair_history( datadir=testdatadir, exchange=exchange, diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index 1da5b2bda..3cd668074 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -1,14 +1,17 @@ -from datetime import datetime, timezone +from datetime import datetime, timedelta from random import randint from unittest.mock import MagicMock, PropertyMock import ccxt +import pandas as pd import pytest from freqtrade.enums import CandleType, MarginMode, TradingMode from freqtrade.exceptions import DependencyException, InvalidOrderException, OperationalException +from freqtrade.exchange.exchange_utils_timeframe import timeframe_to_seconds from freqtrade.persistence import Trade -from tests.conftest import EXMS, get_mock_coro, get_patched_exchange, log_has_re +from freqtrade.util.datetime_helpers import dt_from_ts, dt_ts, dt_utc +from tests.conftest import EXMS, get_patched_exchange from tests.exchange.test_exchange import ccxt_exceptionhandlers @@ -290,6 +293,7 @@ def test_liquidation_price_binance( default_conf["trading_mode"] = trading_mode default_conf["margin_mode"] = margin_mode default_conf["liquidation_buffer"] = 0.0 + mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf, exchange="binance") def get_maint_ratio(pair_, stake_amount): @@ -731,42 +735,243 @@ def test__set_leverage_binance(mocker, default_conf): ) -@pytest.mark.parametrize("candle_type", [CandleType.MARK, ""]) -async def test__async_get_historic_ohlcv_binance(default_conf, mocker, caplog, candle_type): - ohlcv = [ - [ - int((datetime.now(timezone.utc).timestamp() - 1000) * 1000), - 1, # open - 2, # high - 3, # low - 4, # close - 5, # volume (in quote currency) +def patch_binance_vision_ohlcv(mocker, start, archive_end, api_end, timeframe): + def make_storage(start: datetime, end: datetime, timeframe: str): + date = pd.date_range(start, end, freq=timeframe.replace("m", "min")) + df = pd.DataFrame( + data=dict(date=date, open=1.0, high=1.0, low=1.0, close=1.0), + ) + return df + + archive_storage = make_storage(start, archive_end, timeframe) + api_storage = make_storage(start, api_end, timeframe) + + ohlcv = [[dt_ts(start), 1, 1, 1, 1]] + # (pair, timeframe, candle_type, ohlcv, True) + candle_history = [None, None, None, ohlcv, None] + + def get_historic_ohlcv( + # self, + pair: str, + timeframe: str, + since_ms: int, + candle_type: CandleType, + is_new_pair: bool = False, + until_ms: int | None = None, + ): + since = dt_from_ts(since_ms) + until = dt_from_ts(until_ms) if until_ms else api_end + timedelta(seconds=1) + return api_storage.loc[(api_storage["date"] >= since) & (api_storage["date"] < until)] + + async def download_archive_ohlcv( + candle_type, + pair, + timeframe, + since_ms, + until_ms, + markets=None, + stop_on_404=False, + ): + since = dt_from_ts(since_ms) + until = dt_from_ts(until_ms) if until_ms else archive_end + timedelta(seconds=1) + if since < start: + pass + return archive_storage.loc[ + (archive_storage["date"] >= since) & (archive_storage["date"] < until) ] - ] + candle_mock = mocker.patch(f"{EXMS}._async_get_candle_history", return_value=candle_history) + api_mock = mocker.patch(f"{EXMS}.get_historic_ohlcv", side_effect=get_historic_ohlcv) + archive_mock = mocker.patch( + "freqtrade.exchange.binance.download_archive_ohlcv", side_effect=download_archive_ohlcv + ) + return candle_mock, api_mock, archive_mock + + +@pytest.mark.parametrize( + "timeframe,is_new_pair,since,until,first_date,last_date,candle_called,archive_called," + "api_called", + [ + ( + "1m", + True, + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23, 59), + True, + True, + False, + ), + ( + "1m", + True, + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 3), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 2, 23, 59), + True, + True, + True, + ), + ( + "1m", + True, + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 2, 1), + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 2, 0, 59), + True, + False, + True, + ), + ( + "1m", + False, + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23, 59), + False, + True, + False, + ), + ( + "1m", + True, + dt_utc(2019, 1, 1), + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23, 59), + True, + True, + False, + ), + ( + "1m", + False, + dt_utc(2019, 1, 1), + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23, 59), + False, + True, + False, + ), + ( + "1m", + False, + dt_utc(2019, 1, 1), + dt_utc(2019, 1, 2), + None, + None, + False, + True, + True, + ), + ( + "1m", + True, + dt_utc(2019, 1, 1), + dt_utc(2019, 1, 2), + None, + None, + True, + False, + False, + ), + ( + "1m", + False, + dt_utc(2021, 1, 1), + dt_utc(2021, 1, 2), + None, + None, + False, + False, + False, + ), + ( + "1m", + True, + dt_utc(2021, 1, 1), + dt_utc(2021, 1, 2), + None, + None, + True, + False, + False, + ), + ( + "1h", + False, + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23), + False, + False, + True, + ), + ( + "1m", + False, + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 3, 50, 30), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 3, 50), + False, + True, + False, + ), + ], +) +def test_get_historic_ohlcv_binance( + mocker, + default_conf, + timeframe, + is_new_pair, + since, + until, + first_date, + last_date, + candle_called, + archive_called, + api_called, +): exchange = get_patched_exchange(mocker, default_conf, exchange="binance") - # Monkey-patch async function - exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv) - pair = "ETH/BTC" - 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" - assert restype == candle_type - # Call with very old timestamp - causes tons of requests - 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( - pair, "5m", 1500000000000, is_new_pair=True, candle_type=candle_type + start = dt_utc(2020, 1, 1) + archive_end = dt_utc(2020, 1, 2) + api_end = dt_utc(2020, 1, 3) + candle_mock, api_mock, archive_mock = patch_binance_vision_ohlcv( + mocker, start=start, archive_end=archive_end, api_end=api_end, timeframe=timeframe ) - # Called twice - one "init" call - and one to get the actual data. - assert exchange._api_async.fetch_ohlcv.call_count == 2 - assert res == ohlcv - assert log_has_re(r"Candle-data for ETH/BTC available starting with .*", caplog) + candle_type = CandleType.SPOT + pair = "BTC/USDT" + + since_ms = dt_ts(since) + until_ms = dt_ts(until) + + df = exchange.get_historic_ohlcv(pair, timeframe, since_ms, candle_type, is_new_pair, until_ms) + + if df.empty: + assert first_date is None + assert last_date is None + else: + assert df["date"].iloc[0] == first_date + assert df["date"].iloc[-1] == last_date + assert ( + df["date"].diff().iloc[1:] == timedelta(seconds=timeframe_to_seconds(timeframe)) + ).all() + + if candle_called: + candle_mock.assert_called_once() + if archive_called: + archive_mock.assert_called_once() + if api_called: + api_mock.assert_called_once() @pytest.mark.parametrize( diff --git a/tests/exchange/test_binance_public_data.py b/tests/exchange/test_binance_public_data.py new file mode 100644 index 000000000..6eb5a00bb --- /dev/null +++ b/tests/exchange/test_binance_public_data.py @@ -0,0 +1,337 @@ +import asyncio +import datetime +import io +import re +import sys +import zipfile +from datetime import timedelta + +import aiohttp +import pandas as pd +import pytest + +from freqtrade.enums import CandleType +from freqtrade.exchange.binance_public_data import ( + BadHttpStatus, + Http404, + binance_vision_zip_name, + download_archive_ohlcv, + get_daily_ohlcv, +) +from freqtrade.util.datetime_helpers import dt_ts, dt_utc + + +@pytest.fixture(scope="module") +def event_loop_policy(request): + if sys.platform == "win32": + return asyncio.WindowsSelectorEventLoopPolicy() + else: + return asyncio.DefaultEventLoopPolicy() + + +class MockResponse: + """AioHTTP response mock""" + + def __init__(self, content, status, reason=""): + self._content = content + self.status = status + self.reason = reason + + async def read(self): + return self._content + + async def __aexit__(self, exc_type, exc, tb): + pass + + async def __aenter__(self): + return self + + +# spot klines archive csv file format, the futures/um klines don't have the header line +# +# open_time,open,high,low,close,volume,close_time,quote_volume,count,taker_buy_volume,taker_buy_quote_volume,ignore # noqa: E501 +# 1698364800000,34161.6,34182.5,33977.4,34024.2,409953,1698368399999,1202.97118037,15095,192220,564.12041453,0 # noqa: E501 +# 1698368400000,34024.2,34060.1,33776.4,33848.4,740960,1698371999999,2183.75671155,23938,368266,1085.17080793,0 # noqa: E501 +# 1698372000000,33848.5,34150.0,33815.1,34094.2,390376,1698375599999,1147.73267094,13854,231446,680.60405822,0 # noqa: E501 + + +def make_response_from_url(start_date, end_date): + def make_daily_df(date, timeframe): + start = dt_utc(date.year, date.month, date.day) + end = start + timedelta(days=1) + date_col = pd.date_range(start, end, freq=timeframe.replace("m", "min"), inclusive="left") + cols = ( + "open_time,open,high,low,close,volume,close_time,quote_volume,count,taker_buy_volume," + "taker_buy_quote_volume,ignore" + ) + df = pd.DataFrame(columns=cols.split(","), dtype=float) + df["open_time"] = date_col.astype("int64") // 10**6 + df["open"] = df["high"] = df["low"] = df["close"] = df["volume"] = 1.0 + return df + + def make_daily_zip(asset_type_url_segment, symbol, timeframe, date) -> bytes: + df = make_daily_df(date, timeframe) + if asset_type_url_segment == "spot": + header = True + elif asset_type_url_segment == "futures/um": + header = None + else: + raise ValueError + csv = df.to_csv(index=False, header=header) + zip_buffer = io.BytesIO() + with zipfile.ZipFile(zip_buffer, "w") as zipf: + zipf.writestr(binance_vision_zip_name(symbol, timeframe, date), csv) + return zip_buffer.getvalue() + + def make_response(url): + pattern = ( + r"https://data.binance.vision/data/(?Pspot|futures/um)" + r"/daily/klines/(?P.*?)/(?P.*?)/(?P=symbol)-(?P=timeframe)-" + r"(?P\d{4}-\d{2}-\d{2}).zip" + ) + m = re.match(pattern, url) + if not m: + return MockResponse(content="", status=404) + + date = datetime.datetime.strptime(m["date"], "%Y-%m-%d").date() + if date < start_date or date > end_date: + return MockResponse(content="", status=404) + + zip_file = make_daily_zip(m["asset_type_url_segment"], m["symbol"], m["timeframe"], date) + return MockResponse(content=zip_file, status=200) + + return make_response + + +@pytest.mark.parametrize( + "candle_type,pair,since,until,first_date,last_date,stop_on_404", + [ + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23), + False, + ), + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23, 59, 59), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23), + False, + ), + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 5), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 3, 23), + False, + ), + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2019, 12, 25), + dt_utc(2020, 1, 5), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 3, 23), + False, + ), + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2019, 1, 1), + dt_utc(2019, 1, 5), + None, + None, + False, + ), + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2021, 1, 1), + dt_utc(2021, 1, 5), + None, + None, + False, + ), + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2020, 1, 2), + None, + dt_utc(2020, 1, 2), + dt_utc(2020, 1, 3, 23), + False, + ), + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2020, 1, 5), + dt_utc(2020, 1, 1), + None, + None, + False, + ), + ( + CandleType.FUTURES, + "BTC/USDT:USDT", + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23, 59, 59), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23), + False, + ), + ( + CandleType.INDEX, + "N/A", + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 1, 23, 59, 59), + None, + None, + False, + ), + # stop_on_404 = True + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2019, 12, 25), + dt_utc(2020, 1, 5), + None, + None, + True, + ), + ( + CandleType.SPOT, + "BTC/USDT", + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 5), + dt_utc(2020, 1, 1), + dt_utc(2020, 1, 3, 23), + True, + ), + ( + CandleType.FUTURES, + "BTC/USDT:USDT", + dt_utc(2019, 12, 25), + dt_utc(2020, 1, 5), + None, + None, + True, + ), + ], +) +async def test_download_archive_ohlcv( + mocker, candle_type, pair, since, until, first_date, last_date, stop_on_404 +): + history_start = dt_utc(2020, 1, 1).date() + history_end = dt_utc(2020, 1, 3).date() + timeframe = "1h" + + since_ms = dt_ts(since) + until_ms = dt_ts(until) + + mocker.patch( + "freqtrade.exchange.binance_public_data.aiohttp.ClientSession.get", + side_effect=make_response_from_url(history_start, history_end), + ) + markets = {"BTC/USDT": {"id": "BTCUSDT"}, "BTC/USDT:USDT": {"id": "BTCUSDT"}} + + df = await download_archive_ohlcv( + candle_type, + pair, + timeframe, + since_ms=since_ms, + until_ms=until_ms, + markets=markets, + stop_on_404=stop_on_404, + ) + + if df.empty: + assert first_date is None and last_date is None + else: + assert candle_type in [CandleType.SPOT, CandleType.FUTURES] + assert df["date"].iloc[0] == first_date + assert df["date"].iloc[-1] == last_date + + +async def test_download_archive_ohlcv_exception(mocker): + timeframe = "1h" + pair = "BTC/USDT" + + since_ms = dt_ts(dt_utc(2020, 1, 1)) + until_ms = dt_ts(dt_utc(2020, 1, 2)) + + markets = {"BTC/USDT": {"id": "BTCUSDT"}, "BTC/USDT:USDT": {"id": "BTCUSDT"}} + mocker.patch( + "freqtrade.exchange.binance_public_data.aiohttp.ClientSession.get", side_effect=RuntimeError + ) + + df = await download_archive_ohlcv( + CandleType.SPOT, pair, timeframe, since_ms=since_ms, until_ms=until_ms, markets=markets + ) + + assert df.empty + + +async def test_get_daily_ohlcv(mocker, testdatadir): + symbol = "BTCUSDT" + timeframe = "1h" + date = dt_utc(2024, 10, 28).date() + first_date = dt_utc(2024, 10, 28) + last_date = dt_utc(2024, 10, 28, 23) + + async with aiohttp.ClientSession() as session: + spot_path = ( + testdatadir / "binance/binance_public_data/spot-klines-BTCUSDT-1h-2024-10-28.zip" + ) + get = mocker.patch( + "freqtrade.exchange.binance_public_data.aiohttp.ClientSession.get", + return_value=MockResponse(spot_path.read_bytes(), 200), + ) + df = await get_daily_ohlcv("spot", symbol, timeframe, date, session) + assert get.call_count == 1 + assert df["date"].iloc[0] == first_date + assert df["date"].iloc[-1] == last_date + + futures_path = ( + testdatadir / "binance/binance_public_data/futures-um-klines-BTCUSDT-1h-2024-10-28.zip" + ) + get = mocker.patch( + "freqtrade.exchange.binance_public_data.aiohttp.ClientSession.get", + return_value=MockResponse(futures_path.read_bytes(), 200), + ) + df = await get_daily_ohlcv("futures/um", symbol, timeframe, date, session) + assert get.call_count == 1 + assert df["date"].iloc[0] == first_date + assert df["date"].iloc[-1] == last_date + + get = mocker.patch( + "freqtrade.exchange.binance_public_data.aiohttp.ClientSession.get", + return_value=MockResponse(b"", 404), + ) + with pytest.raises(Http404): + df = await get_daily_ohlcv("spot", symbol, timeframe, date, session, retry_delay=0) + assert get.call_count == 1 + + get = mocker.patch( + "freqtrade.exchange.binance_public_data.aiohttp.ClientSession.get", + return_value=MockResponse(b"", 500), + ) + mocker.patch("asyncio.sleep") + with pytest.raises(BadHttpStatus): + df = await get_daily_ohlcv("spot", symbol, timeframe, date, session) + assert get.call_count == 4 # 1 + 3 default retries + + get = mocker.patch( + "freqtrade.exchange.binance_public_data.aiohttp.ClientSession.get", + return_value=MockResponse(b"nop", 200), + ) + with pytest.raises(zipfile.BadZipFile): + df = await get_daily_ohlcv("spot", symbol, timeframe, date, session) + assert get.call_count == 4 # 1 + 3 default retries diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 0d0a5eca9..260dd8f0e 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2006,6 +2006,46 @@ def test_get_tickers(default_conf, mocker, exchange_name, caplog): assert exchange.get_tickers() == {} +@pytest.mark.parametrize("exchange_name", EXCHANGES) +def test_get_conversion_rate(default_conf_usdt, mocker, exchange_name): + api_mock = MagicMock() + tick = { + "ETH/USDT": { + "last": 42, + }, + "BCH/USDT": { + "last": 41, + }, + "ETH/BTC": { + "last": 250, + }, + } + tick2 = { + "ADA/USDT:USDT": { + "last": 2.5, + } + } + mocker.patch(f"{EXMS}.exchange_has", return_value=True) + api_mock.fetch_tickers = MagicMock(side_effect=[tick, tick2]) + api_mock.fetch_bids_asks = MagicMock(return_value={}) + + exchange = get_patched_exchange(mocker, default_conf_usdt, api_mock, exchange=exchange_name) + # retrieve original ticker + assert exchange.get_conversion_rate("USDT", "USDT") == 1 + assert api_mock.fetch_tickers.call_count == 0 + assert exchange.get_conversion_rate("ETH", "USDT") == 42 + assert exchange.get_conversion_rate("ETH", "USDC") is None + assert exchange.get_conversion_rate("ETH", "BTC") == 250 + assert exchange.get_conversion_rate("BTC", "ETH") == 0.004 + + assert api_mock.fetch_tickers.call_count == 1 + api_mock.fetch_tickers.reset_mock() + + assert exchange.get_conversion_rate("ADA", "USDT") == 2.5 + # Only the call to the "others" market + assert api_mock.fetch_tickers.call_count == 1 + + @pytest.mark.parametrize("exchange_name", EXCHANGES) def test_fetch_ticker(default_conf, mocker, exchange_name): api_mock = MagicMock() @@ -2091,6 +2131,7 @@ def test___now_is_time_to_refresh(default_conf, mocker, exchange_name, time_mach @pytest.mark.parametrize("candle_type", ["mark", ""]) @pytest.mark.parametrize("exchange_name", EXCHANGES) def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_type): + caplog.set_level(logging.DEBUG) exchange = get_patched_exchange(mocker, default_conf, exchange=exchange_name) pair = "ETH/BTC" calls = 0 @@ -2123,7 +2164,7 @@ def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_ assert exchange._async_get_candle_history.call_count == 2 # Returns twice the above OHLCV data after truncating the open candle. assert len(ret) == 2 - assert log_has_re(r"Downloaded data for .* with length .*\.", caplog) + assert log_has_re(r"Downloaded data for .* from ccxt with length .*\.", caplog) caplog.clear() @@ -2156,7 +2197,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_ pair = "ETH/USDT" respair, restf, _, res, _ = await exchange._async_get_historic_ohlcv( - pair, "5m", 1500000000000, candle_type=candle_type, is_new_pair=False + pair, "5m", 1500000000000, candle_type=candle_type ) assert respair == pair assert restf == "5m" @@ -2168,7 +2209,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_ end_ts = 1_500_500_000_000 start_ts = 1_500_000_000_000 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 + pair, "5m", since_ms=start_ts, candle_type=candle_type, until_ms=end_ts ) # Required candles candles = (end_ts - start_ts) / 300_000 @@ -4078,10 +4119,16 @@ def test_get_valid_pair_combination(default_conf, mocker, markets): ) ex = Exchange(default_conf) - assert ex.get_valid_pair_combination("ETH", "BTC") == "ETH/BTC" - assert ex.get_valid_pair_combination("BTC", "ETH") == "ETH/BTC" + assert next(ex.get_valid_pair_combination("ETH", "BTC")) == "ETH/BTC" + assert next(ex.get_valid_pair_combination("BTC", "ETH")) == "ETH/BTC" + multicombs = list(ex.get_valid_pair_combination("ETH", "USDT")) + assert len(multicombs) == 2 + assert "ETH/USDT" in multicombs + assert "ETH/USDT:USDT" in multicombs + with pytest.raises(ValueError, match=r"Could not combine.* to get a valid pair."): - ex.get_valid_pair_combination("NOPAIR", "ETH") + for x in ex.get_valid_pair_combination("NOPAIR", "ETH"): + pass @pytest.mark.parametrize( @@ -6130,6 +6177,7 @@ def test_get_liquidation_price( default_conf_usdt["exchange"]["name"] = exchange_name default_conf_usdt["margin_mode"] = margin_mode mocker.patch("freqtrade.exchange.gate.Gate.validate_ordertypes") + mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y, **kwargs: y) exchange = get_patched_exchange(mocker, default_conf_usdt, exchange=exchange_name) exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(0.01, 0.01)) diff --git a/tests/freqai/conftest.py b/tests/freqai/conftest.py index 442f53020..9e14111af 100644 --- a/tests/freqai/conftest.py +++ b/tests/freqai/conftest.py @@ -1,4 +1,3 @@ -import platform import sys from copy import deepcopy from pathlib import Path @@ -20,30 +19,6 @@ def is_py12() -> bool: return sys.version_info >= (3, 12) -def is_mac() -> bool: - machine = platform.system() - return "Darwin" in machine - - -def is_arm() -> bool: - machine = platform.machine() - return "arm" in machine or "aarch64" in machine - - -@pytest.fixture(autouse=True) -def patch_torch_initlogs(mocker) -> None: - if is_mac(): - # Mock torch import completely - import sys - import types - - module_name = "torch" - mocked_module = types.ModuleType(module_name) - sys.modules[module_name] = mocked_module - else: - mocker.patch("torch._logging._init_logs") - - @pytest.fixture(scope="function") def freqai_conf(default_conf, tmp_path): freqaiconf = deepcopy(default_conf) diff --git a/tests/freqai/test_freqai_datakitchen.py b/tests/freqai/test_freqai_datakitchen.py index 27efc3a66..7a219e46e 100644 --- a/tests/freqai/test_freqai_datakitchen.py +++ b/tests/freqai/test_freqai_datakitchen.py @@ -10,11 +10,10 @@ from freqtrade.configuration import TimeRange from freqtrade.data.dataprovider import DataProvider from freqtrade.exceptions import OperationalException from freqtrade.freqai.data_kitchen import FreqaiDataKitchen -from tests.conftest import get_patched_exchange +from tests.conftest import get_patched_exchange, is_mac from tests.freqai.conftest import ( get_patched_data_kitchen, get_patched_freqai_strategy, - is_mac, make_unfiltered_dataframe, ) diff --git a/tests/freqai/test_freqai_interface.py b/tests/freqai/test_freqai_interface.py index 2779ddcb8..0710591c9 100644 --- a/tests/freqai/test_freqai_interface.py +++ b/tests/freqai/test_freqai_interface.py @@ -13,11 +13,16 @@ from freqtrade.freqai.utils import download_all_data_for_training, get_required_ from freqtrade.optimize.backtesting import Backtesting from freqtrade.persistence import Trade from freqtrade.plugins.pairlistmanager import PairListManager -from tests.conftest import EXMS, create_mock_trades, get_patched_exchange, log_has_re -from tests.freqai.conftest import ( - get_patched_freqai_strategy, +from tests.conftest import ( + EXMS, + create_mock_trades, + get_patched_exchange, is_arm, is_mac, + log_has_re, +) +from tests.freqai.conftest import ( + get_patched_freqai_strategy, make_rl_config, mock_pytorch_mlp_model_training_parameters, ) diff --git a/tests/freqtradebot/test_freqtradebot.py b/tests/freqtradebot/test_freqtradebot.py index 97533e150..73ad730d2 100644 --- a/tests/freqtradebot/test_freqtradebot.py +++ b/tests/freqtradebot/test_freqtradebot.py @@ -4022,7 +4022,7 @@ def test_get_real_amount_fees_order( default_conf_usdt, market_buy_order_usdt_doublefee, fee, mocker ): tfo_mock = mocker.patch(f"{EXMS}.get_trades_for_order", return_value=[]) - mocker.patch(f"{EXMS}.get_valid_pair_combination", return_value="BNB/USDT") + mocker.patch(f"{EXMS}.get_valid_pair_combination", return_value=["BNB/USDT"]) mocker.patch(f"{EXMS}.fetch_ticker", return_value={"last": 200}) trade = Trade( pair="LTC/USDT", @@ -5191,6 +5191,13 @@ def test_update_funding_fees( open_exit_order = limit_order_open[exit_side(is_short)] bid = 0.11 enter_rate_mock = MagicMock(return_value=bid) + open_order.update( + { + "status": "closed", + "filled": open_order["amount"], + "remaining": 0, + } + ) enter_mm = MagicMock(return_value=open_order) patch_RPCManager(mocker) patch_exchange(mocker) diff --git a/tests/leverage/test_update_liquidation_price.py b/tests/leverage/test_update_liquidation_price.py index 1b25babd0..68c35509f 100644 --- a/tests/leverage/test_update_liquidation_price.py +++ b/tests/leverage/test_update_liquidation_price.py @@ -29,7 +29,7 @@ def test_update_liquidation_prices(mocker, margin_mode, dry_run): assert trade_mock.set_liquidation_price.call_count == 1 - assert wallets.get_total.call_count == ( + assert wallets.get_collateral.call_count == ( 0 if margin_mode == MarginMode.ISOLATED or not dry_run else 1 ) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 05ebf2298..23922ee42 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -371,8 +371,7 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None: mocker.patch("freqtrade.optimize.backtesting.Backtesting.backtest") mocker.patch("freqtrade.optimize.backtesting.generate_backtest_stats") mocker.patch("freqtrade.optimize.backtesting.show_backtest_results") - sbs = mocker.patch("freqtrade.optimize.backtesting.store_backtest_stats") - sbc = mocker.patch("freqtrade.optimize.backtesting.store_backtest_analysis_results") + sbs = mocker.patch("freqtrade.optimize.backtesting.store_backtest_results") mocker.patch( "freqtrade.plugins.pairlistmanager.PairListManager.whitelist", PropertyMock(return_value=["UNITTEST/BTC"]), @@ -397,7 +396,6 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None: assert backtesting.strategy.bot_start.call_count == 1 assert backtesting.strategy.bot_loop_start.call_count == 0 assert sbs.call_count == 1 - assert sbc.call_count == 1 def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) -> None: @@ -568,6 +566,9 @@ def test_backtest__enter_trade_futures(default_conf_usdt, fee, mocker) -> None: mocker.patch(f"{EXMS}.get_fee", fee) mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=0.00001) mocker.patch(f"{EXMS}.get_max_pair_stake_amount", return_value=float("inf")) + mocker.patch( + "freqtrade.persistence.trade_model.price_to_precision", lambda p, *args, **kwargs: p + ) mocker.patch(f"{EXMS}.get_max_leverage", return_value=100) mocker.patch("freqtrade.optimize.backtesting.price_to_precision", lambda p, *args: p) patch_exchange(mocker) @@ -1842,6 +1843,7 @@ def test_backtest_multi_pair_long_short_switch( if use_detail: default_conf_usdt["timeframe_detail"] = "1m" + mocker.patch(f"{EXMS}.price_to_precision", lambda s, x, y, **kwargs: y) mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=0.00001) mocker.patch(f"{EXMS}.get_max_pair_stake_amount", return_value=float("inf")) mocker.patch(f"{EXMS}.get_fee", fee) diff --git a/tests/optimize/test_hyperoptloss.py b/tests/optimize/test_hyperoptloss.py index 53de37a0e..8f1b1c786 100644 --- a/tests/optimize/test_hyperoptloss.py +++ b/tests/optimize/test_hyperoptloss.py @@ -39,13 +39,34 @@ def test_loss_calculation_prefer_correct_trade_count(hyperopt_conf, hyperopt_res hyperopt_conf.update({"hyperopt_loss": "ShortTradeDurHyperOptLoss"}) hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf) correct = hl.hyperopt_loss_function( - hyperopt_results, 600, datetime(2019, 1, 1), datetime(2019, 5, 1) + results=hyperopt_results, + trade_count=600, + min_date=datetime(2019, 1, 1), + max_date=datetime(2019, 5, 1), + config=hyperopt_conf, + processed=None, + backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()}, + starting_balance=hyperopt_conf["dry_run_wallet"], ) over = hl.hyperopt_loss_function( - hyperopt_results, 600 + 100, datetime(2019, 1, 1), datetime(2019, 5, 1) + results=hyperopt_results, + trade_count=600 + 100, + min_date=datetime(2019, 1, 1), + max_date=datetime(2019, 5, 1), + config=hyperopt_conf, + processed=None, + backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()}, + starting_balance=hyperopt_conf["dry_run_wallet"], ) under = hl.hyperopt_loss_function( - hyperopt_results, 600 - 100, datetime(2019, 1, 1), datetime(2019, 5, 1) + results=hyperopt_results, + trade_count=600 - 100, + min_date=datetime(2019, 1, 1), + max_date=datetime(2019, 5, 1), + config=hyperopt_conf, + processed=None, + backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()}, + starting_balance=hyperopt_conf["dry_run_wallet"], ) assert over > correct assert under > correct @@ -58,9 +79,25 @@ def test_loss_calculation_prefer_shorter_trades(hyperopt_conf, hyperopt_results) hyperopt_conf.update({"hyperopt_loss": "ShortTradeDurHyperOptLoss"}) hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf) longer = hl.hyperopt_loss_function( - hyperopt_results, 100, datetime(2019, 1, 1), datetime(2019, 5, 1) + results=hyperopt_results, + trade_count=100, + min_date=datetime(2019, 1, 1), + max_date=datetime(2019, 5, 1), + config=hyperopt_conf, + processed=None, + backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()}, + starting_balance=hyperopt_conf["dry_run_wallet"], + ) + shorter = hl.hyperopt_loss_function( + results=resultsb, + trade_count=100, + min_date=datetime(2019, 1, 1), + max_date=datetime(2019, 5, 1), + config=hyperopt_conf, + processed=None, + backtest_stats={"profit_total": resultsb["profit_abs"].sum()}, + starting_balance=hyperopt_conf["dry_run_wallet"], ) - shorter = hl.hyperopt_loss_function(resultsb, 100, datetime(2019, 1, 1), datetime(2019, 5, 1)) assert shorter < longer @@ -73,11 +110,34 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) -> hyperopt_conf.update({"hyperopt_loss": "ShortTradeDurHyperOptLoss"}) hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf) correct = hl.hyperopt_loss_function( - hyperopt_results, 600, datetime(2019, 1, 1), datetime(2019, 5, 1) + results=hyperopt_results, + trade_count=600, + min_date=datetime(2019, 1, 1), + max_date=datetime(2019, 5, 1), + config=hyperopt_conf, + processed=None, + backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()}, + starting_balance=hyperopt_conf["dry_run_wallet"], + ) + over = hl.hyperopt_loss_function( + results=results_over, + trade_count=600, + min_date=datetime(2019, 1, 1), + max_date=datetime(2019, 5, 1), + config=hyperopt_conf, + processed=None, + backtest_stats={"profit_total": results_over["profit_abs"].sum()}, + starting_balance=hyperopt_conf["dry_run_wallet"], ) - over = hl.hyperopt_loss_function(results_over, 600, datetime(2019, 1, 1), datetime(2019, 5, 1)) under = hl.hyperopt_loss_function( - results_under, 600, datetime(2019, 1, 1), datetime(2019, 5, 1) + results=results_under, + trade_count=600, + min_date=datetime(2019, 1, 1), + max_date=datetime(2019, 5, 1), + config=hyperopt_conf, + processed=None, + backtest_stats={"profit_total": results_under["profit_abs"].sum()}, + starting_balance=hyperopt_conf["dry_run_wallet"], ) assert over < correct assert under > correct @@ -109,31 +169,34 @@ def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunct default_conf.update({"hyperopt_loss": lossfunction}) hl = HyperOptLossResolver.load_hyperoptloss(default_conf) correct = hl.hyperopt_loss_function( - hyperopt_results, + results=hyperopt_results, trade_count=len(hyperopt_results), min_date=datetime(2019, 1, 1), max_date=datetime(2019, 5, 1), config=default_conf, processed=None, backtest_stats={"profit_total": hyperopt_results["profit_abs"].sum()}, + starting_balance=default_conf["dry_run_wallet"], ) over = hl.hyperopt_loss_function( - results_over, + results=results_over, trade_count=len(results_over), min_date=datetime(2019, 1, 1), max_date=datetime(2019, 5, 1), config=default_conf, processed=None, backtest_stats={"profit_total": results_over["profit_abs"].sum()}, + starting_balance=default_conf["dry_run_wallet"], ) under = hl.hyperopt_loss_function( - results_under, + results=results_under, trade_count=len(results_under), min_date=datetime(2019, 1, 1), max_date=datetime(2019, 5, 1), config=default_conf, processed=None, backtest_stats={"profit_total": results_under["profit_abs"].sum()}, + starting_balance=default_conf["dry_run_wallet"], ) assert over < correct assert under > correct diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 40673a1b6..77fb10655 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -26,8 +26,7 @@ from freqtrade.optimize.optimize_reports import ( generate_strategy_comparison, generate_trading_stats, show_sorted_pairlist, - store_backtest_analysis_results, - store_backtest_stats, + store_backtest_results, text_table_bt_results, text_table_strategy, ) @@ -226,8 +225,9 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmp_path): filename_last = tmp_path / LAST_BT_RESULT_FN _backup_file(filename_last, copy_file=True) assert not filename.is_file() + default_conf["exportfilename"] = filename - store_backtest_stats(filename, stats, "2022_01_01_15_05_13") + store_backtest_results(default_conf, stats, "2022_01_01_15_05_13") # get real Filename (it's btresult-.json) last_fn = get_latest_backtest_filename(filename_last.parent) @@ -246,11 +246,12 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmp_path): filename1.unlink() -def test_store_backtest_stats(testdatadir, mocker): +def test_store_backtest_results(testdatadir, mocker): dump_mock = mocker.patch("freqtrade.optimize.optimize_reports.bt_storage.file_dump_json") data = {"metadata": {}, "strategy": {}, "strategy_comparison": []} - store_backtest_stats(testdatadir, data, "2022_01_01_15_05_13") + + store_backtest_results({"exportfilename": testdatadir}, data, "2022_01_01_15_05_13") assert dump_mock.call_count == 3 assert isinstance(dump_mock.call_args_list[0][0][0], Path) @@ -258,16 +259,16 @@ def test_store_backtest_stats(testdatadir, mocker): dump_mock.reset_mock() filename = testdatadir / "testresult.json" - store_backtest_stats(filename, data, "2022_01_01_15_05_13") + store_backtest_results({"exportfilename": filename}, data, "2022_01_01_15_05_13") assert dump_mock.call_count == 3 assert isinstance(dump_mock.call_args_list[0][0][0], Path) # result will be testdatadir / testresult-.json assert str(dump_mock.call_args_list[0][0][0]).startswith(str(testdatadir / "testresult")) -def test_store_backtest_stats_real(tmp_path): +def test_store_backtest_results_real(tmp_path): data = {"metadata": {}, "strategy": {}, "strategy_comparison": []} - store_backtest_stats(tmp_path, data, "2022_01_01_15_05_13") + store_backtest_results({"exportfilename": tmp_path}, data, "2022_01_01_15_05_13") assert (tmp_path / "backtest-result-2022_01_01_15_05_13.json").is_file() assert (tmp_path / "backtest-result-2022_01_01_15_05_13.meta.json").is_file() @@ -276,7 +277,9 @@ def test_store_backtest_stats_real(tmp_path): fn = get_latest_backtest_filename(tmp_path) assert fn == "backtest-result-2022_01_01_15_05_13.json" - store_backtest_stats(tmp_path, data, "2024_01_01_15_05_25", market_change_data=pd.DataFrame()) + store_backtest_results( + {"exportfilename": tmp_path}, data, "2024_01_01_15_05_25", market_change_data=pd.DataFrame() + ) assert (tmp_path / "backtest-result-2024_01_01_15_05_25.json").is_file() assert (tmp_path / "backtest-result-2024_01_01_15_05_25.meta.json").is_file() assert (tmp_path / "backtest-result-2024_01_01_15_05_25_market_change.feather").is_file() @@ -287,13 +290,27 @@ def test_store_backtest_stats_real(tmp_path): assert fn == "backtest-result-2024_01_01_15_05_25.json" -def test_store_backtest_candles(testdatadir, mocker): +def test_store_backtest_candles(tmp_path, mocker): + mocker.patch("freqtrade.optimize.optimize_reports.bt_storage.file_dump_json") dump_mock = mocker.patch("freqtrade.optimize.optimize_reports.bt_storage.file_dump_joblib") candle_dict = {"DefStrat": {"UNITTEST/BTC": pd.DataFrame()}} + bt_results = {"metadata": {}, "strategy": {}, "strategy_comparison": []} + + mock_conf = { + "exportfilename": tmp_path, + "export": "signals", + "runmode": "backtest", + } # mock directory exporting - store_backtest_analysis_results(testdatadir, candle_dict, {}, {}, "2022_01_01_15_05_13") + data = { + "signals": candle_dict, + "rejected": {}, + "exited": {}, + } + + store_backtest_results(mock_conf, bt_results, "2022_01_01_15_05_13", analysis_results=data) assert dump_mock.call_count == 3 assert isinstance(dump_mock.call_args_list[0][0][0], Path) @@ -303,11 +320,12 @@ def test_store_backtest_candles(testdatadir, mocker): dump_mock.reset_mock() # mock file exporting - filename = Path(testdatadir / "testresult") - store_backtest_analysis_results(filename, candle_dict, {}, {}, "2022_01_01_15_05_13") + filename = Path(tmp_path / "testresult") + mock_conf["exportfilename"] = filename + store_backtest_results(mock_conf, bt_results, "2022_01_01_15_05_13", analysis_results=data) assert dump_mock.call_count == 3 assert isinstance(dump_mock.call_args_list[0][0][0], Path) - # result will be testdatadir / testresult-_signals.pkl + # result will be tmp_path / testresult-_signals.pkl assert str(dump_mock.call_args_list[0][0][0]).endswith("_signals.pkl") assert str(dump_mock.call_args_list[1][0][0]).endswith("_rejected.pkl") assert str(dump_mock.call_args_list[2][0][0]).endswith("_exited.pkl") @@ -317,10 +335,21 @@ def test_store_backtest_candles(testdatadir, mocker): def test_write_read_backtest_candles(tmp_path): candle_dict = {"DefStrat": {"UNITTEST/BTC": pd.DataFrame()}} + bt_results = {"metadata": {}, "strategy": {}, "strategy_comparison": []} + mock_conf = { + "exportfilename": tmp_path, + "export": "signals", + "runmode": "backtest", + } # test directory exporting sample_date = "2022_01_01_15_05_13" - store_backtest_analysis_results(tmp_path, candle_dict, {}, {}, sample_date) + data = { + "signals": candle_dict, + "rejected": {}, + "exited": {}, + } + store_backtest_results(mock_conf, bt_results, sample_date, analysis_results=data) stored_file = tmp_path / f"backtest-result-{sample_date}_signals.pkl" with stored_file.open("rb") as scp: pickled_signal_candles = joblib.load(scp) @@ -335,7 +364,8 @@ def test_write_read_backtest_candles(tmp_path): # test file exporting filename = tmp_path / "testresult" - store_backtest_analysis_results(filename, candle_dict, {}, {}, sample_date) + mock_conf["exportfilename"] = filename + store_backtest_results(mock_conf, bt_results, sample_date, analysis_results=data) stored_file = tmp_path / f"testresult-{sample_date}_signals.pkl" with stored_file.open("rb") as scp: pickled_signal_candles = joblib.load(scp) diff --git a/tests/plugins/test_pairlocks.py b/tests/plugins/test_pairlocks.py index 0102079fe..f227818b3 100644 --- a/tests/plugins/test_pairlocks.py +++ b/tests/plugins/test_pairlocks.py @@ -37,6 +37,7 @@ def test_PairLocks(use_db): assert not PairLocks.is_pair_locked(pair) assert not PairLocks.is_pair_locked(pair, side="long") assert PairLocks.is_pair_locked(pair, side="short") + assert len(PairLocks.get_pair_locks(pair)) == 1 # XRP/BTC should not be locked now pair = "XRP/BTC" @@ -47,9 +48,11 @@ def test_PairLocks(use_db): PairLocks.lock_pair(pair, dt_now() + timedelta(minutes=4)) assert PairLocks.is_pair_locked(pair) - # Get both locks from above + # Get all locks from above locks = PairLocks.get_pair_locks(None) - assert len(locks) == 2 + assert len(locks) == 4 + + assert len(PairLocks.get_pair_locks(None, side="*")) == 2 # Unlock original pair pair = "ETH/BTC" diff --git a/tests/plugins/test_percentchangepairlist.py b/tests/plugins/test_percentchangepairlist.py index df165cf98..6f399fc9f 100644 --- a/tests/plugins/test_percentchangepairlist.py +++ b/tests/plugins/test_percentchangepairlist.py @@ -360,9 +360,16 @@ def test_gen_pairlist_from_tickers(mocker, rpl_config, tickers): exchange = get_patched_exchange(mocker, rpl_config, exchange="binance") pairlistmanager = PairListManager(exchange, rpl_config) - remote_pairlist = PercentChangePairList( - exchange, pairlistmanager, rpl_config, rpl_config["pairlists"][0], 0 - ) + remote_pairlist = pairlistmanager._pairlist_handlers[0] + + # The generator returns BTC ETH and TKN - filtering the first ensures removing pairs + # in this step ain't problematic. + def _validate_pair(pair, ticker): + if pair == "BTC/USDT": + return False + return True + + remote_pairlist._validate_pair = _validate_pair result = remote_pairlist.gen_pairlist(tickers.return_value) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index dd8c1bb9a..9bb8d64ea 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -514,8 +514,13 @@ def test_rpc_balance_handle_error(default_conf, mocker): patch_get_signal(freqtradebot) rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter({}) - with pytest.raises(RPCException, match="Error getting current tickers."): - rpc._rpc_balance(default_conf["stake_currency"], default_conf["fiat_display_currency"]) + res = rpc._rpc_balance(default_conf["stake_currency"], default_conf["fiat_display_currency"]) + assert res["stake"] == "BTC" + + assert len(res["currencies"]) == 1 + assert res["currencies"][0]["currency"] == "BTC" + # ETH has not been converted. + assert all(currency["currency"] != "ETH" for currency in res["currencies"]) def test_rpc_balance_handle(default_conf_usdt, mocker, tickers): @@ -530,6 +535,13 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers): "total": 5.0, "used": 4.0, }, + # Invalid coin not in tickers list. + # This triggers a 2nd call to get_tickers + "NotACoin": { + "free": 0.0, + "total": 2.0, + "used": 0.0, + }, "USDT": { "free": 50.0, "total": 100.0, @@ -574,7 +586,7 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers): fetch_positions=MagicMock(return_value=mock_pos), get_tickers=tickers, get_valid_pair_combination=MagicMock( - side_effect=lambda a, b: f"{b}/{a}" if a == "USDT" else f"{a}/{b}" + side_effect=lambda a, b: [f"{b}/{a}" if a == "USDT" else f"{a}/{b}"] ), ) default_conf_usdt["dry_run"] = False @@ -590,8 +602,10 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers): assert pytest.approx(result["total"]) == 2824.83464 assert pytest.approx(result["value"]) == 2824.83464 * 1.2 - assert tickers.call_count == 1 + assert tickers.call_count == 4 assert tickers.call_args_list[0][1]["cached"] is True + # Testing futures - so we should get spot tickers + assert tickers.call_args_list[-1][1]["market_type"] == "spot" assert "USD" == result["symbol"] assert result["currencies"] == [ { @@ -622,6 +636,20 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers): "is_bot_managed": False, "is_position": False, }, + { + "currency": "NotACoin", + "balance": 2.0, + "bot_owned": 0, + "est_stake": 0, + "est_stake_bot": 0, + "free": 0.0, + "is_bot_managed": False, + "is_position": False, + "position": 0, + "side": "long", + "stake": "USDT", + "used": 0.0, + }, { "currency": "USDT", "free": 50.0, @@ -652,8 +680,8 @@ def test_rpc_balance_handle(default_conf_usdt, mocker, tickers): ] assert pytest.approx(result["total_bot"]) == 69.5 assert pytest.approx(result["total"]) == 2824.83464 # ETH stake is missing. - assert result["starting_capital"] == 50 - assert result["starting_capital_ratio"] == pytest.approx(0.3899999) + assert result["starting_capital"] == 50 * default_conf_usdt["tradable_balance_ratio"] + assert result["starting_capital_ratio"] == pytest.approx(0.4040404) def test_rpc_start(mocker, default_conf) -> None: diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index ee28bcc6c..de3472885 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -556,7 +556,7 @@ def test_api_balance(botclient, mocker, rpc_balance, tickers): ftbot.config["dry_run"] = False mocker.patch(f"{EXMS}.get_balances", return_value=rpc_balance) mocker.patch(f"{EXMS}.get_tickers", tickers) - mocker.patch(f"{EXMS}.get_valid_pair_combination", side_effect=lambda a, b: f"{a}/{b}") + mocker.patch(f"{EXMS}.get_valid_pair_combination", side_effect=lambda a, b: [f"{a}/{b}"]) ftbot.wallets.update() rc = client_get(client, f"{BASE_URI}/balance") @@ -1056,6 +1056,7 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): ) def test_api_profit(botclient, mocker, ticker, fee, markets, is_short, expected): ftbot, client = botclient + ftbot.config["tradable_balance_ratio"] = 1 patch_get_signal(ftbot) mocker.patch.multiple( EXMS, diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index bc7746aef..b71b3975e 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -960,7 +960,7 @@ async def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance default_conf["dry_run"] = False mocker.patch(f"{EXMS}.get_balances", return_value=rpc_balance) mocker.patch(f"{EXMS}.get_tickers", tickers) - mocker.patch(f"{EXMS}.get_valid_pair_combination", side_effect=lambda a, b: f"{a}/{b}") + mocker.patch(f"{EXMS}.get_valid_pair_combination", side_effect=lambda a, b: [f"{a}/{b}"]) telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) patch_get_signal(freqtradebot) @@ -1049,7 +1049,7 @@ async def test_telegram_balance_handle_futures( mocker.patch(f"{EXMS}.get_balances", return_value=rpc_balance) mocker.patch(f"{EXMS}.fetch_positions", return_value=mock_pos) mocker.patch(f"{EXMS}.get_tickers", tickers) - mocker.patch(f"{EXMS}.get_valid_pair_combination", side_effect=lambda a, b: f"{a}/{b}") + mocker.patch(f"{EXMS}.get_valid_pair_combination", side_effect=lambda a, b: [f"{a}/{b}"]) telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf) patch_get_signal(freqtradebot) @@ -1087,7 +1087,7 @@ async def test_balance_handle_empty_response_dry(default_conf, update, mocker) - result = msg_mock.call_args_list[0][0][0] assert msg_mock.call_count == 1 assert "*Warning:* Simulated balances in Dry Mode." in result - assert "Starting capital: `1000 BTC`" in result + assert "Starting capital: `990 BTC`" in result async def test_balance_handle_too_large_response(default_conf, update, mocker) -> None: diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 8011ded96..3e9df382b 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -1481,6 +1481,12 @@ def test_flat_vars_to_nested_dict(caplog): "FREQTRADE__STAKE_AMOUNT": "200.05", "FREQTRADE__TELEGRAM__CHAT_ID": "2151", "NOT_RELEVANT": "200.0", # Will be ignored + "FREQTRADE__ARRAY": '[{"name":"default","host":"xxx"}]', + "FREQTRADE__EXCHANGE__PAIR_WHITELIST": '["BTC/USDT", "ETH/USDT"]', + # Fails due to trailing comma + "FREQTRADE__ARRAY_TRAIL_COMMA": '[{"name":"default","host":"xxx",}]', + # Object fails + "FREQTRADE__OBJECT": '{"name":"default","host":"xxx"}', } expected = { "stake_amount": 200.05, @@ -1494,8 +1500,12 @@ def test_flat_vars_to_nested_dict(caplog): }, "some_setting": True, "some_false_setting": False, + "pair_whitelist": ["BTC/USDT", "ETH/USDT"], }, "telegram": {"chat_id": "2151"}, + "array": [{"name": "default", "host": "xxx"}], + "object": '{"name":"default","host":"xxx"}', + "array_trail_comma": '[{"name":"default","host":"xxx",}]', } res = _flat_vars_to_nested_dict(test_args, ENV_VAR_PREFIX) assert res == expected diff --git a/tests/test_wallets.py b/tests/test_wallets.py index 2c12d27b5..002e27c18 100644 --- a/tests/test_wallets.py +++ b/tests/test_wallets.py @@ -168,7 +168,7 @@ def test_get_trade_stake_amount_unlimited_amount( assert result == 0 freqtrade.config["dry_run_wallet"] = 200 - freqtrade.wallets._start_cap = 200 + freqtrade.wallets._start_cap["BTC"] = 200 result = freqtrade.wallets.get_trade_stake_amount("XRP/USDT", 3) assert round(result, 4) == round(result2, 4) @@ -244,7 +244,7 @@ def test_get_starting_balance( freqtrade = get_patched_freqtradebot(mocker, default_conf) - assert freqtrade.wallets.get_starting_balance() == expected + assert freqtrade.wallets.get_starting_balance() == expected * (1 if available_capital else 0.99) def test_sync_wallet_futures_live(mocker, default_conf): @@ -373,7 +373,10 @@ def test_sync_wallet_dry(mocker, default_conf_usdt, fee): # sum of used and free should be total. assert usdt_bal.total == usdt_bal.free + usdt_bal.used - assert freqtrade.wallets.get_starting_balance() == default_conf_usdt["dry_run_wallet"] + assert ( + freqtrade.wallets.get_starting_balance() + == default_conf_usdt["dry_run_wallet"] * default_conf_usdt["tradable_balance_ratio"] + ) total = freqtrade.wallets.get_total("LTC") free = freqtrade.wallets.get_free("LTC") used = freqtrade.wallets.get_used("LTC") @@ -401,7 +404,10 @@ def test_sync_wallet_futures_dry(mocker, default_conf, fee): assert positions["XRP/BTC"].side == "long" assert positions["LTC/BTC"].side == "short" - assert freqtrade.wallets.get_starting_balance() == default_conf["dry_run_wallet"] + assert ( + freqtrade.wallets.get_starting_balance() + == default_conf["dry_run_wallet"] * default_conf["tradable_balance_ratio"] + ) total = freqtrade.wallets.get_total("BTC") free = freqtrade.wallets.get_free("BTC") used = freqtrade.wallets.get_used("BTC") @@ -451,3 +457,151 @@ def test_check_exit_amount_futures(mocker, default_conf, fee): assert freqtrade.wallets.check_exit_amount(trade) is False assert total_mock.call_count == 0 assert update_mock.call_count == 1 + + +@pytest.mark.parametrize( + "config,wallets", + [ + ( + {"stake_currency": "USDT", "dry_run_wallet": 1000.0}, + {"USDT": {"currency": "USDT", "free": 1000.0, "used": 0.0, "total": 1000.0}}, + ), + ( + {"stake_currency": "USDT", "dry_run_wallet": {"USDT": 1000.0, "BTC": 0.1, "ETH": 2.0}}, + { + "USDT": {"currency": "USDT", "free": 1000.0, "used": 0.0, "total": 1000.0}, + "BTC": {"currency": "BTC", "free": 0.1, "used": 0.0, "total": 0.1}, + "ETH": {"currency": "ETH", "free": 2.0, "used": 0.0, "total": 2.0}, + }, + ), + ( + { + "stake_currency": "USDT", + "margin_mode": "cross", + "dry_run_wallet": {"USDC": 1000.0, "BTC": 0.1, "ETH": 2.0}, + }, + { + # USDT wallet should be created with 0 balance, but Free balance, since + # it's converted from the other currencies + "USDT": {"currency": "USDT", "free": 4200.0, "used": 0.0, "total": 0.0}, + "USDC": {"currency": "USDC", "free": 1000.0, "used": 0.0, "total": 1000.0}, + "BTC": {"currency": "BTC", "free": 0.1, "used": 0.0, "total": 0.1}, + "ETH": {"currency": "ETH", "free": 2.0, "used": 0.0, "total": 2.0}, + }, + ), + ( + { + "stake_currency": "USDT", + "margin_mode": "cross", + "dry_run_wallet": {"USDT": 500, "USDC": 1000.0, "BTC": 0.1, "ETH": 2.0}, + }, + { + # USDT wallet should be created with 500 balance, but Free balance, since + # it's converted from the other currencies + "USDT": {"currency": "USDT", "free": 4700.0, "used": 0.0, "total": 500.0}, + "USDC": {"currency": "USDC", "free": 1000.0, "used": 0.0, "total": 1000.0}, + "BTC": {"currency": "BTC", "free": 0.1, "used": 0.0, "total": 0.1}, + "ETH": {"currency": "ETH", "free": 2.0, "used": 0.0, "total": 2.0}, + }, + ), + ( + # Same as above, but without cross + { + "stake_currency": "USDT", + "dry_run_wallet": {"USDT": 500, "USDC": 1000.0, "BTC": 0.1, "ETH": 2.0}, + }, + { + # No "free" transfer for USDT wallet + "USDT": {"currency": "USDT", "free": 500.0, "used": 0.0, "total": 500.0}, + "USDC": {"currency": "USDC", "free": 1000.0, "used": 0.0, "total": 1000.0}, + "BTC": {"currency": "BTC", "free": 0.1, "used": 0.0, "total": 0.1}, + "ETH": {"currency": "ETH", "free": 2.0, "used": 0.0, "total": 2.0}, + }, + ), + ( + # Same as above, but with futures and cross + { + "stake_currency": "USDT", + "margin_mode": "cross", + "trading_mode": "futures", + "dry_run_wallet": {"USDT": 500, "USDC": 1000.0, "BTC": 0.1, "ETH": 2.0}, + }, + { + # USDT wallet should be created with 500 balance, but Free balance, since + # it's converted from the other currencies + "USDT": {"currency": "USDT", "free": 4700.0, "used": 0.0, "total": 500.0}, + "USDC": {"currency": "USDC", "free": 1000.0, "used": 0.0, "total": 1000.0}, + "BTC": {"currency": "BTC", "free": 0.1, "used": 0.0, "total": 0.1}, + "ETH": {"currency": "ETH", "free": 2.0, "used": 0.0, "total": 2.0}, + }, + ), + ], +) +def test_dry_run_wallet_initialization(mocker, default_conf_usdt, config, wallets): + default_conf_usdt.update(config) + mocker.patch( + f"{EXMS}.get_tickers", + return_value={ + "USDC/USDT": {"last": 1.0}, + "BTC/USDT": {"last": 20_000.0}, + "ETH/USDT": {"last": 1100.0}, + }, + ) + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) + stake_currency = config["stake_currency"] + # Verify each wallet matches the expected values + for currency, expected_wallet in wallets.items(): + wallet = freqtrade.wallets._wallets[currency] + assert wallet.currency == expected_wallet["currency"] + assert wallet.free == expected_wallet["free"] + assert wallet.used == expected_wallet["used"] + assert wallet.total == expected_wallet["total"] + + # Verify no extra wallets were created + assert len(freqtrade.wallets._wallets) == len(wallets) + + # Create a trade and verify the new currency is added to the wallets + mocker.patch(f"{EXMS}.get_min_pair_stake_amount", return_value=0.0) + mocker.patch(f"{EXMS}.get_rate", return_value=2.22) + mocker.patch( + f"{EXMS}.fetch_ticker", + return_value={ + "bid": 0.20, + "ask": 0.22, + "last": 0.22, + }, + ) + # Without position, collateral will be the same as free + assert freqtrade.wallets.get_collateral() == freqtrade.wallets.get_free(stake_currency) + freqtrade.execute_entry("NEO/USDT", 100.0) + + # Update wallets and verify NEO is now included + freqtrade.wallets.update() + if default_conf_usdt["trading_mode"] != "futures": + assert "NEO" in freqtrade.wallets._wallets + + assert freqtrade.wallets._wallets["NEO"].total == 45.04504504 # 100 USDT / 0.22 + assert freqtrade.wallets._wallets["NEO"].used == 0.0 + assert freqtrade.wallets._wallets["NEO"].free == 45.04504504 + assert freqtrade.wallets.get_collateral() == freqtrade.wallets.get_free(stake_currency) + # Verify USDT wallet was reduced by trade amount + assert ( + pytest.approx(freqtrade.wallets._wallets[stake_currency].total) + == wallets[stake_currency]["total"] - 100.0 + ) + assert len(freqtrade.wallets._wallets) == len(wallets) + 1 # Original wallets + NEO + else: + # Futures mode + assert "NEO" not in freqtrade.wallets._wallets + assert freqtrade.wallets._positions["NEO/USDT"].position == 45.04504504 + assert pytest.approx(freqtrade.wallets._positions["NEO/USDT"].collateral) == 100 + + # Verify USDT wallet's free was reduced by trade amount + assert ( + pytest.approx(freqtrade.wallets.get_collateral()) + == freqtrade.wallets.get_free(stake_currency) + 100 + ) + assert ( + pytest.approx(freqtrade.wallets._wallets[stake_currency].free) + == wallets[stake_currency]["free"] - 100.0 + ) diff --git a/tests/testdata/binance/binance_public_data/futures-um-klines-BTCUSDT-1h-2024-10-28.zip b/tests/testdata/binance/binance_public_data/futures-um-klines-BTCUSDT-1h-2024-10-28.zip new file mode 100644 index 000000000..5bda1b271 Binary files /dev/null and b/tests/testdata/binance/binance_public_data/futures-um-klines-BTCUSDT-1h-2024-10-28.zip differ diff --git a/tests/testdata/binance/binance_public_data/spot-klines-BTCUSDT-1h-2024-10-28.zip b/tests/testdata/binance/binance_public_data/spot-klines-BTCUSDT-1h-2024-10-28.zip new file mode 100644 index 000000000..b94090741 Binary files /dev/null and b/tests/testdata/binance/binance_public_data/spot-klines-BTCUSDT-1h-2024-10-28.zip differ