Merge pull request #7093 from freqtrade/fix/gate_futures_stoposs

gateio futures - several fixes
This commit is contained in:
Matthias 2022-07-16 15:18:32 +02:00 committed by GitHub
commit 004bf31142
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 8 deletions

View File

@ -79,6 +79,7 @@ class Exchange:
"ccxt_futures_name": "swap",
"fee_cost_in_contracts": False, # Fee cost needs contract conversion
"needs_trading_fees": False, # use fetch_trading_fees to cache fees
"order_props_in_contracts": ['amount', 'cost', 'filled', 'remaining'],
}
_ft_has: Dict = {}
_ft_has_futures: Dict = {}
@ -425,7 +426,7 @@ class Exchange:
if 'symbol' in order and order['symbol'] is not None:
contract_size = self._get_contract_size(order['symbol'])
if contract_size != 1:
for prop in ['amount', 'cost', 'filled', 'remaining']:
for prop in self._ft_has.get('order_props_in_contracts', []):
if prop in order and order[prop] is not None:
order[prop] = order[prop] * contract_size
return order
@ -823,7 +824,7 @@ class Exchange:
'price': rate,
'average': rate,
'amount': _amount,
'cost': _amount * rate / leverage,
'cost': _amount * rate,
'type': ordertype,
'side': side,
'filled': 0,
@ -1648,7 +1649,7 @@ class Exchange:
fee_curr = fee.get('currency')
if fee_curr is None:
return None
fee_cost = fee['cost']
fee_cost = float(fee['cost'])
if self._ft_has['fee_cost_in_contracts']:
# Convert cost via "contracts" conversion
fee_cost = self._contracts_to_amount(symbol, fee['cost'])
@ -1656,7 +1657,7 @@ class Exchange:
# Calculate fee based on order details
if fee_curr == self.get_pair_base_currency(symbol):
# Base currency - divide by amount
return round(fee['cost'] / amount, 8)
return round(fee_cost / amount, 8)
elif fee_curr == self.get_pair_quote_currency(symbol):
# Quote currency - divide by cost
return round(fee_cost / cost, 8) if cost else None
@ -1687,7 +1688,7 @@ class Exchange:
:param amount: Amount of the order
:return: Tuple with cost, currency, rate of the given fee dict
"""
return (fee['cost'],
return (float(fee['cost']),
fee['currency'],
self.calculate_fee_rate(
fee,

View File

@ -1,12 +1,13 @@
""" Gate.io exchange subclass """
import logging
from datetime import datetime
from typing import Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Tuple
from freqtrade.constants import BuySell
from freqtrade.enums import MarginMode, TradingMode
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import Exchange
from freqtrade.misc import safe_value_fallback2
logger = logging.getLogger(__name__)
@ -34,6 +35,7 @@ class Gateio(Exchange):
_ft_has_futures: Dict = {
"needs_trading_fees": True,
"fee_cost_in_contracts": False, # Set explicitly to false for clarity
"order_props_in_contracts": ['amount', 'filled', 'remaining'],
}
_supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [
@ -96,12 +98,29 @@ class Gateio(Exchange):
}
return trades
def get_order_id_conditional(self, order: Dict[str, Any]) -> str:
if self.trading_mode == TradingMode.FUTURES:
return safe_value_fallback2(order, order, 'id_stop', 'id')
return order['id']
def fetch_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict:
return self.fetch_order(
order = self.fetch_order(
order_id=order_id,
pair=pair,
params={'stop': True}
)
if self.trading_mode == TradingMode.FUTURES:
if order['status'] == 'closed':
# Places a real order - which we need to fetch explicitly.
new_orderid = order.get('info', {}).get('trade_id')
if new_orderid:
order1 = self.fetch_order(order_id=new_orderid, pair=pair, params=params)
order1['id_stop'] = order1['id']
order1['id'] = order_id
order1['stopPrice'] = order.get('stopPrice')
return order1
return order
def cancel_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict:
return self.cancel_order(

View File

@ -332,6 +332,8 @@ class FreqtradeBot(LoggingMixin):
if not trade.is_open and not trade.fee_updated(trade.exit_side):
# Get sell fee
order = trade.select_order(trade.exit_side, False)
if not order:
order = trade.select_order('stoploss', False)
if order:
logger.info(
f"Updating {trade.exit_side}-fee on trade {trade}"

View File

@ -1135,7 +1135,7 @@ def test_create_dry_run_order(default_conf, mocker, side, exchange_name, leverag
assert order["symbol"] == "ETH/BTC"
assert order["amount"] == 1
assert order["leverage"] == leverage
assert order["cost"] == 1 * 200 / leverage
assert order["cost"] == 1 * 200
@pytest.mark.parametrize("side,startprice,endprice", [

View File

@ -53,6 +53,25 @@ def test_fetch_stoploss_order_gateio(default_conf, mocker):
assert fetch_order_mock.call_args_list[0][1]['pair'] == 'ETH/BTC'
assert fetch_order_mock.call_args_list[0][1]['params'] == {'stop': True}
default_conf['trading_mode'] = 'futures'
default_conf['margin_mode'] = 'isolated'
exchange = get_patched_exchange(mocker, default_conf, id='gateio')
exchange.fetch_order = MagicMock(return_value={
'status': 'closed',
'id': '1234',
'stopPrice': 5.62,
'info': {
'trade_id': '222555'
}
})
exchange.fetch_stoploss_order('1234', 'ETH/BTC')
assert exchange.fetch_order.call_count == 2
assert exchange.fetch_order.call_args_list[0][1]['order_id'] == '1234'
assert exchange.fetch_order.call_args_list[1][1]['order_id'] == '222555'
def test_cancel_stoploss_order_gateio(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, id='gateio')