merge with feat/short interest changes

This commit is contained in:
Sam Germain 2021-08-11 01:55:31 -06:00
commit 8b87620cbc
9 changed files with 172 additions and 136 deletions

View File

@ -1,7 +1,6 @@
# flake8: noqa: F401 # flake8: noqa: F401
from freqtrade.enums.backteststate import BacktestState from freqtrade.enums.backteststate import BacktestState
from freqtrade.enums.collateral import Collateral from freqtrade.enums.collateral import Collateral
from freqtrade.enums.interestmode import InterestMode
from freqtrade.enums.rpcmessagetype import RPCMessageType from freqtrade.enums.rpcmessagetype import RPCMessageType
from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode
from freqtrade.enums.selltype import SellType from freqtrade.enums.selltype import SellType

View File

@ -1,28 +0,0 @@
from decimal import Decimal
from enum import Enum
from math import ceil
from freqtrade.exceptions import OperationalException
one = Decimal(1.0)
four = Decimal(4.0)
twenty_four = Decimal(24.0)
class InterestMode(Enum):
"""Equations to calculate interest"""
HOURSPERDAY = "HOURSPERDAY"
HOURSPER4 = "HOURSPER4" # Hours per 4 hour segment
NONE = "NONE"
def __call__(self, borrowed: Decimal, rate: Decimal, hours: Decimal):
if self.name == "HOURSPERDAY":
return borrowed * rate * ceil(hours)/twenty_four
elif self.name == "HOURSPER4":
# Rounded based on https://kraken-fees-calculator.github.io/
return borrowed * rate * (1+ceil(hours/four))
else:
raise OperationalException("Leverage not available on this exchange with freqtrade")

View File

@ -1,2 +1,3 @@
# flake8: noqa: F401 # flake8: noqa: F401
from freqtrade.leverage.interest import interest
from freqtrade.leverage.liquidation_price import liquidation_price from freqtrade.leverage.liquidation_price import liquidation_price

View File

@ -0,0 +1,42 @@
from decimal import Decimal
from math import ceil
from freqtrade.exceptions import OperationalException
one = Decimal(1.0)
four = Decimal(4.0)
twenty_four = Decimal(24.0)
def interest(
exchange_name: str,
borrowed: Decimal,
rate: Decimal,
hours: Decimal
) -> Decimal:
"""
Equation to calculate interest on margin trades
:param exchange_name: The exchanged being trading on
:param borrowed: The amount of currency being borrowed
:param rate: The rate of interest
:param hours: The time in hours that the currency has been borrowed for
Raises:
OperationalException: Raised if freqtrade does
not support margin trading for this exchange
Returns: The amount of interest owed (currency matches borrowed)
"""
exchange_name = exchange_name.lower()
if exchange_name == "binance":
return borrowed * rate * ceil(hours)/twenty_four
elif exchange_name == "kraken":
# Rounded based on https://kraken-fees-calculator.github.io/
return borrowed * rate * (one+ceil(hours/four))
elif exchange_name == "ftx":
# TODO-lev: Add FTX interest formula
raise OperationalException(f"Leverage not available on {exchange_name} with freqtrade")
else:
raise OperationalException(f"Leverage not available on {exchange_name} with freqtrade")

View File

@ -54,7 +54,6 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
isolated_liq = get_column_def(cols, 'isolated_liq', 'null') isolated_liq = get_column_def(cols, 'isolated_liq', 'null')
# sqlite does not support literals for booleans # sqlite does not support literals for booleans
is_short = get_column_def(cols, 'is_short', '0') is_short = get_column_def(cols, 'is_short', '0')
interest_mode = get_column_def(cols, 'interest_mode', 'null')
# If ticker-interval existed use that, else null. # If ticker-interval existed use that, else null.
if has_column(cols, 'ticker_interval'): if has_column(cols, 'ticker_interval'):
timeframe = get_column_def(cols, 'timeframe', 'ticker_interval') timeframe = get_column_def(cols, 'timeframe', 'ticker_interval')
@ -66,7 +65,7 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
close_profit_abs = get_column_def( close_profit_abs = get_column_def(
cols, 'close_profit_abs', cols, 'close_profit_abs',
f"(amount * close_rate * (1 - {fee_close})) - {open_trade_value}") f"(amount * close_rate * (1 - {fee_close})) - {open_trade_value}")
# TODO-mg: update to exit order status # TODO-lev: update to exit order status
sell_order_status = get_column_def(cols, 'sell_order_status', 'null') sell_order_status = get_column_def(cols, 'sell_order_status', 'null')
amount_requested = get_column_def(cols, 'amount_requested', 'amount') amount_requested = get_column_def(cols, 'amount_requested', 'amount')
@ -92,7 +91,7 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
stoploss_order_id, stoploss_last_update, stoploss_order_id, stoploss_last_update,
max_rate, min_rate, sell_reason, sell_order_status, strategy, buy_tag, max_rate, min_rate, sell_reason, sell_order_status, strategy, buy_tag,
timeframe, open_trade_value, close_profit_abs, timeframe, open_trade_value, close_profit_abs,
leverage, interest_rate, isolated_liq, is_short, interest_mode leverage, interest_rate, isolated_liq, is_short
) )
select id, lower(exchange), pair, select id, lower(exchange), pair,
is_open, {fee_open} fee_open, {fee_open_cost} fee_open_cost, is_open, {fee_open} fee_open, {fee_open_cost} fee_open_cost,
@ -110,8 +109,7 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
{strategy} strategy, {buy_tag} buy_tag, {timeframe} timeframe, {strategy} strategy, {buy_tag} buy_tag, {timeframe} timeframe,
{open_trade_value} open_trade_value, {close_profit_abs} close_profit_abs, {open_trade_value} open_trade_value, {close_profit_abs} close_profit_abs,
{leverage} leverage, {interest_rate} interest_rate, {leverage} leverage, {interest_rate} interest_rate,
{isolated_liq} isolated_liq, {is_short} is_short, {isolated_liq} isolated_liq, {is_short} is_short
{interest_mode} interest_mode
from {table_back_name} from {table_back_name}
""")) """))

