Merge branch 'freqtrade:develop' into dca
This commit is contained in:
commit
8dacd987b9
@ -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. <br>*Defaults to `60` minutes.* <br> **Datatype:** Positive Integer
|
| `exchange.markets_refresh_interval` | The interval in minutes in which markets are reloaded. <br>*Defaults to `60` minutes.* <br> **Datatype:** Positive Integer
|
||||||
| `exchange.skip_pair_validation` | Skip pairlist validation on startup.<br>*Defaults to `false`<br> **Datatype:** Boolean
|
| `exchange.skip_pair_validation` | Skip pairlist validation on startup.<br>*Defaults to `false`<br> **Datatype:** Boolean
|
||||||
| `exchange.skip_open_order_update` | Skips open order updates on startup should the exchange cause problems. Only relevant in live conditions.<br>*Defaults to `false`<br> **Datatype:** Boolean
|
| `exchange.skip_open_order_update` | Skips open order updates on startup should the exchange cause problems. Only relevant in live conditions.<br>*Defaults to `false`<br> **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".<br>*Defaults to `None`<br> **Datatype:** float
|
||||||
| `exchange.log_responses` | Log relevant exchange responses. For debug mode only - use with care.<br>*Defaults to `false`<br> **Datatype:** Boolean
|
| `exchange.log_responses` | Log relevant exchange responses. For debug mode only - use with care.<br>*Defaults to `false`<br> **Datatype:** Boolean
|
||||||
| `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation.
|
| `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. <br>*Defaults to `true`.* <br> **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. <br>*Defaults to `true`.* <br> **Datatype:** Boolean
|
||||||
|
@ -199,6 +199,11 @@ OKEX requires a passphrase for each api key, you will therefore need to add this
|
|||||||
!!! Warning
|
!!! 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.
|
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
|
## 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.
|
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.
|
||||||
|
@ -395,6 +395,7 @@ CONF_SCHEMA = {
|
|||||||
},
|
},
|
||||||
'uniqueItems': True
|
'uniqueItems': True
|
||||||
},
|
},
|
||||||
|
'unknown_fee_rate': {'type': 'number'},
|
||||||
'outdated_offset': {'type': 'integer', 'minimum': 1},
|
'outdated_offset': {'type': 'integer', 'minimum': 1},
|
||||||
'markets_refresh_interval': {'type': 'integer'},
|
'markets_refresh_interval': {'type': 'integer'},
|
||||||
'ccxt_config': {'type': 'object'},
|
'ccxt_config': {'type': 'object'},
|
||||||
|
@ -1194,9 +1194,11 @@ class Exchange:
|
|||||||
tick = self.fetch_ticker(comb)
|
tick = self.fetch_ticker(comb)
|
||||||
|
|
||||||
fee_to_quote_rate = safe_value_fallback2(tick, tick, 'last', 'ask')
|
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:
|
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]]:
|
def extract_cost_curr_rate(self, order: Dict) -> Tuple[float, str, Optional[float]]:
|
||||||
"""
|
"""
|
||||||
|
@ -160,7 +160,7 @@ class ShowConfig(BaseModel):
|
|||||||
trailing_stop_positive_offset: Optional[float]
|
trailing_stop_positive_offset: Optional[float]
|
||||||
trailing_only_offset_is_reached: Optional[bool]
|
trailing_only_offset_is_reached: Optional[bool]
|
||||||
unfilledtimeout: UnfilledTimeout
|
unfilledtimeout: UnfilledTimeout
|
||||||
order_types: OrderTypes
|
order_types: Optional[OrderTypes]
|
||||||
use_custom_stoploss: Optional[bool]
|
use_custom_stoploss: Optional[bool]
|
||||||
timeframe: Optional[str]
|
timeframe: Optional[str]
|
||||||
timeframe_ms: int
|
timeframe_ms: int
|
||||||
|
@ -7,7 +7,7 @@ ccxt==1.63.55
|
|||||||
cryptography==36.0.0
|
cryptography==36.0.0
|
||||||
aiohttp==3.8.1
|
aiohttp==3.8.1
|
||||||
SQLAlchemy==1.4.28
|
SQLAlchemy==1.4.28
|
||||||
python-telegram-bot==13.8.1
|
python-telegram-bot==13.9
|
||||||
arrow==1.2.1
|
arrow==1.2.1
|
||||||
cachetools==4.2.2
|
cachetools==4.2.2
|
||||||
requests==2.26.0
|
requests==2.26.0
|
||||||
@ -32,7 +32,7 @@ sdnotify==0.3.2
|
|||||||
|
|
||||||
# API Server
|
# API Server
|
||||||
fastapi==0.70.0
|
fastapi==0.70.0
|
||||||
uvicorn==0.15.0
|
uvicorn==0.16.0
|
||||||
pyjwt==2.3.0
|
pyjwt==2.3.0
|
||||||
aiofiles==0.8.0
|
aiofiles==0.8.0
|
||||||
psutil==5.8.0
|
psutil==5.8.0
|
||||||
|
@ -2948,39 +2948,49 @@ def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None:
|
|||||||
assert ex.extract_cost_curr_rate(order) == expected
|
assert ex.extract_cost_curr_rate(order) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("order,expected", [
|
@pytest.mark.parametrize("order,unknown_fee_rate,expected", [
|
||||||
# Using base-currency
|
# Using base-currency
|
||||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
({'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,
|
({'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
|
# Using quote currency
|
||||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
({'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,
|
({'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
|
# Using foreign currency
|
||||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
({'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,
|
({'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
|
# Rate included in return - return as is
|
||||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
|
({'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,
|
({'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)
|
# 0.1% filled - no costs (kraken - #3431)
|
||||||
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.0,
|
({'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,
|
({'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,
|
({'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})
|
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)
|
ex = get_patched_exchange(mocker, default_conf)
|
||||||
|
|
||||||
assert ex.calculate_fee_rate(order) == expected
|
assert ex.calculate_fee_rate(order) == expected
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user