Merge branch 'feat/short' into pr/samgermain/6467
This commit is contained in:
@@ -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)]
|
||||
)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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")
|
||||
|
Reference in New Issue
Block a user