View File

@ -6,7 +6,7 @@ from datetime import datetime, timezone
from decimal import Decimal from decimal import Decimal
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String, from sqlalchemy import (Boolean, Column, DateTime, Float, ForeignKey, Integer, String,
create_engine, desc, func, inspect) create_engine, desc, func, inspect)
from sqlalchemy.exc import NoSuchModuleError from sqlalchemy.exc import NoSuchModuleError
from sqlalchemy.orm import Query, declarative_base, relationship, scoped_session, sessionmaker from sqlalchemy.orm import Query, declarative_base, relationship, scoped_session, sessionmaker
@ -14,9 +14,9 @@ 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 SellType
from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.leverage import liquidation_price from freqtrade.leverage import interest, liquidation_price
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
@ -265,12 +265,13 @@ class LocalTrade():
buy_tag: Optional[str] = None buy_tag: Optional[str] = None
timeframe: Optional[int] = None timeframe: Optional[int] = None
# Leverage trading properties
is_short: bool = False
isolated_liq: Optional[float] = None
leverage: float = 1.0
# Margin trading properties # Margin trading properties
interest_rate: float = 0.0 interest_rate: float = 0.0
isolated_liq: Optional[float] = None
is_short: bool = False
leverage: float = 1.0
interest_mode: InterestMode = InterestMode.NONE
@property @property
def has_no_leverage(self) -> bool: def has_no_leverage(self) -> bool:
@ -480,12 +481,12 @@ class LocalTrade():
if self.is_short: if self.is_short:
new_loss = float(current_price * (1 + abs(stoploss))) new_loss = float(current_price * (1 + abs(stoploss)))
# If trading on margin, don't set the stoploss below the liquidation price # If trading with leverage, don't set the stoploss below the liquidation price
if self.isolated_liq: if self.isolated_liq:
new_loss = min(self.isolated_liq, new_loss) new_loss = min(self.isolated_liq, new_loss)
else: else:
new_loss = float(current_price * (1 - abs(stoploss))) new_loss = float(current_price * (1 - abs(stoploss)))
# If trading on margin, don't set the stoploss below the liquidation price # If trading with leverage, don't set the stoploss below the liquidation price
if self.isolated_liq: if self.isolated_liq:
new_loss = max(self.isolated_liq, new_loss) new_loss = max(self.isolated_liq, new_loss)
@ -506,7 +507,8 @@ class LocalTrade():
lower_stop = new_loss < self.stop_loss lower_stop = new_loss < self.stop_loss
# stop losses only walk up, never down!, # stop losses only walk up, never down!,
# ? But adding more to a margin account would create a lower liquidation price, # TODO-lev
# ? But adding more to a leveraged trade would create a lower liquidation price,
# ? decreasing the minimum stoploss # ? decreasing the minimum stoploss
if (higher_stop and not self.is_short) or (lower_stop and self.is_short): if (higher_stop and not self.is_short) or (lower_stop and self.is_short):
logger.debug(f"{self.pair} - Adjusting stoploss...") logger.debug(f"{self.pair} - Adjusting stoploss...")
@ -554,10 +556,11 @@ class LocalTrade():
elif order_type in ('market', 'limit') and self.exit_side == order['side']: elif order_type in ('market', 'limit') and self.exit_side == order['side']:
if self.is_open: if self.is_open:
payment = "BUY" if self.is_short else "SELL" payment = "BUY" if self.is_short else "SELL"
# TODO-mg: On shorts, you buy a little bit more than the amount (amount + interest) # TODO-lev: On shorts, you buy a little bit more than the amount (amount + interest)
# This wll only print the original amount # This wll only print the original amount
logger.info(f'{order_type.upper()}_{payment} has been fulfilled for {self}.') logger.info(f'{order_type.upper()}_{payment} has been fulfilled for {self}.')
self.close(safe_value_fallback(order, 'average', 'price')) # TODO-mg: Double check this # TODO-lev: Double check this
self.close(safe_value_fallback(order, 'average', 'price'))
elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'): elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'):
self.stoploss_order_id = None self.stoploss_order_id = None
self.close_rate_requested = self.stop_loss self.close_rate_requested = self.stop_loss
@ -659,7 +662,7 @@ 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)
return self.interest_mode(borrowed=borrowed, rate=rate, hours=hours) return interest(exchange_name=self.exchange, borrowed=borrowed, rate=rate, hours=hours)
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,
@ -892,19 +895,19 @@ class Trade(_DECL_BASE, LocalTrade):
max_rate = Column(Float, nullable=True, default=0.0) max_rate = Column(Float, nullable=True, default=0.0)
# Lowest price reached # Lowest price reached
min_rate = Column(Float, nullable=True) min_rate = Column(Float, nullable=True)
sell_reason = Column(String(100), nullable=True) # TODO-mg: Change to close_reason sell_reason = Column(String(100), nullable=True) # TODO-lev: Change to close_reason
sell_order_status = Column(String(100), nullable=True) # TODO-mg: Change to close_order_status sell_order_status = Column(String(100), nullable=True) # TODO-lev: Change to close_order_status
strategy = Column(String(100), nullable=True) strategy = Column(String(100), nullable=True)
buy_tag = Column(String(100), nullable=True) buy_tag = Column(String(100), nullable=True)
timeframe = Column(Integer, nullable=True) timeframe = Column(Integer, nullable=True)
# Margin trading properties # Leverage trading properties
leverage = Column(Float, nullable=True, default=1.0) leverage = Column(Float, nullable=True, default=1.0)
interest_rate = Column(Float, nullable=False, default=0.0)
isolated_liq = Column(Float, nullable=True)
is_short = Column(Boolean, nullable=False, default=False) is_short = Column(Boolean, nullable=False, default=False)
interest_mode = Column(Enum(InterestMode), nullable=True) isolated_liq = Column(Float, nullable=True)
# End of margin trading properties
# Margin Trading Properties
interest_rate = Column(Float, nullable=False, default=0.0)
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)

