Merge pull request #1673 from freqtrade/refactor/persistance_stoplossupdate

trailing stop backtest problems
This commit is contained in:
Misagh
2019-03-28 20:44:24 +01:00
committed by GitHub
6 changed files with 165 additions and 98 deletions

View File

@@ -28,6 +28,7 @@ class BTContainer(NamedTuple):
roi: float
trades: List[BTrade]
profit_perc: float
trailing_stop: bool = False
def _get_frame_time_from_offset(offset):

View File

@@ -14,10 +14,10 @@ from freqtrade.tests.optimize import (BTrade, BTContainer, _build_backtest_dataf
from freqtrade.tests.conftest import patch_exchange
# Test 0 Minus 8% Close
# Test 1 Minus 8% Close
# Test with Stop-loss at 1%
# TC1: Stop-Loss Triggered 1% loss
tc0 = BTContainer(data=[
tc1 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
@@ -30,10 +30,10 @@ tc0 = BTContainer(data=[
)
# Test 1 Minus 4% Low, minus 1% close
# Test 2 Minus 4% Low, minus 1% close
# Test with Stop-Loss at 3%
# TC2: Stop-Loss Triggered 3% Loss
tc1 = BTContainer(data=[
tc2 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
@@ -49,11 +49,10 @@ tc1 = BTContainer(data=[
# Test 3 Candle drops 4%, Recovers 1%.
# Entry Criteria Met
# Candle drops 20%
# Candle Data for test 3
# Test with Stop-Loss at 2%
# TC3: Trade-A: Stop-Loss Triggered 2% Loss
# Trade-B: Stop-Loss Triggered 2% Loss
tc2 = BTContainer(data=[
tc3 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
@@ -71,7 +70,7 @@ tc2 = BTContainer(data=[
# Candle Data for test 3 Candle drops 3% Closed 15% up
# Test with Stop-loss at 2% ROI 6%
# TC4: Stop-Loss Triggered 2% Loss
tc3 = BTContainer(data=[
tc4 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
@@ -83,10 +82,10 @@ tc3 = BTContainer(data=[
trades=[BTrade(sell_reason=SellType.STOP_LOSS, open_tick=1, close_tick=2)]
)
# Test 4 / Drops 0.5% Closes +20%
# Test 5 / Drops 0.5% Closes +20%
# Set stop-loss at 1% ROI 3%
# TC5: ROI triggers 3% Gain
tc4 = BTContainer(data=[
tc5 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4980, 4987, 6172, 1, 0],
[1, 5000, 5025, 4980, 4987, 6172, 0, 0], # enter trade (signal on last candle)
@@ -99,10 +98,9 @@ tc4 = BTContainer(data=[
)
# Test 6 / Drops 3% / Recovers 6% Positive / Closes 1% positve
# Candle Data for test 6
# Set stop-loss at 2% ROI at 5%
# TC6: Stop-Loss triggers 2% Loss
tc5 = BTContainer(data=[
tc6 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
@@ -115,10 +113,9 @@ tc5 = BTContainer(data=[
)
# Test 7 - 6% Positive / 1% Negative / Close 1% Positve
# Candle Data for test 7
# Set stop-loss at 2% ROI at 3%
# TC7: ROI Triggers 3% Gain
tc6 = BTContainer(data=[
tc7 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
@@ -130,14 +127,47 @@ tc6 = BTContainer(data=[
trades=[BTrade(sell_reason=SellType.ROI, open_tick=1, close_tick=2)]
)
# Test 8 - trailing_stop should raise so candle 3 causes a stoploss.
# Set stop-loss at 10%, ROI at 10% (should not apply)
# TC8: Trailing stoploss - stoploss should be adjusted candle 2
tc8 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
[1, 5000, 5050, 4950, 5000, 6172, 0, 0],
[2, 5000, 5250, 4750, 4850, 6172, 0, 0],
[3, 4850, 5050, 4650, 4750, 6172, 0, 0],
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi=0.10, profit_perc=-0.055, trailing_stop=True,
trades=[BTrade(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
)
# Test 9 - trailing_stop should raise - high and low in same candle.
# Candle Data for test 9
# Set stop-loss at 10%, ROI at 10% (should not apply)
# TC9: Trailing stoploss - stoploss should be adjusted candle 2
tc9 = BTContainer(data=[
# D O H L C V B S
[0, 5000, 5050, 4950, 5000, 6172, 1, 0],
[1, 5000, 5050, 4950, 5000, 6172, 0, 0],
[2, 5000, 5050, 4950, 5000, 6172, 0, 0],
[3, 5000, 5200, 4550, 4850, 6172, 0, 0],
[4, 4750, 4950, 4350, 4750, 6172, 0, 0]],
stop_loss=-0.10, roi=0.10, profit_perc=-0.064, trailing_stop=True,
trades=[BTrade(sell_reason=SellType.TRAILING_STOP_LOSS, open_tick=1, close_tick=3)]
)
TESTS = [
tc0,
tc1,
tc2,
tc3,
tc4,
tc5,
tc6,
tc7,
tc8,
tc9,
]
@@ -148,8 +178,9 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
"""
default_conf["stoploss"] = data.stop_loss
default_conf["minimal_roi"] = {"0": data.roi}
default_conf['ticker_interval'] = tests_ticker_interval
mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.0))
default_conf["ticker_interval"] = tests_ticker_interval
default_conf["trailing_stop"] = data.trailing_stop
mocker.patch("freqtrade.exchange.Exchange.get_fee", MagicMock(return_value=0.0))
patch_exchange(mocker)
frame = _build_backtest_dataframe(data.data)
backtesting = Backtesting(default_conf)
@@ -157,7 +188,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
backtesting.advise_sell = lambda a, m: frame
caplog.set_level(logging.DEBUG)
pair = 'UNITTEST/BTC'
pair = "UNITTEST/BTC"
# Dummy data as we mock the analyze functions
data_processed = {pair: DataFrame()}
min_date, max_date = get_timeframe({pair: frame})

View File

@@ -2265,9 +2265,8 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, market
}
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)
freqtrade.strategy.stop_loss_reached = \
lambda current_rate, trade, current_time, force_stoploss, current_profit: SellCheckTuple(
sell_flag=False, sell_type=SellType.NONE)
freqtrade.strategy.stop_loss_reached = MagicMock(return_value=SellCheckTuple(
sell_flag=False, sell_type=SellType.NONE))
freqtrade.create_trade()
trade = Trade.query.first()
@@ -2413,8 +2412,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets
}))
# stop-loss not reached, adjusted stoploss
assert freqtrade.handle_trade(trade) is False
assert log_has(f'using positive stop loss mode: 0.01 with offset 0 '
f'since we have profit 0.2666%',
assert log_has(f'using positive stop loss: 0.01 offset: 0 profit: 0.2666%',
caplog.record_tuples)
assert log_has(f'adjusted stop loss', caplog.record_tuples)
assert trade.stop_loss == 0.0000138501
@@ -2473,8 +2471,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee,
}))
# stop-loss not reached, adjusted stoploss
assert freqtrade.handle_trade(trade) is False
assert log_has(f'using positive stop loss mode: 0.01 with offset 0.011 '
f'since we have profit 0.2666%',
assert log_has(f'using positive stop loss: 0.01 offset: 0.011 profit: 0.2666%',
caplog.record_tuples)
assert log_has(f'adjusted stop loss', caplog.record_tuples)
assert trade.stop_loss == 0.0000138501
@@ -2553,8 +2550,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee,
}))
assert freqtrade.handle_trade(trade) is False
assert log_has(f'using positive stop loss mode: 0.05 with offset 0.055 '
f'since we have profit 0.1218%',
assert log_has(f'using positive stop loss: 0.05 offset: 0.055 profit: 0.1218%',
caplog.record_tuples)
assert log_has(f'adjusted stop loss', caplog.record_tuples)
assert trade.stop_loss == 0.0000117705

View File

@@ -510,6 +510,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog):
assert trade.pair == "ETC/BTC"
assert trade.exchange == "binance"
assert trade.max_rate == 0.0
assert trade.min_rate is None
assert trade.stop_loss == 0.0
assert trade.initial_stop_loss == 0.0
assert trade.sell_reason is None
@@ -585,7 +586,48 @@ def test_migrate_mid_state(mocker, default_conf, fee, caplog):
caplog.record_tuples)
def test_adjust_stop_loss(limit_buy_order, limit_sell_order, fee):
def test_adjust_stop_loss(fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
fee_open=fee.return_value,
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.initial_stop_loss == 0.95
# Get percent of profit with a lower rate
trade.adjust_stop_loss(0.96, 0.05)
assert trade.stop_loss == 0.95
assert trade.initial_stop_loss == 0.95
# Get percent of profit with a custom rate (Higher than open rate)
trade.adjust_stop_loss(1.3, -0.1)
assert round(trade.stop_loss, 8) == 1.17
assert trade.initial_stop_loss == 0.95
# current rate lower again ... should not change
trade.adjust_stop_loss(1.2, 0.1)
assert round(trade.stop_loss, 8) == 1.17
assert trade.initial_stop_loss == 0.95
# current rate higher... should raise stoploss
trade.adjust_stop_loss(1.4, 0.1)
assert round(trade.stop_loss, 8) == 1.26
assert trade.initial_stop_loss == 0.95
# Initial is true but stop_loss set - so doesn't do anything
trade.adjust_stop_loss(1.7, 0.1, True)
assert round(trade.stop_loss, 8) == 1.26
assert trade.initial_stop_loss == 0.95
def test_adjust_min_max_rates(fee):
trade = Trade(
pair='ETH/BTC',
stake_amount=0.001,
@@ -595,40 +637,24 @@ def test_adjust_stop_loss(limit_buy_order, limit_sell_order, fee):
open_rate=1,
)
trade.adjust_stop_loss(trade.open_rate, 0.05, True)
assert trade.stop_loss == 0.95
trade.adjust_min_max_rates(trade.open_rate)
assert trade.max_rate == 1
assert trade.initial_stop_loss == 0.95
assert trade.min_rate == 1
# Get percent of profit with a lowre rate
trade.adjust_stop_loss(0.96, 0.05)
assert trade.stop_loss == 0.95
# check min adjusted, max remained
trade.adjust_min_max_rates(0.96)
assert trade.max_rate == 1
assert trade.initial_stop_loss == 0.95
assert trade.min_rate == 0.96
# Get percent of profit with a custom rate (Higher than open rate)
trade.adjust_stop_loss(1.3, -0.1)
assert round(trade.stop_loss, 8) == 1.17
assert trade.max_rate == 1.3
assert trade.initial_stop_loss == 0.95
# check max adjusted, min remains
trade.adjust_min_max_rates(1.05)
assert trade.max_rate == 1.05
assert trade.min_rate == 0.96
# current rate lower again ... should not change
trade.adjust_stop_loss(1.2, 0.1)
assert round(trade.stop_loss, 8) == 1.17
assert trade.max_rate == 1.3
assert trade.initial_stop_loss == 0.95
# current rate higher... should raise stoploss
trade.adjust_stop_loss(1.4, 0.1)
assert round(trade.stop_loss, 8) == 1.26
assert trade.max_rate == 1.4
assert trade.initial_stop_loss == 0.95
# Initial is true but stop_loss set - so doesn't do anything
trade.adjust_stop_loss(1.7, 0.1, True)
assert round(trade.stop_loss, 8) == 1.26
assert trade.max_rate == 1.4
assert trade.initial_stop_loss == 0.95
# current rate "in the middle" - no adjustment
trade.adjust_min_max_rates(1.03)
assert trade.max_rate == 1.05
assert trade.min_rate == 0.96
def test_get_open(default_conf, fee):