diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 875e1202a..d2df5d512 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -319,7 +319,7 @@ class LocalTrade(): for key in kwargs: setattr(self, key, kwargs[key]) if self.isolated_liq: - self.set_isolated_liq(self.isolated_liq) + self.set_isolated_liq(isolated_liq=self.isolated_liq) self.recalc_open_trade_value() def _set_stop_loss(self, stop_loss: float, percent: float): @@ -351,7 +351,10 @@ class LocalTrade(): Assures stop_loss is not passed the liquidation price """ - isolated_liq: float == self.liq_formula(trading_mode=self.trading_mode, **k) + if k['isolated_liq']: + isolated_liq: float = k['isolated_liq'] + else: + isolated_liq: float == self.liq_formula(trading_mode=self.trading_mode, **k) if self.stop_loss is not None: if self.is_short: @@ -689,12 +692,13 @@ class LocalTrade(): return 0.0 amount = Decimal(self.amount) + trading_mode = self.trading_mode or TradingMode.SPOT - if self.trading_mode == TradingMode.SPOT: + if trading_mode == TradingMode.SPOT: return float(self._calc_base_close(amount, rate, fee)) - elif (self.trading_mode == TradingMode.CROSS_MARGIN or - self.trading_mode == TradingMode.ISOLATED_MARGIN): + elif (trading_mode == TradingMode.CROSS_MARGIN or + trading_mode == TradingMode.ISOLATED_MARGIN): interest = self.calculate_interest(interest_rate) @@ -705,8 +709,8 @@ class LocalTrade(): # Currency already owned for longs, no need to purchase return float(self._calc_base_close(amount, rate, fee) - interest) - elif (self.trading_mode == TradingMode.CROSS_FUTURES or - self.trading_mode == TradingMode.ISOLATED_FUTURES): + elif (trading_mode == TradingMode.CROSS_FUTURES or + trading_mode == TradingMode.ISOLATED_FUTURES): # TODO-lev: implement raise OperationalException("Futures is not yet available using freqtrade") else: @@ -924,7 +928,10 @@ class Trade(_DECL_BASE, LocalTrade): interest_rate = Column(Float, nullable=False, default=0.0) isolated_liq = Column(Float, nullable=True) is_short = Column(Boolean, nullable=False, default=False) + + trading_mode = Column(Enum(TradingMode), default=TradingMode.SPOT) interest_mode = Column(Enum(InterestMode), nullable=True) + liq_formula = Column(Enum(LiqFormula), nullable=True) # End of margin trading properties def __init__(self, **kwargs): diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 4a9407884..3455cc96e 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -11,7 +11,7 @@ import pytest from sqlalchemy import create_engine, inspect, text from freqtrade import constants -from freqtrade.enums import InterestMode +from freqtrade.enums import InterestMode, TradingMode from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.persistence import LocalTrade, Order, Trade, clean_dry_run_db, init_db from tests.conftest import create_mock_trades, create_mock_trades_with_leverage, log_has, log_has_re @@ -91,7 +91,7 @@ def test_enter_exit_side(fee): @pytest.mark.usefixtures("init_persistence") -def test__set_stop_loss_isolated_liq(fee): +def test_set_stop_loss_isolated_liq(fee): trade = Trade( id=2, pair='ADA/USDT', @@ -106,7 +106,7 @@ def test__set_stop_loss_isolated_liq(fee): is_short=False, leverage=2.0 ) - trade.set_isolated_liq(0.09) + trade.set_isolated_liq(isolated_liq=0.09) assert trade.isolated_liq == 0.09 assert trade.stop_loss == 0.09 assert trade.initial_stop_loss == 0.09 @@ -116,12 +116,12 @@ def test__set_stop_loss_isolated_liq(fee): assert trade.stop_loss == 0.1 assert trade.initial_stop_loss == 0.09 - trade.set_isolated_liq(0.08) + trade.set_isolated_liq(isolated_liq=0.08) assert trade.isolated_liq == 0.08 assert trade.stop_loss == 0.1 assert trade.initial_stop_loss == 0.09 - trade.set_isolated_liq(0.11) + trade.set_isolated_liq(isolated_liq=0.11) assert trade.isolated_liq == 0.11 assert trade.stop_loss == 0.11 assert trade.initial_stop_loss == 0.09 @@ -145,7 +145,7 @@ def test__set_stop_loss_isolated_liq(fee): trade.stop_loss = None trade.initial_stop_loss = None - trade.set_isolated_liq(0.09) + trade.set_isolated_liq(isolated_liq=0.09) assert trade.isolated_liq == 0.09 assert trade.stop_loss == 0.09 assert trade.initial_stop_loss == 0.09 @@ -155,12 +155,12 @@ def test__set_stop_loss_isolated_liq(fee): assert trade.stop_loss == 0.08 assert trade.initial_stop_loss == 0.09 - trade.set_isolated_liq(0.1) + trade.set_isolated_liq(isolated_liq=0.1) assert trade.isolated_liq == 0.1 assert trade.stop_loss == 0.08 assert trade.initial_stop_loss == 0.09 - trade.set_isolated_liq(0.07) + trade.set_isolated_liq(isolated_liq=0.07) assert trade.isolated_liq == 0.07 assert trade.stop_loss == 0.07 assert trade.initial_stop_loss == 0.09 @@ -237,7 +237,8 @@ def test_interest(market_buy_order_usdt, fee): exchange='kraken', leverage=3.0, interest_rate=0.0005, - interest_mode=InterestMode.HOURSPERDAY + interest_mode=InterestMode.HOURSPERDAY, + trading_mode=TradingMode.CROSS_MARGIN ) # 10min, 3x leverage @@ -506,7 +507,7 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca open_date=arrow.utcnow().datetime, fee_open=fee.return_value, fee_close=fee.return_value, - exchange='binance', + exchange='binance' ) assert trade.open_order_id is None assert trade.close_profit is None @@ -550,7 +551,8 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca is_short=True, leverage=3.0, interest_rate=0.0005, - interest_mode=InterestMode.HOURSPERDAY + interest_mode=InterestMode.HOURSPERDAY, + trading_mode=TradingMode.CROSS_MARGIN ) trade.open_order_id = 'something' trade.update(limit_sell_order_usdt) @@ -642,7 +644,9 @@ def test_calc_open_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt assert isclose(trade.calc_close_trade_value(), 65.835) assert trade.calc_profit() == 5.685 assert trade.calc_profit_ratio() == round(0.0945137157107232, 8) + # 3x leverage, binance + trade.trading_mode = TradingMode.ISOLATED_MARGIN trade.leverage = 3 trade.interest_mode = InterestMode.HOURSPERDAY assert trade._calc_open_trade_value() == 60.15 @@ -801,12 +805,19 @@ def test_calc_open_trade_value(limit_buy_order_usdt, fee): # Get the open rate price with the standard fee rate assert trade._calc_open_trade_value() == 60.15 + + # Margin + trade.trading_mode = TradingMode.CROSS_MARGIN trade.is_short = True trade.recalc_open_trade_value() assert trade._calc_open_trade_value() == 59.85 + + # 3x short margin leverage trade.leverage = 3 trade.interest_mode = InterestMode.HOURSPERDAY assert trade._calc_open_trade_value() == 59.85 + + # 3x long margin leverage trade.is_short = False trade.recalc_open_trade_value() assert trade._calc_open_trade_value() == 60.15 @@ -844,6 +855,7 @@ def test_calc_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt, fee assert trade.calc_close_trade_value(fee=0.005) == 65.67 # 3x leverage binance + trade.trading_mode = TradingMode.CROSS_MARGIN trade.leverage = 3.0 assert round(trade.calc_close_trade_value(rate=2.5), 8) == 74.81166667 assert round(trade.calc_close_trade_value(rate=2.5, fee=0.003), 8) == 74.77416667 @@ -1044,6 +1056,8 @@ def test_calc_profit(limit_buy_order_usdt, limit_sell_order_usdt, fee): trade.open_trade_value = 0.0 trade.open_trade_value = trade._calc_open_trade_value() + # Margin + trade.trading_mode = TradingMode.CROSS_MARGIN # 3x leverage, long ################################################### trade.leverage = 3.0 # Higher than open rate - 2.1 quote @@ -1147,6 +1161,8 @@ def test_calc_profit_ratio(limit_buy_order_usdt, limit_sell_order_usdt, fee): assert trade.calc_profit_ratio(fee=0.003) == 0.0 trade.open_trade_value = trade._calc_open_trade_value() + # Margin + trade.trading_mode = TradingMode.CROSS_MARGIN # 3x leverage, long ################################################### trade.leverage = 3.0 # 2.1 quote - Higher than open rate @@ -1579,7 +1595,7 @@ def test_adjust_stop_loss_short(fee): assert trade.initial_stop_loss == 1.05 assert trade.initial_stop_loss_pct == 0.05 assert trade.stop_loss_pct == 0.1 - trade.set_isolated_liq(0.63) + trade.set_isolated_liq(isolated_liq=0.63) trade.adjust_stop_loss(0.59, -0.1) assert trade.stop_loss == 0.63 assert trade.isolated_liq == 0.63 @@ -1899,7 +1915,7 @@ def test_stoploss_reinitialization_short(default_conf, fee): assert trade_adj.initial_stop_loss == 1.04 assert trade_adj.initial_stop_loss_pct == 0.04 # Stoploss can't go above liquidation price - trade_adj.set_isolated_liq(1.0) + trade_adj.set_isolated_liq(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