View File

@ -1,6 +1,5 @@
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from freqtrade.enums import InterestMode
from freqtrade.persistence.models import Order, Trade from freqtrade.persistence.models import Order, Trade
@ -380,11 +379,10 @@ def short_trade(fee):
open_order_id='dry_run_exit_short_12345', open_order_id='dry_run_exit_short_12345',
strategy='DefaultStrategy', strategy='DefaultStrategy',
timeframe=5, timeframe=5,
sell_reason='sell_signal', # TODO-mg: Update to exit/close reason sell_reason='sell_signal', # TODO-lev: Update to exit/close reason
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
# close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), # close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
is_short=True, is_short=True
interest_mode=InterestMode.HOURSPERDAY
) )
o = Order.parse_from_ccxt_object(short_order(), 'ETC/BTC', 'sell') o = Order.parse_from_ccxt_object(short_order(), 'ETC/BTC', 'sell')
trade.orders.append(o) trade.orders.append(o)
@ -470,11 +468,10 @@ def leverage_trade(fee):
open_order_id='dry_run_leverage_buy_12368', open_order_id='dry_run_leverage_buy_12368',
strategy='DefaultStrategy', strategy='DefaultStrategy',
timeframe=5, timeframe=5,
sell_reason='sell_signal', # TODO-mg: Update to exit/close reason sell_reason='sell_signal', # TODO-lev: Update to exit/close reason
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=300), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=300),
close_date=datetime.now(tz=timezone.utc), close_date=datetime.now(tz=timezone.utc),
interest_rate=0.0005, interest_rate=0.0005
interest_mode=InterestMode.HOURSPER4
) )
o = Order.parse_from_ccxt_object(leverage_order(), 'DOGE/BTC', 'sell') o = Order.parse_from_ccxt_object(leverage_order(), 'DOGE/BTC', 'sell')
trade.orders.append(o) trade.orders.append(o)

View File

