Updated tests to new persistence
This commit is contained in:
parent
e0d42d2eb7
commit
78708b27f2
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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'
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user