From 762604300f26afb5712d0ac92f01a57048a63f9e Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 29 Dec 2019 04:17:49 +0300 Subject: [PATCH 01/12] Refactor create_trades() --- freqtrade/freqtradebot.py | 104 ++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 90eb7beba..d15624e9f 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -294,65 +294,48 @@ class FreqtradeBot: # See also #2575 at github. return max(min_stake_amounts) / amount_reserve_percent - def create_trades(self) -> bool: + def create_trade(self, pair: str) -> bool: """ - Checks the implemented trading strategy for buy-signals, using the active pair whitelist. - If a pair triggers the buy_signal a new trade record gets created. - Checks pairs as long as the open trade count is below `max_open_trades`. - :return: True if at least one trade has been created. + Check the implemented trading strategy for buy-signals. + If the pair triggers the buy_signal a new trade record gets created. + :return: True if a trade has been created. """ - whitelist = copy.deepcopy(self.active_pair_whitelist) + logger.debug(f"create_trade for pair {pair}") - if not whitelist: - logger.info("Active pair whitelist is empty.") + if self.strategy.is_pair_locked(pair): + logger.info(f"Pair {pair} is currently locked.") return False - # Remove currently opened and latest pairs from whitelist - for trade in Trade.get_open_trades(): - if trade.pair in whitelist: - whitelist.remove(trade.pair) - logger.debug('Ignoring %s in pair whitelist', trade.pair) - - if not whitelist: - logger.info("No currency pair in active pair whitelist, " - "but checking to sell open trades.") - return False - - buycount = 0 # running get_signal on historical data fetched - for pair in whitelist: - if self.strategy.is_pair_locked(pair): - logger.info(f"Pair {pair} is currently locked.") - continue + (buy, sell) = self.strategy.get_signal( + pair, self.strategy.ticker_interval, + self.dataprovider.ohlcv(pair, self.strategy.ticker_interval)) - (buy, sell) = self.strategy.get_signal( - pair, self.strategy.ticker_interval, - self.dataprovider.ohlcv(pair, self.strategy.ticker_interval)) + if buy and not sell: + if not self.get_free_open_trades(): + logger.debug("Can't open a new trade: max number of trades is reached") + return False - if buy and not sell: - if not self.get_free_open_trades(): - logger.debug("Can't open a new trade: max number of trades is reached") - continue + stake_amount = self.get_trade_stake_amount(pair) + if not stake_amount: + logger.debug("Stake amount is 0, ignoring possible trade for {pair}.") + return False - stake_amount = self.get_trade_stake_amount(pair) - if not stake_amount: - logger.debug("Stake amount is 0, ignoring possible trade for {pair}.") - continue + logger.info(f"Buy signal found: about create a new trade with stake_amount: " + f"{stake_amount} ...") - logger.info(f"Buy signal found: about create a new trade with stake_amount: " - f"{stake_amount} ...") + bidstrat_check_depth_of_market = self.config.get('bid_strategy', {}).\ + get('check_depth_of_market', {}) + if (bidstrat_check_depth_of_market.get('enabled', False)) and\ + (bidstrat_check_depth_of_market.get('bids_to_ask_delta', 0) > 0): + if self._check_depth_of_market_buy(pair, bidstrat_check_depth_of_market): + return self.execute_buy(pair, stake_amount) + else: + return False - bidstrat_check_depth_of_market = self.config.get('bid_strategy', {}).\ - get('check_depth_of_market', {}) - if (bidstrat_check_depth_of_market.get('enabled', False)) and\ - (bidstrat_check_depth_of_market.get('bids_to_ask_delta', 0) > 0): - if self._check_depth_of_market_buy(pair, bidstrat_check_depth_of_market): - buycount += self.execute_buy(pair, stake_amount) - continue - - buycount += self.execute_buy(pair, stake_amount) - - return buycount > 0 + return self.execute_buy(pair, stake_amount) + else: + return False def _check_depth_of_market_buy(self, pair: str, conf: Dict) -> bool: """ @@ -479,10 +462,31 @@ class FreqtradeBot: """ Tries to execute buy orders for trades in a safe way """ + result = False try: - # Create entity and execute trade - if not self.create_trades(): + whitelist = copy.deepcopy(self.active_pair_whitelist) + + if not whitelist: + logger.info("Active pair whitelist is empty.") + else: + # Remove currently opened and latest pairs from whitelist + for trade in Trade.get_open_trades(): + if trade.pair in whitelist: + whitelist.remove(trade.pair) + logger.debug('Ignoring %s in pair whitelist', trade.pair) + + if not whitelist: + logger.info("No currency pair in active pair whitelist, " + "but checking to sell open trades.") + else: + # Create entity and execute trade for each pair from whitelist + for pair in whitelist: + if self.create_trade(pair): + result = True + + if not result: logger.debug('Found no buy signals for whitelisted currencies. Trying again...') + except DependencyException as exception: logger.warning('Unable to create trade: %s', exception) From ce84f74528de4ee06977967a859722b68a1f6b31 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 29 Dec 2019 04:38:28 +0300 Subject: [PATCH 02/12] Adjust tests --- tests/rpc/test_rpc.py | 22 ++--- tests/rpc/test_rpc_apiserver.py | 8 +- tests/rpc/test_rpc_telegram.py | 22 ++--- tests/test_freqtradebot.py | 151 ++++++++++++++++---------------- tests/test_integration.py | 4 +- 5 files changed, 105 insertions(+), 102 deletions(-) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 3b897572c..a9f73e98d 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -41,7 +41,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: with pytest.raises(RPCException, match=r'.*no active trade*'): rpc._rpc_trade_status() - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() results = rpc._rpc_trade_status() assert { 'trade_id': 1, @@ -116,7 +116,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: with pytest.raises(RPCException, match=r'.*no active order*'): rpc._rpc_status_table(default_conf['stake_currency'], 'USD') - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') assert "Since" in headers @@ -162,7 +162,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee, rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -217,7 +217,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade trade.update(limit_buy_order) @@ -231,7 +231,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, trade.close_date = datetime.utcnow() trade.is_open = False - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade trade.update(limit_buy_order) @@ -299,7 +299,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, rpc = RPC(freqtradebot) # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade trade.update(limit_buy_order) @@ -529,7 +529,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: msg = rpc._rpc_forcesell('all') assert msg == {'result': 'Created sell orders for all open trades.'} - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() msg = rpc._rpc_forcesell('all') assert msg == {'result': 'Created sell orders for all open trades.'} @@ -563,7 +563,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: assert cancel_order_mock.call_count == 1 assert trade.amount == filled_amount - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.filter(Trade.id == '2').first() amount = trade.amount # make an limit-buy open trade, if there is no 'filled', don't sell it @@ -582,7 +582,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: assert cancel_order_mock.call_count == 2 assert trade.amount == amount - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() # make an limit-sell open trade mocker.patch( 'freqtrade.exchange.Exchange.get_order', @@ -613,7 +613,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee, rpc = RPC(freqtradebot) # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -649,7 +649,7 @@ def test_rpc_count(mocker, default_conf, ticker, fee) -> None: assert counts["current"] == 0 # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() counts = rpc._rpc_count() assert counts["current"] == 1 diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 36bb81e41..94af85349 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -267,7 +267,7 @@ def test_api_count(botclient, mocker, ticker, fee, markets): assert rc.json["max"] == 1.0 # Create some test data - ftbot.create_trades() + ftbot.process_maybe_execute_buys() rc = client_get(client, f"{BASE_URI}/count") assert_response(rc) assert rc.json["current"] == 1.0 @@ -333,7 +333,7 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, li assert len(rc.json) == 1 assert rc.json == {"error": "Error querying _profit: no closed trade"} - ftbot.create_trades() + ftbot.process_maybe_execute_buys() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade @@ -422,7 +422,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets): assert_response(rc, 200) assert rc.json == [] - ftbot.create_trades() + ftbot.process_maybe_execute_buys() rc = client_get(client, f"{BASE_URI}/status") assert_response(rc) assert len(rc.json) == 1 @@ -552,7 +552,7 @@ def test_api_forcesell(botclient, mocker, ticker, fee, markets): assert_response(rc, 502) assert rc.json == {"error": "Error querying _forcesell: invalid argument"} - ftbot.create_trades() + ftbot.process_maybe_execute_buys() rc = client_post(client, f"{BASE_URI}/forcesell", data='{"tradeid": "1"}') diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index f8b9ca8ab..d9a7e2f5b 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -189,7 +189,7 @@ def test_status(default_conf, update, mocker, fee, ticker,) -> None: # Create some test data for _ in range(3): - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() telegram._status(update=update, context=MagicMock()) assert msg_mock.call_count == 1 @@ -236,7 +236,7 @@ def test_status_handle(default_conf, update, ticker, fee, mocker) -> None: msg_mock.reset_mock() # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() # Trigger status while we have a fulfilled order for the open trade telegram._status(update=update, context=MagicMock()) @@ -285,7 +285,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None: msg_mock.reset_mock() # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() telegram._status_table(update=update, context=MagicMock()) @@ -322,7 +322,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -352,7 +352,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, msg_mock.reset_mock() freqtradebot.config['max_open_trades'] = 2 # Add two other trades - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trades = Trade.query.all() for trade in trades: @@ -431,7 +431,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, msg_mock.reset_mock() # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade @@ -709,7 +709,7 @@ def test_forcesell_handle(default_conf, update, ticker, fee, telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -764,7 +764,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() # Decrease the price and sell it mocker.patch.multiple( @@ -821,7 +821,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() rpc_mock.reset_mock() # /forcesell all @@ -971,7 +971,7 @@ def test_performance_handle(default_conf, update, ticker, fee, telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -1014,7 +1014,7 @@ def test_count_handle(default_conf, update, ticker, fee, mocker) -> None: freqtradebot.state = State.RUNNING # Create some test data - freqtradebot.create_trades() + freqtradebot.process_maybe_execute_buys() msg_mock.reset_mock() telegram._count(update=update, context=MagicMock()) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 2f8c786fd..be6a9b392 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -247,7 +247,7 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, edge_conf freqtrade.active_pair_whitelist = ['NEO/BTC'] patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) ############################################# @@ -287,7 +287,7 @@ def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee, freqtrade.active_pair_whitelist = ['NEO/BTC'] patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) ############################################# @@ -310,7 +310,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, ) freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade is not None @@ -318,7 +318,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, assert trade.is_open assert trade.open_date is not None - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.order_by(Trade.id.desc()).first() assert trade is not None @@ -462,7 +462,7 @@ def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None: assert round(result, 8) == round(max(0.0001, 0.001 * 0.020405) / 0.9, 8) -def test_create_trades(default_conf, ticker, limit_buy_order, fee, mocker) -> None: +def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -476,7 +476,7 @@ def test_create_trades(default_conf, ticker, limit_buy_order, fee, mocker) -> No whitelist = deepcopy(default_conf['exchange']['pair_whitelist']) freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.create_trade('ETH/BTC') trade = Trade.query.first() assert trade is not None @@ -494,8 +494,8 @@ def test_create_trades(default_conf, ticker, limit_buy_order, fee, mocker) -> No assert whitelist == default_conf['exchange']['pair_whitelist'] -def test_create_trades_no_stake_amount(default_conf, ticker, limit_buy_order, - fee, mocker) -> None: +def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order, + fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) patch_wallet(mocker, free=default_conf['stake_amount'] * 0.5) @@ -509,11 +509,11 @@ def test_create_trades_no_stake_amount(default_conf, ticker, limit_buy_order, patch_get_signal(freqtrade) with pytest.raises(DependencyException, match=r'.*stake amount.*'): - freqtrade.create_trades() + freqtrade.create_trade('ETH/BTC') -def test_create_trades_minimal_amount(default_conf, ticker, limit_buy_order, - fee, mocker) -> None: +def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order, + fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) buy_mock = MagicMock(return_value={'id': limit_buy_order['id']}) @@ -527,13 +527,13 @@ def test_create_trades_minimal_amount(default_conf, ticker, limit_buy_order, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.create_trade('ETH/BTC') rate, amount = buy_mock.call_args[1]['rate'], buy_mock.call_args[1]['amount'] assert rate * amount >= default_conf['stake_amount'] -def test_create_trades_too_small_stake_amount(default_conf, ticker, limit_buy_order, - fee, mocker) -> None: +def test_create_trade_too_small_stake_amount(default_conf, ticker, limit_buy_order, + fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) buy_mock = MagicMock(return_value={'id': limit_buy_order['id']}) @@ -549,11 +549,11 @@ def test_create_trades_too_small_stake_amount(default_conf, ticker, limit_buy_or patch_get_signal(freqtrade) - assert not freqtrade.create_trades() + assert not freqtrade.create_trade('ETH/BTC') -def test_create_trades_limit_reached(default_conf, ticker, limit_buy_order, - fee, markets, mocker) -> None: +def test_create_trade_limit_reached(default_conf, ticker, limit_buy_order, + fee, markets, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -569,12 +569,13 @@ def test_create_trades_limit_reached(default_conf, ticker, limit_buy_order, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - assert not freqtrade.create_trades() + assert not freqtrade.create_trade('ETH/BTC') assert freqtrade.get_trade_stake_amount('ETH/BTC') is None -def test_create_trades_no_pairs_let(default_conf, ticker, limit_buy_order, fee, - mocker, caplog) -> None: +def test_process_maybe_execute_buys_no_pairs_let(default_conf, ticker, + limit_buy_order, fee, + mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -588,14 +589,15 @@ def test_create_trades_no_pairs_let(default_conf, ticker, limit_buy_order, fee, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - assert freqtrade.create_trades() - assert not freqtrade.create_trades() - assert log_has("No currency pair in active pair whitelist, " - "but checking to sell open trades.", caplog) + freqtrade.process_maybe_execute_buys() + assert not log_has_re(r"No currency pair in active pair whitelist.*", caplog) + freqtrade.process_maybe_execute_buys() + assert log_has_re(r"No currency pair in active pair whitelist.*", caplog) -def test_create_trades_no_pairs_in_whitelist(default_conf, ticker, limit_buy_order, fee, - mocker, caplog) -> None: +def test_process_maybe_execute_buys_no_pairs_in_whitelist(default_conf, ticker, + limit_buy_order, fee, + mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -608,11 +610,11 @@ def test_create_trades_no_pairs_in_whitelist(default_conf, ticker, limit_buy_ord freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - assert not freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() assert log_has("Active pair whitelist is empty.", caplog) -def test_create_trades_no_signal(default_conf, fee, mocker) -> None: +def test_create_trade_no_signal(default_conf, fee, mocker) -> None: default_conf['dry_run'] = True patch_RPCManager(mocker) @@ -628,7 +630,7 @@ def test_create_trades_no_signal(default_conf, fee, mocker) -> None: Trade.query = MagicMock() Trade.query.filter = MagicMock() - assert not freqtrade.create_trades() + assert not freqtrade.create_trade('ETH/BTC') @pytest.mark.parametrize("max_open", range(0, 5)) @@ -646,7 +648,7 @@ def test_create_trades_multiple_trades(default_conf, ticker, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trades = Trade.get_open_trades() assert len(trades) == max_open @@ -672,7 +674,8 @@ def test_create_trades_preopen(default_conf, ticker, fee, mocker) -> None: assert len(Trade.get_open_trades()) == 2 # Create 2 new trades using create_trades - assert freqtrade.create_trades() + assert freqtrade.create_trade('ETH/BTC') + assert freqtrade.create_trade('NEO/BTC') trades = Trade.get_open_trades() assert len(trades) == 4 @@ -1056,7 +1059,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, # should unset stoploss_order_id and return true # as a trade actually happened caplog.clear() - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1114,7 +1117,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.is_open = True trade.open_order_id = '12345' @@ -1149,7 +1152,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, patch_get_signal(freqtrade) freqtrade.strategy.order_types['stoploss_on_exchange'] = True - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() caplog.clear() freqtrade.create_stoploss_order(trade, 200, 199) @@ -1207,7 +1210,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog, patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1295,7 +1298,7 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c # setting stoploss_on_exchange_interval to 60 seconds freqtrade.strategy.order_types['stoploss_on_exchange_interval'] = 60 patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1376,7 +1379,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, freqtrade.active_pair_whitelist = freqtrade.edge.adjust(freqtrade.active_pair_whitelist) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1444,7 +1447,7 @@ def test_process_maybe_execute_buys(mocker, default_conf, caplog) -> None: caplog.set_level(logging.DEBUG) freqtrade = get_patched_freqtradebot(mocker, default_conf) - mocker.patch('freqtrade.freqtradebot.FreqtradeBot.create_trades', MagicMock(return_value=False)) + mocker.patch('freqtrade.freqtradebot.FreqtradeBot.create_trade', MagicMock(return_value=False)) freqtrade.process_maybe_execute_buys() assert log_has('Found no buy signals for whitelisted currencies. Trying again...', caplog) @@ -1453,7 +1456,7 @@ def test_process_maybe_execute_buys_exception(mocker, default_conf, caplog) -> N freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch( - 'freqtrade.freqtradebot.FreqtradeBot.create_trades', + 'freqtrade.freqtradebot.FreqtradeBot.create_trade', MagicMock(side_effect=DependencyException) ) freqtrade.process_maybe_execute_buys() @@ -1674,7 +1677,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mock freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -1711,7 +1714,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, patch_get_signal(freqtrade, value=(True, True)) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() # Buy and Sell triggering, so doing nothing ... trades = Trade.query.all() @@ -1720,7 +1723,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, # Buy is triggering, so buying ... patch_get_signal(freqtrade, value=(True, False)) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trades = Trade.query.all() nb_trades = len(trades) assert nb_trades == 1 @@ -1764,7 +1767,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, patch_get_signal(freqtrade, value=(True, False)) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.is_open = True @@ -1795,7 +1798,7 @@ def test_handle_trade_use_sell_signal( freqtrade = get_patched_freqtradebot(mocker, default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.is_open = True @@ -1823,7 +1826,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, patch_get_signal(freqtrade) # Create trade and sell it - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -2183,7 +2186,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> N patch_get_signal(freqtrade) # Create some test data - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -2231,7 +2234,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker) patch_get_signal(freqtrade) # Create some test data - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -2281,7 +2284,7 @@ def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fe patch_get_signal(freqtrade) # Create some test data - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -2339,7 +2342,7 @@ def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee, c freqtrade.strategy.order_types['stoploss_on_exchange'] = True patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() Trade.session = MagicMock() @@ -2382,7 +2385,7 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf, ticker, fee, ticke patch_get_signal(freqtrade) # Create some test data - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -2432,7 +2435,7 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf, ticker, f patch_get_signal(freqtrade) # Create some test data - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trades = [trade] freqtrade.process_maybe_execute_sells(trades) @@ -2484,7 +2487,7 @@ def test_execute_sell_market_order(default_conf, ticker, fee, patch_get_signal(freqtrade) # Create some test data - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -2546,7 +2549,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2577,7 +2580,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2608,7 +2611,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, mocker patch_get_signal(freqtrade) freqtrade.strategy.stop_loss_reached = MagicMock(return_value=SellCheckTuple( sell_flag=False, sell_type=SellType.NONE)) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2638,7 +2641,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocke patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2667,7 +2670,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() amnt = trade.amount @@ -2735,7 +2738,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo patch_get_signal(freqtrade) # Create some test data - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -2754,7 +2757,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo # reinit - should buy other pair. caplog.clear() - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() assert log_has(f"Pair {trade.pair} is currently locked.", caplog) @@ -2779,7 +2782,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, mocker) -> patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2812,7 +2815,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, caplog, mocker) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert freqtrade.handle_trade(trade) is False @@ -2867,7 +2870,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2924,7 +2927,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2987,7 +2990,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -3046,7 +3049,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trade.update(limit_buy_order) @@ -3377,7 +3380,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, whitelist = deepcopy(default_conf['exchange']['pair_whitelist']) freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade is not None @@ -3412,7 +3415,7 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o # Save state of current whitelist freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade is None @@ -3514,7 +3517,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trade = Trade.query.first() assert trade @@ -3604,7 +3607,7 @@ def test_process_i_am_alive(default_conf, mocker, caplog): @pytest.mark.usefixtures("init_persistence") -def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order): +def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order, caplog): default_conf['dry_run'] = True # Initialize to 2 times stake amount default_conf['dry_run_wallet'] = 0.002 @@ -3621,12 +3624,12 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order) patch_get_signal(bot) assert bot.wallets.get_free('BTC') == 0.002 - bot.create_trades() + bot.process_maybe_execute_buys() trades = Trade.query.all() assert len(trades) == 2 bot.config['max_open_trades'] = 3 - with pytest.raises( - DependencyException, - match=r"Available balance \(0 BTC\) is lower than stake amount \(0.001 BTC\)"): - bot.create_trades() + bot.process_maybe_execute_buys() + assert log_has_re(r"Unable to create trade: " + r"Available balance \(0 BTC\) is lower than stake amount \(0.001 BTC\)", + caplog) diff --git a/tests/test_integration.py b/tests/test_integration.py index 11dbca225..2c95bc6e3 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -80,7 +80,7 @@ def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee, patch_get_signal(freqtrade) # Create some test data - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() wallets_mock.reset_mock() Trade.session = MagicMock() @@ -153,7 +153,7 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, limit_buy_order, moc patch_get_signal(freqtrade) # Create 4 trades - freqtrade.create_trades() + freqtrade.process_maybe_execute_buys() trades = Trade.query.all() assert len(trades) == 4 From 04f28ed9bcd337e6f0dbdddd0c1d51f62e67c613 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sun, 29 Dec 2019 05:03:10 +0300 Subject: [PATCH 03/12] Refactor try/except: handle DependencyException for each pair separately --- freqtrade/freqtradebot.py | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d15624e9f..e47a4a85c 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -463,32 +463,32 @@ class FreqtradeBot: Tries to execute buy orders for trades in a safe way """ result = False - try: - whitelist = copy.deepcopy(self.active_pair_whitelist) + + whitelist = copy.deepcopy(self.active_pair_whitelist) + if not whitelist: + logger.info("Active pair whitelist is empty.") + else: + # Remove currently opened and latest pairs from whitelist + for trade in Trade.get_open_trades(): + if trade.pair in whitelist: + whitelist.remove(trade.pair) + logger.debug('Ignoring %s in pair whitelist', trade.pair) if not whitelist: - logger.info("Active pair whitelist is empty.") + logger.info("No currency pair in active pair whitelist, " + "but checking to sell open trades.") else: - # Remove currently opened and latest pairs from whitelist - for trade in Trade.get_open_trades(): - if trade.pair in whitelist: - whitelist.remove(trade.pair) - logger.debug('Ignoring %s in pair whitelist', trade.pair) - - if not whitelist: - logger.info("No currency pair in active pair whitelist, " - "but checking to sell open trades.") - else: - # Create entity and execute trade for each pair from whitelist - for pair in whitelist: + # Create entity and execute trade for each pair from whitelist + for pair in whitelist: + try: if self.create_trade(pair): result = True + except DependencyException as exception: + logger.warning('Unable to create trade: %s', exception) - if not result: - logger.debug('Found no buy signals for whitelisted currencies. Trying again...') - - except DependencyException as exception: - logger.warning('Unable to create trade: %s', exception) + if not result: + logger.debug("Found no buy signals for whitelisted currencies. " + "Trying again...") def process_maybe_execute_sells(self, trades: List[Any]) -> None: """ From 4c9295fe2d657fdf373601ea8d2350fb1990ebc8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 30 Dec 2019 14:00:34 +0100 Subject: [PATCH 04/12] Rename Bid-strategy helpervariable to something shorter avoids unnecessary wrapping... --- freqtrade/freqtradebot.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index e47a4a85c..68091ed76 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -313,7 +313,7 @@ class FreqtradeBot: if buy and not sell: if not self.get_free_open_trades(): - logger.debug("Can't open a new trade: max number of trades is reached") + logger.debug("Can't open a new trade: max number of trades is reached.") return False stake_amount = self.get_trade_stake_amount(pair) @@ -324,11 +324,10 @@ class FreqtradeBot: logger.info(f"Buy signal found: about create a new trade with stake_amount: " f"{stake_amount} ...") - bidstrat_check_depth_of_market = self.config.get('bid_strategy', {}).\ - get('check_depth_of_market', {}) - if (bidstrat_check_depth_of_market.get('enabled', False)) and\ - (bidstrat_check_depth_of_market.get('bids_to_ask_delta', 0) > 0): - if self._check_depth_of_market_buy(pair, bidstrat_check_depth_of_market): + bid_check_dom = self.config.get('bid_strategy', {}).get('check_depth_of_market', {}) + if ((bid_check_dom.get('enabled', False)) and + (bid_check_dom.get('bids_to_ask_delta', 0) > 0)): + if self._check_depth_of_market_buy(pair, bid_check_dom): return self.execute_buy(pair, stake_amount) else: return False From 4d56e3b36e02d2fb8bd41bde5cbf0fabc0cd7a28 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 30 Dec 2019 20:54:32 +0300 Subject: [PATCH 05/12] Address some comments made in the review --- freqtrade/freqtradebot.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 68091ed76..3bfa74005 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -296,8 +296,11 @@ class FreqtradeBot: def create_trade(self, pair: str) -> bool: """ - Check the implemented trading strategy for buy-signals. - If the pair triggers the buy_signal a new trade record gets created. + Check the implemented trading strategy for buy signals. + + If the pair triggers the buy signal a new trade record gets created + and the buy-order opening the trade gets issued towards the exchange. + :return: True if a trade has been created. """ logger.debug(f"create_trade for pair {pair}") @@ -467,7 +470,7 @@ class FreqtradeBot: if not whitelist: logger.info("Active pair whitelist is empty.") else: - # Remove currently opened and latest pairs from whitelist + # Remove pairs for currently opened trades from the whitelist for trade in Trade.get_open_trades(): if trade.pair in whitelist: whitelist.remove(trade.pair) From b00406a7eb0e73f2b104598441958782d4c95497 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 30 Dec 2019 21:09:35 +0300 Subject: [PATCH 06/12] Make process_maybe_execute_*() returning integers --- freqtrade/freqtradebot.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3bfa74005..e6f51e5fa 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -460,11 +460,11 @@ class FreqtradeBot: return True - def process_maybe_execute_buys(self) -> None: + def process_maybe_execute_buys(self) -> int: """ Tries to execute buy orders for trades in a safe way """ - result = False + trades_created = 0 whitelist = copy.deepcopy(self.active_pair_whitelist) if not whitelist: @@ -483,39 +483,42 @@ class FreqtradeBot: # Create entity and execute trade for each pair from whitelist for pair in whitelist: try: - if self.create_trade(pair): - result = True + trades_created += self.create_trade(pair) except DependencyException as exception: logger.warning('Unable to create trade: %s', exception) - if not result: + if not trades_created: logger.debug("Found no buy signals for whitelisted currencies. " "Trying again...") - def process_maybe_execute_sells(self, trades: List[Any]) -> None: + return trades_created + + def process_maybe_execute_sells(self, trades: List[Any]) -> int: """ Tries to execute sell orders for trades in a safe way """ - result = False + trades_closed = 0 for trade in trades: try: self.update_trade_state(trade) if (self.strategy.order_types.get('stoploss_on_exchange') and self.handle_stoploss_on_exchange(trade)): - result = True + trades_closed += 1 continue # Check if we can sell our current pair if trade.open_order_id is None and self.handle_trade(trade): - result = True + trades_closed += 1 except DependencyException as exception: logger.warning('Unable to sell trade: %s', exception) # Updating wallets if any trade occured - if result: + if trades_closed: self.wallets.update() + return trades_closed + def get_real_amount(self, trade: Trade, order: Dict, order_amount: float = None) -> float: """ Get real amount for the trade From 84918ad42481a7558bd935a1639b29de5f317931 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 30 Dec 2019 22:08:36 +0300 Subject: [PATCH 07/12] Rename process_maybe_execute_sells() --> exit_positions() --- freqtrade/freqtradebot.py | 8 ++++---- tests/test_freqtradebot.py | 22 ++++++++++++---------- tests/test_integration.py | 6 ++++-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index e6f51e5fa..695302bf9 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -132,8 +132,8 @@ class FreqtradeBot: self.dataprovider.refresh(self._create_pair_whitelist(self.active_pair_whitelist), self.strategy.informative_pairs()) - # First process current opened trades - self.process_maybe_execute_sells(trades) + # First process current opened trades (positions) + self.exit_positions(trades) # Then looking for buy opportunities if self.get_free_open_trades(): @@ -493,9 +493,9 @@ class FreqtradeBot: return trades_created - def process_maybe_execute_sells(self, trades: List[Any]) -> int: + def exit_positions(self, trades: List[Any]) -> int: """ - Tries to execute sell orders for trades in a safe way + Tries to execute sell orders for open trades (positions) """ trades_closed = 0 for trade in trades: diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index be6a9b392..22110dd1c 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -990,7 +990,7 @@ def test_add_stoploss_on_exchange(mocker, default_conf, limit_buy_order) -> None trade.is_open = True trades = [trade] - freqtrade.process_maybe_execute_sells(trades) + freqtrade.exit_positions(trades) assert trade.stoploss_order_id == '13434334' assert stoploss_limit.call_count == 1 assert trade.is_open is True @@ -1463,7 +1463,7 @@ def test_process_maybe_execute_buys_exception(mocker, default_conf, caplog) -> N assert log_has('Unable to create trade: ', caplog) -def test_process_maybe_execute_sells(mocker, default_conf, limit_buy_order, caplog) -> None: +def test_exit_positions(mocker, default_conf, limit_buy_order, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_trade', MagicMock(return_value=True)) @@ -1476,7 +1476,8 @@ def test_process_maybe_execute_sells(mocker, default_conf, limit_buy_order, capl trade.open_order_id = '123' trade.open_fee = 0.001 trades = [trade] - assert not freqtrade.process_maybe_execute_sells(trades) + n = freqtrade.exit_positions(trades) + assert n == 0 # Test amount not modified by fee-logic assert not log_has( 'Applying fee to amount for Trade {} from 90.99181073 to 90.81'.format(trade), caplog @@ -1484,11 +1485,11 @@ def test_process_maybe_execute_sells(mocker, default_conf, limit_buy_order, capl mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount', return_value=90.81) # test amount modified by fee-logic - assert not freqtrade.process_maybe_execute_sells(trades) + n = freqtrade.exit_positions(trades) + assert n == 0 -def test_process_maybe_execute_sells_exception(mocker, default_conf, - limit_buy_order, caplog) -> None: +def test_exit_positions_exception(mocker, default_conf, limit_buy_order, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch('freqtrade.exchange.Exchange.get_order', return_value=limit_buy_order) @@ -1502,7 +1503,8 @@ def test_process_maybe_execute_sells_exception(mocker, default_conf, 'freqtrade.freqtradebot.FreqtradeBot.update_trade_state', side_effect=DependencyException() ) - freqtrade.process_maybe_execute_sells(trades) + n = freqtrade.exit_positions(trades) + assert n == 0 assert log_has('Unable to sell trade: ', caplog) @@ -2391,7 +2393,7 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf, ticker, fee, ticke assert trade trades = [trade] - freqtrade.process_maybe_execute_sells(trades) + freqtrade.exit_positions(trades) # Increase the price and sell it mocker.patch.multiple( @@ -2438,7 +2440,7 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf, ticker, f freqtrade.process_maybe_execute_buys() trade = Trade.query.first() trades = [trade] - freqtrade.process_maybe_execute_sells(trades) + freqtrade.exit_positions(trades) assert trade assert trade.stoploss_order_id == '123' assert trade.open_order_id is None @@ -2466,7 +2468,7 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf, ticker, f }) mocker.patch('freqtrade.exchange.Exchange.get_order', stoploss_limit_executed) - freqtrade.process_maybe_execute_sells(trades) + freqtrade.exit_positions(trades) assert trade.stoploss_order_id is None assert trade.is_open is False assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value diff --git a/tests/test_integration.py b/tests/test_integration.py index 2c95bc6e3..a73beeabe 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -90,7 +90,8 @@ def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee, trade.stoploss_order_id = 3 trade.open_order_id = None - freqtrade.process_maybe_execute_sells(trades) + n = freqtrade.exit_positions(trades) + assert n == 2 assert should_sell_mock.call_count == 2 # Only order for 3rd trade needs to be cancelled @@ -170,7 +171,8 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, limit_buy_order, moc assert len(trades) == 5 bals = freqtrade.wallets.get_all_balances() - freqtrade.process_maybe_execute_sells(trades) + n = freqtrade.exit_positions(trades) + assert n == 1 trades = Trade.get_open_trades() # One trade sold assert len(trades) == 4 From fd7af587da29851de854fdd2be7a7d697cdcdbe2 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 30 Dec 2019 22:50:56 +0300 Subject: [PATCH 08/12] Rename process_maybe_execute_buys() --> enter_positions() --- freqtrade/freqtradebot.py | 6 +- tests/rpc/test_rpc.py | 22 +++--- tests/rpc/test_rpc_apiserver.py | 8 +-- tests/rpc/test_rpc_telegram.py | 25 +++---- tests/test_freqtradebot.py | 118 +++++++++++++++++--------------- tests/test_integration.py | 5 +- 6 files changed, 96 insertions(+), 88 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 695302bf9..c595150ac 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -137,7 +137,7 @@ class FreqtradeBot: # Then looking for buy opportunities if self.get_free_open_trades(): - self.process_maybe_execute_buys() + self.enter_positions() # Check and handle any timed out open orders self.check_handle_timedout() @@ -460,9 +460,9 @@ class FreqtradeBot: return True - def process_maybe_execute_buys(self) -> int: + def enter_positions(self) -> int: """ - Tries to execute buy orders for trades in a safe way + Tries to execute buy orders for new trades (positions) """ trades_created = 0 diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index a9f73e98d..3581e3d18 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -41,7 +41,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: with pytest.raises(RPCException, match=r'.*no active trade*'): rpc._rpc_trade_status() - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() results = rpc._rpc_trade_status() assert { 'trade_id': 1, @@ -116,7 +116,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: with pytest.raises(RPCException, match=r'.*no active order*'): rpc._rpc_status_table(default_conf['stake_currency'], 'USD') - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') assert "Since" in headers @@ -162,7 +162,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee, rpc = RPC(freqtradebot) rpc._fiat_converter = CryptoToFiatConverter() # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() assert trade @@ -217,7 +217,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade trade.update(limit_buy_order) @@ -231,7 +231,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, trade.close_date = datetime.utcnow() trade.is_open = False - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade trade.update(limit_buy_order) @@ -299,7 +299,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, rpc = RPC(freqtradebot) # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade trade.update(limit_buy_order) @@ -529,7 +529,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: msg = rpc._rpc_forcesell('all') assert msg == {'result': 'Created sell orders for all open trades.'} - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() msg = rpc._rpc_forcesell('all') assert msg == {'result': 'Created sell orders for all open trades.'} @@ -563,7 +563,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: assert cancel_order_mock.call_count == 1 assert trade.amount == filled_amount - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.filter(Trade.id == '2').first() amount = trade.amount # make an limit-buy open trade, if there is no 'filled', don't sell it @@ -582,7 +582,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: assert cancel_order_mock.call_count == 2 assert trade.amount == amount - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() # make an limit-sell open trade mocker.patch( 'freqtrade.exchange.Exchange.get_order', @@ -613,7 +613,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee, rpc = RPC(freqtradebot) # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() assert trade @@ -649,7 +649,7 @@ def test_rpc_count(mocker, default_conf, ticker, fee) -> None: assert counts["current"] == 0 # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() counts = rpc._rpc_count() assert counts["current"] == 1 diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 94af85349..25c971bf7 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -267,7 +267,7 @@ def test_api_count(botclient, mocker, ticker, fee, markets): assert rc.json["max"] == 1.0 # Create some test data - ftbot.process_maybe_execute_buys() + ftbot.enter_positions() rc = client_get(client, f"{BASE_URI}/count") assert_response(rc) assert rc.json["current"] == 1.0 @@ -333,7 +333,7 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, li assert len(rc.json) == 1 assert rc.json == {"error": "Error querying _profit: no closed trade"} - ftbot.process_maybe_execute_buys() + ftbot.enter_positions() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade @@ -422,7 +422,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets): assert_response(rc, 200) assert rc.json == [] - ftbot.process_maybe_execute_buys() + ftbot.enter_positions() rc = client_get(client, f"{BASE_URI}/status") assert_response(rc) assert len(rc.json) == 1 @@ -552,7 +552,7 @@ def test_api_forcesell(botclient, mocker, ticker, fee, markets): assert_response(rc, 502) assert rc.json == {"error": "Error querying _forcesell: invalid argument"} - ftbot.process_maybe_execute_buys() + ftbot.enter_positions() rc = client_post(client, f"{BASE_URI}/forcesell", data='{"tradeid": "1"}') diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index d9a7e2f5b..44e51514e 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -188,8 +188,8 @@ def test_status(default_conf, update, mocker, fee, ticker,) -> None: telegram = Telegram(freqtradebot) # Create some test data - for _ in range(3): - freqtradebot.process_maybe_execute_buys() + n = freqtradebot.enter_positions() + assert n == 1 telegram._status(update=update, context=MagicMock()) assert msg_mock.call_count == 1 @@ -236,7 +236,7 @@ def test_status_handle(default_conf, update, ticker, fee, mocker) -> None: msg_mock.reset_mock() # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() # Trigger status while we have a fulfilled order for the open trade telegram._status(update=update, context=MagicMock()) @@ -285,7 +285,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, mocker) -> None: msg_mock.reset_mock() # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() telegram._status_table(update=update, context=MagicMock()) @@ -322,7 +322,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() assert trade @@ -352,7 +352,8 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee, msg_mock.reset_mock() freqtradebot.config['max_open_trades'] = 2 # Add two other trades - freqtradebot.process_maybe_execute_buys() + n = freqtradebot.enter_positions() + assert n == 2 trades = Trade.query.all() for trade in trades: @@ -431,7 +432,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee, msg_mock.reset_mock() # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() # Simulate fulfilled LIMIT_BUY order for trade @@ -709,7 +710,7 @@ def test_forcesell_handle(default_conf, update, ticker, fee, telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() assert trade @@ -764,7 +765,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() # Decrease the price and sell it mocker.patch.multiple( @@ -821,7 +822,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() rpc_mock.reset_mock() # /forcesell all @@ -971,7 +972,7 @@ def test_performance_handle(default_conf, update, ticker, fee, telegram = Telegram(freqtradebot) # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() trade = Trade.query.first() assert trade @@ -1014,7 +1015,7 @@ def test_count_handle(default_conf, update, ticker, fee, mocker) -> None: freqtradebot.state = State.RUNNING # Create some test data - freqtradebot.process_maybe_execute_buys() + freqtradebot.enter_positions() msg_mock.reset_mock() telegram._count(update=update, context=MagicMock()) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 22110dd1c..f99b14286 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -247,7 +247,7 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, edge_conf freqtrade.active_pair_whitelist = ['NEO/BTC'] patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) ############################################# @@ -287,7 +287,7 @@ def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee, freqtrade.active_pair_whitelist = ['NEO/BTC'] patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) ############################################# @@ -310,7 +310,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, ) freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade is not None @@ -318,7 +318,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, assert trade.is_open assert trade.open_date is not None - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.order_by(Trade.id.desc()).first() assert trade is not None @@ -573,9 +573,8 @@ def test_create_trade_limit_reached(default_conf, ticker, limit_buy_order, assert freqtrade.get_trade_stake_amount('ETH/BTC') is None -def test_process_maybe_execute_buys_no_pairs_let(default_conf, ticker, - limit_buy_order, fee, - mocker, caplog) -> None: +def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order, fee, + mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -589,15 +588,16 @@ def test_process_maybe_execute_buys_no_pairs_let(default_conf, ticker, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + n = freqtrade.enter_positions() + assert n == 1 assert not log_has_re(r"No currency pair in active pair whitelist.*", caplog) - freqtrade.process_maybe_execute_buys() + n = freqtrade.enter_positions() + assert n == 0 assert log_has_re(r"No currency pair in active pair whitelist.*", caplog) -def test_process_maybe_execute_buys_no_pairs_in_whitelist(default_conf, ticker, - limit_buy_order, fee, - mocker, caplog) -> None: +def test_enter_positions_no_pairs_in_whitelist(default_conf, ticker, limit_buy_order, fee, + mocker, caplog) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -610,7 +610,8 @@ def test_process_maybe_execute_buys_no_pairs_in_whitelist(default_conf, ticker, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + n = freqtrade.enter_positions() + assert n == 0 assert log_has("Active pair whitelist is empty.", caplog) @@ -648,7 +649,8 @@ def test_create_trades_multiple_trades(default_conf, ticker, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + n = freqtrade.enter_positions() + assert n == max_open trades = Trade.get_open_trades() assert len(trades) == max_open @@ -1059,7 +1061,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog, # should unset stoploss_order_id and return true # as a trade actually happened caplog.clear() - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1117,7 +1119,7 @@ def test_handle_sle_cancel_cant_recreate(mocker, default_conf, fee, caplog, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.is_open = True trade.open_order_id = '12345' @@ -1152,7 +1154,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, patch_get_signal(freqtrade) freqtrade.strategy.order_types['stoploss_on_exchange'] = True - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() caplog.clear() freqtrade.create_stoploss_order(trade, 200, 199) @@ -1210,7 +1212,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog, patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1298,7 +1300,7 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c # setting stoploss_on_exchange_interval to 60 seconds freqtrade.strategy.order_types['stoploss_on_exchange_interval'] = 60 patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1379,7 +1381,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, freqtrade.active_pair_whitelist = freqtrade.edge.adjust(freqtrade.active_pair_whitelist) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.is_open = True trade.open_order_id = None @@ -1443,23 +1445,25 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, stop_price=0.00002344 * 0.99) -def test_process_maybe_execute_buys(mocker, default_conf, caplog) -> None: +def test_enter_positions(mocker, default_conf, caplog) -> None: caplog.set_level(logging.DEBUG) freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch('freqtrade.freqtradebot.FreqtradeBot.create_trade', MagicMock(return_value=False)) - freqtrade.process_maybe_execute_buys() + n = freqtrade.enter_positions() + assert n == 0 assert log_has('Found no buy signals for whitelisted currencies. Trying again...', caplog) -def test_process_maybe_execute_buys_exception(mocker, default_conf, caplog) -> None: +def test_enter_positions_exception(mocker, default_conf, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) mocker.patch( 'freqtrade.freqtradebot.FreqtradeBot.create_trade', MagicMock(side_effect=DependencyException) ) - freqtrade.process_maybe_execute_buys() + n = freqtrade.enter_positions() + assert n == 0 assert log_has('Unable to create trade: ', caplog) @@ -1679,7 +1683,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mock freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -1702,7 +1706,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, fee, mock assert trade.close_date is not None -def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, mocker) -> None: +def test_handle_overlapping_signals(default_conf, ticker, limit_buy_order, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -1716,7 +1720,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, patch_get_signal(freqtrade, value=(True, True)) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() # Buy and Sell triggering, so doing nothing ... trades = Trade.query.all() @@ -1725,7 +1729,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, # Buy is triggering, so buying ... patch_get_signal(freqtrade, value=(True, False)) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trades = Trade.query.all() nb_trades = len(trades) assert nb_trades == 1 @@ -1769,7 +1773,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, patch_get_signal(freqtrade, value=(True, False)) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.is_open = True @@ -1800,7 +1804,7 @@ def test_handle_trade_use_sell_signal( freqtrade = get_patched_freqtradebot(mocker, default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.is_open = True @@ -1828,7 +1832,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, patch_get_signal(freqtrade) # Create trade and sell it - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -2188,7 +2192,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> N patch_get_signal(freqtrade) # Create some test data - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -2236,7 +2240,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker) patch_get_signal(freqtrade) # Create some test data - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -2286,7 +2290,7 @@ def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fe patch_get_signal(freqtrade) # Create some test data - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -2344,7 +2348,7 @@ def test_execute_sell_sloe_cancel_exception(mocker, default_conf, ticker, fee, c freqtrade.strategy.order_types['stoploss_on_exchange'] = True patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() Trade.session = MagicMock() @@ -2387,7 +2391,7 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf, ticker, fee, ticke patch_get_signal(freqtrade) # Create some test data - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -2437,7 +2441,7 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf, ticker, f patch_get_signal(freqtrade) # Create some test data - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trades = [trade] freqtrade.exit_positions(trades) @@ -2489,7 +2493,7 @@ def test_execute_sell_market_order(default_conf, ticker, fee, patch_get_signal(freqtrade) # Create some test data - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -2551,7 +2555,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2582,7 +2586,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2613,7 +2617,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, mocker patch_get_signal(freqtrade) freqtrade.strategy.stop_loss_reached = MagicMock(return_value=SellCheckTuple( sell_flag=False, sell_type=SellType.NONE)) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2643,7 +2647,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, mocke patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2672,7 +2676,7 @@ def test_sell_not_enough_balance(default_conf, limit_buy_order, patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() amnt = trade.amount @@ -2740,7 +2744,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo patch_get_signal(freqtrade) # Create some test data - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -2759,7 +2763,7 @@ def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplo # reinit - should buy other pair. caplog.clear() - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() assert log_has(f"Pair {trade.pair} is currently locked.", caplog) @@ -2784,7 +2788,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, mocker) -> patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2817,7 +2821,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, caplog, mocker) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert freqtrade.handle_trade(trade) is False @@ -2872,7 +2876,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2929,7 +2933,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -2992,7 +2996,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=False) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -3051,7 +3055,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, patch_get_signal(freqtrade) freqtrade.strategy.min_roi_reached = MagicMock(return_value=True) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() trade.update(limit_buy_order) @@ -3382,7 +3386,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, whitelist = deepcopy(default_conf['exchange']['pair_whitelist']) freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade is not None @@ -3417,7 +3421,7 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o # Save state of current whitelist freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade is None @@ -3519,7 +3523,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() trade = Trade.query.first() assert trade @@ -3626,12 +3630,14 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order, patch_get_signal(bot) assert bot.wallets.get_free('BTC') == 0.002 - bot.process_maybe_execute_buys() + n = bot.enter_positions() + assert n == 2 trades = Trade.query.all() assert len(trades) == 2 bot.config['max_open_trades'] = 3 - bot.process_maybe_execute_buys() + n = bot.enter_positions() + assert n == 0 assert log_has_re(r"Unable to create trade: " r"Available balance \(0 BTC\) is lower than stake amount \(0.001 BTC\)", caplog) diff --git a/tests/test_integration.py b/tests/test_integration.py index a73beeabe..1108969ad 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -80,7 +80,7 @@ def test_may_execute_sell_stoploss_on_exchange_multi(default_conf, ticker, fee, patch_get_signal(freqtrade) # Create some test data - freqtrade.process_maybe_execute_buys() + freqtrade.enter_positions() wallets_mock.reset_mock() Trade.session = MagicMock() @@ -154,7 +154,8 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, limit_buy_order, moc patch_get_signal(freqtrade) # Create 4 trades - freqtrade.process_maybe_execute_buys() + n = freqtrade.enter_positions() + assert n == 4 trades = Trade.query.all() assert len(trades) == 4 From a88464de3a5ffb4c6802040c6463d4079c5dc868 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 Dec 2019 07:01:58 +0100 Subject: [PATCH 09/12] Improve some test code --- tests/rpc/test_rpc_telegram.py | 10 ---------- tests/test_freqtradebot.py | 3 ++- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 44e51514e..9a39f2119 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -148,11 +148,6 @@ def test_status(default_conf, update, mocker, fee, ticker,) -> None: default_conf['telegram']['enabled'] = False default_conf['telegram']['chat_id'] = "123" - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - fetch_ticker=ticker, - get_fee=fee, - ) msg_mock = MagicMock() status_table = MagicMock() mocker.patch.multiple( @@ -184,13 +179,8 @@ def test_status(default_conf, update, mocker, fee, ticker,) -> None: ) freqtradebot = get_patched_freqtradebot(mocker, default_conf) - patch_get_signal(freqtradebot, (True, False)) telegram = Telegram(freqtradebot) - # Create some test data - n = freqtradebot.enter_positions() - assert n == 1 - telegram._status(update=update, context=MagicMock()) assert msg_mock.call_count == 1 diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index f99b14286..434633f5f 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1458,12 +1458,13 @@ def test_enter_positions(mocker, default_conf, caplog) -> None: def test_enter_positions_exception(mocker, default_conf, caplog) -> None: freqtrade = get_patched_freqtradebot(mocker, default_conf) - mocker.patch( + mock_ct = mocker.patch( 'freqtrade.freqtradebot.FreqtradeBot.create_trade', MagicMock(side_effect=DependencyException) ) n = freqtrade.enter_positions() assert n == 0 + assert mock_ct.call_count == len(default_conf['exchange']['pair_whitelist']) assert log_has('Unable to create trade: ', caplog) From 6ebb9017c7bc0b0d39d8f83d663a7218d776c48a Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 Dec 2019 07:03:57 +0100 Subject: [PATCH 10/12] Improve test enter_positions --- tests/test_freqtradebot.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 434633f5f..812ba4e3e 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1449,10 +1449,12 @@ def test_enter_positions(mocker, default_conf, caplog) -> None: caplog.set_level(logging.DEBUG) freqtrade = get_patched_freqtradebot(mocker, default_conf) - mocker.patch('freqtrade.freqtradebot.FreqtradeBot.create_trade', MagicMock(return_value=False)) + mock_ct = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.create_trade', + MagicMock(return_value=False)) n = freqtrade.enter_positions() assert n == 0 assert log_has('Found no buy signals for whitelisted currencies. Trying again...', caplog) + assert mock_ct.call_count == 4 def test_enter_positions_exception(mocker, default_conf, caplog) -> None: From 9d518b9d29cdcf90ccdc8efc4117ccff0ba5c380 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 Dec 2019 07:05:21 +0100 Subject: [PATCH 11/12] Add comment and don't hardcode 4 in test --- tests/test_freqtradebot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 812ba4e3e..6527554be 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1454,7 +1454,8 @@ def test_enter_positions(mocker, default_conf, caplog) -> None: n = freqtrade.enter_positions() assert n == 0 assert log_has('Found no buy signals for whitelisted currencies. Trying again...', caplog) - assert mock_ct.call_count == 4 + # create_trade should be called once for every pair in the whitelist. + assert mock_ct.call_count == len(default_conf['exchange']['pair_whitelist']) def test_enter_positions_exception(mocker, default_conf, caplog) -> None: From 26a2395aebd0b1ed39aaadb63e674dcf64a592bc Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 31 Dec 2019 07:11:09 +0100 Subject: [PATCH 12/12] Include Pair name in exception log message --- freqtrade/freqtradebot.py | 2 +- tests/test_freqtradebot.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c595150ac..a642e6ea7 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -485,7 +485,7 @@ class FreqtradeBot: try: trades_created += self.create_trade(pair) except DependencyException as exception: - logger.warning('Unable to create trade: %s', exception) + logger.warning('Unable to create trade for %s: %s', pair, exception) if not trades_created: logger.debug("Found no buy signals for whitelisted currencies. " diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 6527554be..cf395ef39 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1468,7 +1468,7 @@ def test_enter_positions_exception(mocker, default_conf, caplog) -> None: n = freqtrade.enter_positions() assert n == 0 assert mock_ct.call_count == len(default_conf['exchange']['pair_whitelist']) - assert log_has('Unable to create trade: ', caplog) + assert log_has('Unable to create trade for ETH/BTC: ', caplog) def test_exit_positions(mocker, default_conf, limit_buy_order, caplog) -> None: @@ -3642,6 +3642,6 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order, bot.config['max_open_trades'] = 3 n = bot.enter_positions() assert n == 0 - assert log_has_re(r"Unable to create trade: " + assert log_has_re(r"Unable to create trade for XRP/BTC: " r"Available balance \(0 BTC\) is lower than stake amount \(0.001 BTC\)", caplog)