From 78708b27f290e2142172408c6bbf23cb92faefd4 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sun, 4 Jul 2021 00:11:59 -0600 Subject: [PATCH] Updated tests to new persistence --- freqtrade/exchange/binance.py | 10 + freqtrade/exchange/kraken.py | 9 + freqtrade/persistence/migrations.py | 11 +- freqtrade/persistence/models.py | 118 ++--- tests/conftest.py | 90 ++-- tests/conftest_trades.py | 5 +- tests/rpc/test_rpc.py | 6 - tests/test_persistence.py | 64 +-- tests/test_persistence_long.py | 793 ++++++++++++++-------------- tests/test_persistence_short.py | 741 +++++++++++++------------- 10 files changed, 874 insertions(+), 973 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 0c470cb24..a8d60d6c0 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -3,6 +3,7 @@ import logging from typing import Dict import ccxt +from decimal import Decimal from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, OperationalException, TemporaryError) @@ -89,3 +90,12 @@ class Binance(Exchange): f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e except ccxt.BaseError as e: raise OperationalException(e) from e + + @staticmethod + def calculate_interest(borrowed: Decimal, hours: Decimal, interest_rate: Decimal) -> Decimal: + # Rate is per day but accrued hourly or something + # binance: https://www.binance.com/en-AU/support/faq/360030157812 + one = Decimal(1) + twenty_four = Decimal(24) + # TODO-mg: Is hours rounded? + return borrowed * interest_rate * max(hours, one)/twenty_four diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 1b069aa6c..2cd2ac118 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -3,6 +3,7 @@ import logging from typing import Any, Dict import ccxt +from decimal import Decimal from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, OperationalException, TemporaryError) @@ -124,3 +125,11 @@ class Kraken(Exchange): f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e except ccxt.BaseError as e: raise OperationalException(e) from e + + @staticmethod + def calculate_interest(borrowed: Decimal, hours: Decimal, interest_rate: Decimal) -> Decimal: + four = Decimal(4.0) + # https://support.kraken.com/hc/en-us/articles/206161568-What-are-the-fees-for-margin-trading- + opening_fee = borrowed * interest_rate + roll_over_fee = borrowed * interest_rate * max(0, (hours-four)/four) + return opening_fee + roll_over_fee diff --git a/freqtrade/persistence/migrations.py b/freqtrade/persistence/migrations.py index efadc7467..8e2f708d5 100644 --- a/freqtrade/persistence/migrations.py +++ b/freqtrade/persistence/migrations.py @@ -49,9 +49,6 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col strategy = get_column_def(cols, 'strategy', 'null') leverage = get_column_def(cols, 'leverage', 'null') - borrowed = get_column_def(cols, 'borrowed', '0.0') - borrowed_currency = get_column_def(cols, 'borrowed_currency', 'null') - collateral_currency = get_column_def(cols, 'collateral_currency', 'null') interest_rate = get_column_def(cols, 'interest_rate', '0.0') liquidation_price = get_column_def(cols, 'liquidation_price', 'null') is_short = get_column_def(cols, 'is_short', 'False') @@ -91,8 +88,7 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col stoploss_order_id, stoploss_last_update, max_rate, min_rate, sell_reason, sell_order_status, strategy, timeframe, open_trade_value, close_profit_abs, - leverage, borrowed, borrowed_currency, collateral_currency, interest_rate, - liquidation_price, is_short + leverage, interest_rate, liquidation_price, is_short ) select id, lower(exchange), case @@ -116,14 +112,11 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col {sell_order_status} sell_order_status, {strategy} strategy, {timeframe} timeframe, {open_trade_value} open_trade_value, {close_profit_abs} close_profit_abs, - {leverage} leverage, {borrowed} borrowed, {borrowed_currency} borrowed_currency, - {collateral_currency} collateral_currency, {interest_rate} interest_rate, + {leverage} leverage, {interest_rate} interest_rate, {liquidation_price} liquidation_price, {is_short} is_short from {table_back_name} """)) -# TODO: Does leverage go in here? - def migrate_open_orders_to_trades(engine): with engine.begin() as connection: diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 8a52b4d4e..ebfae72b9 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -132,7 +132,11 @@ class Order(_DECL_BASE): order_filled_date = Column(DateTime, nullable=True) order_update_date = Column(DateTime, nullable=True) + leverage = Column(Float, nullable=True, default=None) + is_short = Column(Boolean, nullable=True, default=False) + def __repr__(self): + return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, ' f'side={self.side}, order_type={self.order_type}, status={self.status})') @@ -226,7 +230,6 @@ class LocalTrade(): fee_close_currency: str = '' open_rate: float = 0.0 open_rate_requested: Optional[float] = None - # open_trade_value - calculated via _calc_open_trade_value open_trade_value: float = 0.0 close_rate: Optional[float] = None @@ -261,61 +264,23 @@ class LocalTrade(): timeframe: Optional[int] = None # Margin trading properties - borrowed_currency: str = None - collateral_currency: str = None interest_rate: float = 0.0 liquidation_price: float = None is_short: bool = False - borrowed: float = 0.0 leverage: float = None - # @property - # def base_currency(self) -> str: - # if not self.pair: - # raise OperationalException('LocalTrade.pair must be assigned') - # return self.pair.split("/")[1] + @property + def has_no_leverage(self) -> bool: + return (self.leverage == 1.0 and not self.is_short) or self.leverage is None - # TODO: @samgermain: Amount should be persisted "as is". - # I've partially reverted this (this killed most of your tests) - # but leave this here as i'm not sure where you intended to use this. - # @property - # def amount(self) -> float: - # if self._leverage is not None: - # return self._amount * self.leverage - # else: - # return self._amount - - # @amount.setter - # def amount(self, value): - # self._amount = value - - # @property - # def borrowed(self) -> float: - # if self._leverage is not None: - # if self.is_short: - # # If shorting the full amount must be borrowed - # return self._amount * self._leverage - # else: - # # If not shorting, then the trader already owns a bit - # return self._amount * (self._leverage-1) - # else: - # return self._borrowed - - # @borrowed.setter - # def borrowed(self, value): - # self._borrowed = value - # self._leverage = None - - # @property - # def leverage(self) -> float: - # return self._leverage - - # @leverage.setter - # def leverage(self, value): - # self._leverage = value - # self._borrowed = None - - # End of margin trading properties + @property + def borrowed(self) -> float: + if self.has_no_leverage: + return 0.0 + elif not self.is_short: + return self.stake_amount * (self.leverage-1) + else: + return self.amount @property def open_date_utc(self): @@ -326,13 +291,8 @@ class LocalTrade(): return self.close_date.replace(tzinfo=timezone.utc) def __init__(self, **kwargs): - if kwargs.get('leverage') and kwargs.get('borrowed'): - # TODO-mg: should I raise an error? - raise OperationalException('Cannot pass both borrowed and leverage to Trade') for key in kwargs: setattr(self, key, kwargs[key]) - if not self.is_short: - self.is_short = False self.recalc_open_trade_value() def __repr__(self): @@ -404,9 +364,6 @@ class LocalTrade(): 'max_rate': self.max_rate, 'leverage': self.leverage, - 'borrowed': self.borrowed, - 'borrowed_currency': self.borrowed_currency, - 'collateral_currency': self.collateral_currency, 'interest_rate': self.interest_rate, 'liquidation_price': self.liquidation_price, 'is_short': self.is_short, @@ -473,7 +430,7 @@ class LocalTrade(): # evaluate if the stop loss needs to be updated else: - # stop losses only walk up, never down!, #TODO: But adding more to a margin account would create a lower liquidation price, decreasing the minimum stoploss + # stop losses only walk up, never down!, #But adding more to a margin account would create a lower liquidation price, decreasing the minimum stoploss if (new_loss > self.stop_loss and not self.is_short) or (new_loss < self.stop_loss and self.is_short): logger.debug(f"{self.pair} - Adjusting stoploss...") self._set_new_stoploss(new_loss, stoploss) @@ -510,13 +467,8 @@ class LocalTrade(): """ order_type = order['type'] - if ('leverage' in order and 'borrowed' in order): - raise OperationalException( - 'Pass only one of Leverage or Borrowed to the order in update trade') - if 'is_short' in order and order['side'] == 'sell': # Only set's is_short on opening trades, ignores non-shorts - # TODO-mg: I don't like this, but it might be the only way self.is_short = order['is_short'] # Ignore open and cancelled orders @@ -527,15 +479,10 @@ class LocalTrade(): if order_type in ('market', 'limit') and self.is_opening_trade(order['side']): # Update open rate and actual amount - self.open_rate = float(safe_value_fallback(order, 'average', 'price')) self.amount = float(safe_value_fallback(order, 'filled', 'amount')) - - if 'borrowed' in order: - self.borrowed = order['borrowed'] - elif 'leverage' in order: + if 'leverage' in order: self.leverage = order['leverage'] - self.recalc_open_trade_value() if self.is_open: payment = "SELL" if self.is_short else "BUY" @@ -544,7 +491,8 @@ class LocalTrade(): elif order_type in ('market', 'limit') and self.is_closing_trade(order['side']): if self.is_open: payment = "BUY" if self.is_short else "SELL" - # TODO: On Shorts technically your buying a little bit more than the amount because it's the ammount plus the interest + # TODO-mg: On Shorts technically your buying a little bit more than the amount because it's the ammount plus the interest + # But this wll only print the original logger.info(f'{order_type.upper()}_{payment} has been fulfilled for {self}.') self.close(safe_value_fallback(order, 'average', 'price')) # TODO: Double check this elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'): @@ -632,17 +580,16 @@ class LocalTrade(): : param interest_rate: interest_charge for borrowing this coin(optional). If interest_rate is not set self.interest_rate will be used """ - # TODO-mg: Need to set other conditions because sometimes self.open_date is not defined, but why would it ever not be set + zero = Decimal(0.0) - if not (self.borrowed): + # If nothing was borrowed + if (self.leverage == 1.0 and not self.is_short) or not self.leverage: return zero open_date = self.open_date.replace(tzinfo=None) - now = datetime.utcnow() - # sec_per_day = Decimal(86400) + now = (self.close_date or datetime.utcnow()).replace(tzinfo=None) sec_per_hour = Decimal(3600) total_seconds = Decimal((now - open_date).total_seconds()) - # days = total_seconds/sec_per_day or zero hours = total_seconds/sec_per_hour or zero rate = Decimal(interest_rate or self.interest_rate) @@ -654,7 +601,7 @@ class LocalTrade(): if self.exchange == 'binance': # Rate is per day but accrued hourly or something # binance: https://www.binance.com/en-AU/support/faq/360030157812 - return borrowed * rate * max(hours, one)/twenty_four # TODO-mg: Is hours rounded? + return borrowed * rate * max(hours, one)/twenty_four elif self.exchange == 'kraken': # https://support.kraken.com/hc/en-us/articles/206161568-What-are-the-fees-for-margin-trading- opening_fee = borrowed * rate @@ -746,16 +693,15 @@ class LocalTrade(): if (self.is_short and close_trade_value == 0.0) or (not self.is_short and self.open_trade_value == 0.0): return 0.0 else: - if self.borrowed: # TODO: This is only needed so that previous tests that included dummy stake_amounts don't fail. Undate those tests and get rid of this else + if self.has_no_leverage: + # TODO: This is only needed so that previous tests that included dummy stake_amounts don't fail. Undate those tests and get rid of this else + profit_ratio = (close_trade_value/self.open_trade_value) - 1 + else: if self.is_short: profit_ratio = ((self.open_trade_value - close_trade_value) / self.stake_amount) else: profit_ratio = ((close_trade_value - self.open_trade_value) / self.stake_amount) - else: # TODO: This is only needed so that previous tests that included dummy stake_amounts don't fail. Undate those tests and get rid of this else - if self.is_short: - profit_ratio = 1 - (close_trade_value/self.open_trade_value) - else: - profit_ratio = (close_trade_value/self.open_trade_value) - 1 + return float(f"{profit_ratio:.8f}") def select_order(self, order_side: str, is_open: Optional[bool]) -> Optional[Order]: @@ -907,14 +853,10 @@ class Trade(_DECL_BASE, LocalTrade): timeframe = Column(Integer, nullable=True) # Margin trading properties - leverage = Column(Float, nullable=True) # TODO: can this be nullable, or should it default to 1? (must also be changed in migrations eventually) - borrowed = Column(Float, nullable=False, default=0.0) + leverage = Column(Float, nullable=True) interest_rate = Column(Float, nullable=False, default=0.0) liquidation_price = Column(Float, nullable=True) is_short = Column(Boolean, nullable=False, default=False) - # TODO: Bottom 2 might not be needed - borrowed_currency = Column(Float, nullable=True) - collateral_currency = Column(String(25), nullable=True) # End of margin trading properties def __init__(self, **kwargs): diff --git a/tests/conftest.py b/tests/conftest.py index b17f9658e..843769df0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,10 +7,12 @@ from datetime import datetime, timedelta from functools import reduce from pathlib import Path from unittest.mock import MagicMock, Mock, PropertyMock + import arrow import numpy as np import pytest from telegram import Chat, Message, Update + from freqtrade import constants from freqtrade.commands import Arguments from freqtrade.data.converter import ohlcv_to_dataframe @@ -23,7 +25,11 @@ from freqtrade.resolvers import ExchangeResolver from freqtrade.worker import Worker from tests.conftest_trades import (mock_trade_1, mock_trade_2, mock_trade_3, mock_trade_4, mock_trade_5, mock_trade_6, short_trade, leverage_trade) + + logging.getLogger('').setLevel(logging.INFO) + + # Do not mask numpy errors as warnings that no one read, raise the exсeption np.seterr(all='raise') @@ -63,6 +69,7 @@ def get_args(args): def get_mock_coro(return_value): async def mock_coro(*args, **kwargs): return return_value + return Mock(wraps=mock_coro) @@ -85,6 +92,7 @@ def patch_exchange(mocker, api_mock=None, id='binance', mock_markets=True) -> No if mock_markets: mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=get_markets())) + if api_mock: mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) else: @@ -118,6 +126,7 @@ def patch_edge(mocker) -> None: # "LTC/BTC", # "XRP/BTC", # "NEO/BTC" + mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( return_value={ 'NEO/BTC': PairInfo(-0.20, 0.66, 3.71, 0.50, 1.71, 10, 25), @@ -131,6 +140,7 @@ def get_patched_edge(mocker, config) -> Edge: patch_edge(mocker) edge = Edge(config) return edge + # Functions for recurrent object patching @@ -191,6 +201,7 @@ def create_mock_trades(fee, use_db: bool = True): Trade.query.session.add(trade) else: LocalTrade.add_bt_trade(trade) + # Simulate dry_run entries trade = mock_trade_1(fee) add_trade(trade) @@ -220,14 +231,19 @@ def create_mock_trades_with_leverage(fee, use_db: bool = True): add_trade(trade) trade = mock_trade_2(fee) add_trade(trade) + trade = mock_trade_3(fee) add_trade(trade) + trade = mock_trade_4(fee) add_trade(trade) + trade = mock_trade_5(fee) add_trade(trade) + trade = mock_trade_6(fee) add_trade(trade) + trade = short_trade(fee) add_trade(trade) trade = leverage_trade(fee) @@ -243,6 +259,7 @@ def patch_coingekko(mocker) -> None: :param mocker: mocker to patch coingekko class :return: None """ + tickermock = MagicMock(return_value={'bitcoin': {'usd': 12345.0}, 'ethereum': {'usd': 12345.0}}) listmock = MagicMock(return_value=[{'id': 'bitcoin', 'name': 'Bitcoin', 'symbol': 'btc', 'website_slug': 'bitcoin'}, @@ -253,13 +270,13 @@ def patch_coingekko(mocker) -> None: 'freqtrade.rpc.fiat_convert.CoinGeckoAPI', get_price=tickermock, get_coins_list=listmock, + ) @pytest.fixture(scope='function') def init_persistence(default_conf): init_db(default_conf['db_url'], default_conf['dry_run']) - # TODO-mg: trade with leverage and/or borrowed? @pytest.fixture(scope="function") @@ -924,17 +941,18 @@ def limit_sell_order_old(): @pytest.fixture def limit_buy_order_old_partial(): - return {'id': 'mocked_limit_buy_old_partial', - 'type': 'limit', - 'side': 'buy', - 'symbol': 'ETH/BTC', - 'datetime': arrow.utcnow().shift(minutes=-601).isoformat(), - 'price': 0.00001099, - 'amount': 90.99181073, - 'filled': 23.0, - 'remaining': 67.99181073, - 'status': 'open' - } + return { + 'id': 'mocked_limit_buy_old_partial', + 'type': 'limit', + 'side': 'buy', + 'symbol': 'ETH/BTC', + 'datetime': arrow.utcnow().shift(minutes=-601).isoformat(), + 'price': 0.00001099, + 'amount': 90.99181073, + 'filled': 23.0, + 'remaining': 67.99181073, + 'status': 'open' + } @pytest.fixture @@ -950,6 +968,7 @@ def limit_buy_order_canceled_empty(request): # Indirect fixture # Documentation: # https://docs.pytest.org/en/latest/example/parametrize.html#apply-indirect-on-particular-arguments + exchange_name = request.param if exchange_name == 'ftx': return { @@ -1123,7 +1142,7 @@ def order_book_l2_usd(): [25.576, 262.016], [25.577, 178.557], [25.578, 78.614] - ], + ], 'timestamp': None, 'datetime': None, 'nonce': 2372149736 @@ -1739,6 +1758,7 @@ def edge_conf(default_conf): "max_trade_duration_minute": 1440, "remove_pumps": False } + return conf @@ -1776,7 +1796,6 @@ def rpc_balance(): 'used': 0.0 }, } - # TODO-mg: Add shorts and leverage? @pytest.fixture @@ -1796,9 +1815,12 @@ def import_fails() -> None: if name in ["filelock", 'systemd.journal', 'uvloop']: raise ImportError(f"No module named '{name}'") return realimport(name, *args, **kwargs) + builtins.__import__ = mockedimport + # Run test - then cleanup yield + # restore previous importfunction builtins.__import__ = realimport @@ -2083,6 +2105,7 @@ def saved_hyperopt_results(): 'is_best': False } ] + for res in hyperopt_res: res['results_metrics']['holding_avg_s'] = res['results_metrics']['holding_avg' ].total_seconds() @@ -2091,16 +2114,6 @@ def saved_hyperopt_results(): # * Margin Tests -@pytest.fixture -def ten_minutes_ago(): - return datetime.utcnow() - timedelta(hours=0, minutes=10) - - -@pytest.fixture -def five_hours_ago(): - return datetime.utcnow() - timedelta(hours=5, minutes=0) - - @pytest.fixture(scope='function') def limit_short_order_open(): return { @@ -2112,12 +2125,12 @@ def limit_short_order_open(): 'timestamp': arrow.utcnow().int_timestamp, 'price': 0.00001173, 'amount': 90.99181073, - 'borrowed': 90.99181073, + 'leverage': 1.0, 'filled': 0.0, 'cost': 0.00106733393, 'remaining': 90.99181073, 'status': 'open', - 'exchange': 'binance' + 'is_short': True } @@ -2131,11 +2144,10 @@ def limit_exit_short_order_open(): 'datetime': arrow.utcnow().isoformat(), 'timestamp': arrow.utcnow().int_timestamp, 'price': 0.00001099, - 'amount': 90.99181073, + 'amount': 90.99370639272354, 'filled': 0.0, - 'remaining': 90.99181073, - 'status': 'open', - 'exchange': 'binance' + 'remaining': 90.99370639272354, + 'status': 'open' } @@ -2166,13 +2178,12 @@ def market_short_order(): 'symbol': 'mocked', 'datetime': arrow.utcnow().isoformat(), 'price': 0.00004173, - 'amount': 91.99181073, - 'filled': 91.99181073, + 'amount': 275.97543219, + 'filled': 275.97543219, 'remaining': 0.0, 'status': 'closed', 'is_short': True, - # 'leverage': 3.0, - 'exchange': 'kraken' + 'leverage': 3.0 } @@ -2185,12 +2196,11 @@ def market_exit_short_order(): 'symbol': 'mocked', 'datetime': arrow.utcnow().isoformat(), 'price': 0.00004099, - 'amount': 91.99181073, - 'filled': 91.99181073, + 'amount': 276.113419906095, + 'filled': 276.113419906095, 'remaining': 0.0, 'status': 'closed', - # 'leverage': 3.0, - 'exchange': 'kraken' + 'leverage': 3.0 } @@ -2207,8 +2217,9 @@ def limit_leveraged_buy_order_open(): 'price': 0.00001099, 'amount': 272.97543219, 'filled': 0.0, - 'cost': 0.0029999999997681, + 'cost': 0.0009999999999226999, 'remaining': 272.97543219, + 'leverage': 3.0, 'status': 'open', 'exchange': 'binance' } @@ -2236,6 +2247,7 @@ def limit_leveraged_sell_order_open(): 'amount': 272.97543219, 'filled': 0.0, 'remaining': 272.97543219, + 'leverage': 3.0, 'status': 'open', 'exchange': 'binance' } diff --git a/tests/conftest_trades.py b/tests/conftest_trades.py index bc728dd44..f6b38f59a 100644 --- a/tests/conftest_trades.py +++ b/tests/conftest_trades.py @@ -3,7 +3,7 @@ from datetime import datetime, timedelta, timezone from freqtrade.persistence.models import Order, Trade -MOCK_TRADE_COUNT = 6 # TODO-mg: Increase for short and leverage +MOCK_TRADE_COUNT = 6 def mock_order_1(): @@ -433,8 +433,7 @@ def leverage_trade(fee): interest_rate: 0.05% per day open_rate: 0.123 base close_rate: 0.128 base - amount: 123.0 crypto - amount_with_leverage: 615.0 + amount: 615 crypto stake_amount: 15.129 base borrowed: 60.516 base leverage: 5 diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index e324626c3..4fd6e716a 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -109,9 +109,6 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'exchange': 'binance', 'leverage': None, - 'borrowed': 0.0, - 'borrowed_currency': None, - 'collateral_currency': None, 'interest_rate': 0.0, 'liquidation_price': None, 'is_short': False, @@ -183,9 +180,6 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'exchange': 'binance', 'leverage': None, - 'borrowed': 0.0, - 'borrowed_currency': None, - 'collateral_currency': None, 'interest_rate': 0.0, 'liquidation_price': None, 'is_short': False, diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 484a8739a..74176ab49 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -105,27 +105,6 @@ def test_is_opening_closing_trade(fee): assert trade.is_closing_trade('sell') == False -@pytest.mark.usefixtures("init_persistence") -def test_amount(limit_buy_order, limit_sell_order, fee, caplog): - trade = Trade( - id=2, - pair='ETH/BTC', - stake_amount=0.001, - open_rate=0.01, - amount=5, - is_open=True, - open_date=arrow.utcnow().datetime, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - is_short=False - ) - assert trade.amount == 5 - trade.leverage = 3 - assert trade.amount == 15 - assert trade._amount == 5 - - @pytest.mark.usefixtures("init_persistence") def test_update_with_binance(limit_buy_order, limit_sell_order, fee, caplog): """ @@ -728,6 +707,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): FOREIGN KEY(ft_trade_id) REFERENCES trades (id) ) """)) + connection.execute(text(""" insert into orders ( id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id, status, symbol, order_type, side, price, amount, filled, remaining, cost, order_date, @@ -978,9 +958,6 @@ def test_to_json(default_conf, fee): 'exchange': 'binance', 'leverage': None, - 'borrowed': None, - 'borrowed_currency': None, - 'collateral_currency': None, 'interest_rate': None, 'liquidation_price': None, 'is_short': None, @@ -1051,9 +1028,6 @@ def test_to_json(default_conf, fee): 'exchange': 'binance', 'leverage': None, - 'borrowed': None, - 'borrowed_currency': None, - 'collateral_currency': None, 'interest_rate': None, 'liquidation_price': None, 'is_short': None, @@ -1189,42 +1163,6 @@ def test_fee_updated(fee): assert not trade.fee_updated('asfd') -@pytest.mark.usefixtures("init_persistence") -def test_update_leverage(fee, ten_minutes_ago): - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=5, - open_rate=0.00001099, - open_date=ten_minutes_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - is_short=True, - interest_rate=0.0005 - ) - trade.leverage = 3.0 - assert trade.borrowed == 15.0 - assert trade.amount == 15.0 - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=5, - open_rate=0.00001099, - open_date=ten_minutes_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - is_short=False, - interest_rate=0.0005 - ) - - trade.leverage = 5.0 - assert trade.borrowed == 20.0 - assert trade.amount == 25.0 - - @pytest.mark.usefixtures("init_persistence") @pytest.mark.parametrize('use_db', [True, False]) def test_total_open_trades_stakes(fee, use_db): diff --git a/tests/test_persistence_long.py b/tests/test_persistence_long.py index cd0267cd1..98b6735e0 100644 --- a/tests/test_persistence_long.py +++ b/tests/test_persistence_long.py @@ -14,7 +14,358 @@ from tests.conftest import create_mock_trades_with_leverage, log_has, log_has_re @pytest.mark.usefixtures("init_persistence") -def test_update_with_binance(limit_leveraged_buy_order, limit_leveraged_sell_order, fee, ten_minutes_ago, caplog): +def test_interest_kraken(market_leveraged_buy_order, fee): + """ + Market trade on Kraken at 3x and 5x leverage + Short trade + interest_rate: 0.05%, 0.25% per 4 hrs + open_rate: 0.00004099 base + close_rate: 0.00004173 base + stake_amount: 0.0037707443218227 + borrowed: 0.0075414886436454 + amount: + 275.97543219 crypto + 459.95905365 crypto + borrowed: + 0.0075414886436454 base + 0.0150829772872908 base + time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) + 5 hours = 5/4 + + interest: borrowed * interest_rate * time-periods + = 0.0075414886436454 * 0.0005 * 1 = 3.7707443218227e-06 base + = 0.0075414886436454 * 0.00025 * 5/4 = 2.3567152011391876e-06 base + = 0.0150829772872908 * 0.0005 * 5/4 = 9.42686080455675e-06 base + = 0.0150829772872908 * 0.00025 * 1 = 3.7707443218227e-06 base + """ + + trade = Trade( + pair='ETH/BTC', + stake_amount=0.0037707443218227, + amount=275.97543219, + open_rate=0.00001099, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='kraken', + leverage=3.0, + interest_rate=0.0005 + ) + + # The trades that last 10 minutes do not need to be rounded because they round up to 4 hours on kraken so we can predict the correct value + assert float(trade.calculate_interest()) == 3.7707443218227e-06 + trade.open_date = datetime.utcnow() - timedelta(hours=5, minutes=0) + # The trades that last for 5 hours have to be rounded because the length of time that the test takes will vary every time it runs, so we can't predict the exact value + assert float(round(trade.calculate_interest(interest_rate=0.00025), 11) + ) == round(2.3567152011391876e-06, 11) + + trade = Trade( + pair='ETH/BTC', + stake_amount=0.0037707443218227, + amount=459.95905365, + open_rate=0.00001099, + open_date=datetime.utcnow() - timedelta(hours=5, minutes=0), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='kraken', + leverage=5.0, + interest_rate=0.0005 + ) + + assert float(round(trade.calculate_interest(), 11) + ) == round(9.42686080455675e-06, 11) + trade.open_date = datetime.utcnow() - timedelta(hours=0, minutes=10) + assert float(trade.calculate_interest(interest_rate=0.00025)) == 3.7707443218227e-06 + + +@pytest.mark.usefixtures("init_persistence") +def test_interest_binance(market_leveraged_buy_order, fee): + """ + Market trade on Kraken at 3x and 5x leverage + Short trade + interest_rate: 0.05%, 0.25% per 4 hrs + open_rate: 0.00001099 base + close_rate: 0.00001173 base + stake_amount: 0.0009999999999226999 + borrowed: 0.0019999999998453998 + amount: + 90.99181073 * leverage(3) = 272.97543219 crypto + 90.99181073 * leverage(5) = 454.95905365 crypto + borrowed: + 0.0019999999998453998 base + 0.0039999999996907995 base + time-periods: 10 minutes(rounds up to 1/24 time-period of 24hrs) + 5 hours = 5/24 + + interest: borrowed * interest_rate * time-periods + = 0.0019999999998453998 * 0.00050 * 1/24 = 4.166666666344583e-08 base + = 0.0019999999998453998 * 0.00025 * 5/24 = 1.0416666665861459e-07 base + = 0.0039999999996907995 * 0.00050 * 5/24 = 4.1666666663445834e-07 base + = 0.0039999999996907995 * 0.00025 * 1/24 = 4.166666666344583e-08 base + """ + + trade = Trade( + pair='ETH/BTC', + stake_amount=0.0009999999999226999, + amount=272.97543219, + open_rate=0.00001099, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='binance', + + leverage=3.0, + interest_rate=0.0005 + ) + # The trades that last 10 minutes do not always need to be rounded because they round up to 4 hours on kraken so we can predict the correct value + assert round(float(trade.calculate_interest()), 22) == round(4.166666666344583e-08, 22) + trade.open_date = datetime.utcnow() - timedelta(hours=5, minutes=0) + # The trades that last for 5 hours have to be rounded because the length of time that the test takes will vary every time it runs, so we can't predict the exact value + assert float(round(trade.calculate_interest(interest_rate=0.00025), 14) + ) == round(1.0416666665861459e-07, 14) + + trade = Trade( + pair='ETH/BTC', + stake_amount=0.0009999999999226999, + amount=459.95905365, + open_rate=0.00001099, + open_date=datetime.utcnow() - timedelta(hours=5, minutes=0), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='binance', + leverage=5.0, + interest_rate=0.0005 + ) + + assert float(round(trade.calculate_interest(), 14)) == round(4.1666666663445834e-07, 14) + trade.open_date = datetime.utcnow() - timedelta(hours=0, minutes=10) + assert float(round(trade.calculate_interest(interest_rate=0.00025), 22) + ) == round(4.166666666344583e-08, 22) + + +@pytest.mark.usefixtures("init_persistence") +def test_update_open_order(limit_leveraged_buy_order): + trade = Trade( + pair='ETH/BTC', + stake_amount=1.00, + open_rate=0.01, + amount=5, + fee_open=0.1, + fee_close=0.1, + interest_rate=0.0005, + leverage=3.0, + exchange='binance', + ) + assert trade.open_order_id is None + assert trade.close_profit is None + assert trade.close_date is None + limit_leveraged_buy_order['status'] = 'open' + trade.update(limit_leveraged_buy_order) + assert trade.open_order_id is None + assert trade.close_profit is None + assert trade.close_date is None + + +@pytest.mark.usefixtures("init_persistence") +def test_calc_open_trade_value(market_leveraged_buy_order, fee): + """ + 10 minute leveraged market trade on Kraken at 3x leverage + Short trade + fee: 0.25% base + interest_rate: 0.05% per 4 hrs + open_rate: 0.00004099 base + close_rate: 0.00004173 base + amount: 91.99181073 * leverage(3) = 275.97543219 crypto + stake_amount: 0.0037707443218227 + borrowed: 0.0075414886436454 base + time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) + interest: borrowed * interest_rate * time-periods + = 0.0075414886436454 * 0.0005 * 1 = 3.7707443218227e-06 crypto + open_value: (amount * open_rate) + (amount * open_rate * fee) + = (275.97543219 * 0.00004099) + (275.97543219 * 0.00004099 * 0.0025) + = 0.01134051354788177 + """ + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=5, + open_rate=0.00004099, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + fee_open=fee.return_value, + fee_close=fee.return_value, + interest_rate=0.0005, + exchange='kraken', + leverage=3 + ) + trade.open_order_id = 'open_trade' + trade.update(market_leveraged_buy_order) # Buy @ 0.00001099 + # Get the open rate price with the standard fee rate + assert trade._calc_open_trade_value() == 0.01134051354788177 + trade.fee_open = 0.003 + # Get the open rate price with a custom fee rate + assert trade._calc_open_trade_value() == 0.011346169664364504 + + +@pytest.mark.usefixtures("init_persistence") +def test_calc_open_close_trade_price(limit_leveraged_buy_order, limit_leveraged_sell_order, fee): + """ + 5 hour leveraged trade on Binance + + fee: 0.25% base + interest_rate: 0.05% per day + open_rate: 0.00001099 base + close_rate: 0.00001173 base + amount: 272.97543219 crypto + stake_amount: 0.0009999999999226999 base + borrowed: 0.0019999999998453998 base + time-periods: 5 hours(rounds up to 5/24 time-period of 1 day) + interest: borrowed * interest_rate * time-periods + = 0.0019999999998453998 * 0.0005 * 5/24 = 2.0833333331722917e-07 base + open_value: (amount * open_rate) + (amount * open_rate * fee) + = (272.97543219 * 0.00001099) + (272.97543219 * 0.00001099 * 0.0025) + = 0.0030074999997675204 + close_value: ((amount_closed * close_rate) - (amount_closed * close_rate * fee)) - interest + = (272.97543219 * 0.00001173) - (272.97543219 * 0.00001173 * 0.0025) - 2.0833333331722917e-07 + = 0.003193788481706411 + total_profit = close_value - open_value + = 0.003193788481706411 - 0.0030074999997675204 + = 0.00018628848193889044 + total_profit_percentage = total_profit / stake_amount + = 0.00018628848193889054 / 0.0009999999999226999 + = 0.18628848195329067 + """ + trade = Trade( + pair='ETH/BTC', + stake_amount=0.0009999999999226999, + open_rate=0.01, + amount=5, + open_date=datetime.utcnow() - timedelta(hours=5, minutes=0), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='binance', + interest_rate=0.0005 + ) + trade.open_order_id = 'something' + trade.update(limit_leveraged_buy_order) + assert trade._calc_open_trade_value() == 0.00300749999976752 + trade.update(limit_leveraged_sell_order) + + # Will be slightly different due to slight changes in compilation time, and the fact that interest depends on time + assert round(trade.calc_close_trade_value(), 11) == round(0.003193788481706411, 11) + # Profit in BTC + assert round(trade.calc_profit(), 8) == round(0.00018628848193889054, 8) + # Profit in percent + assert round(trade.calc_profit_ratio(), 8) == round(0.18628848195329067, 8) + + +@pytest.mark.usefixtures("init_persistence") +def test_trade_close(fee): + """ + 5 hour leveraged market trade on Kraken at 3x leverage + fee: 0.25% base + interest_rate: 0.05% per 4 hrs + open_rate: 0.1 base + close_rate: 0.2 base + amount: 5 * leverage(3) = 15 crypto + stake_amount: 0.5 + borrowed: 1 base + time-periods: 5/4 periods of 4hrs + interest: borrowed * interest_rate * time-periods + = 1 * 0.0005 * 5/4 = 0.000625 crypto + open_value: (amount * open_rate) + (amount * open_rate * fee) + = (15 * 0.1) + (15 * 0.1 * 0.0025) + = 1.50375 + close_value: (amount_closed * close_rate) + (amount_closed * close_rate * fee) - interest + = (15 * 0.2) - (15 * 0.2 * 0.0025) - 0.000625 + = 2.9918750000000003 + total_profit = close_value - open_value + = 2.9918750000000003 - 1.50375 + = 1.4881250000000001 + total_profit_percentage = total_profit / stake_amount + = 1.4881250000000001 / 0.5 + = 2.9762500000000003 + """ + trade = Trade( + pair='ETH/BTC', + stake_amount=0.5, + open_rate=0.1, + amount=15, + is_open=True, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_date=datetime.utcnow() - timedelta(hours=5, minutes=0), + exchange='kraken', + leverage=3.0, + interest_rate=0.0005 + ) + assert trade.close_profit is None + assert trade.close_date is None + assert trade.is_open is True + trade.close(0.2) + assert trade.is_open is False + assert trade.close_profit == round(2.9762500000000003, 8) + assert trade.close_date is not None + + # TODO-mg: Remove these comments probably + # new_date = arrow.Arrow(2020, 2, 2, 15, 6, 1).datetime, + # assert trade.close_date != new_date + # # Close should NOT update close_date if the trade has been closed already + # assert trade.is_open is False + # trade.close_date = new_date + # trade.close(0.02) + # assert trade.close_date == new_date + + +@pytest.mark.usefixtures("init_persistence") +def test_calc_close_trade_price(market_leveraged_buy_order, market_leveraged_sell_order, fee): + """ + 10 minute leveraged market trade on Kraken at 3x leverage + Short trade + fee: 0.25% base + interest_rate: 0.05% per 4 hrs + open_rate: 0.00004099 base + close_rate: 0.00004173 base + amount: 91.99181073 * leverage(3) = 275.97543219 crypto + stake_amount: 0.0037707443218227 + borrowed: 0.0075414886436454 base + time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) + interest: borrowed * interest_rate * time-periods + = 0.0075414886436454 * 0.0005 * 1 = 3.7707443218227e-06 crypto + open_value: (amount * open_rate) + (amount * open_rate * fee) + = (275.97543219 * 0.00004099) + (275.97543219 * 0.00004099 * 0.0025) + = 0.01134051354788177 + close_value: (amount_closed * close_rate) - (amount_closed * close_rate * fee) - interest + = (275.97543219 * 0.00001234) - (275.97543219 * 0.00001234 * 0.0025) - 3.7707443218227e-06 = 0.003393252246819716 + = (275.97543219 * 0.00001234) - (275.97543219 * 0.00001234 * 0.003) - 3.7707443218227e-06 = 0.003391549478403104 + = (275.97543219 * 0.00004173) - (275.97543219 * 0.00004173 * 0.005) - 3.7707443218227e-06 = 0.011455101767040435 + + """ + trade = Trade( + pair='ETH/BTC', + stake_amount=0.0037707443218227, + amount=5, + open_rate=0.00004099, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + interest_rate=0.0005, + + leverage=3.0, + exchange='kraken', + ) + trade.open_order_id = 'close_trade' + trade.update(market_leveraged_buy_order) # Buy @ 0.00001099 + # Get the close rate price with a custom close rate and a regular fee rate + assert isclose(trade.calc_close_trade_value(rate=0.00001234), 0.003393252246819716) + # Get the close rate price with a custom close rate and a custom fee rate + assert isclose(trade.calc_close_trade_value(rate=0.00001234, fee=0.003), 0.003391549478403104) + # Test when we apply a Sell order, and ask price with a custom fee rate + trade.update(market_leveraged_sell_order) + assert isclose(trade.calc_close_trade_value(fee=0.005), 0.011455101767040435) + + +@pytest.mark.usefixtures("init_persistence") +def test_update_limit_order(limit_leveraged_buy_order, limit_leveraged_sell_order, fee, caplog): """ 10 minute leveraged limit trade on binance at 3x leverage @@ -50,18 +401,17 @@ def test_update_with_binance(limit_leveraged_buy_order, limit_leveraged_sell_ord open_rate=0.01, amount=5, is_open=True, - open_date=ten_minutes_ago, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), fee_open=fee.return_value, fee_close=fee.return_value, - # borrowed=90.99181073, + leverage=3.0, interest_rate=0.0005, exchange='binance' ) # assert trade.open_order_id is None assert trade.close_profit is None assert trade.close_date is None - assert trade.borrowed is None - assert trade.is_short is None + # trade.open_order_id = 'something' trade.update(limit_leveraged_buy_order) # assert trade.open_order_id is None @@ -69,7 +419,6 @@ def test_update_with_binance(limit_leveraged_buy_order, limit_leveraged_sell_ord assert trade.close_profit is None assert trade.close_date is None assert trade.borrowed == 0.0019999999998453998 - assert trade.is_short is True assert log_has_re(r"LIMIT_BUY has been fulfilled for Trade\(id=2, " r"pair=ETH/BTC, amount=272.97543219, open_rate=0.00001099, open_since=.*\).", caplog) @@ -78,7 +427,7 @@ def test_update_with_binance(limit_leveraged_buy_order, limit_leveraged_sell_ord trade.update(limit_leveraged_sell_order) # assert trade.open_order_id is None assert trade.close_rate == 0.00001173 - assert trade.close_profit == 0.18645514861995735 + assert trade.close_profit == round(0.18645514861995735, 8) assert trade.close_date is not None assert log_has_re(r"LIMIT_SELL has been fulfilled for Trade\(id=2, " r"pair=ETH/BTC, amount=272.97543219, open_rate=0.00001099, open_since=.*\).", @@ -86,7 +435,7 @@ def test_update_with_binance(limit_leveraged_buy_order, limit_leveraged_sell_ord @pytest.mark.usefixtures("init_persistence") -def test_update_market_order(limit_leveraged_buy_order, limit_leveraged_sell_order, fee, ten_minutes_ago, caplog): +def test_update_market_order(market_leveraged_buy_order, market_leveraged_sell_order, fee, caplog): """ 10 minute leveraged market trade on Kraken at 3x leverage Short trade @@ -94,7 +443,7 @@ def test_update_market_order(limit_leveraged_buy_order, limit_leveraged_sell_ord interest_rate: 0.05% per 4 hrs open_rate: 0.00004099 base close_rate: 0.00004173 base - amount: 91.99181073 * leverage(3) = 275.97543219 crypto + amount: = 275.97543219 crypto stake_amount: 0.0037707443218227 borrowed: 0.0075414886436454 base time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) @@ -118,19 +467,18 @@ def test_update_market_order(limit_leveraged_buy_order, limit_leveraged_sell_ord pair='ETH/BTC', stake_amount=0.0037707443218227, amount=5, - open_rate=0.01, + open_rate=0.00004099, is_open=True, leverage=3, fee_open=fee.return_value, fee_close=fee.return_value, - open_date=ten_minutes_ago, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), interest_rate=0.0005, exchange='kraken' ) trade.open_order_id = 'something' - trade.update(limit_leveraged_buy_order) + trade.update(market_leveraged_buy_order) assert trade.leverage == 3.0 - assert trade.is_short == True assert trade.open_order_id is None assert trade.open_rate == 0.00004099 assert trade.close_profit is None @@ -144,10 +492,10 @@ def test_update_market_order(limit_leveraged_buy_order, limit_leveraged_sell_ord caplog.clear() trade.is_open = True trade.open_order_id = 'something' - trade.update(limit_leveraged_sell_order) + trade.update(market_leveraged_sell_order) assert trade.open_order_id is None assert trade.close_rate == 0.00004173 - assert trade.close_profit == 0.03802415223225211 + assert trade.close_profit == round(0.03802415223225211, 8) assert trade.close_date is not None # TODO: The amount should maybe be the opening amount + the interest # TODO: Uncomment the next assert and make it work. @@ -157,116 +505,6 @@ def test_update_market_order(limit_leveraged_buy_order, limit_leveraged_sell_ord caplog) -@pytest.mark.usefixtures("init_persistence") -def test_calc_open_close_trade_price(limit_leveraged_buy_order, limit_leveraged_sell_order, five_hours_ago, fee): - """ - 5 hour leveraged trade on Binance - - fee: 0.25% base - interest_rate: 0.05% per day - open_rate: 0.00001099 base - close_rate: 0.00001173 base - amount: 272.97543219 crypto - stake_amount: 0.0009999999999226999 base - borrowed: 0.0019999999998453998 base - time-periods: 5 hours(rounds up to 5/24 time-period of 1 day) - interest: borrowed * interest_rate * time-periods - = 0.0019999999998453998 * 0.0005 * 5/24 = 2.0833333331722917e-07 base - open_value: (amount * open_rate) + (amount * open_rate * fee) - = (272.97543219 * 0.00001099) + (272.97543219 * 0.00001099 * 0.0025) - = 0.0030074999997675204 - close_value: (amount_closed * close_rate) - (amount_closed * close_rate * fee) - = (272.97543219 * 0.00001173) - (272.97543219 * 0.00001173 * 0.0025) - = 0.003193996815039728 - total_profit = close_value - open_value - interest - = 0.003193996815039728 - 0.0030074999997675204 - 2.0833333331722917e-07 - = 0.00018628848193889054 - total_profit_percentage = total_profit / stake_amount - = 0.00018628848193889054 / 0.0009999999999226999 - = 0.18628848195329067 - """ - trade = Trade( - pair='ETH/BTC', - stake_amount=0.0009999999999226999, - open_rate=0.01, - amount=5, - open_date=five_hours_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - interest_rate=0.0005 - ) - trade.open_order_id = 'something' - trade.update(limit_leveraged_buy_order) - assert trade._calc_open_trade_value() == 0.0030074999997675204 - trade.update(limit_leveraged_sell_order) - - # Will be slightly different due to slight changes in compilation time, and the fact that interest depends on time - assert round(trade.calc_close_trade_value(), 11) == round(0.003193996815039728, 11) - # Profit in BTC - assert round(trade.calc_profit(), 8) == round(0.18628848195329067, 8) - # Profit in percent - # assert round(trade.calc_profit_ratio(), 11) == round(0.05822425142973869, 11) - - -@pytest.mark.usefixtures("init_persistence") -def test_trade_close(fee, five_hours_ago): - """ - 5 hour leveraged market trade on Kraken at 3x leverage - fee: 0.25% base - interest_rate: 0.05% per 4 hrs - open_rate: 0.1 base - close_rate: 0.2 base - amount: 5 * leverage(3) = 15 crypto - stake_amount: 0.5 - borrowed: 1 base - time-periods: 5/4 periods of 4hrs - interest: borrowed * interest_rate * time-periods - = 1 * 0.0005 * 5/4 = 0.000625 crypto - open_value: (amount * open_rate) + (amount * open_rate * fee) - = (15 * 0.1) + (15 * 0.1 * 0.0025) - = 1.50375 - close_value: (amount_closed * close_rate) + (amount_closed * close_rate * fee) - = (15 * 0.2) - (15 * 0.2 * 0.0025) - = 2.9925 - total_profit = close_value - open_value - interest - = 2.9925 - 1.50375 - 0.000625 - = 1.4881250000000001 - total_profit_percentage = total_profit / stake_amount - = 1.4881250000000001 / 0.5 - = 2.9762500000000003 - """ - trade = Trade( - pair='ETH/BTC', - stake_amount=0.1, - open_rate=0.01, - amount=5, - is_open=True, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_date=five_hours_ago, - exchange='kraken', - leverage=3.0, - interest_rate=0.0005 - ) - assert trade.close_profit is None - assert trade.close_date is None - assert trade.is_open is True - trade.close(0.02) - assert trade.is_open is False - assert trade.close_profit == round(2.9762500000000003, 8) - assert trade.close_date is not None - - # TODO-mg: Remove these comments probably - # new_date = arrow.Arrow(2020, 2, 2, 15, 6, 1).datetime, - # assert trade.close_date != new_date - # # Close should NOT update close_date if the trade has been closed already - # assert trade.is_open is False - # trade.close_date = new_date - # trade.close(0.02) - # assert trade.close_date == new_date - - @pytest.mark.usefixtures("init_persistence") def test_calc_close_trade_price_exception(limit_leveraged_buy_order, fee): trade = Trade( @@ -278,7 +516,7 @@ def test_calc_close_trade_price_exception(limit_leveraged_buy_order, fee): fee_close=fee.return_value, exchange='binance', interest_rate=0.0005, - borrowed=0.002 + leverage=3.0 ) trade.open_order_id = 'something' trade.update(limit_leveraged_buy_order) @@ -286,118 +524,7 @@ def test_calc_close_trade_price_exception(limit_leveraged_buy_order, fee): @pytest.mark.usefixtures("init_persistence") -def test_update_open_order(limit_leveraged_buy_order): - trade = Trade( - pair='ETH/BTC', - stake_amount=1.00, - open_rate=0.01, - amount=5, - fee_open=0.1, - fee_close=0.1, - interest_rate=0.0005, - borrowed=2.00, - exchange='binance', - ) - assert trade.open_order_id is None - assert trade.close_profit is None - assert trade.close_date is None - limit_leveraged_buy_order['status'] = 'open' - trade.update(limit_leveraged_buy_order) - assert trade.open_order_id is None - assert trade.close_profit is None - assert trade.close_date is None - - -@pytest.mark.usefixtures("init_persistence") -def test_calc_open_trade_value(market_leveraged_buy_order, ten_minutes_ago, fee): - """ - 10 minute leveraged market trade on Kraken at 3x leverage - Short trade - fee: 0.25% base - interest_rate: 0.05% per 4 hrs - open_rate: 0.00004099 base - close_rate: 0.00004173 base - amount: 91.99181073 * leverage(3) = 275.97543219 crypto - stake_amount: 0.0037707443218227 - borrowed: 0.0075414886436454 base - time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) - interest: borrowed * interest_rate * time-periods - = 0.0075414886436454 * 0.0005 * 1 = 3.7707443218227e-06 crypto - open_value: (amount * open_rate) + (amount * open_rate * fee) - = (275.97543219 * 0.00004099) + (275.97543219 * 0.00004099 * 0.0025) - = 0.01134051354788177 - """ - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=5, - open_rate=0.00004099, - open_date=ten_minutes_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - interest_rate=0.0005, - exchange='kraken', - leverage=3 - ) - trade.open_order_id = 'open_trade' - trade.update(market_leveraged_buy_order) # Buy @ 0.00001099 - # Get the open rate price with the standard fee rate - assert trade._calc_open_trade_value() == 0.01134051354788177 - trade.fee_open = 0.003 - # Get the open rate price with a custom fee rate - assert trade._calc_open_trade_value() == 0.011346169664364504 - - -@pytest.mark.usefixtures("init_persistence") -def test_calc_close_trade_price(market_leveraged_buy_order, market_leveraged_sell_order, ten_minutes_ago, fee): - """ - 10 minute leveraged market trade on Kraken at 3x leverage - Short trade - fee: 0.25% base - interest_rate: 0.05% per 4 hrs - open_rate: 0.00004099 base - close_rate: 0.00004173 base - amount: 91.99181073 * leverage(3) = 275.97543219 crypto - stake_amount: 0.0037707443218227 - borrowed: 0.0075414886436454 base - time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) - interest: borrowed * interest_rate * time-periods - = 0.0075414886436454 * 0.0005 * 1 = 3.7707443218227e-06 crypto - open_value: (amount * open_rate) + (amount * open_rate * fee) - = (275.97543219 * 0.00004099) + (275.97543219 * 0.00004099 * 0.0025) - = 0.01134051354788177 - close_value: (amount_closed * close_rate) - (amount_closed * close_rate * fee) - = (275.97543219 * 0.00001234) - (275.97543219 * 0.00001234 * 0.0025) = 0.0033970229911415386 - = (275.97543219 * 0.00001234) - (275.97543219 * 0.00001234 * 0.003) = 0.0033953202227249265 - = (275.97543219 * 0.00004173) - (275.97543219 * 0.00004173 * 0.005) = 0.011458872511362258 - - """ - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=5, - open_rate=0.00001099, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_date=ten_minutes_ago, - interest_rate=0.0005, - is_short=True, - leverage=3.0, - exchange='kraken', - ) - trade.open_order_id = 'close_trade' - trade.update(market_leveraged_buy_order) # Buy @ 0.00001099 - # Get the close rate price with a custom close rate and a regular fee rate - assert isclose(trade.calc_close_trade_value(rate=0.00001234), 0.0033970229911415386) - # Get the close rate price with a custom close rate and a custom fee rate - assert isclose(trade.calc_close_trade_value(rate=0.00001234, fee=0.003), 0.0033953202227249265) - # Test when we apply a Sell order, and ask price with a custom fee rate - trade.update(market_leveraged_sell_order) - assert isclose(trade.calc_close_trade_value(fee=0.005), 0.011458872511362258) - - -@pytest.mark.usefixtures("init_persistence") -def test_calc_profit(market_leveraged_buy_order, market_leveraged_sell_order, ten_minutes_ago, five_hours_ago, fee): +def test_calc_profit(market_leveraged_buy_order, market_leveraged_sell_order, fee): """ # TODO: Update this one Leveraged trade on Kraken at 3x leverage @@ -412,35 +539,35 @@ def test_calc_profit(market_leveraged_buy_order, market_leveraged_sell_order, te 5 hours = 5/4 interest: borrowed * interest_rate * time-periods - = 0.0075414886436454 * 0.0005 * 1 = 3.7707443218227e-06 crypto + = 0.0075414886436454 * 0.0005 * 1 = 3.7707443218227e-06 crypto = 0.0075414886436454 * 0.00025 * 5/4 = 2.3567152011391876e-06 crypto - = 0.0075414886436454 * 0.0005 * 5/4 = 4.713430402278375e-06 crypto - = 0.0075414886436454 * 0.00025 * 1 = 1.88537216091135e-06 crypto + = 0.0075414886436454 * 0.0005 * 5/4 = 4.713430402278375e-06 crypto + = 0.0075414886436454 * 0.00025 * 1 = 1.88537216091135e-06 crypto open_value: (amount * open_rate) + (amount * open_rate * fee) = (275.97543219 * 0.00004099) + (275.97543219 * 0.00004099 * 0.0025) = 0.01134051354788177 - close_value: (amount_closed * close_rate) - (amount_closed * close_rate * fee) - (275.97543219 * 0.00005374) - (275.97543219 * 0.00005374 * 0.0025) = 0.014793842426575873 - (275.97543219 * 0.00000437) - (275.97543219 * 0.00000437 * 0.0025) = 0.0012029976070736241 - (275.97543219 * 0.00005374) - (275.97543219 * 0.00005374 * 0.003) = 0.014786426966712927 - (275.97543219 * 0.00000437) - (275.97543219 * 0.00000437 * 0.003) = 0.0012023946007542888 + close_value: (amount_closed * close_rate) - (amount_closed * close_rate * fee) - interest + (275.97543219 * 0.00005374) - (275.97543219 * 0.00005374 * 0.0025) - 3.7707443218227e-06 = 0.01479007168225405 + (275.97543219 * 0.00000437) - (275.97543219 * 0.00000437 * 0.0025) - 2.3567152011391876e-06 = 0.001200640891872485 + (275.97543219 * 0.00005374) - (275.97543219 * 0.00005374 * 0.003) - 4.713430402278375e-06 = 0.014781713536310649 + (275.97543219 * 0.00000437) - (275.97543219 * 0.00000437 * 0.003) - 1.88537216091135e-06 = 0.0012005092285933775 total_profit = close_value - open_value - = 0.014793842426575873 - 0.01134051354788177 = 0.003453328878694104 - = 0.0012029976070736241 - 0.01134051354788177 = -0.010137515940808145 - = 0.014786426966712927 - 0.01134051354788177 = 0.0034459134188311574 - = 0.0012023946007542888 - 0.01134051354788177 = -0.01013811894712748 + = 0.01479007168225405 - 0.01134051354788177 = 0.003449558134372281 + = 0.001200640891872485 - 0.01134051354788177 = -0.010139872656009285 + = 0.014781713536310649 - 0.01134051354788177 = 0.0034411999884288794 + = 0.0012005092285933775 - 0.01134051354788177 = -0.010140004319288392 total_profit_percentage = total_profit / stake_amount - 0.003453328878694104/0.0037707443218227 = 0.9158215418394733 - -0.010137515940808145/0.0037707443218227 = -2.6884654793852154 - 0.0034459134188311574/0.0037707443218227 = 0.9138549646255183 - -0.01013811894712748/0.0037707443218227 = -2.6886253964381557 + 0.003449558134372281/0.0037707443218227 = 0.9148215418394732 + -0.010139872656009285/0.0037707443218227 = -2.6890904793852157 + 0.0034411999884288794/0.0037707443218227 = 0.9126049646255184 + -0.010140004319288392/0.0037707443218227 = -2.6891253964381554 """ trade = Trade( pair='ETH/BTC', - stake_amount=0.0038388182617629, + stake_amount=0.0037707443218227, amount=5, open_rate=0.00004099, - open_date=ten_minutes_ago, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), fee_open=fee.return_value, fee_close=fee.return_value, exchange='kraken', @@ -452,31 +579,31 @@ def test_calc_profit(market_leveraged_buy_order, market_leveraged_sell_order, te # Custom closing rate and regular fee rate # Higher than open rate - assert trade.calc_profit(rate=0.00004374, interest_rate=0.0005) == round( - 0.003453328878694104, 8) + assert trade.calc_profit(rate=0.00005374, interest_rate=0.0005) == round( + 0.003449558134372281, 8) assert trade.calc_profit_ratio( - rate=0.00004374, interest_rate=0.0005) == round(0.9158215418394733, 8) + rate=0.00005374, interest_rate=0.0005) == round(0.9148215418394732, 8) # Lower than open rate - trade.open_date = five_hours_ago + trade.open_date = datetime.utcnow() - timedelta(hours=5, minutes=0) assert trade.calc_profit( - rate=0.00000437, interest_rate=0.00025) == round(-0.010137515940808145, 8) + rate=0.00000437, interest_rate=0.00025) == round(-0.010139872656009285, 8) assert trade.calc_profit_ratio( - rate=0.00000437, interest_rate=0.00025) == round(-2.6884654793852154, 8) + rate=0.00000437, interest_rate=0.00025) == round(-2.6890904793852157, 8) # Custom closing rate and custom fee rate # Higher than open rate - assert trade.calc_profit(rate=0.00004374, fee=0.003, - interest_rate=0.0005) == round(0.0034459134188311574, 8) - assert trade.calc_profit_ratio(rate=0.00004374, fee=0.003, - interest_rate=0.0005) == round(0.9138549646255183, 8) + assert trade.calc_profit(rate=0.00005374, fee=0.003, + interest_rate=0.0005) == round(0.0034411999884288794, 8) + assert trade.calc_profit_ratio(rate=0.00005374, fee=0.003, + interest_rate=0.0005) == round(0.9126049646255184, 8) # Lower than open rate - trade.open_date = ten_minutes_ago + trade.open_date = datetime.utcnow() - timedelta(hours=0, minutes=10) assert trade.calc_profit(rate=0.00000437, fee=0.003, - interest_rate=0.00025) == round(-0.01013811894712748, 8) + interest_rate=0.00025) == round(-0.010140004319288392, 8) assert trade.calc_profit_ratio(rate=0.00000437, fee=0.003, - interest_rate=0.00025) == round(-2.6886253964381557, 8) + interest_rate=0.00025) == round(-2.6891253964381554, 8) # Test when we apply a Sell order. Sell higher than open rate @ 0.00001173 trade.update(market_leveraged_sell_order) @@ -486,131 +613,3 @@ def test_calc_profit(market_leveraged_buy_order, market_leveraged_sell_order, te # Test with a custom fee rate on the close trade # assert trade.calc_profit(fee=0.003) == 0.00006163 # assert trade.calc_profit_ratio(fee=0.003) == 0.06147824 - - -@pytest.mark.usefixtures("init_persistence") -def test_interest_kraken(market_leveraged_buy_order, ten_minutes_ago, five_hours_ago, fee): - """ - Market trade on Kraken at 3x and 8x leverage - Short trade - interest_rate: 0.05%, 0.25% per 4 hrs - open_rate: 0.00004099 base - close_rate: 0.00004173 base - stake_amount: 0.0037707443218227 - borrowed: 0.0075414886436454 - amount: - 91.99181073 * leverage(3) = 275.97543219 crypto - 91.99181073 * leverage(5) = 459.95905365 crypto - borrowed: - 0.0075414886436454 base - 0.0150829772872908 base - time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) - 5 hours = 5/4 - - interest: borrowed * interest_rate * time-periods - = 0.0075414886436454 * 0.0005 * 1 = 3.7707443218227e-06 base - = 0.0075414886436454 * 0.00025 * 5/4 = 2.3567152011391876e-06 base - = 0.0150829772872908 * 0.0005 * 5/4 = 9.42686080455675e-06 base - = 0.0150829772872908 * 0.00025 * 1 = 3.7707443218227e-06 base - """ - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.0037707443218227, - amount=91.99181073, - open_rate=0.00001099, - open_date=ten_minutes_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='kraken', - leverage=3.0, - interest_rate=0.0005 - ) - - assert float(round(trade.calculate_interest(), 8)) == 3.7707443218227e-06 - trade.open_date = five_hours_ago - assert float(round(trade.calculate_interest(interest_rate=0.00025), 8) - ) == 2.3567152011391876e-06 # TODO: Fails with 0.08624233 - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.0037707443218227, - amount=91.99181073, - open_rate=0.00001099, - open_date=five_hours_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='kraken', - is_short=True, - leverage=5.0, - interest_rate=0.0005 - ) - - assert float(round(trade.calculate_interest(), 8) - ) == 9.42686080455675e-06 # TODO: Fails with 0.28747445 - trade.open_date = ten_minutes_ago - assert float(round(trade.calculate_interest(interest_rate=0.00025), 8)) == 3.7707443218227e-06 - - -@pytest.mark.usefixtures("init_persistence") -def test_interest_binance(market_leveraged_buy_order, ten_minutes_ago, five_hours_ago, fee): - """ - Market trade on Kraken at 3x and 8x leverage - Short trade - interest_rate: 0.05%, 0.25% per 4 hrs - open_rate: 0.00004099 base - close_rate: 0.00004173 base - stake_amount: 0.0037707443218227 - borrowed: 0.0075414886436454 - amount: - 91.99181073 * leverage(3) = 275.97543219 crypto - 91.99181073 * leverage(5) = 459.95905365 crypto - borrowed: - 0.0075414886436454 base - 0.0150829772872908 base - time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) - 5 hours = 5/24 - - interest: borrowed * interest_rate * time-periods - = 0.0075414886436454 * 0.0005 * 1/24 = 1.571143467426125e-07 base - = 0.0075414886436454 * 0.00025 * 5/24 = 3.9278586685653125e-07 base - = 0.0150829772872908 * 0.0005 * 5/24 = 1.571143467426125e-06 base - = 0.0150829772872908 * 0.00025 * 1/24 = 1.571143467426125e-07 base - """ - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=275.97543219, - open_rate=0.00001099, - open_date=ten_minutes_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - is_short=True, - borrowed=275.97543219, - interest_rate=0.0005 - ) - - assert float(round(trade.calculate_interest(), 8)) == 1.571143467426125e-07 - trade.open_date = five_hours_ago - assert float(round(trade.calculate_interest(interest_rate=0.00025), 8) - ) == 3.9278586685653125e-07 - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=459.95905365, - open_rate=0.00001099, - open_date=five_hours_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - is_short=True, - borrowed=459.95905365, - interest_rate=0.0005 - ) - - assert float(round(trade.calculate_interest(), 8)) == 1.571143467426125e-06 - trade.open_date = ten_minutes_ago - assert float(round(trade.calculate_interest(interest_rate=0.00025), 8)) == 1.571143467426125e-07 diff --git a/tests/test_persistence_short.py b/tests/test_persistence_short.py index 759b25a1a..c9abff4b0 100644 --- a/tests/test_persistence_short.py +++ b/tests/test_persistence_short.py @@ -14,7 +14,357 @@ from tests.conftest import create_mock_trades_with_leverage, log_has, log_has_re @pytest.mark.usefixtures("init_persistence") -def test_update_with_binance(limit_short_order, limit_exit_short_order, fee, ten_minutes_ago, caplog): +def test_interest_kraken(market_short_order, fee): + """ + Market trade on Kraken at 3x and 8x leverage + Short trade + interest_rate: 0.05%, 0.25% per 4 hrs + open_rate: 0.00004173 base + close_rate: 0.00004099 base + amount: + 275.97543219 crypto + 459.95905365 crypto + borrowed: + 275.97543219 crypto + 459.95905365 crypto + time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) + 5 hours = 5/4 + + interest: borrowed * interest_rate * time-periods + = 275.97543219 * 0.0005 * 1 = 0.137987716095 crypto + = 275.97543219 * 0.00025 * 5/4 = 0.086242322559375 crypto + = 459.95905365 * 0.0005 * 5/4 = 0.28747440853125 crypto + = 459.95905365 * 0.00025 * 1 = 0.1149897634125 crypto + """ + + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=275.97543219, + open_rate=0.00001099, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='kraken', + is_short=True, + leverage=3.0, + interest_rate=0.0005 + ) + + assert float(round(trade.calculate_interest(), 8)) == round(0.137987716095, 8) + trade.open_date = datetime.utcnow() - timedelta(hours=5, minutes=0) + assert float(round(trade.calculate_interest(interest_rate=0.00025), 8) + ) == round(0.086242322559375, 8) + + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=459.95905365, + open_rate=0.00001099, + open_date=datetime.utcnow() - timedelta(hours=5, minutes=0), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='kraken', + is_short=True, + leverage=5.0, + interest_rate=0.0005 + ) + + assert float(round(trade.calculate_interest(), 8)) == round(0.28747440853125, 8) + trade.open_date = datetime.utcnow() - timedelta(hours=0, minutes=10) + assert float(round(trade.calculate_interest(interest_rate=0.00025), 8) + ) == round(0.1149897634125, 8) + + +@ pytest.mark.usefixtures("init_persistence") +def test_interest_binance(market_short_order, fee): + """ + Market trade on Binance at 3x and 5x leverage + Short trade + interest_rate: 0.05%, 0.25% per 1 day + open_rate: 0.00004173 base + close_rate: 0.00004099 base + amount: + 91.99181073 * leverage(3) = 275.97543219 crypto + 91.99181073 * leverage(5) = 459.95905365 crypto + borrowed: + 275.97543219 crypto + 459.95905365 crypto + time-periods: 10 minutes(rounds up to 1/24 time-period of 1 day) + 5 hours = 5/24 + + interest: borrowed * interest_rate * time-periods + = 275.97543219 * 0.0005 * 1/24 = 0.005749488170625 crypto + = 275.97543219 * 0.00025 * 5/24 = 0.0143737204265625 crypto + = 459.95905365 * 0.0005 * 5/24 = 0.047912401421875 crypto + = 459.95905365 * 0.00025 * 1/24 = 0.0047912401421875 crypto + """ + + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=275.97543219, + open_rate=0.00001099, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='binance', + is_short=True, + leverage=3.0, + interest_rate=0.0005 + ) + + assert float(round(trade.calculate_interest(), 8)) == 0.00574949 + trade.open_date = datetime.utcnow() - timedelta(hours=5, minutes=0) + assert float(round(trade.calculate_interest(interest_rate=0.00025), 8)) == 0.01437372 + + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=459.95905365, + open_rate=0.00001099, + open_date=datetime.utcnow() - timedelta(hours=5, minutes=0), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='binance', + is_short=True, + leverage=5.0, + interest_rate=0.0005 + ) + + assert float(round(trade.calculate_interest(), 8)) == 0.04791240 + trade.open_date = datetime.utcnow() - timedelta(hours=0, minutes=10) + assert float(round(trade.calculate_interest(interest_rate=0.00025), 8)) == 0.00479124 + + +@ pytest.mark.usefixtures("init_persistence") +def test_calc_open_trade_value(market_short_order, fee): + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=5, + open_rate=0.00004173, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + fee_open=fee.return_value, + fee_close=fee.return_value, + interest_rate=0.0005, + is_short=True, + leverage=3.0, + exchange='kraken', + ) + trade.open_order_id = 'open_trade' + trade.update(market_short_order) # Buy @ 0.00001099 + # Get the open rate price with the standard fee rate + assert trade._calc_open_trade_value() == 0.011487663648325479 + trade.fee_open = 0.003 + # Get the open rate price with a custom fee rate + assert trade._calc_open_trade_value() == 0.011481905420932834 + + +@ pytest.mark.usefixtures("init_persistence") +def test_update_open_order(limit_short_order): + trade = Trade( + pair='ETH/BTC', + stake_amount=1.00, + open_rate=0.01, + amount=5, + leverage=3.0, + fee_open=0.1, + fee_close=0.1, + interest_rate=0.0005, + is_short=True, + exchange='binance', + ) + assert trade.open_order_id is None + assert trade.close_profit is None + assert trade.close_date is None + limit_short_order['status'] = 'open' + trade.update(limit_short_order) + assert trade.open_order_id is None + assert trade.close_profit is None + assert trade.close_date is None + + +@ pytest.mark.usefixtures("init_persistence") +def test_calc_close_trade_price_exception(limit_short_order, fee): + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + open_rate=0.1, + amount=15.0, + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='binance', + interest_rate=0.0005, + leverage=3.0, + is_short=True + ) + trade.open_order_id = 'something' + trade.update(limit_short_order) + assert trade.calc_close_trade_value() == 0.0 + + +@ pytest.mark.usefixtures("init_persistence") +def test_calc_close_trade_price(market_short_order, market_exit_short_order, fee): + """ + 10 minute short market trade on Kraken at 3x leverage + Short trade + fee: 0.25% base + interest_rate: 0.05% per 4 hrs + open_rate: 0.00004173 base + close_rate: 0.00001234 base + amount: = 275.97543219 crypto + borrowed: 275.97543219 crypto + time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) + interest: borrowed * interest_rate * time-periods + = 275.97543219 * 0.0005 * 1 = 0.137987716095 crypto + amount_closed: amount + interest = 275.97543219 + 0.137987716095 = 276.113419906095 + close_value: (amount_closed * close_rate) + (amount_closed * close_rate * fee) + = (276.113419906095 * 0.00001234) + (276.113419906095 * 0.00001234 * 0.0025) + = 0.01134618380465571 + """ + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + amount=5, + open_rate=0.00001099, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + interest_rate=0.0005, + is_short=True, + leverage=3.0, + exchange='kraken', + ) + trade.open_order_id = 'close_trade' + trade.update(market_short_order) # Buy @ 0.00001099 + # Get the close rate price with a custom close rate and a regular fee rate + assert isclose(trade.calc_close_trade_value(rate=0.00001234), 0.003415757700645315) + # Get the close rate price with a custom close rate and a custom fee rate + assert isclose(trade.calc_close_trade_value(rate=0.00001234, fee=0.003), 0.0034174613204461354) + # Test when we apply a Sell order, and ask price with a custom fee rate + trade.update(market_exit_short_order) + assert isclose(trade.calc_close_trade_value(fee=0.005), 0.011374478527360586) + + +@ pytest.mark.usefixtures("init_persistence") +def test_calc_open_close_trade_price(limit_short_order, limit_exit_short_order, fee): + """ + 5 hour short trade on Binance + Short trade + fee: 0.25% base + interest_rate: 0.05% per day + open_rate: 0.00001173 base + close_rate: 0.00001099 base + amount: 90.99181073 crypto + borrowed: 90.99181073 crypto + stake_amount: 0.0010673339398629 + time-periods: 5 hours = 5/24 + interest: borrowed * interest_rate * time-periods + = 90.99181073 * 0.0005 * 5/24 = 0.009478313617708333 crypto + open_value: (amount * open_rate) - (amount * open_rate * fee) + = (90.99181073 * 0.00001173) - (90.99181073 * 0.00001173 * 0.0025) + = 0.0010646656050132426 + amount_closed: amount + interest = 90.99181073 + 0.009478313617708333 = 91.0012890436177 + close_value: (amount_closed * close_rate) + (amount_closed * close_rate * fee) + = (91.0012890436177 * 0.00001099) + (91.0012890436177 * 0.00001099 * 0.0025) + = 0.001002604427005832 + total_profit = open_value - close_value + = 0.0010646656050132426 - 0.001002604427005832 + = 0.00006206117800741065 + total_profit_percentage = (close_value - open_value) / stake_amount + = (0.0010646656050132426 - 0.0010025208853391716)/0.0010673339398629 + = 0.05822425142973869 + """ + trade = Trade( + pair='ETH/BTC', + stake_amount=0.0010673339398629, + open_rate=0.01, + amount=5, + open_date=datetime.utcnow() - timedelta(hours=5, minutes=0), + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='binance', + interest_rate=0.0005 + ) + trade.open_order_id = 'something' + trade.update(limit_short_order) + assert trade._calc_open_trade_value() == 0.0010646656050132426 + trade.update(limit_exit_short_order) + + # Will be slightly different due to slight changes in compilation time, and the fact that interest depends on time + assert round(trade.calc_close_trade_value(), 11) == round(0.001002604427005832, 11) + # Profit in BTC + assert round(trade.calc_profit(), 8) == round(0.00006206117800741065, 8) + # Profit in percent + # assert round(trade.calc_profit_ratio(), 11) == round(0.05822425142973869, 11) + + +@ pytest.mark.usefixtures("init_persistence") +def test_trade_close(fee): + """ + Five hour short trade on Kraken at 3x leverage + Short trade + Exchange: Kraken + fee: 0.25% base + interest_rate: 0.05% per 4 hours + open_rate: 0.02 base + close_rate: 0.01 base + leverage: 3.0 + amount: 15 crypto + borrowed: 15 crypto + time-periods: 5 hours = 5/4 + + interest: borrowed * interest_rate * time-periods + = 15 * 0.0005 * 5/4 = 0.009375 crypto + open_value: (amount * open_rate) - (amount * open_rate * fee) + = (15 * 0.02) - (15 * 0.02 * 0.0025) + = 0.29925 + amount_closed: amount + interest = 15 + 0.009375 = 15.009375 + close_value: (amount_closed * close_rate) + (amount_closed * close_rate * fee) + = (15.009375 * 0.01) + (15.009375 * 0.01 * 0.0025) + = 0.150468984375 + total_profit = open_value - close_value + = 0.29925 - 0.150468984375 + = 0.148781015625 + total_profit_percentage = total_profit / stake_amount + = 0.148781015625 / 0.1 + = 1.4878101562500001 + """ + trade = Trade( + pair='ETH/BTC', + stake_amount=0.1, + open_rate=0.02, + amount=15, + is_open=True, + fee_open=fee.return_value, + fee_close=fee.return_value, + open_date=datetime.utcnow() - timedelta(hours=5, minutes=0), + exchange='kraken', + is_short=True, + leverage=3.0, + interest_rate=0.0005 + ) + assert trade.close_profit is None + assert trade.close_date is None + assert trade.is_open is True + trade.close(0.01) + assert trade.is_open is False + assert trade.close_profit == round(1.4878101562500001, 8) + assert trade.close_date is not None + + # TODO-mg: Remove these comments probably + # new_date = arrow.Arrow(2020, 2, 2, 15, 6, 1).datetime, + # assert trade.close_date != new_date + # # Close should NOT update close_date if the trade has been closed already + # assert trade.is_open is False + # trade.close_date = new_date + # trade.close(0.02) + # assert trade.close_date == new_date + + +@ pytest.mark.usefixtures("init_persistence") +def test_update_with_binance(limit_short_order, limit_exit_short_order, fee, caplog): """ 10 minute short limit trade on binance @@ -40,7 +390,7 @@ def test_update_with_binance(limit_short_order, limit_exit_short_order, fee, ten = 0.0010646656050132426 - 0.0010025208853391716 = 0.00006214471967407108 total_profit_percentage = (close_value - open_value) / stake_amount - = (0.0010646656050132426 - 0.0010025208853391716) / 0.0010673339398629 + = 0.00006214471967407108 / 0.0010673339398629 = 0.05822425142973869 """ @@ -51,7 +401,7 @@ def test_update_with_binance(limit_short_order, limit_exit_short_order, fee, ten open_rate=0.01, amount=5, is_open=True, - open_date=ten_minutes_ago, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), fee_open=fee.return_value, fee_close=fee.return_value, # borrowed=90.99181073, @@ -61,7 +411,7 @@ def test_update_with_binance(limit_short_order, limit_exit_short_order, fee, ten # assert trade.open_order_id is None assert trade.close_profit is None assert trade.close_date is None - assert trade.borrowed is None + assert trade.borrowed == 0.0 assert trade.is_short is None # trade.open_order_id = 'something' trade.update(limit_short_order) @@ -86,12 +436,11 @@ def test_update_with_binance(limit_short_order, limit_exit_short_order, fee, ten caplog) -@pytest.mark.usefixtures("init_persistence") +@ pytest.mark.usefixtures("init_persistence") def test_update_market_order( market_short_order, market_exit_short_order, fee, - ten_minutes_ago, caplog ): """ @@ -101,7 +450,7 @@ def test_update_market_order( interest_rate: 0.05% per 4 hrs open_rate: 0.00004173 base close_rate: 0.00004099 base - amount: 91.99181073 * leverage(3) = 275.97543219 crypto + amount: = 275.97543219 crypto stake_amount: 0.0038388182617629 borrowed: 275.97543219 crypto time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) @@ -130,7 +479,8 @@ def test_update_market_order( is_open=True, fee_open=fee.return_value, fee_close=fee.return_value, - open_date=ten_minutes_ago, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), + leverage=3.0, interest_rate=0.0005, exchange='kraken' ) @@ -164,233 +514,8 @@ def test_update_market_order( # caplog) -@pytest.mark.usefixtures("init_persistence") -def test_calc_open_close_trade_price(limit_short_order, limit_exit_short_order, five_hours_ago, fee): - """ - 5 hour short trade on Binance - Short trade - fee: 0.25% base - interest_rate: 0.05% per day - open_rate: 0.00001173 base - close_rate: 0.00001099 base - amount: 90.99181073 crypto - borrowed: 90.99181073 crypto - stake_amount: 0.0010673339398629 - time-periods: 5 hours = 5/24 - interest: borrowed * interest_rate * time-periods - = 90.99181073 * 0.0005 * 5/24 = 0.009478313617708333 crypto - open_value: (amount * open_rate) - (amount * open_rate * fee) - = (90.99181073 * 0.00001173) - (90.99181073 * 0.00001173 * 0.0025) - = 0.0010646656050132426 - amount_closed: amount + interest = 90.99181073 + 0.009478313617708333 = 91.0012890436177 - close_value: (amount_closed * close_rate) + (amount_closed * close_rate * fee) - = (91.0012890436177 * 0.00001099) + (91.0012890436177 * 0.00001099 * 0.0025) - = 0.001002604427005832 - total_profit = open_value - close_value - = 0.0010646656050132426 - 0.001002604427005832 - = 0.00006206117800741065 - total_profit_percentage = (close_value - open_value) / stake_amount - = (0.0010646656050132426 - 0.0010025208853391716)/0.0010673339398629 - = 0.05822425142973869 - """ - trade = Trade( - pair='ETH/BTC', - stake_amount=0.0010673339398629, - open_rate=0.01, - amount=5, - open_date=five_hours_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - interest_rate=0.0005 - ) - trade.open_order_id = 'something' - trade.update(limit_short_order) - assert trade._calc_open_trade_value() == 0.0010646656050132426 - trade.update(limit_exit_short_order) - - # Will be slightly different due to slight changes in compilation time, and the fact that interest depends on time - assert round(trade.calc_close_trade_value(), 11) == round(0.001002604427005832, 11) - # Profit in BTC - assert round(trade.calc_profit(), 8) == round(0.00006206117800741065, 8) - # Profit in percent - # assert round(trade.calc_profit_ratio(), 11) == round(0.05822425142973869, 11) - - -@pytest.mark.usefixtures("init_persistence") -def test_trade_close(fee, five_hours_ago): - """ - Five hour short trade on Kraken at 3x leverage - Short trade - Exchange: Kraken - fee: 0.25% base - interest_rate: 0.05% per 4 hours - open_rate: 0.02 base - close_rate: 0.01 base - leverage: 3.0 - amount: 5 * 3 = 15 crypto - borrowed: 15 crypto - time-periods: 5 hours = 5/4 - - interest: borrowed * interest_rate * time-periods - = 15 * 0.0005 * 5/4 = 0.009375 crypto - open_value: (amount * open_rate) - (amount * open_rate * fee) - = (15 * 0.02) - (15 * 0.02 * 0.0025) - = 0.29925 - amount_closed: amount + interest = 15 + 0.009375 = 15.009375 - close_value: (amount_closed * close_rate) + (amount_closed * close_rate * fee) - = (15.009375 * 0.01) + (15.009375 * 0.01 * 0.0025) - = 0.150468984375 - total_profit = open_value - close_value - = 0.29925 - 0.150468984375 - = 0.148781015625 - total_profit_percentage = total_profit / stake_amount - = 0.148781015625 / 0.1 - = 1.4878101562500001 - """ - trade = Trade( - pair='ETH/BTC', - stake_amount=0.1, - open_rate=0.02, - amount=5, - is_open=True, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_date=five_hours_ago, - exchange='kraken', - is_short=True, - leverage=3.0, - interest_rate=0.0005 - ) - assert trade.close_profit is None - assert trade.close_date is None - assert trade.is_open is True - trade.close(0.01) - assert trade.is_open is False - assert trade.close_profit == round(1.4878101562500001, 8) - assert trade.close_date is not None - - # TODO-mg: Remove these comments probably - # new_date = arrow.Arrow(2020, 2, 2, 15, 6, 1).datetime, - # assert trade.close_date != new_date - # # Close should NOT update close_date if the trade has been closed already - # assert trade.is_open is False - # trade.close_date = new_date - # trade.close(0.02) - # assert trade.close_date == new_date - - -@pytest.mark.usefixtures("init_persistence") -def test_calc_close_trade_price_exception(limit_short_order, fee): - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - open_rate=0.1, - amount=5, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - interest_rate=0.0005, - is_short=True, - borrowed=15 - ) - trade.open_order_id = 'something' - trade.update(limit_short_order) - assert trade.calc_close_trade_value() == 0.0 - - -@pytest.mark.usefixtures("init_persistence") -def test_update_open_order(limit_short_order): - trade = Trade( - pair='ETH/BTC', - stake_amount=1.00, - open_rate=0.01, - amount=5, - fee_open=0.1, - fee_close=0.1, - interest_rate=0.0005, - is_short=True, - exchange='binance', - ) - assert trade.open_order_id is None - assert trade.close_profit is None - assert trade.close_date is None - limit_short_order['status'] = 'open' - trade.update(limit_short_order) - assert trade.open_order_id is None - assert trade.close_profit is None - assert trade.close_date is None - - -@pytest.mark.usefixtures("init_persistence") -def test_calc_open_trade_value(market_short_order, ten_minutes_ago, fee): - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=5, - open_rate=0.00004173, - open_date=ten_minutes_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - interest_rate=0.0005, - is_short=True, - leverage=3.0, - exchange='kraken', - ) - trade.open_order_id = 'open_trade' - trade.update(market_short_order) # Buy @ 0.00001099 - # Get the open rate price with the standard fee rate - assert trade._calc_open_trade_value() == 0.011487663648325479 - trade.fee_open = 0.003 - # Get the open rate price with a custom fee rate - assert trade._calc_open_trade_value() == 0.011481905420932834 - - -@pytest.mark.usefixtures("init_persistence") -def test_calc_close_trade_price(market_short_order, market_exit_short_order, ten_minutes_ago, fee): - """ - 10 minute short market trade on Kraken at 3x leverage - Short trade - fee: 0.25% base - interest_rate: 0.05% per 4 hrs - open_rate: 0.00004173 base - close_rate: 0.00001234 base - amount: 91.99181073 * leverage(3) = 275.97543219 crypto - borrowed: 275.97543219 crypto - time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) - interest: borrowed * interest_rate * time-periods - = 275.97543219 * 0.0005 * 1 = 0.137987716095 crypto - amount_closed: amount + interest = 275.97543219 + 0.137987716095 = 276.113419906095 - close_value: (amount_closed * close_rate) + (amount_closed * close_rate * fee) - = (276.113419906095 * 0.00001234) + (276.113419906095 * 0.00001234 * 0.0025) - = 0.01134618380465571 - """ - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=5, - open_rate=0.00001099, - fee_open=fee.return_value, - fee_close=fee.return_value, - open_date=ten_minutes_ago, - interest_rate=0.0005, - is_short=True, - leverage=3.0, - exchange='kraken', - ) - trade.open_order_id = 'close_trade' - trade.update(market_short_order) # Buy @ 0.00001099 - # Get the close rate price with a custom close rate and a regular fee rate - assert isclose(trade.calc_close_trade_value(rate=0.00001234), 0.003415757700645315) - # Get the close rate price with a custom close rate and a custom fee rate - assert isclose(trade.calc_close_trade_value(rate=0.00001234, fee=0.003), 0.0034174613204461354) - # Test when we apply a Sell order, and ask price with a custom fee rate - trade.update(market_exit_short_order) - assert isclose(trade.calc_close_trade_value(fee=0.005), 0.011374478527360586) - - -@pytest.mark.usefixtures("init_persistence") -def test_calc_profit(market_short_order, market_exit_short_order, ten_minutes_ago, five_hours_ago, fee): +@ pytest.mark.usefixtures("init_persistence") +def test_calc_profit(market_short_order, market_exit_short_order, fee): """ Market trade on Kraken at 3x leverage Short trade @@ -399,7 +524,7 @@ def test_calc_profit(market_short_order, market_exit_short_order, ten_minutes_ag open_rate: 0.00004173 base close_rate: 0.00004099 base stake_amount: 0.0038388182617629 - amount: 91.99181073 * leverage(3) = 275.97543219 crypto + amount: = 275.97543219 crypto borrowed: 275.97543219 crypto time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) 5 hours = 5/4 @@ -438,7 +563,7 @@ def test_calc_profit(market_short_order, market_exit_short_order, ten_minutes_ag stake_amount=0.0038388182617629, amount=5, open_rate=0.00001099, - open_date=ten_minutes_ago, + open_date=datetime.utcnow() - timedelta(hours=0, minutes=10), fee_open=fee.return_value, fee_close=fee.return_value, exchange='kraken', @@ -456,7 +581,7 @@ def test_calc_profit(market_short_order, market_exit_short_order, ten_minutes_ag rate=0.00004374, interest_rate=0.0005) == round(-0.16143779115744006, 8) # Lower than open rate - trade.open_date = five_hours_ago + trade.open_date = datetime.utcnow() - timedelta(hours=5, minutes=0) assert trade.calc_profit(rate=0.00000437, interest_rate=0.00025) == round(0.01027826, 8) assert trade.calc_profit_ratio( rate=0.00000437, interest_rate=0.00025) == round(2.677453699564163, 8) @@ -469,7 +594,7 @@ def test_calc_profit(market_short_order, market_exit_short_order, ten_minutes_ag interest_rate=0.0005) == round(-0.16340506919482353, 8) # Lower than open rate - trade.open_date = ten_minutes_ago + trade.open_date = datetime.utcnow() - timedelta(hours=0, minutes=10) assert trade.calc_profit(rate=0.00000437, fee=0.003, interest_rate=0.00025) == round(0.01027773, 8) assert trade.calc_profit_ratio(rate=0.00000437, fee=0.003, @@ -485,129 +610,6 @@ def test_calc_profit(market_short_order, market_exit_short_order, ten_minutes_ag # assert trade.calc_profit_ratio(fee=0.003) == 0.06147824 -@pytest.mark.usefixtures("init_persistence") -def test_interest_kraken(market_short_order, ten_minutes_ago, five_hours_ago, fee): - """ - Market trade on Kraken at 3x and 8x leverage - Short trade - interest_rate: 0.05%, 0.25% per 4 hrs - open_rate: 0.00004173 base - close_rate: 0.00004099 base - amount: - 91.99181073 * leverage(3) = 275.97543219 crypto - 91.99181073 * leverage(5) = 459.95905365 crypto - borrowed: - 275.97543219 crypto - 459.95905365 crypto - time-periods: 10 minutes(rounds up to 1 time-period of 4hrs) - 5 hours = 5/4 - - interest: borrowed * interest_rate * time-periods - = 275.97543219 * 0.0005 * 1 = 0.137987716095 crypto - = 275.97543219 * 0.00025 * 5/4 = 0.086242322559375 crypto - = 459.95905365 * 0.0005 * 5/4 = 0.28747440853125 crypto - = 459.95905365 * 0.00025 * 1 = 0.1149897634125 crypto - """ - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=91.99181073, - open_rate=0.00001099, - open_date=ten_minutes_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='kraken', - is_short=True, - leverage=3.0, - interest_rate=0.0005 - ) - - assert float(round(trade.calculate_interest(), 8)) == 0.13798772 - trade.open_date = five_hours_ago - assert float(round(trade.calculate_interest(interest_rate=0.00025), 8) - ) == 0.08624232 # TODO: Fails with 0.08624233 - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=91.99181073, - open_rate=0.00001099, - open_date=five_hours_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='kraken', - is_short=True, - leverage=5.0, - interest_rate=0.0005 - ) - - assert float(round(trade.calculate_interest(), 8)) == 0.28747441 # TODO: Fails with 0.28747445 - trade.open_date = ten_minutes_ago - assert float(round(trade.calculate_interest(interest_rate=0.00025), 8)) == 0.11498976 - - -@pytest.mark.usefixtures("init_persistence") -def test_interest_binance(market_short_order, ten_minutes_ago, five_hours_ago, fee): - """ - Market trade on Binance at 3x and 5x leverage - Short trade - interest_rate: 0.05%, 0.25% per 1 day - open_rate: 0.00004173 base - close_rate: 0.00004099 base - amount: - 91.99181073 * leverage(3) = 275.97543219 crypto - 91.99181073 * leverage(5) = 459.95905365 crypto - borrowed: - 275.97543219 crypto - 459.95905365 crypto - time-periods: 10 minutes(rounds up to 1/24 time-period of 1 day) - 5 hours = 5/24 - - interest: borrowed * interest_rate * time-periods - = 275.97543219 * 0.0005 * 1/24 = 0.005749488170625 crypto - = 275.97543219 * 0.00025 * 5/24 = 0.0143737204265625 crypto - = 459.95905365 * 0.0005 * 5/24 = 0.047912401421875 crypto - = 459.95905365 * 0.00025 * 1/24 = 0.0047912401421875 crypto - """ - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=275.97543219, - open_rate=0.00001099, - open_date=ten_minutes_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - is_short=True, - borrowed=275.97543219, - interest_rate=0.0005 - ) - - assert float(round(trade.calculate_interest(), 8)) == 0.00574949 - trade.open_date = five_hours_ago - assert float(round(trade.calculate_interest(interest_rate=0.00025), 8)) == 0.01437372 - - trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=459.95905365, - open_rate=0.00001099, - open_date=five_hours_ago, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='binance', - is_short=True, - borrowed=459.95905365, - interest_rate=0.0005 - ) - - assert float(round(trade.calculate_interest(), 8)) == 0.04791240 - trade.open_date = ten_minutes_ago - assert float(round(trade.calculate_interest(interest_rate=0.00025), 8)) == 0.00479124 - - def test_adjust_stop_loss(fee): trade = Trade( pair='ETH/BTC', @@ -653,11 +655,13 @@ def test_adjust_stop_loss(fee): assert trade.initial_stop_loss == 1.05 assert trade.initial_stop_loss_pct == 0.05 assert trade.stop_loss_pct == 0.1 + trade.liquidation_price == 1.03 + # TODO-mg: Do a test with a trade that has a liquidation price -@pytest.mark.usefixtures("init_persistence") -@pytest.mark.parametrize('use_db', [True, False]) +@ pytest.mark.usefixtures("init_persistence") +@ pytest.mark.parametrize('use_db', [True, False]) def test_get_open(fee, use_db): Trade.use_db = use_db Trade.reset_trades() @@ -679,7 +683,8 @@ def test_stoploss_reinitialization(default_conf, fee): exchange='binance', open_rate=1, max_rate=1, - is_short=True + is_short=True, + leverage=3.0, ) trade.adjust_stop_loss(trade.open_rate, -0.05, True) assert trade.stop_loss == 1.05 @@ -720,8 +725,8 @@ def test_stoploss_reinitialization(default_conf, fee): assert trade_adj.initial_stop_loss_pct == 0.04 -@pytest.mark.usefixtures("init_persistence") -@pytest.mark.parametrize('use_db', [True, False]) +@ pytest.mark.usefixtures("init_persistence") +@ pytest.mark.parametrize('use_db', [True, False]) def test_total_open_trades_stakes(fee, use_db): Trade.use_db = use_db Trade.reset_trades() @@ -733,7 +738,7 @@ def test_total_open_trades_stakes(fee, use_db): Trade.use_db = True -@pytest.mark.usefixtures("init_persistence") +@ pytest.mark.usefixtures("init_persistence") def test_get_best_pair(fee): res = Trade.get_best_pair() assert res is None