Merge branch 'develop' into stoploss_market
This commit is contained in:
		| @@ -7,6 +7,7 @@ import traceback | ||||
| from datetime import datetime | ||||
| from math import isclose | ||||
| from os import getpid | ||||
| from threading import Lock | ||||
| from typing import Any, Dict, List, Optional, Tuple | ||||
|  | ||||
| import arrow | ||||
| @@ -27,7 +28,6 @@ from freqtrade.state import State | ||||
| from freqtrade.strategy.interface import IStrategy, SellType | ||||
| from freqtrade.wallets import Wallets | ||||
|  | ||||
|  | ||||
| logger = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| @@ -92,6 +92,8 @@ class FreqtradeBot: | ||||
|         # the initial state of the bot. | ||||
|         # Keep this at the end of this initialization method. | ||||
|         self.rpc: RPCManager = RPCManager(self) | ||||
|         # Protect sell-logic from forcesell and viceversa | ||||
|         self._sell_lock = Lock() | ||||
|  | ||||
|     def cleanup(self) -> None: | ||||
|         """ | ||||
| @@ -132,6 +134,10 @@ class FreqtradeBot: | ||||
|         self.dataprovider.refresh(self._create_pair_whitelist(self.active_pair_whitelist), | ||||
|                                   self.strategy.informative_pairs()) | ||||
|  | ||||
|         # Protect from collisions with forcesell. | ||||
|         # Without this, freqtrade my try to recreate stoploss_on_exchange orders | ||||
|         # while selling is in process, since telegram messages arrive in an different thread. | ||||
|         with self._sell_lock: | ||||
|             # First process current opened trades (positions) | ||||
|             self.exit_positions(trades) | ||||
|  | ||||
|   | ||||
| @@ -420,11 +420,13 @@ class RPC: | ||||
|         if self._freqtrade.state != State.RUNNING: | ||||
|             raise RPCException('trader is not running') | ||||
|  | ||||
|         with self._freqtrade._sell_lock: | ||||
|             if trade_id == 'all': | ||||
|                 # Execute sell for all open orders | ||||
|                 for trade in Trade.get_open_trades(): | ||||
|                     _exec_forcesell(trade) | ||||
|                 Trade.session.flush() | ||||
|                 self._freqtrade.wallets.update() | ||||
|                 return {'result': 'Created sell orders for all open trades.'} | ||||
|  | ||||
|             # Query for trade | ||||
| @@ -437,6 +439,7 @@ class RPC: | ||||
|  | ||||
|             _exec_forcesell(trade) | ||||
|             Trade.session.flush() | ||||
|             self._freqtrade.wallets.update() | ||||
|             return {'result': f'Created sell order for trade {trade_id}.'} | ||||
|  | ||||
|     def _rpc_forcebuy(self, pair: str, price: Optional[float]) -> Optional[Trade]: | ||||
|   | ||||
| @@ -906,30 +906,22 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None: | ||||
|     assert ("ETH/BTC", default_conf["ticker_interval"]) in refresh_mock.call_args[0][0] | ||||
|  | ||||
|  | ||||
| def test_balance_fully_ask_side(mocker, default_conf) -> None: | ||||
|     default_conf['bid_strategy']['ask_last_balance'] = 0.0 | ||||
| @pytest.mark.parametrize("ask,last,last_ab,expected", [ | ||||
|     (20, 10, 0.0, 20),  # Full ask side | ||||
|     (20, 10, 1.0, 10),  # Full last side | ||||
|     (20, 10, 0.5, 15),  # Between ask and last | ||||
|     (20, 10, 0.7, 13),  # Between ask and last | ||||
|     (20, 10, 0.3, 17),  # Between ask and last | ||||
|     (5, 10, 1.0, 5),  # last bigger than ask | ||||
|     (5, 10, 0.5, 5),  # last bigger than ask | ||||
| ]) | ||||
| def test_get_buy_rate(mocker, default_conf, ask, last, last_ab, expected) -> None: | ||||
|     default_conf['bid_strategy']['ask_last_balance'] = last_ab | ||||
|     freqtrade = get_patched_freqtradebot(mocker, default_conf) | ||||
|     mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', | ||||
|                  MagicMock(return_value={'ask': 20, 'last': 10})) | ||||
|                  MagicMock(return_value={'ask': ask, 'last': last})) | ||||
|  | ||||
|     assert freqtrade.get_buy_rate('ETH/BTC') == 20 | ||||
|  | ||||
|  | ||||
| def test_balance_fully_last_side(mocker, default_conf) -> None: | ||||
|     default_conf['bid_strategy']['ask_last_balance'] = 1.0 | ||||
|     freqtrade = get_patched_freqtradebot(mocker, default_conf) | ||||
|     mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', | ||||
|                  MagicMock(return_value={'ask': 20, 'last': 10})) | ||||
|  | ||||
|     assert freqtrade.get_buy_rate('ETH/BTC') == 10 | ||||
|  | ||||
|  | ||||
| def test_balance_bigger_last_ask(mocker, default_conf) -> None: | ||||
|     default_conf['bid_strategy']['ask_last_balance'] = 1.0 | ||||
|     freqtrade = get_patched_freqtradebot(mocker, default_conf) | ||||
|     mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', | ||||
|                  MagicMock(return_value={'ask': 5, 'last': 10})) | ||||
|     assert freqtrade.get_buy_rate('ETH/BTC') == 5 | ||||
|     assert freqtrade.get_buy_rate('ETH/BTC') == expected | ||||
|  | ||||
|  | ||||
| def test_execute_buy(mocker, default_conf, fee, limit_buy_order) -> None: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user