@ -1,7 +1,10 @@
# from decimal import Decimal from decimal import Decimal
from math import isclose
import pytest
from freqtrade.enums import Collateral, TradingMode from freqtrade.enums import Collateral, TradingMode
from freqtrade.leverage import liquidation_price from freqtrade.leverage import interest, liquidation_price
# from freqtrade.exceptions import OperationalException # from freqtrade.exceptions import OperationalException
@ -87,3 +90,34 @@ def test_liquidation_price():
# liquidation_price(ftx, trading_mode=futures, collateral=isolated) # liquidation_price(ftx, trading_mode=futures, collateral=isolated)
# assert exception thrown #TODO-lev: Check that exception is thrown # assert exception thrown #TODO-lev: Check that exception is thrown
ten_mins = Decimal(1/6)
five_hours = Decimal(5.0)
twentyfive_hours = Decimal(25.0)
@pytest.mark.parametrize('exchange,interest_rate,hours,expected', [
('binance', 0.0005, ten_mins, 0.00125),
('binance', 0.00025, ten_mins, 0.000625),
('binance', 0.00025, five_hours, 0.003125),
('binance', 0.00025, twentyfive_hours, 0.015625),
# Kraken
('kraken', 0.0005, ten_mins, 0.06),
('kraken', 0.00025, ten_mins, 0.03),
('kraken', 0.00025, five_hours, 0.045),
('kraken', 0.00025, twentyfive_hours, 0.12),
# FTX
# TODO-lev: - implement FTX tests
# ('ftx', Decimal(0.0005), ten_mins, 0.06),
# ('ftx', Decimal(0.0005), five_hours, 0.045),
])
def test_interest(exchange, interest_rate, hours, expected):
borrowed = Decimal(60.0)
assert isclose(interest(
exchange_name=exchange,
borrowed=borrowed,
rate=Decimal(interest_rate),
hours=hours
), expected)

View File

