integrated liqformula into persistence/models, addjusted calc_close_value to change based on trading mode

This commit is contained in:
Sam Germain 2021-08-01 20:45:07 -06:00
parent a30926005c
commit 52e6de27b6

View File

@ -14,7 +14,7 @@ from sqlalchemy.pool import StaticPool
from sqlalchemy.sql.schema import UniqueConstraint from sqlalchemy.sql.schema import UniqueConstraint
from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.constants import DATETIME_PRINT_FORMAT
from freqtrade.enums import InterestMode, SellType from freqtrade.enums import InterestMode, LiqFormula, SellType, TradingMode
from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.misc import safe_value_fallback from freqtrade.misc import safe_value_fallback
from freqtrade.persistence.migrations import check_migrate from freqtrade.persistence.migrations import check_migrate
@ -264,12 +264,15 @@ class LocalTrade():
buy_tag: Optional[str] = None buy_tag: Optional[str] = None
timeframe: Optional[int] = None timeframe: Optional[int] = None
# Margin trading properties # Leverage trading properties
interest_rate: float = 0.0 interest_rate: float = 0.0
isolated_liq: Optional[float] = None isolated_liq: Optional[float] = None
is_short: bool = False is_short: bool = False
leverage: float = 1.0 leverage: float = 1.0
trading_mode: TradingMode = TradingMode.SPOT
interest_mode: InterestMode = InterestMode.NONE interest_mode: InterestMode = InterestMode.NONE
liq_formula: LiqFormula = LiqFormula.NONE
@property @property
def has_no_leverage(self) -> bool: def has_no_leverage(self) -> bool:
@ -342,11 +345,14 @@ class LocalTrade():
self.stop_loss_pct = -1 * abs(percent) self.stop_loss_pct = -1 * abs(percent)
self.stoploss_last_update = datetime.utcnow() self.stoploss_last_update = datetime.utcnow()
def set_isolated_liq(self, isolated_liq: float): def set_isolated_liq(self, **k):
""" """
Method you should use to set self.liquidation price. Method you should use to set self.liquidation price.
Assures stop_loss is not passed the liquidation price Assures stop_loss is not passed the liquidation price
""" """
isolated_liq: float == self.liq_formula(trading_mode=self.trading_mode, **k)
if self.stop_loss is not None: if self.stop_loss is not None:
if self.is_short: if self.is_short:
self.stop_loss = min(self.stop_loss, isolated_liq) self.stop_loss = min(self.stop_loss, isolated_liq)
@ -651,8 +657,20 @@ class LocalTrade():
rate = Decimal(interest_rate or self.interest_rate) rate = Decimal(interest_rate or self.interest_rate)
borrowed = Decimal(self.borrowed) borrowed = Decimal(self.borrowed)
# TODO-lev: Pass trading mode to interest_mode maybe
return self.interest_mode(borrowed=borrowed, rate=rate, hours=hours) return self.interest_mode(borrowed=borrowed, rate=rate, hours=hours)
def _calc_base_close(self, amount: Decimal, rate: Optional[float] = None,
fee: Optional[float] = None) -> Decimal:
close_trade = Decimal(amount) * Decimal(rate or self.close_rate) # type: ignore
fees = close_trade * Decimal(fee or self.fee_close)
if self.is_short:
return close_trade + fees
else:
return close_trade - fees
def calc_close_trade_value(self, rate: Optional[float] = None, def calc_close_trade_value(self, rate: Optional[float] = None,
fee: Optional[float] = None, fee: Optional[float] = None,
interest_rate: Optional[float] = None) -> float: interest_rate: Optional[float] = None) -> float:
@ -666,23 +684,34 @@ class LocalTrade():
If interest_rate is not set self.interest_rate will be used If interest_rate is not set self.interest_rate will be used
:return: Price in BTC of the open trade :return: Price in BTC of the open trade
""" """
if rate is None and not self.close_rate: if rate is None and not self.close_rate:
return 0.0 return 0.0
interest = self.calculate_interest(interest_rate) amount = Decimal(self.amount)
if self.is_short:
amount = Decimal(self.amount) + Decimal(interest)
else:
# Currency already owned for longs, no need to purchase
amount = Decimal(self.amount)
close_trade = Decimal(amount) * Decimal(rate or self.close_rate) # type: ignore if self.trading_mode == TradingMode.SPOT:
fees = close_trade * Decimal(fee or self.fee_close) return float(self._calc_base_close(amount, rate, fee))
if self.is_short: elif (self.trading_mode == TradingMode.CROSS_MARGIN or
return float(close_trade + fees) self.trading_mode == TradingMode.ISOLATED_MARGIN):
interest = self.calculate_interest(interest_rate)
if self.is_short:
amount = amount + interest
return float(self._calc_base_close(amount, rate, fee))
else:
# 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):
# TODO-lev: implement
raise OperationalException("Futures is not yet available using freqtrade")
else: else:
return float(close_trade - fees - interest) raise OperationalException(
f"{self.trading_mode.value} trading is not yet available using freqtrade")
def calc_profit(self, rate: Optional[float] = None, def calc_profit(self, rate: Optional[float] = None,
fee: Optional[float] = None, fee: Optional[float] = None,