Merge branch 'feat/short' into pr/samgermain/6467

This commit is contained in:
Matthias
2022-02-28 20:07:19 +01:00
10 changed files with 290 additions and 107 deletions

View File

@@ -634,7 +634,7 @@ tc39 = BTContainer(data=[
[3, 5010, 5010, 4986, 5010, 6172, 0, 1],
[4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0]],
stop_loss=-0.01, roi={"0": 1}, profit_perc=0.002 * 5.0, use_sell_signal=True,
stop_loss=-0.05, roi={"0": 1}, profit_perc=0.002 * 5.0, use_sell_signal=True,
leverage=5.0,
trades=[BTrade(sell_reason=SellType.SELL_SIGNAL, open_tick=1, close_tick=4)]
)

View File

@@ -21,7 +21,6 @@ from freqtrade.data.converter import clean_ohlcv_dataframe
from freqtrade.data.dataprovider import DataProvider
from freqtrade.data.history import get_timerange
from freqtrade.enums import RunMode, SellType
from freqtrade.enums.tradingmode import TradingMode
from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.exchange.exchange import timeframe_to_next_date
from freqtrade.misc import get_strategy_run_id

View File

@@ -183,7 +183,7 @@ class StrategyTestV3(IStrategy):
current_profit: float, min_stake: float, max_stake: float, **kwargs):
if current_profit < -0.0075:
orders = trade.select_filled_orders('buy')
orders = trade.select_filled_orders(trade.enter_side)
return round(orders[0].cost, 0)
return None

View File

