Merge pull request #1868 from freqtrade/stoploss_restart
Stoploss restart
This commit is contained in:
@@ -90,6 +90,16 @@ class FreqtradeBot(object):
|
||||
self.rpc.cleanup()
|
||||
persistence.cleanup()
|
||||
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Called on startup and after reloading the bot - triggers notifications and
|
||||
performs startup tasks
|
||||
"""
|
||||
self.rpc.startup_messages(self.config, self.pairlists)
|
||||
if not self.edge:
|
||||
# Adjust stoploss if it was changed
|
||||
Trade.stoploss_reinitialization(self.strategy.stoploss)
|
||||
|
||||
def process(self) -> bool:
|
||||
"""
|
||||
Queries the persistence layer for open trades and handles them,
|
||||
|
@@ -422,3 +422,22 @@ class Trade(_DECL_BASE):
|
||||
Query trades from persistence layer
|
||||
"""
|
||||
return Trade.query.filter(Trade.is_open.is_(True)).all()
|
||||
|
||||
@staticmethod
|
||||
def stoploss_reinitialization(desired_stoploss):
|
||||
"""
|
||||
Adjust initial Stoploss to desired stoploss for all open trades.
|
||||
"""
|
||||
for trade in Trade.get_open_trades():
|
||||
logger.info("Found open trade: %s", trade)
|
||||
|
||||
# skip case if trailing-stop changed the stoploss already.
|
||||
if (trade.stop_loss == trade.initial_stop_loss
|
||||
and trade.initial_stop_loss_pct != desired_stoploss):
|
||||
# Stoploss value got changed
|
||||
|
||||
logger.info(f"Stoploss for {trade} needs adjustment.")
|
||||
# Force reset of stoploss
|
||||
trade.stop_loss = None
|
||||
trade.adjust_stop_loss(trade.open_rate, desired_stoploss)
|
||||
logger.info(f"new stoploss: {trade.stop_loss}, ")
|
||||
|
@@ -2,6 +2,7 @@
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
from functools import reduce
|
||||
from unittest.mock import MagicMock, PropertyMock
|
||||
@@ -952,9 +953,10 @@ def buy_order_fee():
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def edge_conf(default_conf):
|
||||
default_conf['max_open_trades'] = -1
|
||||
default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
||||
default_conf['edge'] = {
|
||||
conf = deepcopy(default_conf)
|
||||
conf['max_open_trades'] = -1
|
||||
conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
|
||||
conf['edge'] = {
|
||||
"enabled": True,
|
||||
"process_throttle_secs": 1800,
|
||||
"calculate_since_number_of_days": 14,
|
||||
@@ -970,7 +972,7 @@ def edge_conf(default_conf):
|
||||
"remove_pumps": False
|
||||
}
|
||||
|
||||
return default_conf
|
||||
return conf
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@@ -105,6 +105,7 @@ def test_cleanup(mocker, default_conf, caplog) -> None:
|
||||
def test_worker_running(mocker, default_conf, caplog) -> None:
|
||||
mock_throttle = MagicMock()
|
||||
mocker.patch('freqtrade.worker.Worker._throttle', mock_throttle)
|
||||
mocker.patch('freqtrade.persistence.Trade.stoploss_reinitialization', MagicMock())
|
||||
|
||||
worker = get_patched_worker(mocker, default_conf)
|
||||
|
||||
@@ -3144,10 +3145,27 @@ def test_get_sell_rate(default_conf, mocker, ticker, order_book_l2) -> None:
|
||||
assert rate == 0.043936
|
||||
|
||||
|
||||
def test_startup_messages(default_conf, mocker):
|
||||
def test_startup_state(default_conf, mocker):
|
||||
default_conf['pairlist'] = {'method': 'VolumePairList',
|
||||
'config': {'number_assets': 20}
|
||||
}
|
||||
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
|
||||
worker = get_patched_worker(mocker, default_conf)
|
||||
assert worker.state is State.RUNNING
|
||||
|
||||
|
||||
def test_startup_trade_reinit(default_conf, edge_conf, mocker):
|
||||
|
||||
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
|
||||
reinit_mock = MagicMock()
|
||||
mocker.patch('freqtrade.persistence.Trade.stoploss_reinitialization', reinit_mock)
|
||||
|
||||
ftbot = get_patched_freqtradebot(mocker, default_conf)
|
||||
ftbot.startup()
|
||||
assert reinit_mock.call_count == 1
|
||||
|
||||
reinit_mock.reset_mock()
|
||||
|
||||
ftbot = get_patched_freqtradebot(mocker, edge_conf)
|
||||
ftbot.startup()
|
||||
assert reinit_mock.call_count == 0
|
||||
|
@@ -777,3 +777,63 @@ def test_to_json(default_conf, fee):
|
||||
'stop_loss_pct': None,
|
||||
'initial_stop_loss': None,
|
||||
'initial_stop_loss_pct': None}
|
||||
|
||||
|
||||
def test_stoploss_reinitialization(default_conf, fee):
|
||||
init(default_conf['db_url'])
|
||||
trade = Trade(
|
||||
pair='ETH/BTC',
|
||||
stake_amount=0.001,
|
||||
fee_open=fee.return_value,
|
||||
open_date=arrow.utcnow().shift(hours=-2).datetime,
|
||||
amount=10,
|
||||
fee_close=fee.return_value,
|
||||
exchange='bittrex',
|
||||
open_rate=1,
|
||||
max_rate=1,
|
||||
)
|
||||
|
||||
trade.adjust_stop_loss(trade.open_rate, 0.05, True)
|
||||
assert trade.stop_loss == 0.95
|
||||
assert trade.stop_loss_pct == -0.05
|
||||
assert trade.initial_stop_loss == 0.95
|
||||
assert trade.initial_stop_loss_pct == -0.05
|
||||
Trade.session.add(trade)
|
||||
|
||||
# Lower stoploss
|
||||
Trade.stoploss_reinitialization(0.06)
|
||||
|
||||
trades = Trade.get_open_trades()
|
||||
assert len(trades) == 1
|
||||
trade_adj = trades[0]
|
||||
assert trade_adj.stop_loss == 0.94
|
||||
assert trade_adj.stop_loss_pct == -0.06
|
||||
assert trade_adj.initial_stop_loss == 0.94
|
||||
assert trade_adj.initial_stop_loss_pct == -0.06
|
||||
|
||||
# Raise stoploss
|
||||
Trade.stoploss_reinitialization(0.04)
|
||||
|
||||
trades = Trade.get_open_trades()
|
||||
assert len(trades) == 1
|
||||
trade_adj = trades[0]
|
||||
assert trade_adj.stop_loss == 0.96
|
||||
assert trade_adj.stop_loss_pct == -0.04
|
||||
assert trade_adj.initial_stop_loss == 0.96
|
||||
assert trade_adj.initial_stop_loss_pct == -0.04
|
||||
|
||||
# Trailing stoploss (move stoplos up a bit)
|
||||
trade.adjust_stop_loss(1.02, 0.04)
|
||||
assert trade_adj.stop_loss == 0.9792
|
||||
assert trade_adj.initial_stop_loss == 0.96
|
||||
|
||||
Trade.stoploss_reinitialization(0.04)
|
||||
|
||||
trades = Trade.get_open_trades()
|
||||
assert len(trades) == 1
|
||||
trade_adj = trades[0]
|
||||
# Stoploss should not change in this case.
|
||||
assert trade_adj.stop_loss == 0.9792
|
||||
assert trade_adj.stop_loss_pct == -0.04
|
||||
assert trade_adj.initial_stop_loss == 0.96
|
||||
assert trade_adj.initial_stop_loss_pct == -0.04
|
||||
|
@@ -91,7 +91,7 @@ class Worker(object):
|
||||
})
|
||||
logger.info('Changing state to: %s', state.name)
|
||||
if state == State.RUNNING:
|
||||
self.freqtrade.rpc.startup_messages(self._config, self.freqtrade.pairlists)
|
||||
self.freqtrade.startup()
|
||||
|
||||
if state == State.STOPPED:
|
||||
# Ping systemd watchdog before sleeping in the stopped state
|
||||
|
Reference in New Issue
Block a user