From e729fad99c0a0bfb365b65fce7a74b785bed1069 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Dec 2021 15:26:08 +0100 Subject: [PATCH 1/4] Add unknown_fee_rate parameter --- docs/configuration.md | 1 + docs/exchanges.md | 5 +++++ freqtrade/constants.py | 1 + freqtrade/exchange/exchange.py | 6 ++++-- tests/exchange/test_exchange.py | 36 +++++++++++++++++++++------------ 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 00ab66ceb..f18f947e7 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -135,6 +135,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `exchange.markets_refresh_interval` | The interval in minutes in which markets are reloaded.
*Defaults to `60` minutes.*
**Datatype:** Positive Integer | `exchange.skip_pair_validation` | Skip pairlist validation on startup.
*Defaults to `false`
**Datatype:** Boolean | `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 | `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation. | `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 diff --git a/docs/exchanges.md b/docs/exchanges.md index 3883e0b1d..374a6b8cc 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -199,6 +199,11 @@ OKEX requires a passphrase for each api key, you will therefore need to add this !!! Warning OKEX only provides 100 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode. +## Gate.io + +Gate.io allows the use of `POINT` to pay for fees. As this is not a tradable currency (no regular market available), automatic fee calculations will fail (and default to a fee of 0). +The configuration parameter `exchange.unknown_fee_rate` can be used to specify the exchange rate between Point and the stake currency. Obviously, changing the stake-currency will also require changes to this value. + ## All exchanges Should you experience constant errors with Nonce (like `InvalidNonce`), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index e074718ca..f15759ea5 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -395,6 +395,7 @@ CONF_SCHEMA = { }, 'uniqueItems': True }, + 'unknown_fee_rate': {'type': 'number'}, 'outdated_offset': {'type': 'integer', 'minimum': 1}, 'markets_refresh_interval': {'type': 'integer'}, 'ccxt_config': {'type': 'object'}, diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 22041ddef..66d6b3b55 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1194,9 +1194,11 @@ class Exchange: tick = self.fetch_ticker(comb) fee_to_quote_rate = safe_value_fallback2(tick, tick, 'last', 'ask') - return round((order['fee']['cost'] * fee_to_quote_rate) / order['cost'], 8) except ExchangeError: - return None + fee_to_quote_rate = self._config['exchange'].get('unknown_fee_rate', None) + if not fee_to_quote_rate: + return None + return round((order['fee']['cost'] * fee_to_quote_rate) / order['cost'], 8) def extract_cost_curr_rate(self, order: Dict) -> Tuple[float, str, Optional[float]]: """ diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index b33e0cbb7..a4b151742 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2948,39 +2948,49 @@ def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None: assert ex.extract_cost_curr_rate(order) == expected -@pytest.mark.parametrize("order,expected", [ +@pytest.mark.parametrize("order,unknown_fee_rate,expected", [ # Using base-currency ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05, - 'fee': {'currency': 'ETH', 'cost': 0.004, 'rate': None}}, 0.1), + 'fee': {'currency': 'ETH', 'cost': 0.004, 'rate': None}}, None, 0.1), ({'symbol': 'ETH/BTC', 'amount': 0.05, 'cost': 0.05, - 'fee': {'currency': 'ETH', 'cost': 0.004, 'rate': None}}, 0.08), + 'fee': {'currency': 'ETH', 'cost': 0.004, 'rate': None}}, None, 0.08), # Using quote currency ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05, - 'fee': {'currency': 'BTC', 'cost': 0.005}}, 0.1), + 'fee': {'currency': 'BTC', 'cost': 0.005}}, None, 0.1), ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05, - 'fee': {'currency': 'BTC', 'cost': 0.002, 'rate': None}}, 0.04), + 'fee': {'currency': 'BTC', 'cost': 0.002, 'rate': None}}, None, 0.04), # Using foreign currency ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05, - 'fee': {'currency': 'NEO', 'cost': 0.0012}}, 0.001944), + 'fee': {'currency': 'NEO', 'cost': 0.0012}}, None, 0.001944), ({'symbol': 'ETH/BTC', 'amount': 2.21, 'cost': 0.02992561, - 'fee': {'currency': 'NEO', 'cost': 0.00027452}}, 0.00074305), + 'fee': {'currency': 'NEO', 'cost': 0.00027452}}, None, 0.00074305), # Rate included in return - return as is ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05, - 'fee': {'currency': 'USDT', 'cost': 0.34, 'rate': 0.01}}, 0.01), + 'fee': {'currency': 'USDT', 'cost': 0.34, 'rate': 0.01}}, None, 0.01), ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05, - 'fee': {'currency': 'USDT', 'cost': 0.34, 'rate': 0.005}}, 0.005), + 'fee': {'currency': 'USDT', 'cost': 0.34, 'rate': 0.005}}, None, 0.005), # 0.1% filled - no costs (kraken - #3431) ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.0, - 'fee': {'currency': 'BTC', 'cost': 0.0, 'rate': None}}, None), + 'fee': {'currency': 'BTC', 'cost': 0.0, 'rate': None}}, None, None), ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.0, - 'fee': {'currency': 'ETH', 'cost': 0.0, 'rate': None}}, 0.0), + 'fee': {'currency': 'ETH', 'cost': 0.0, 'rate': None}}, None, 0.0), ({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.0, - 'fee': {'currency': 'NEO', 'cost': 0.0, 'rate': None}}, None), + 'fee': {'currency': 'NEO', 'cost': 0.0, 'rate': None}}, None, None), + # Invalid pair combination - POINT/BTC is not a pair + ({'symbol': 'POINT/BTC', 'amount': 0.04, 'cost': 0.5, + 'fee': {'currency': 'POINT', 'cost': 2.0, 'rate': None}}, None, None), + ({'symbol': 'POINT/BTC', 'amount': 0.04, 'cost': 0.5, + 'fee': {'currency': 'POINT', 'cost': 2.0, 'rate': None}}, 1, 4.0), + ({'symbol': 'POINT/BTC', 'amount': 0.04, 'cost': 0.5, + 'fee': {'currency': 'POINT', 'cost': 2.0, 'rate': None}}, 2, 8.0), ]) -def test_calculate_fee_rate(mocker, default_conf, order, expected) -> None: +def test_calculate_fee_rate(mocker, default_conf, order, expected, unknown_fee_rate) -> None: mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'last': 0.081}) + if unknown_fee_rate: + default_conf['exchange']['unknown_fee_rate'] = unknown_fee_rate ex = get_patched_exchange(mocker, default_conf) + assert ex.calculate_fee_rate(order) == expected From 81cafd090d75645f0d20acf038c7e41708afb725 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Dec 2021 14:55:05 +0000 Subject: [PATCH 2/4] Bump uvicorn from 0.15.0 to 0.16.0 Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.15.0 to 0.16.0. - [Release notes](https://github.com/encode/uvicorn/releases) - [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md) - [Commits](https://github.com/encode/uvicorn/compare/0.15.0...0.16.0) --- updated-dependencies: - dependency-name: uvicorn dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1caf4e1ef..f4260f984 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,7 +32,7 @@ sdnotify==0.3.2 # API Server fastapi==0.70.0 -uvicorn==0.15.0 +uvicorn==0.16.0 pyjwt==2.3.0 aiofiles==0.8.0 psutil==5.8.0 From 58cd91bd802b92b3ca6a7139cf1c1de13fe61c94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Dec 2021 16:00:35 +0000 Subject: [PATCH 3/4] Bump python-telegram-bot from 13.8.1 to 13.9 Bumps [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) from 13.8.1 to 13.9. - [Release notes](https://github.com/python-telegram-bot/python-telegram-bot/releases) - [Changelog](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/CHANGES.rst) - [Commits](https://github.com/python-telegram-bot/python-telegram-bot/compare/v13.8.1...v13.9) --- updated-dependencies: - dependency-name: python-telegram-bot dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 675d91a87..6e8d6ee9d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ ccxt==1.63.55 cryptography==36.0.0 aiohttp==3.8.1 SQLAlchemy==1.4.28 -python-telegram-bot==13.8.1 +python-telegram-bot==13.9 arrow==1.2.1 cachetools==4.2.2 requests==2.26.0 From b90c5e56fb774635fd2cddde754a8a476aba8252 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 11 Dec 2021 19:46:35 +0100 Subject: [PATCH 4/4] Fix webserver schema bug when running in webserver mode --- freqtrade/rpc/api_server/api_schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index d669600a2..10f181bb6 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -160,7 +160,7 @@ class ShowConfig(BaseModel): trailing_stop_positive_offset: Optional[float] trailing_only_offset_is_reached: Optional[bool] unfilledtimeout: UnfilledTimeout - order_types: OrderTypes + order_types: Optional[OrderTypes] use_custom_stoploss: Optional[bool] timeframe: Optional[str] timeframe_ms: int