diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 127f4e91635..18e754e3f78 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -11,6 +11,7 @@ class Binance(Exchange): _ft_has: Dict = { "stoploss_on_exchange": True, + "order_time_in_force": ['gtc', 'fok', 'ioc'], } def get_order_book(self, pair: str, limit: int = 100) -> dict: diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index ea8bcfac17d..011be58e57e 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -13,7 +13,7 @@ import ccxt.async_support as ccxt_async from pandas import DataFrame -from freqtrade import constants, OperationalException, DependencyException, TemporaryError +from freqtrade import constants, DependencyException, OperationalException, TemporaryError from freqtrade.data.converter import parse_ticker_dataframe logger = logging.getLogger(__name__) @@ -21,13 +21,6 @@ API_RETRY_COUNT = 4 -# Urls to exchange markets, insert quote and base with .format() -_EXCHANGE_URLS = { - ccxt.bittrex.__name__: '/Market/Index?MarketName={quote}-{base}', - ccxt.binance.__name__: '/tradeDetail.html?symbol={base}_{quote}', -} - - def retrier_async(f): async def wrapper(*args, **kwargs): count = kwargs.pop('count', API_RETRY_COUNT) @@ -72,8 +65,9 @@ class Exchange(object): # Dict to specify which options each exchange implements # TODO: this should be merged with attributes from subclasses # To avoid having to copy/paste this to all subclasses. - _ft_has = { + _ft_has: Dict = { "stoploss_on_exchange": False, + "order_time_in_force": ["gtc"], } def __init__(self, config: dict) -> None: @@ -275,10 +269,10 @@ def validate_order_time_in_force(self, order_time_in_force: Dict) -> None: """ Checks if order time in force configured in strategy/config are supported """ - if any(v != 'gtc' for k, v in order_time_in_force.items()): - if self.name != 'Binance': - raise OperationalException( - f'Time in force policies are not supporetd for {self.name} yet.') + if any(v not in self._ft_has["order_time_in_force"] + for k, v in order_time_in_force.items()): + raise OperationalException( + f'Time in force policies are not supported for {self.name} yet.') def exchange_has(self, endpoint: str) -> bool: """ diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 736f2298ad0..eed16d39b8d 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -139,6 +139,28 @@ def test_exchange_resolver(default_conf, mocker, caplog): caplog.record_tuples) +def test_validate_order_time_in_force(default_conf, mocker, caplog): + caplog.set_level(logging.INFO) + # explicitly test bittrex, exchanges implementing other policies need seperate tests + ex = get_patched_exchange(mocker, default_conf, id="bittrex") + tif = { + "buy": "gtc", + "sell": "gtc", + } + + ex.validate_order_time_in_force(tif) + tif2 = { + "buy": "fok", + "sell": "ioc", + } + with pytest.raises(OperationalException, match=r"Time in force.*not supported for .*"): + ex.validate_order_time_in_force(tif2) + + # Patch to see if this will pass if the values are in the ft dict + ex._ft_has.update({"order_time_in_force": ["gtc", "fok", "ioc"]}) + ex.validate_order_time_in_force(tif2) + + def test_symbol_amount_prec(default_conf, mocker): ''' Test rounds down to 4 Decimal places