@@ -231,13 +231,13 @@ def test_dca_buying(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
assert len(Trade.get_trades().all()) == 1
trade = Trade.get_trades().first()
assert len(trade.orders) == 1
assert trade.stake_amount == 60
assert pytest.approx(trade.stake_amount) == 60
assert trade.open_rate == 2.0
# No adjustment
freqtrade.process()
trade = Trade.get_trades().first()
assert len(trade.orders) == 1
assert trade.stake_amount == 60
assert pytest.approx(trade.stake_amount) == 60
# Reduce bid amount
ticker_usdt_modif = ticker_usdt.return_value
@@ -266,6 +266,7 @@ def test_dca_buying(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
assert trade.amount == trade.orders[0].amount + trade.orders[1].amount
assert trade.nr_of_successful_buys == 2
assert trade.nr_of_successful_entries == 2
# Sell
patch_get_signal(freqtrade, enter_long=False, exit_long=True)
@@ -280,3 +281,75 @@ def test_dca_buying(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
assert trade.orders[2].amount == trade.amount
assert trade.nr_of_successful_buys == 2
assert trade.nr_of_successful_entries == 2
def test_dca_short(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
default_conf_usdt['position_adjustment_enable'] = True
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
fetch_ticker=ticker_usdt,
get_fee=fee,
amount_to_precision=lambda s, x, y: y,
price_to_precision=lambda s, x, y: y,
)
patch_get_signal(freqtrade, enter_long=False, enter_short=True)
freqtrade.enter_positions()
assert len(Trade.get_trades().all()) == 1
trade = Trade.get_trades().first()
assert len(trade.orders) == 1
assert pytest.approx(trade.stake_amount) == 60
assert trade.open_rate == 2.02
# No adjustment
freqtrade.process()
trade = Trade.get_trades().first()
assert len(trade.orders) == 1
assert pytest.approx(trade.stake_amount) == 60
# Reduce bid amount
ticker_usdt_modif = ticker_usdt.return_value
ticker_usdt_modif['ask'] = ticker_usdt_modif['ask'] * 1.015
ticker_usdt_modif['bid'] = ticker_usdt_modif['bid'] * 1.0125
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value=ticker_usdt_modif)
# additional buy order
freqtrade.process()
trade = Trade.get_trades().first()
assert len(trade.orders) == 2
for o in trade.orders:
assert o.status == "closed"
assert pytest.approx(trade.stake_amount) == 120
# Open-rate averaged between 2.0 and 2.0 * 1.015
assert trade.open_rate >= 2.02
assert trade.open_rate < 2.02 * 1.015
# No action - profit raised above 1% (the bar set in the strategy).
freqtrade.process()
trade = Trade.get_trades().first()
assert len(trade.orders) == 2
assert pytest.approx(trade.stake_amount) == 120
# assert trade.orders[0].amount == 30
assert trade.orders[1].amount == 60 / ticker_usdt_modif['ask']
assert trade.amount == trade.orders[0].amount + trade.orders[1].amount
assert trade.nr_of_successful_entries == 2
# Buy
patch_get_signal(freqtrade, enter_long=False, exit_short=True)
freqtrade.process()
trade = Trade.get_trades().first()
assert trade.is_open is False
# assert trade.orders[0].amount == 30
assert trade.orders[0].side == 'sell'
assert trade.orders[1].amount == 60 / ticker_usdt_modif['ask']
# Sold everything
assert trade.orders[-1].side == 'buy'
assert trade.orders[2].amount == trade.amount
assert trade.nr_of_successful_entries == 2
assert trade.nr_of_successful_exits == 1

View File

@@ -1749,6 +1749,67 @@ def test_stoploss_reinitialization(default_conf, fee):
assert trade_adj.initial_stop_loss_pct == -0.04
def test_stoploss_reinitialization_leverage(default_conf, fee):
init_db(default_conf['db_url'])
trade = Trade(
pair='ADA/USDT',
stake_amount=30.0,
fee_open=fee.return_value,
open_date=arrow.utcnow().shift(hours=-2).datetime,
amount=30.0,
fee_close=fee.return_value,
exchange='binance',
open_rate=1,
max_rate=1,
leverage=5.0,
)
trade.adjust_stop_loss(trade.open_rate, 0.1, True)
assert trade.stop_loss == 0.98
assert trade.stop_loss_pct == -0.1
assert trade.initial_stop_loss == 0.98
assert trade.initial_stop_loss_pct == -0.1
Trade.query.session.add(trade)
# Lower stoploss
Trade.stoploss_reinitialization(0.15)
trades = Trade.get_open_trades()
assert len(trades) == 1
trade_adj = trades[0]
assert trade_adj.stop_loss == 0.97
assert trade_adj.stop_loss_pct == -0.15
assert trade_adj.initial_stop_loss == 0.97
assert trade_adj.initial_stop_loss_pct == -0.15
# Raise stoploss
Trade.stoploss_reinitialization(0.05)
trades = Trade.get_open_trades()
assert len(trades) == 1
trade_adj = trades[0]
assert trade_adj.stop_loss == 0.99
assert trade_adj.stop_loss_pct == -0.05
assert trade_adj.initial_stop_loss == 0.99
assert trade_adj.initial_stop_loss_pct == -0.05
# Trailing stoploss (move stoplos up a bit)
trade.adjust_stop_loss(1.02, 0.05)
assert trade_adj.stop_loss == 1.0098
assert trade_adj.initial_stop_loss == 0.99
Trade.stoploss_reinitialization(0.05)
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 == 1.0098
assert trade_adj.stop_loss_pct == -0.05
assert trade_adj.initial_stop_loss == 0.99
assert trade_adj.initial_stop_loss_pct == -0.05
def test_stoploss_reinitialization_short(default_conf, fee):
init_db(default_conf['db_url'])
trade = Trade(
@@ -1762,50 +1823,50 @@ def test_stoploss_reinitialization_short(default_conf, fee):
open_rate=1,
max_rate=1,
is_short=True,
leverage=3.0,
leverage=5.0,
)
trade.adjust_stop_loss(trade.open_rate, -0.05, True)
assert trade.stop_loss == 1.05
assert trade.stop_loss_pct == 0.05
assert trade.initial_stop_loss == 1.05
assert trade.initial_stop_loss_pct == 0.05
trade.adjust_stop_loss(trade.open_rate, -0.1, True)
assert trade.stop_loss == 1.02
assert trade.stop_loss_pct == 0.1
assert trade.initial_stop_loss == 1.02
assert trade.initial_stop_loss_pct == 0.1
Trade.query.session.add(trade)
# Lower stoploss
Trade.stoploss_reinitialization(-0.06)
Trade.stoploss_reinitialization(-0.15)
trades = Trade.get_open_trades()
assert len(trades) == 1
trade_adj = trades[0]
assert trade_adj.stop_loss == 1.06
assert trade_adj.stop_loss_pct == 0.06
assert trade_adj.initial_stop_loss == 1.06
assert trade_adj.initial_stop_loss_pct == 0.06
assert trade_adj.stop_loss == 1.03
assert trade_adj.stop_loss_pct == 0.15
assert trade_adj.initial_stop_loss == 1.03
assert trade_adj.initial_stop_loss_pct == 0.15
# Raise stoploss
Trade.stoploss_reinitialization(-0.04)
Trade.stoploss_reinitialization(-0.05)
trades = Trade.get_open_trades()
assert len(trades) == 1
trade_adj = trades[0]
assert trade_adj.stop_loss == 1.04
assert trade_adj.stop_loss_pct == 0.04
assert trade_adj.initial_stop_loss == 1.04
assert trade_adj.initial_stop_loss_pct == 0.04
assert trade_adj.stop_loss == 1.01
assert trade_adj.stop_loss_pct == 0.05
assert trade_adj.initial_stop_loss == 1.01
assert trade_adj.initial_stop_loss_pct == 0.05
# Trailing stoploss
trade.adjust_stop_loss(0.98, -0.04)
assert trade_adj.stop_loss == 1.0192
assert trade_adj.initial_stop_loss == 1.04
Trade.stoploss_reinitialization(-0.04)
trade.adjust_stop_loss(0.98, -0.05)
assert trade_adj.stop_loss == 0.9898
assert trade_adj.initial_stop_loss == 1.01
Trade.stoploss_reinitialization(-0.05)
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 == 1.0192
assert trade_adj.stop_loss_pct == 0.04
assert trade_adj.initial_stop_loss == 1.04
assert trade_adj.initial_stop_loss_pct == 0.04
assert trade_adj.stop_loss == 0.9898
assert trade_adj.stop_loss_pct == 0.05
assert trade_adj.initial_stop_loss == 1.01
assert trade_adj.initial_stop_loss_pct == 0.05
# Stoploss can't go above liquidation price
trade_adj.set_isolated_liq(1.0)
trade.adjust_stop_loss(0.97, -0.04)
assert trade_adj.stop_loss == 1.0
assert trade_adj.stop_loss == 1.0
trade_adj.set_isolated_liq(0.985)
trade.adjust_stop_loss(0.9799, -0.05)
assert trade_adj.stop_loss == 0.985
assert trade_adj.stop_loss == 0.985
def test_update_fee(fee):
@@ -2310,13 +2371,16 @@ def test_recalc_trade_from_orders(fee):
assert pytest.approx(trade.open_trade_value) == o1_trade_val + o2_trade_val + o3_trade_val
def test_recalc_trade_from_orders_ignores_bad_orders(fee):
@pytest.mark.parametrize('is_short', [True, False])
def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
o1_amount = 100
o1_rate = 1
o1_cost = o1_amount * o1_rate
o1_fee_cost = o1_cost * fee.return_value
o1_trade_val = o1_cost + o1_fee_cost
o1_trade_val = o1_cost - o1_fee_cost if is_short else o1_cost + o1_fee_cost
enter_side = "sell" if is_short else "buy"
exit_side = "buy" if is_short else "sell"
trade = Trade(
pair='ADA/USDT',
@@ -2328,17 +2392,18 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
exchange='binance',
open_rate=o1_rate,
max_rate=o1_rate,
is_short=is_short,
)
trade.update_fee(o1_fee_cost, 'BNB', fee.return_value, 'buy')
trade.update_fee(o1_fee_cost, 'BNB', fee.return_value, enter_side)
# Check with 1 order
order1 = Order(
ft_order_side='buy',
ft_order_side=enter_side,
ft_pair=trade.pair,
ft_is_open=False,
status="closed",
symbol=trade.pair,
order_type="market",
side="buy",
side=enter_side,
price=o1_rate,
average=o1_rate,
filled=o1_amount,
@@ -2356,16 +2421,16 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
assert trade.open_rate == o1_rate
assert trade.fee_open_cost == o1_fee_cost
assert trade.open_trade_value == o1_trade_val
assert trade.nr_of_successful_buys == 1
assert trade.nr_of_successful_entries == 1
order2 = Order(
ft_order_side='buy',
ft_order_side=enter_side,
ft_pair=trade.pair,
ft_is_open=True,
status="open",
symbol=trade.pair,
order_type="market",
side="buy",
side=enter_side,
price=o1_rate,
average=o1_rate,
filled=o1_amount,
@@ -2383,17 +2448,17 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
assert trade.open_rate == o1_rate
assert trade.fee_open_cost == o1_fee_cost
assert trade.open_trade_value == o1_trade_val
assert trade.nr_of_successful_buys == 1
assert trade.nr_of_successful_entries == 1
# Let's try with some other orders
order3 = Order(
ft_order_side='buy',
ft_order_side=enter_side,
ft_pair=trade.pair,
ft_is_open=False,
status="cancelled",
symbol=trade.pair,
order_type="market",
side="buy",
side=enter_side,
price=1,
average=2,
filled=0,
@@ -2411,16 +2476,16 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
assert trade.open_rate == o1_rate
assert trade.fee_open_cost == o1_fee_cost
assert trade.open_trade_value == o1_trade_val
assert trade.nr_of_successful_buys == 1
assert trade.nr_of_successful_entries == 1
order4 = Order(
ft_order_side='buy',
ft_order_side=enter_side,
ft_pair=trade.pair,
ft_is_open=False,
status="closed",
symbol=trade.pair,
order_type="market",
side="buy",
side=enter_side,
price=o1_rate,
average=o1_rate,
filled=o1_amount,
@@ -2438,17 +2503,17 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
assert trade.open_rate == o1_rate
assert trade.fee_open_cost == 2 * o1_fee_cost
assert trade.open_trade_value == 2 * o1_trade_val
assert trade.nr_of_successful_buys == 2
assert trade.nr_of_successful_entries == 2
# Just to make sure sell orders are ignored, let's calculate one more time.
# Just to make sure exit orders are ignored, let's calculate one more time.
sell1 = Order(
ft_order_side='sell',
ft_order_side=exit_side,
ft_pair=trade.pair,
ft_is_open=False,
status="closed",
symbol=trade.pair,
order_type="market",
side="sell",
side=exit_side,
price=4,
average=3,
filled=2,
@@ -2465,16 +2530,17 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
assert trade.open_rate == o1_rate
assert trade.fee_open_cost == 2 * o1_fee_cost
assert trade.open_trade_value == 2 * o1_trade_val
assert trade.nr_of_successful_buys == 2
assert trade.nr_of_successful_entries == 2
# Check with 1 order
order_noavg = Order(
ft_order_side='buy',
ft_order_side=enter_side,
ft_pair=trade.pair,
ft_is_open=False,
status="closed",
symbol=trade.pair,
order_type="market",
side="buy",
side=enter_side,
price=o1_rate,
average=None,
filled=o1_amount,
@@ -2492,7 +2558,7 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
assert trade.open_rate == o1_rate
assert trade.fee_open_cost == 3 * o1_fee_cost
assert trade.open_trade_value == 3 * o1_trade_val
assert trade.nr_of_successful_buys == 3
assert trade.nr_of_successful_entries == 3
@pytest.mark.usefixtures("init_persistence")