diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 4af9db6db..8e0116368 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -249,7 +249,7 @@ class Exchange(object): price = ceil(big_price) / pow(10, symbol_prec) return price - def buy(self, pair: str, rate: float, amount: float) -> Dict: + def buy(self, pair: str, rate: float, amount: float, ordertype: str = 'limt') -> Dict: if self._conf['dry_run']: order_id = f'dry_run_buy_{randint(0, 10**6)}' self._dry_run_open_orders[order_id] = { @@ -270,7 +270,7 @@ class Exchange(object): amount = self.symbol_amount_prec(pair, amount) rate = self.symbol_price_prec(pair, rate) - return self._api.create_limit_buy_order(pair, amount, rate) + return self._api.create_order(pair, ordertype, 'buy', amount, rate) except ccxt.InsufficientFunds as e: raise DependencyException( f'Insufficient funds to create limit buy order on market {pair}.' @@ -287,7 +287,7 @@ class Exchange(object): except ccxt.BaseError as e: raise OperationalException(e) - def sell(self, pair: str, rate: float, amount: float) -> Dict: + def sell(self, pair: str, rate: float, amount: float, ordertype: str = 'limt') -> Dict: if self._conf['dry_run']: order_id = f'dry_run_sell_{randint(0, 10**6)}' self._dry_run_open_orders[order_id] = { @@ -307,7 +307,7 @@ class Exchange(object): amount = self.symbol_amount_prec(pair, amount) rate = self.symbol_price_prec(pair, rate) - return self._api.create_limit_sell_order(pair, amount, rate) + return self._api.create_order(pair, ordertype, 'sell', amount, rate) except ccxt.InsufficientFunds as e: raise DependencyException( f'Insufficient funds to create limit sell order on market {pair}.' diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index eb92375ec..75f935c0c 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -475,7 +475,8 @@ class FreqtradeBot(object): amount = stake_amount / buy_limit - order_id = self.exchange.buy(pair, buy_limit, amount)['id'] + order_id = self.exchange.buy(pair=pair, rate=buy_limit, amount=amount, + ordertype=self.strategy.order_types['buy'])['id'] self.rpc.send_msg({ 'type': RPCMessageType.BUY_NOTIFICATION, @@ -762,8 +763,12 @@ class FreqtradeBot(object): :param sellreason: Reason the sell was triggered :return: None """ + sell_type = 'sell' + if sell_reason in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS): + sell_type = 'stoploss' # Execute sell and update trade record - order_id = self.exchange.sell(str(trade.pair), limit, trade.amount)['id'] + order_id = self.exchange.sell(pair=str(trade.pair), rate=limit, amount=trade.amount, + ordertype=self.strategy.order_types[sell_type])['id'] trade.open_order_id = order_id trade.close_rate_requested = limit trade.sell_reason = sell_reason.value diff --git a/freqtrade/strategy/default_strategy.py b/freqtrade/strategy/default_strategy.py index f1646779b..458847636 100644 --- a/freqtrade/strategy/default_strategy.py +++ b/freqtrade/strategy/default_strategy.py @@ -28,6 +28,13 @@ class DefaultStrategy(IStrategy): # Optimal ticker interval for the strategy ticker_interval = '5m' + # Optional order types + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market' + } + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 212559c8c..9d6c5f098 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -70,6 +70,13 @@ class IStrategy(ABC): # associated ticker interval ticker_interval: str + # Optional order types + order_types: Dict = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market' + } + # run "populate_indicators" only for new candle process_only_new_candles: bool = False diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 788ef4518..fe37c6ac1 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -381,7 +381,7 @@ def test_buy_dry_run(default_conf, mocker): def test_buy_prod(default_conf, mocker): api_mock = MagicMock() order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) - api_mock.create_limit_buy_order = MagicMock(return_value={ + api_mock.create_order = MagicMock(return_value={ 'id': order_id, 'info': { 'foo': 'bar' @@ -397,22 +397,22 @@ def test_buy_prod(default_conf, mocker): # test exception handling with pytest.raises(DependencyException): - api_mock.create_limit_buy_order = MagicMock(side_effect=ccxt.InsufficientFunds) + api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.buy(pair='ETH/BTC', rate=200, amount=1) with pytest.raises(DependencyException): - api_mock.create_limit_buy_order = MagicMock(side_effect=ccxt.InvalidOrder) + api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.buy(pair='ETH/BTC', rate=200, amount=1) with pytest.raises(TemporaryError): - api_mock.create_limit_buy_order = MagicMock(side_effect=ccxt.NetworkError) + api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.buy(pair='ETH/BTC', rate=200, amount=1) with pytest.raises(OperationalException): - api_mock.create_limit_buy_order = MagicMock(side_effect=ccxt.BaseError) + api_mock.create_order = MagicMock(side_effect=ccxt.BaseError) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.buy(pair='ETH/BTC', rate=200, amount=1) @@ -429,7 +429,7 @@ def test_sell_dry_run(default_conf, mocker): def test_sell_prod(default_conf, mocker): api_mock = MagicMock() order_id = 'test_prod_sell_{}'.format(randint(0, 10 ** 6)) - api_mock.create_limit_sell_order = MagicMock(return_value={ + api_mock.create_order = MagicMock(return_value={ 'id': order_id, 'info': { 'foo': 'bar' @@ -446,22 +446,22 @@ def test_sell_prod(default_conf, mocker): # test exception handling with pytest.raises(DependencyException): - api_mock.create_limit_sell_order = MagicMock(side_effect=ccxt.InsufficientFunds) + api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.sell(pair='ETH/BTC', rate=200, amount=1) with pytest.raises(DependencyException): - api_mock.create_limit_sell_order = MagicMock(side_effect=ccxt.InvalidOrder) + api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.sell(pair='ETH/BTC', rate=200, amount=1) with pytest.raises(TemporaryError): - api_mock.create_limit_sell_order = MagicMock(side_effect=ccxt.NetworkError) + api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.sell(pair='ETH/BTC', rate=200, amount=1) with pytest.raises(OperationalException): - api_mock.create_limit_sell_order = MagicMock(side_effect=ccxt.BaseError) + api_mock.create_order = MagicMock(side_effect=ccxt.BaseError) exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange.sell(pair='ETH/BTC', rate=200, amount=1)