@ -11,7 +11,6 @@ import pytest
from sqlalchemy import create_engine, inspect, text from sqlalchemy import create_engine, inspect, text
from freqtrade import constants from freqtrade import constants
from freqtrade.enums import InterestMode
from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.persistence import LocalTrade, Order, Trade, clean_dry_run_db, init_db 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 from tests.conftest import create_mock_trades, create_mock_trades_with_leverage, log_has, log_has_re
@ -237,23 +236,22 @@ def test_interest(market_buy_order_usdt, fee):
exchange='binance', exchange='binance',
leverage=3.0, leverage=3.0,
interest_rate=0.0005, interest_rate=0.0005,
interest_mode=InterestMode.HOURSPERDAY
) )
# 10min, 3x leverage # 10min, 3x leverage
# binance # binance
assert round(float(trade.calculate_interest()), 8) == round(0.0008333333333333334, 8) assert round(float(trade.calculate_interest()), 8) == round(0.0008333333333333334, 8)
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert float(trade.calculate_interest()) == 0.040 assert float(trade.calculate_interest()) == 0.040
# Short # Short
trade.is_short = True trade.is_short = True
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# binace # binace
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert float(trade.calculate_interest()) == 0.000625 assert float(trade.calculate_interest()) == 0.000625
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert isclose(float(trade.calculate_interest()), 0.030) assert isclose(float(trade.calculate_interest()), 0.030)
# 5hr, long # 5hr, long
@ -261,40 +259,40 @@ def test_interest(market_buy_order_usdt, fee):
trade.is_short = False trade.is_short = False
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# binance # binance
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert round(float(trade.calculate_interest()), 8) == round(0.004166666666666667, 8) assert round(float(trade.calculate_interest()), 8) == round(0.004166666666666667, 8)
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert float(trade.calculate_interest()) == 0.06 assert float(trade.calculate_interest()) == 0.06
# short # short
trade.is_short = True trade.is_short = True
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# binace # binace
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert round(float(trade.calculate_interest()), 8) == round(0.0031249999999999997, 8) assert round(float(trade.calculate_interest()), 8) == round(0.0031249999999999997, 8)
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert float(trade.calculate_interest()) == 0.045 assert float(trade.calculate_interest()) == 0.045
# 0.00025 interest, 5hr, long # 0.00025 interest, 5hr, long
trade.is_short = False trade.is_short = False
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# binance # binance
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert round(float(trade.calculate_interest(interest_rate=0.00025)), assert round(float(trade.calculate_interest(interest_rate=0.00025)),
8) == round(0.0020833333333333333, 8) 8) == round(0.0020833333333333333, 8)
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert isclose(float(trade.calculate_interest(interest_rate=0.00025)), 0.03) assert isclose(float(trade.calculate_interest(interest_rate=0.00025)), 0.03)
# short # short
trade.is_short = True trade.is_short = True
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# binace # binace
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert round(float(trade.calculate_interest(interest_rate=0.00025)), assert round(float(trade.calculate_interest(interest_rate=0.00025)),
8) == round(0.0015624999999999999, 8) 8) == round(0.0015624999999999999, 8)
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert float(trade.calculate_interest(interest_rate=0.00025)) == 0.0225 assert float(trade.calculate_interest(interest_rate=0.00025)) == 0.0225
# 5x leverage, 0.0005 interest, 5hr, long # 5x leverage, 0.0005 interest, 5hr, long
@ -302,19 +300,19 @@ def test_interest(market_buy_order_usdt, fee):
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
trade.leverage = 5.0 trade.leverage = 5.0
# binance # binance
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert round(float(trade.calculate_interest()), 8) == 0.005 assert round(float(trade.calculate_interest()), 8) == 0.005
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert float(trade.calculate_interest()) == round(0.07200000000000001, 8) assert float(trade.calculate_interest()) == round(0.07200000000000001, 8)
# short # short
trade.is_short = True trade.is_short = True
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# binace # binace
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert round(float(trade.calculate_interest()), 8) == round(0.0031249999999999997, 8) assert round(float(trade.calculate_interest()), 8) == round(0.0031249999999999997, 8)
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert float(trade.calculate_interest()) == 0.045 assert float(trade.calculate_interest()) == 0.045
# 1x leverage, 0.0005 interest, 5hr # 1x leverage, 0.0005 interest, 5hr
@ -322,19 +320,19 @@ def test_interest(market_buy_order_usdt, fee):
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
trade.leverage = 1.0 trade.leverage = 1.0
# binance # binance
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert float(trade.calculate_interest()) == 0.0 assert float(trade.calculate_interest()) == 0.0
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert float(trade.calculate_interest()) == 0.0 assert float(trade.calculate_interest()) == 0.0
# short # short
trade.is_short = True trade.is_short = True
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# binace # binace
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert float(trade.calculate_interest()) == 0.003125 assert float(trade.calculate_interest()) == 0.003125
# kraken # kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert float(trade.calculate_interest()) == 0.045 assert float(trade.calculate_interest()) == 0.045
@ -550,7 +548,6 @@ def test_update_limit_order(limit_buy_order_usdt, limit_sell_order_usdt, fee, ca
is_short=True, is_short=True,
leverage=3.0, leverage=3.0,
interest_rate=0.0005, interest_rate=0.0005,
interest_mode=InterestMode.HOURSPERDAY
) )
trade.open_order_id = 'something' trade.open_order_id = 'something'
trade.update(limit_sell_order_usdt) trade.update(limit_sell_order_usdt)
@ -628,7 +625,6 @@ def test_calc_open_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt
amount=30.0, amount=30.0,
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=10), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=10),
interest_rate=0.0005, interest_rate=0.0005,
interest_mode=InterestMode.HOURSPERDAY,
fee_open=fee.return_value, fee_open=fee.return_value,
fee_close=fee.return_value, fee_close=fee.return_value,
exchange='binance', exchange='binance',
@ -644,12 +640,12 @@ def test_calc_open_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt
assert trade.calc_profit_ratio() == round(0.0945137157107232, 8) assert trade.calc_profit_ratio() == round(0.0945137157107232, 8)
# 3x leverage, binance # 3x leverage, binance
trade.leverage = 3 trade.leverage = 3
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert trade._calc_open_trade_value() == 60.15 assert trade._calc_open_trade_value() == 60.15
assert round(trade.calc_close_trade_value(), 8) == 65.83416667 assert round(trade.calc_close_trade_value(), 8) == 65.83416667
assert trade.calc_profit() == round(5.684166670000003, 8) assert trade.calc_profit() == round(5.684166670000003, 8)
assert trade.calc_profit_ratio() == round(0.2834995845386534, 8) assert trade.calc_profit_ratio() == round(0.2834995845386534, 8)
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
# 3x leverage, kraken # 3x leverage, kraken
assert trade._calc_open_trade_value() == 60.15 assert trade._calc_open_trade_value() == 60.15
assert trade.calc_close_trade_value() == 65.795 assert trade.calc_close_trade_value() == 65.795
@ -662,7 +658,7 @@ def test_calc_open_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt
assert trade.calc_close_trade_value() == 66.231165 assert trade.calc_close_trade_value() == 66.231165
assert trade.calc_profit() == round(-6.381165000000003, 8) assert trade.calc_profit() == round(-6.381165000000003, 8)
assert trade.calc_profit_ratio() == round(-0.319857894736842, 8) assert trade.calc_profit_ratio() == round(-0.319857894736842, 8)
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
# 3x leverage, short, binance # 3x leverage, short, binance
assert trade._calc_open_trade_value() == 59.85 assert trade._calc_open_trade_value() == 59.85
assert trade.calc_close_trade_value() == 66.1663784375 assert trade.calc_close_trade_value() == 66.1663784375
@ -675,7 +671,7 @@ def test_calc_open_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt
assert trade.calc_profit() == round(-6.316378437500013, 8) assert trade.calc_profit() == round(-6.316378437500013, 8)
assert trade.calc_profit_ratio() == round(-0.1055368159983292, 8) assert trade.calc_profit_ratio() == round(-0.1055368159983292, 8)
# 1x leverage, short, kraken # 1x leverage, short, kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert trade._calc_open_trade_value() == 59.850 assert trade._calc_open_trade_value() == 59.850
assert trade.calc_close_trade_value() == 66.231165 assert trade.calc_close_trade_value() == 66.231165
assert trade.calc_profit() == -6.381165 assert trade.calc_profit() == -6.381165
@ -694,7 +690,6 @@ def test_trade_close(limit_buy_order_usdt, limit_sell_order_usdt, fee):
fee_close=fee.return_value, fee_close=fee.return_value,
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=10), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=10),
interest_rate=0.0005, interest_rate=0.0005,
interest_mode=InterestMode.HOURSPERDAY,
exchange='binance', exchange='binance',
) )
assert trade.close_profit is None assert trade.close_profit is None
@ -805,7 +800,7 @@ def test_calc_open_trade_value(limit_buy_order_usdt, fee):
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
assert trade._calc_open_trade_value() == 59.85 assert trade._calc_open_trade_value() == 59.85
trade.leverage = 3 trade.leverage = 3
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert trade._calc_open_trade_value() == 59.85 assert trade._calc_open_trade_value() == 59.85
trade.is_short = False trade.is_short = False
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
@ -832,7 +827,6 @@ def test_calc_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt, fee
fee_close=fee.return_value, fee_close=fee.return_value,
exchange='binance', exchange='binance',
interest_rate=0.0005, interest_rate=0.0005,
interest_mode=InterestMode.HOURSPERDAY
) )
trade.open_order_id = 'close_trade' trade.open_order_id = 'close_trade'
trade.update(limit_buy_order_usdt) trade.update(limit_buy_order_usdt)
@ -849,7 +843,7 @@ def test_calc_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt, fee
assert round(trade.calc_close_trade_value(rate=2.5, fee=0.003), 8) == 74.77416667 assert round(trade.calc_close_trade_value(rate=2.5, fee=0.003), 8) == 74.77416667
# 3x leverage kraken # 3x leverage kraken
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert trade.calc_close_trade_value(rate=2.5) == 74.7725 assert trade.calc_close_trade_value(rate=2.5) == 74.7725
assert trade.calc_close_trade_value(rate=2.5, fee=0.003) == 74.735 assert trade.calc_close_trade_value(rate=2.5, fee=0.003) == 74.735
@ -860,7 +854,7 @@ def test_calc_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt, fee
assert trade.calc_close_trade_value(rate=2.5, fee=0.003) == 75.300225 assert trade.calc_close_trade_value(rate=2.5, fee=0.003) == 75.300225
# 3x leverage binance, short # 3x leverage binance, short
trade.interest_mode = InterestMode.HOURSPERDAY trade.exchange = "binance"
assert round(trade.calc_close_trade_value(rate=2.5), 8) == 75.18906641 assert round(trade.calc_close_trade_value(rate=2.5), 8) == 75.18906641
assert round(trade.calc_close_trade_value(rate=2.5, fee=0.003), 8) == 75.22656719 assert round(trade.calc_close_trade_value(rate=2.5, fee=0.003), 8) == 75.22656719
@ -870,7 +864,7 @@ def test_calc_close_trade_price(limit_buy_order_usdt, limit_sell_order_usdt, fee
assert round(trade.calc_close_trade_value(rate=2.5, fee=0.003), 8) == 75.22656719 assert round(trade.calc_close_trade_value(rate=2.5, fee=0.003), 8) == 75.22656719
# 1x leverage kraken, short # 1x leverage kraken, short
trade.interest_mode = InterestMode.HOURSPER4 trade.exchange = "kraken"
assert round(trade.calc_close_trade_value(rate=2.5), 8) == 75.2626875 assert round(trade.calc_close_trade_value(rate=2.5), 8) == 75.2626875
assert trade.calc_close_trade_value(rate=2.5, fee=0.003) == 75.300225 assert trade.calc_close_trade_value(rate=2.5, fee=0.003) == 75.300225
@ -1013,7 +1007,6 @@ def test_calc_profit(limit_buy_order_usdt, limit_sell_order_usdt, fee):
open_rate=2.0, open_rate=2.0,
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=10), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=10),
interest_rate=0.0005, interest_rate=0.0005,
interest_mode=InterestMode.HOURSPERDAY,
fee_open=fee.return_value, fee_open=fee.return_value,
fee_close=fee.return_value, fee_close=fee.return_value,
exchange='binance' exchange='binance'
@ -1047,62 +1040,62 @@ def test_calc_profit(limit_buy_order_usdt, limit_sell_order_usdt, fee):
# 3x leverage, long ################################################### # 3x leverage, long ###################################################
trade.leverage = 3.0 trade.leverage = 3.0
# Higher than open rate - 2.1 quote # Higher than open rate - 2.1 quote
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(rate=2.1, fee=0.0025) == 2.69166667 assert trade.calc_profit(rate=2.1, fee=0.0025) == 2.69166667
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(rate=2.1, fee=0.0025) == 2.6525 assert trade.calc_profit(rate=2.1, fee=0.0025) == 2.6525
# 1.9 quote # 1.9 quote
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(rate=1.9, fee=0.0025) == -3.29333333 assert trade.calc_profit(rate=1.9, fee=0.0025) == -3.29333333
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(rate=1.9, fee=0.0025) == -3.3325 assert trade.calc_profit(rate=1.9, fee=0.0025) == -3.3325
# 2.2 quote # 2.2 quote
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(fee=0.0025) == 5.68416667 assert trade.calc_profit(fee=0.0025) == 5.68416667
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(fee=0.0025) == 5.645 assert trade.calc_profit(fee=0.0025) == 5.645
# 3x leverage, short ################################################### # 3x leverage, short ###################################################
trade.is_short = True trade.is_short = True
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# 2.1 quote - Higher than open rate # 2.1 quote - Higher than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(rate=2.1, fee=0.0025) == round(-3.308815781249997, 8) assert trade.calc_profit(rate=2.1, fee=0.0025) == round(-3.308815781249997, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(rate=2.1, fee=0.0025) == -3.3706575 assert trade.calc_profit(rate=2.1, fee=0.0025) == -3.3706575
# 1.9 quote - Lower than open rate # 1.9 quote - Lower than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(rate=1.9, fee=0.0025) == round(2.7063095312499996, 8) assert trade.calc_profit(rate=1.9, fee=0.0025) == round(2.7063095312499996, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(rate=1.9, fee=0.0025) == 2.6503575 assert trade.calc_profit(rate=1.9, fee=0.0025) == 2.6503575
# Test when we apply a Sell order. Uses sell order used above # Test when we apply a Sell order. Uses sell order used above
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(fee=0.0025) == round(-6.316378437499999, 8) assert trade.calc_profit(fee=0.0025) == round(-6.316378437499999, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(fee=0.0025) == -6.381165 assert trade.calc_profit(fee=0.0025) == -6.381165
# 1x leverage, short ################################################### # 1x leverage, short ###################################################
trade.leverage = 1.0 trade.leverage = 1.0
# 2.1 quote - Higher than open rate # 2.1 quote - Higher than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(rate=2.1, fee=0.0025) == round(-3.308815781249997, 8) assert trade.calc_profit(rate=2.1, fee=0.0025) == round(-3.308815781249997, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(rate=2.1, fee=0.0025) == -3.3706575 assert trade.calc_profit(rate=2.1, fee=0.0025) == -3.3706575
# 1.9 quote - Lower than open rate # 1.9 quote - Lower than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(rate=1.9, fee=0.0025) == round(2.7063095312499996, 8) assert trade.calc_profit(rate=1.9, fee=0.0025) == round(2.7063095312499996, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(rate=1.9, fee=0.0025) == 2.6503575 assert trade.calc_profit(rate=1.9, fee=0.0025) == 2.6503575
# Test when we apply a Sell order. Uses sell order used above # Test when we apply a Sell order. Uses sell order used above
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit(fee=0.0025) == round(-6.316378437499999, 8) assert trade.calc_profit(fee=0.0025) == round(-6.316378437499999, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit(fee=0.0025) == -6.381165 assert trade.calc_profit(fee=0.0025) == -6.381165
@ -1115,7 +1108,6 @@ def test_calc_profit_ratio(limit_buy_order_usdt, limit_sell_order_usdt, fee):
open_rate=2.0, open_rate=2.0,
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=10), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=10),
interest_rate=0.0005, interest_rate=0.0005,
interest_mode=InterestMode.HOURSPERDAY,
fee_open=fee.return_value, fee_open=fee.return_value,
fee_close=fee.return_value, fee_close=fee.return_value,
exchange='binance' exchange='binance'
@ -1150,62 +1142,62 @@ def test_calc_profit_ratio(limit_buy_order_usdt, limit_sell_order_usdt, fee):
# 3x leverage, long ################################################### # 3x leverage, long ###################################################
trade.leverage = 3.0 trade.leverage = 3.0
# 2.1 quote - Higher than open rate # 2.1 quote - Higher than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit_ratio(rate=2.1) == round(0.13424771421446402, 8) assert trade.calc_profit_ratio(rate=2.1) == round(0.13424771421446402, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio(rate=2.1) == round(0.13229426433915248, 8) assert trade.calc_profit_ratio(rate=2.1) == round(0.13229426433915248, 8)
# 1.9 quote - Lower than open rate # 1.9 quote - Lower than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit_ratio(rate=1.9) == round(-0.16425602643391513, 8) assert trade.calc_profit_ratio(rate=1.9) == round(-0.16425602643391513, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio(rate=1.9) == round(-0.16620947630922667, 8) assert trade.calc_profit_ratio(rate=1.9) == round(-0.16620947630922667, 8)
# Test when we apply a Sell order. Uses sell order used above # Test when we apply a Sell order. Uses sell order used above
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit_ratio() == round(0.2834995845386534, 8) assert trade.calc_profit_ratio() == round(0.2834995845386534, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio() == round(0.2815461346633419, 8) assert trade.calc_profit_ratio() == round(0.2815461346633419, 8)
# 3x leverage, short ################################################### # 3x leverage, short ###################################################
trade.is_short = True trade.is_short = True
trade.recalc_open_trade_value() trade.recalc_open_trade_value()
# 2.1 quote - Higher than open rate # 2.1 quote - Higher than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit_ratio(rate=2.1) == round(-0.1658554276315789, 8) assert trade.calc_profit_ratio(rate=2.1) == round(-0.1658554276315789, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio(rate=2.1) == round(-0.16895526315789455, 8) assert trade.calc_profit_ratio(rate=2.1) == round(-0.16895526315789455, 8)
# 1.9 quote - Lower than open rate # 1.9 quote - Lower than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit_ratio(rate=1.9) == round(0.13565461309523819, 8) assert trade.calc_profit_ratio(rate=1.9) == round(0.13565461309523819, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio(rate=1.9) == round(0.13285000000000002, 8) assert trade.calc_profit_ratio(rate=1.9) == round(0.13285000000000002, 8)
# Test when we apply a Sell order. Uses sell order used above # Test when we apply a Sell order. Uses sell order used above
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit_ratio() == round(-0.3166104479949876, 8) assert trade.calc_profit_ratio() == round(-0.3166104479949876, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio() == round(-0.319857894736842, 8) assert trade.calc_profit_ratio() == round(-0.319857894736842, 8)
# 1x leverage, short ################################################### # 1x leverage, short ###################################################
trade.leverage = 1.0 trade.leverage = 1.0
# 2.1 quote - Higher than open rate # 2.1 quote - Higher than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance" # binance
assert trade.calc_profit_ratio(rate=2.1) == round(-0.05528514254385963, 8) assert trade.calc_profit_ratio(rate=2.1) == round(-0.05528514254385963, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio(rate=2.1) == round(-0.05631842105263152, 8) assert trade.calc_profit_ratio(rate=2.1) == round(-0.05631842105263152, 8)
# 1.9 quote - Lower than open rate # 1.9 quote - Lower than open rate
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance"
assert trade.calc_profit_ratio(rate=1.9) == round(0.045218204365079395, 8) assert trade.calc_profit_ratio(rate=1.9) == round(0.045218204365079395, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio(rate=1.9) == round(0.04428333333333334, 8) assert trade.calc_profit_ratio(rate=1.9) == round(0.04428333333333334, 8)
# Test when we apply a Sell order. Uses sell order used above # Test when we apply a Sell order. Uses sell order used above
trade.interest_mode = InterestMode.HOURSPERDAY # binance trade.exchange = "binance"
assert trade.calc_profit_ratio() == round(-0.1055368159983292, 8) assert trade.calc_profit_ratio() == round(-0.1055368159983292, 8)
trade.interest_mode = InterestMode.HOURSPER4 # kraken trade.exchange = "kraken"
assert trade.calc_profit_ratio() == round(-0.106619298245614, 8) assert trade.calc_profit_ratio() == round(-0.106619298245614, 8)
@ -1542,7 +1534,6 @@ def test_adjust_stop_loss_short(fee):
open_rate=1, open_rate=1,
max_rate=1, max_rate=1,
is_short=True, is_short=True,
interest_mode=InterestMode.HOURSPERDAY
) )
trade.adjust_stop_loss(trade.open_rate, 0.05, True) trade.adjust_stop_loss(trade.open_rate, 0.05, True)
assert trade.stop_loss == 1.05 assert trade.stop_loss == 1.05
@ -1859,7 +1850,6 @@ def test_stoploss_reinitialization_short(default_conf, fee):
max_rate=1, max_rate=1,
is_short=True, is_short=True,
leverage=3.0, leverage=3.0,
interest_mode=InterestMode.HOURSPERDAY
) )
trade.adjust_stop_loss(trade.open_rate, -0.05, True) trade.adjust_stop_loss(trade.open_rate, -0.05, True)
assert trade.stop_loss == 1.05 assert trade.stop_loss == 1.05