Merge pull request #2674 from freqtrade/bt_trade_open_price
Pre-calculate open_trade_price
This commit is contained in:
commit
3a542bce62
@ -108,7 +108,7 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame:
|
|||||||
trades = pd.DataFrame([(t.pair,
|
trades = pd.DataFrame([(t.pair,
|
||||||
t.open_date.replace(tzinfo=timezone.utc),
|
t.open_date.replace(tzinfo=timezone.utc),
|
||||||
t.close_date.replace(tzinfo=timezone.utc) if t.close_date else None,
|
t.close_date.replace(tzinfo=timezone.utc) if t.close_date else None,
|
||||||
t.calc_profit(), t.calc_profit_percent(),
|
t.calc_profit(), t.calc_profit_ratio(),
|
||||||
t.open_rate, t.close_rate, t.amount,
|
t.open_rate, t.close_rate, t.amount,
|
||||||
(round((t.close_date.timestamp() - t.open_date.timestamp()) / 60, 2)
|
(round((t.close_date.timestamp() - t.open_date.timestamp()) / 60, 2)
|
||||||
if t.close_date else None),
|
if t.close_date else None),
|
||||||
|
@ -555,6 +555,7 @@ class FreqtradeBot:
|
|||||||
order['amount'] = new_amount
|
order['amount'] = new_amount
|
||||||
# Fee was applied, so set to 0
|
# Fee was applied, so set to 0
|
||||||
trade.fee_open = 0
|
trade.fee_open = 0
|
||||||
|
trade.recalc_open_trade_price()
|
||||||
|
|
||||||
except DependencyException as exception:
|
except DependencyException as exception:
|
||||||
logger.warning("Could not update trade amount: %s", exception)
|
logger.warning("Could not update trade amount: %s", exception)
|
||||||
@ -850,6 +851,7 @@ class FreqtradeBot:
|
|||||||
trade.amount = new_amount
|
trade.amount = new_amount
|
||||||
# Fee was applied, so set to 0
|
# Fee was applied, so set to 0
|
||||||
trade.fee_open = 0
|
trade.fee_open = 0
|
||||||
|
trade.recalc_open_trade_price()
|
||||||
except DependencyException as e:
|
except DependencyException as e:
|
||||||
logger.warning("Could not update trade amount: %s", e)
|
logger.warning("Could not update trade amount: %s", e)
|
||||||
|
|
||||||
@ -948,7 +950,7 @@ class FreqtradeBot:
|
|||||||
profit_trade = trade.calc_profit(rate=profit_rate)
|
profit_trade = trade.calc_profit(rate=profit_rate)
|
||||||
# Use cached ticker here - it was updated seconds ago.
|
# Use cached ticker here - it was updated seconds ago.
|
||||||
current_rate = self.get_sell_rate(trade.pair, False)
|
current_rate = self.get_sell_rate(trade.pair, False)
|
||||||
profit_percent = trade.calc_profit_percent(profit_rate)
|
profit_percent = trade.calc_profit_ratio(profit_rate)
|
||||||
gain = "profit" if profit_percent > 0 else "loss"
|
gain = "profit" if profit_percent > 0 else "loss"
|
||||||
|
|
||||||
msg = {
|
msg = {
|
||||||
|
@ -329,7 +329,7 @@ class Backtesting:
|
|||||||
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)
|
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)
|
||||||
|
|
||||||
return BacktestResult(pair=pair,
|
return BacktestResult(pair=pair,
|
||||||
profit_percent=trade.calc_profit_percent(rate=closerate),
|
profit_percent=trade.calc_profit_ratio(rate=closerate),
|
||||||
profit_abs=trade.calc_profit(rate=closerate),
|
profit_abs=trade.calc_profit(rate=closerate),
|
||||||
open_time=buy_row.date,
|
open_time=buy_row.date,
|
||||||
close_time=sell_row.date,
|
close_time=sell_row.date,
|
||||||
@ -345,7 +345,7 @@ class Backtesting:
|
|||||||
# no sell condition found - trade stil open at end of backtest period
|
# no sell condition found - trade stil open at end of backtest period
|
||||||
sell_row = partial_ticker[-1]
|
sell_row = partial_ticker[-1]
|
||||||
bt_res = BacktestResult(pair=pair,
|
bt_res = BacktestResult(pair=pair,
|
||||||
profit_percent=trade.calc_profit_percent(rate=sell_row.open),
|
profit_percent=trade.calc_profit_ratio(rate=sell_row.open),
|
||||||
profit_abs=trade.calc_profit(rate=sell_row.open),
|
profit_abs=trade.calc_profit(rate=sell_row.open),
|
||||||
open_time=buy_row.date,
|
open_time=buy_row.date,
|
||||||
close_time=sell_row.date,
|
close_time=sell_row.date,
|
||||||
|
@ -86,7 +86,7 @@ def check_migrate(engine) -> None:
|
|||||||
logger.debug(f'trying {table_back_name}')
|
logger.debug(f'trying {table_back_name}')
|
||||||
|
|
||||||
# Check for latest column
|
# Check for latest column
|
||||||
if not has_column(cols, 'stop_loss_pct'):
|
if not has_column(cols, 'open_trade_price'):
|
||||||
logger.info(f'Running database migration - backup available as {table_back_name}')
|
logger.info(f'Running database migration - backup available as {table_back_name}')
|
||||||
|
|
||||||
fee_open = get_column_def(cols, 'fee_open', 'fee')
|
fee_open = get_column_def(cols, 'fee_open', 'fee')
|
||||||
@ -104,6 +104,8 @@ def check_migrate(engine) -> None:
|
|||||||
sell_reason = get_column_def(cols, 'sell_reason', 'null')
|
sell_reason = get_column_def(cols, 'sell_reason', 'null')
|
||||||
strategy = get_column_def(cols, 'strategy', 'null')
|
strategy = get_column_def(cols, 'strategy', 'null')
|
||||||
ticker_interval = get_column_def(cols, 'ticker_interval', 'null')
|
ticker_interval = get_column_def(cols, 'ticker_interval', 'null')
|
||||||
|
open_trade_price = get_column_def(cols, 'open_trade_price',
|
||||||
|
f'amount * open_rate * (1 + {fee_open})')
|
||||||
|
|
||||||
# Schema migration necessary
|
# Schema migration necessary
|
||||||
engine.execute(f"alter table trades rename to {table_back_name}")
|
engine.execute(f"alter table trades rename to {table_back_name}")
|
||||||
@ -121,7 +123,7 @@ def check_migrate(engine) -> None:
|
|||||||
stop_loss, stop_loss_pct, initial_stop_loss, initial_stop_loss_pct,
|
stop_loss, stop_loss_pct, initial_stop_loss, initial_stop_loss_pct,
|
||||||
stoploss_order_id, stoploss_last_update,
|
stoploss_order_id, stoploss_last_update,
|
||||||
max_rate, min_rate, sell_reason, strategy,
|
max_rate, min_rate, sell_reason, strategy,
|
||||||
ticker_interval
|
ticker_interval, open_trade_price
|
||||||
)
|
)
|
||||||
select id, lower(exchange),
|
select id, lower(exchange),
|
||||||
case
|
case
|
||||||
@ -140,7 +142,8 @@ def check_migrate(engine) -> None:
|
|||||||
{initial_stop_loss_pct} initial_stop_loss_pct,
|
{initial_stop_loss_pct} initial_stop_loss_pct,
|
||||||
{stoploss_order_id} stoploss_order_id, {stoploss_last_update} stoploss_last_update,
|
{stoploss_order_id} stoploss_order_id, {stoploss_last_update} stoploss_last_update,
|
||||||
{max_rate} max_rate, {min_rate} min_rate, {sell_reason} sell_reason,
|
{max_rate} max_rate, {min_rate} min_rate, {sell_reason} sell_reason,
|
||||||
{strategy} strategy, {ticker_interval} ticker_interval
|
{strategy} strategy, {ticker_interval} ticker_interval,
|
||||||
|
{open_trade_price} open_trade_price
|
||||||
from {table_back_name}
|
from {table_back_name}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@ -182,6 +185,8 @@ class Trade(_DECL_BASE):
|
|||||||
fee_close = Column(Float, nullable=False, default=0.0)
|
fee_close = Column(Float, nullable=False, default=0.0)
|
||||||
open_rate = Column(Float)
|
open_rate = Column(Float)
|
||||||
open_rate_requested = Column(Float)
|
open_rate_requested = Column(Float)
|
||||||
|
# open_trade_price - calcuated via _calc_open_trade_price
|
||||||
|
open_trade_price = Column(Float)
|
||||||
close_rate = Column(Float)
|
close_rate = Column(Float)
|
||||||
close_rate_requested = Column(Float)
|
close_rate_requested = Column(Float)
|
||||||
close_profit = Column(Float)
|
close_profit = Column(Float)
|
||||||
@ -210,6 +215,10 @@ class Trade(_DECL_BASE):
|
|||||||
strategy = Column(String, nullable=True)
|
strategy = Column(String, nullable=True)
|
||||||
ticker_interval = Column(Integer, nullable=True)
|
ticker_interval = Column(Integer, nullable=True)
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.recalc_open_trade_price()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
open_since = self.open_date.strftime('%Y-%m-%d %H:%M:%S') if self.is_open else 'closed'
|
open_since = self.open_date.strftime('%Y-%m-%d %H:%M:%S') if self.is_open else 'closed'
|
||||||
|
|
||||||
@ -302,6 +311,7 @@ class Trade(_DECL_BASE):
|
|||||||
# Update open rate and actual amount
|
# Update open rate and actual amount
|
||||||
self.open_rate = Decimal(order['price'])
|
self.open_rate = Decimal(order['price'])
|
||||||
self.amount = Decimal(order['amount'])
|
self.amount = Decimal(order['amount'])
|
||||||
|
self.recalc_open_trade_price()
|
||||||
logger.info('%s_BUY has been fulfilled for %s.', order_type.upper(), self)
|
logger.info('%s_BUY has been fulfilled for %s.', order_type.upper(), self)
|
||||||
self.open_order_id = None
|
self.open_order_id = None
|
||||||
elif order_type in ('market', 'limit') and order['side'] == 'sell':
|
elif order_type in ('market', 'limit') and order['side'] == 'sell':
|
||||||
@ -322,7 +332,7 @@ class Trade(_DECL_BASE):
|
|||||||
and marks trade as closed
|
and marks trade as closed
|
||||||
"""
|
"""
|
||||||
self.close_rate = Decimal(rate)
|
self.close_rate = Decimal(rate)
|
||||||
self.close_profit = self.calc_profit_percent()
|
self.close_profit = self.calc_profit_ratio()
|
||||||
self.close_date = datetime.utcnow()
|
self.close_date = datetime.utcnow()
|
||||||
self.is_open = False
|
self.is_open = False
|
||||||
self.open_order_id = None
|
self.open_order_id = None
|
||||||
@ -331,17 +341,22 @@ class Trade(_DECL_BASE):
|
|||||||
self
|
self
|
||||||
)
|
)
|
||||||
|
|
||||||
def calc_open_trade_price(self, fee: Optional[float] = None) -> float:
|
def _calc_open_trade_price(self) -> float:
|
||||||
"""
|
"""
|
||||||
Calculate the open_rate including fee.
|
Calculate the open_rate including open_fee.
|
||||||
:param fee: fee to use on the open rate (optional).
|
|
||||||
If rate is not set self.fee will be used
|
|
||||||
:return: Price in of the open trade incl. Fees
|
:return: Price in of the open trade incl. Fees
|
||||||
"""
|
"""
|
||||||
buy_trade = (Decimal(self.amount) * Decimal(self.open_rate))
|
buy_trade = Decimal(self.amount) * Decimal(self.open_rate)
|
||||||
fees = buy_trade * Decimal(fee or self.fee_open)
|
fees = buy_trade * Decimal(self.fee_open)
|
||||||
return float(buy_trade + fees)
|
return float(buy_trade + fees)
|
||||||
|
|
||||||
|
def recalc_open_trade_price(self) -> None:
|
||||||
|
"""
|
||||||
|
Recalculate open_trade_price.
|
||||||
|
Must be called whenever open_rate or fee_open is changed.
|
||||||
|
"""
|
||||||
|
self.open_trade_price = self._calc_open_trade_price()
|
||||||
|
|
||||||
def calc_close_trade_price(self, rate: Optional[float] = None,
|
def calc_close_trade_price(self, rate: Optional[float] = None,
|
||||||
fee: Optional[float] = None) -> float:
|
fee: Optional[float] = None) -> float:
|
||||||
"""
|
"""
|
||||||
@ -355,7 +370,7 @@ class Trade(_DECL_BASE):
|
|||||||
if rate is None and not self.close_rate:
|
if rate is None and not self.close_rate:
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
sell_trade = (Decimal(self.amount) * Decimal(rate or self.close_rate))
|
sell_trade = Decimal(self.amount) * Decimal(rate or self.close_rate)
|
||||||
fees = sell_trade * Decimal(fee or self.fee_close)
|
fees = sell_trade * Decimal(fee or self.fee_close)
|
||||||
return float(sell_trade - fees)
|
return float(sell_trade - fees)
|
||||||
|
|
||||||
@ -369,29 +384,27 @@ class Trade(_DECL_BASE):
|
|||||||
If rate is not set self.close_rate will be used
|
If rate is not set self.close_rate will be used
|
||||||
:return: profit in stake currency as float
|
:return: profit in stake currency as float
|
||||||
"""
|
"""
|
||||||
open_trade_price = self.calc_open_trade_price()
|
|
||||||
close_trade_price = self.calc_close_trade_price(
|
close_trade_price = self.calc_close_trade_price(
|
||||||
rate=(rate or self.close_rate),
|
rate=(rate or self.close_rate),
|
||||||
fee=(fee or self.fee_close)
|
fee=(fee or self.fee_close)
|
||||||
)
|
)
|
||||||
profit = close_trade_price - open_trade_price
|
profit = close_trade_price - self.open_trade_price
|
||||||
return float(f"{profit:.8f}")
|
return float(f"{profit:.8f}")
|
||||||
|
|
||||||
def calc_profit_percent(self, rate: Optional[float] = None,
|
def calc_profit_ratio(self, rate: Optional[float] = None,
|
||||||
fee: Optional[float] = None) -> float:
|
fee: Optional[float] = None) -> float:
|
||||||
"""
|
"""
|
||||||
Calculates the profit in percentage (including fee).
|
Calculates the profit as ratio (including fee).
|
||||||
:param rate: rate to compare with (optional).
|
:param rate: rate to compare with (optional).
|
||||||
If rate is not set self.close_rate will be used
|
If rate is not set self.close_rate will be used
|
||||||
:param fee: fee to use on the close rate (optional).
|
:param fee: fee to use on the close rate (optional).
|
||||||
:return: profit in percentage as float
|
:return: profit ratio as float
|
||||||
"""
|
"""
|
||||||
open_trade_price = self.calc_open_trade_price()
|
|
||||||
close_trade_price = self.calc_close_trade_price(
|
close_trade_price = self.calc_close_trade_price(
|
||||||
rate=(rate or self.close_rate),
|
rate=(rate or self.close_rate),
|
||||||
fee=(fee or self.fee_close)
|
fee=(fee or self.fee_close)
|
||||||
)
|
)
|
||||||
profit_percent = (close_trade_price / open_trade_price) - 1
|
profit_percent = (close_trade_price / self.open_trade_price) - 1
|
||||||
return float(f"{profit_percent:.8f}")
|
return float(f"{profit_percent:.8f}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -123,7 +123,7 @@ class RPC:
|
|||||||
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
||||||
except DependencyException:
|
except DependencyException:
|
||||||
current_rate = NAN
|
current_rate = NAN
|
||||||
current_profit = trade.calc_profit_percent(current_rate)
|
current_profit = trade.calc_profit_ratio(current_rate)
|
||||||
fmt_close_profit = (f'{round(trade.close_profit * 100, 2):.2f}%'
|
fmt_close_profit = (f'{round(trade.close_profit * 100, 2):.2f}%'
|
||||||
if trade.close_profit else None)
|
if trade.close_profit else None)
|
||||||
trade_dict = trade.to_json()
|
trade_dict = trade.to_json()
|
||||||
@ -151,7 +151,7 @@ class RPC:
|
|||||||
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
||||||
except DependencyException:
|
except DependencyException:
|
||||||
current_rate = NAN
|
current_rate = NAN
|
||||||
trade_perc = (100 * trade.calc_profit_percent(current_rate))
|
trade_perc = (100 * trade.calc_profit_ratio(current_rate))
|
||||||
trade_profit = trade.calc_profit(current_rate)
|
trade_profit = trade.calc_profit(current_rate)
|
||||||
profit_str = f'{trade_perc:.2f}%'
|
profit_str = f'{trade_perc:.2f}%'
|
||||||
if self._fiat_converter:
|
if self._fiat_converter:
|
||||||
@ -240,7 +240,7 @@ class RPC:
|
|||||||
durations.append((trade.close_date - trade.open_date).total_seconds())
|
durations.append((trade.close_date - trade.open_date).total_seconds())
|
||||||
|
|
||||||
if not trade.is_open:
|
if not trade.is_open:
|
||||||
profit_percent = trade.calc_profit_percent()
|
profit_percent = trade.calc_profit_ratio()
|
||||||
profit_closed_coin.append(trade.calc_profit())
|
profit_closed_coin.append(trade.calc_profit())
|
||||||
profit_closed_perc.append(profit_percent)
|
profit_closed_perc.append(profit_percent)
|
||||||
else:
|
else:
|
||||||
@ -249,7 +249,7 @@ class RPC:
|
|||||||
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
current_rate = self._freqtrade.get_sell_rate(trade.pair, False)
|
||||||
except DependencyException:
|
except DependencyException:
|
||||||
current_rate = NAN
|
current_rate = NAN
|
||||||
profit_percent = trade.calc_profit_percent(rate=current_rate)
|
profit_percent = trade.calc_profit_ratio(rate=current_rate)
|
||||||
|
|
||||||
profit_all_coin.append(
|
profit_all_coin.append(
|
||||||
trade.calc_profit(rate=trade.close_rate or current_rate)
|
trade.calc_profit(rate=trade.close_rate or current_rate)
|
||||||
|
@ -296,7 +296,7 @@ class IStrategy(ABC):
|
|||||||
"""
|
"""
|
||||||
# Set current rate to low for backtesting sell
|
# Set current rate to low for backtesting sell
|
||||||
current_rate = low or rate
|
current_rate = low or rate
|
||||||
current_profit = trade.calc_profit_percent(current_rate)
|
current_profit = trade.calc_profit_ratio(current_rate)
|
||||||
|
|
||||||
trade.adjust_min_max_rates(high or current_rate)
|
trade.adjust_min_max_rates(high or current_rate)
|
||||||
|
|
||||||
@ -311,7 +311,7 @@ class IStrategy(ABC):
|
|||||||
|
|
||||||
# Set current rate to high for backtesting sell
|
# Set current rate to high for backtesting sell
|
||||||
current_rate = high or rate
|
current_rate = high or rate
|
||||||
current_profit = trade.calc_profit_percent(current_rate)
|
current_profit = trade.calc_profit_ratio(current_rate)
|
||||||
config_ask_strategy = self.config.get('ask_strategy', {})
|
config_ask_strategy = self.config.get('ask_strategy', {})
|
||||||
|
|
||||||
if buy and config_ask_strategy.get('ignore_roi_if_buy_signal', False):
|
if buy and config_ask_strategy.get('ignore_roi_if_buy_signal', False):
|
||||||
@ -360,7 +360,7 @@ class IStrategy(ABC):
|
|||||||
sl_offset = self.trailing_stop_positive_offset
|
sl_offset = self.trailing_stop_positive_offset
|
||||||
|
|
||||||
# Make sure current_profit is calculated using high for backtesting.
|
# Make sure current_profit is calculated using high for backtesting.
|
||||||
high_profit = current_profit if not high else trade.calc_profit_percent(high)
|
high_profit = current_profit if not high else trade.calc_profit_ratio(high)
|
||||||
|
|
||||||
# Don't update stoploss if trailing_only_offset_is_reached is true.
|
# Don't update stoploss if trailing_only_offset_is_reached is true.
|
||||||
if not (self.trailing_only_offset_is_reached and high_profit < sl_offset):
|
if not (self.trailing_only_offset_is_reached and high_profit < sl_offset):
|
||||||
|
@ -381,7 +381,7 @@ def test_api_performance(botclient, mocker, ticker, fee):
|
|||||||
close_rate=0.265441,
|
close_rate=0.265441,
|
||||||
|
|
||||||
)
|
)
|
||||||
trade.close_profit = trade.calc_profit_percent()
|
trade.close_profit = trade.calc_profit_ratio()
|
||||||
Trade.session.add(trade)
|
Trade.session.add(trade)
|
||||||
|
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
@ -396,7 +396,7 @@ def test_api_performance(botclient, mocker, ticker, fee):
|
|||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
close_rate=0.391
|
close_rate=0.391
|
||||||
)
|
)
|
||||||
trade.close_profit = trade.calc_profit_percent()
|
trade.close_profit = trade.calc_profit_ratio()
|
||||||
Trade.session.add(trade)
|
Trade.session.add(trade)
|
||||||
Trade.session.flush()
|
Trade.session.flush()
|
||||||
|
|
||||||
|
@ -125,6 +125,7 @@ def test_min_roi_reached(default_conf, fee) -> None:
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
open_date=arrow.utcnow().shift(hours=-1).datetime,
|
open_date=arrow.utcnow().shift(hours=-1).datetime,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
@ -162,6 +163,7 @@ def test_min_roi_reached2(default_conf, fee) -> None:
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
open_date=arrow.utcnow().shift(hours=-1).datetime,
|
open_date=arrow.utcnow().shift(hours=-1).datetime,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
@ -195,6 +197,7 @@ def test_min_roi_reached3(default_conf, fee) -> None:
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
open_date=arrow.utcnow().shift(hours=-1).datetime,
|
open_date=arrow.utcnow().shift(hours=-1).datetime,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
|
@ -1512,13 +1512,15 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No
|
|||||||
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount',
|
mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_real_amount',
|
||||||
return_value=limit_buy_order['amount'])
|
return_value=limit_buy_order['amount'])
|
||||||
|
|
||||||
trade = Trade()
|
trade = Trade(
|
||||||
# Mock session away
|
open_order_id=123,
|
||||||
Trade.session = MagicMock()
|
fee_open=0.001,
|
||||||
trade.open_order_id = '123'
|
fee_close=0.001,
|
||||||
trade.open_fee = 0.001
|
open_rate=0.01,
|
||||||
|
open_date=arrow.utcnow().datetime,
|
||||||
|
amount=11,
|
||||||
|
)
|
||||||
# Add datetime explicitly since sqlalchemy defaults apply only once written to database
|
# Add datetime explicitly since sqlalchemy defaults apply only once written to database
|
||||||
trade.open_date = arrow.utcnow().datetime
|
|
||||||
freqtrade.update_trade_state(trade)
|
freqtrade.update_trade_state(trade)
|
||||||
# Test amount not modified by fee-logic
|
# Test amount not modified by fee-logic
|
||||||
assert not log_has_re(r'Applying fee to .*', caplog)
|
assert not log_has_re(r'Applying fee to .*', caplog)
|
||||||
@ -1541,7 +1543,8 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No
|
|||||||
assert log_has_re('Found open order for.*', caplog)
|
assert log_has_re('Found open order for.*', caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order, mocker):
|
def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_buy_order, fee,
|
||||||
|
mocker):
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
||||||
# get_order should not be called!!
|
# get_order should not be called!!
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_order', MagicMock(side_effect=ValueError))
|
mocker.patch('freqtrade.exchange.Exchange.get_order', MagicMock(side_effect=ValueError))
|
||||||
@ -1554,6 +1557,8 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_
|
|||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_order_id="123456",
|
open_order_id="123456",
|
||||||
is_open=True,
|
is_open=True,
|
||||||
)
|
)
|
||||||
@ -1562,7 +1567,7 @@ def test_update_trade_state_withorderdict(default_conf, trades_for_order, limit_
|
|||||||
assert trade.amount == limit_buy_order['amount']
|
assert trade.amount == limit_buy_order['amount']
|
||||||
|
|
||||||
|
|
||||||
def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_order,
|
def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_order, fee,
|
||||||
limit_buy_order, mocker, caplog):
|
limit_buy_order, mocker, caplog):
|
||||||
trades_for_order[0]['amount'] = limit_buy_order['amount'] + 1e-14
|
trades_for_order[0]['amount'] = limit_buy_order['amount'] + 1e-14
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
||||||
@ -1577,6 +1582,8 @@ def test_update_trade_state_withorderdict_rounding_fee(default_conf, trades_for_
|
|||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_order_id="123456",
|
open_order_id="123456",
|
||||||
is_open=True,
|
is_open=True,
|
||||||
open_date=arrow.utcnow().datetime,
|
open_date=arrow.utcnow().datetime,
|
||||||
@ -2972,7 +2979,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order,
|
|||||||
assert trade.sell_reason == SellType.STOP_LOSS.value
|
assert trade.sell_reason == SellType.STOP_LOSS.value
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, caplog, mocker):
|
def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, fee, caplog, mocker):
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order)
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
@ -2982,6 +2989,8 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, ca
|
|||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf)
|
freqtrade = FreqtradeBot(default_conf)
|
||||||
@ -2994,7 +3003,7 @@ def test_get_real_amount_quote(default_conf, trades_for_order, buy_order_fee, ca
|
|||||||
caplog)
|
caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker):
|
def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker, fee):
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
|
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=[])
|
||||||
|
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
@ -3005,6 +3014,8 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker):
|
|||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf)
|
freqtrade = FreqtradeBot(default_conf)
|
||||||
@ -3017,7 +3028,7 @@ def test_get_real_amount_no_trade(default_conf, buy_order_fee, caplog, mocker):
|
|||||||
caplog)
|
caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, mocker):
|
def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||||
trades_for_order[0]['fee']['currency'] = 'ETH'
|
trades_for_order[0]['fee']['currency'] = 'ETH'
|
||||||
|
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
@ -3028,6 +3039,8 @@ def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, mo
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
@ -3038,7 +3051,8 @@ def test_get_real_amount_stake(default_conf, trades_for_order, buy_order_fee, mo
|
|||||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_order_fee, mocker):
|
def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_order_fee,
|
||||||
|
fee, mocker):
|
||||||
|
|
||||||
limit_buy_order = deepcopy(buy_order_fee)
|
limit_buy_order = deepcopy(buy_order_fee)
|
||||||
limit_buy_order['fee'] = {'cost': 0.004, 'currency': None}
|
limit_buy_order['fee'] = {'cost': 0.004, 'currency': None}
|
||||||
@ -3052,6 +3066,8 @@ def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
@ -3062,7 +3078,7 @@ def test_get_real_amount_no_currency_in_fee(default_conf, trades_for_order, buy_
|
|||||||
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount
|
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mocker):
|
def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||||
trades_for_order[0]['fee']['currency'] = 'BNB'
|
trades_for_order[0]['fee']['currency'] = 'BNB'
|
||||||
trades_for_order[0]['fee']['cost'] = 0.00094518
|
trades_for_order[0]['fee']['cost'] = 0.00094518
|
||||||
|
|
||||||
@ -3074,6 +3090,8 @@ def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mock
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
@ -3084,7 +3102,7 @@ def test_get_real_amount_BNB(default_conf, trades_for_order, buy_order_fee, mock
|
|||||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, caplog, mocker):
|
def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, caplog, fee, mocker):
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order2)
|
mocker.patch('freqtrade.exchange.Exchange.get_trades_for_order', return_value=trades_for_order2)
|
||||||
@ -3093,6 +3111,8 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, c
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
@ -3106,7 +3126,8 @@ def test_get_real_amount_multi(default_conf, trades_for_order2, buy_order_fee, c
|
|||||||
caplog)
|
caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, caplog, mocker):
|
def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee, fee,
|
||||||
|
caplog, mocker):
|
||||||
limit_buy_order = deepcopy(buy_order_fee)
|
limit_buy_order = deepcopy(buy_order_fee)
|
||||||
limit_buy_order['fee'] = {'cost': 0.004, 'currency': 'LTC'}
|
limit_buy_order['fee'] = {'cost': 0.004, 'currency': 'LTC'}
|
||||||
|
|
||||||
@ -3119,6 +3140,8 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
@ -3132,7 +3155,7 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee
|
|||||||
caplog)
|
caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, mocker):
|
def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||||
limit_buy_order = deepcopy(buy_order_fee)
|
limit_buy_order = deepcopy(buy_order_fee)
|
||||||
limit_buy_order['fee'] = {'cost': 0.004}
|
limit_buy_order['fee'] = {'cost': 0.004}
|
||||||
|
|
||||||
@ -3144,6 +3167,8 @@ def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
@ -3154,7 +3179,7 @@ def test_get_real_amount_invalid_order(default_conf, trades_for_order, buy_order
|
|||||||
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount
|
assert freqtrade.get_real_amount(trade, limit_buy_order) == amount
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_fee, mocker):
|
def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||||
limit_buy_order = deepcopy(buy_order_fee)
|
limit_buy_order = deepcopy(buy_order_fee)
|
||||||
limit_buy_order['amount'] = limit_buy_order['amount'] - 0.001
|
limit_buy_order['amount'] = limit_buy_order['amount'] - 0.001
|
||||||
|
|
||||||
@ -3167,6 +3192,8 @@ def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_
|
|||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf)
|
freqtrade = FreqtradeBot(default_conf)
|
||||||
@ -3177,7 +3204,7 @@ def test_get_real_amount_wrong_amount(default_conf, trades_for_order, buy_order_
|
|||||||
freqtrade.get_real_amount(trade, limit_buy_order)
|
freqtrade.get_real_amount(trade, limit_buy_order)
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, buy_order_fee,
|
def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, buy_order_fee, fee,
|
||||||
mocker):
|
mocker):
|
||||||
# Floats should not be compared directly.
|
# Floats should not be compared directly.
|
||||||
limit_buy_order = deepcopy(buy_order_fee)
|
limit_buy_order = deepcopy(buy_order_fee)
|
||||||
@ -3191,6 +3218,8 @@ def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, b
|
|||||||
pair='LTC/ETH',
|
pair='LTC/ETH',
|
||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
@ -3202,7 +3231,7 @@ def test_get_real_amount_wrong_amount_rounding(default_conf, trades_for_order, b
|
|||||||
abs_tol=MATH_CLOSE_PREC,)
|
abs_tol=MATH_CLOSE_PREC,)
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, mocker):
|
def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee, fee, mocker):
|
||||||
# Remove "Currency" from fee dict
|
# Remove "Currency" from fee dict
|
||||||
trades_for_order[0]['fee'] = {'cost': 0.008}
|
trades_for_order[0]['fee'] = {'cost': 0.008}
|
||||||
|
|
||||||
@ -3215,6 +3244,9 @@ def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee,
|
|||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
|
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
freqtrade = FreqtradeBot(default_conf)
|
freqtrade = FreqtradeBot(default_conf)
|
||||||
@ -3223,7 +3255,7 @@ def test_get_real_amount_invalid(default_conf, trades_for_order, buy_order_fee,
|
|||||||
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
assert freqtrade.get_real_amount(trade, buy_order_fee) == amount
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_amount_open_trade(default_conf, mocker):
|
def test_get_real_amount_open_trade(default_conf, fee, mocker):
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
amount = 12345
|
amount = 12345
|
||||||
@ -3232,6 +3264,8 @@ def test_get_real_amount_open_trade(default_conf, mocker):
|
|||||||
amount=amount,
|
amount=amount,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
open_rate=0.245441,
|
open_rate=0.245441,
|
||||||
|
fee_open=fee.return_value,
|
||||||
|
fee_close=fee.return_value,
|
||||||
open_order_id="123456"
|
open_order_id="123456"
|
||||||
)
|
)
|
||||||
order = {
|
order = {
|
||||||
|
@ -136,12 +136,13 @@ def test_update_with_bittrex(limit_buy_order, limit_sell_order, fee, caplog):
|
|||||||
id=2,
|
id=2,
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
open_rate=0.01,
|
||||||
|
amount=5,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.open_rate is None
|
|
||||||
assert trade.close_profit is None
|
assert trade.close_profit is None
|
||||||
assert trade.close_date is None
|
assert trade.close_date is None
|
||||||
|
|
||||||
@ -173,6 +174,8 @@ def test_update_market_order(market_buy_order, market_sell_order, fee, caplog):
|
|||||||
id=1,
|
id=1,
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
|
open_rate=0.01,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -205,6 +208,8 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
open_rate=0.01,
|
||||||
|
amount=5,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -212,7 +217,7 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee):
|
|||||||
|
|
||||||
trade.open_order_id = 'something'
|
trade.open_order_id = 'something'
|
||||||
trade.update(limit_buy_order)
|
trade.update(limit_buy_order)
|
||||||
assert trade.calc_open_trade_price() == 0.0010024999999225068
|
assert trade._calc_open_trade_price() == 0.0010024999999225068
|
||||||
|
|
||||||
trade.update(limit_sell_order)
|
trade.update(limit_sell_order)
|
||||||
assert trade.calc_close_trade_price() == 0.0010646656050132426
|
assert trade.calc_close_trade_price() == 0.0010646656050132426
|
||||||
@ -221,7 +226,7 @@ def test_calc_open_close_trade_price(limit_buy_order, limit_sell_order, fee):
|
|||||||
assert trade.calc_profit() == 0.00006217
|
assert trade.calc_profit() == 0.00006217
|
||||||
|
|
||||||
# Profit in percent
|
# Profit in percent
|
||||||
assert trade.calc_profit_percent() == 0.06201058
|
assert trade.calc_profit_ratio() == 0.06201058
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("init_persistence")
|
@pytest.mark.usefixtures("init_persistence")
|
||||||
@ -229,6 +234,8 @@ def test_calc_close_trade_price_exception(limit_buy_order, fee):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
open_rate=0.1,
|
||||||
|
amount=5,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -244,13 +251,14 @@ def test_update_open_order(limit_buy_order):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=1.00,
|
stake_amount=1.00,
|
||||||
|
open_rate=0.01,
|
||||||
|
amount=5,
|
||||||
fee_open=0.1,
|
fee_open=0.1,
|
||||||
fee_close=0.1,
|
fee_close=0.1,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
)
|
)
|
||||||
|
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.open_rate is None
|
|
||||||
assert trade.close_profit is None
|
assert trade.close_profit is None
|
||||||
assert trade.close_date is None
|
assert trade.close_date is None
|
||||||
|
|
||||||
@ -258,7 +266,6 @@ def test_update_open_order(limit_buy_order):
|
|||||||
trade.update(limit_buy_order)
|
trade.update(limit_buy_order)
|
||||||
|
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.open_rate is None
|
|
||||||
assert trade.close_profit is None
|
assert trade.close_profit is None
|
||||||
assert trade.close_date is None
|
assert trade.close_date is None
|
||||||
|
|
||||||
@ -268,6 +275,8 @@ def test_update_invalid_order(limit_buy_order):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=1.00,
|
stake_amount=1.00,
|
||||||
|
amount=5,
|
||||||
|
open_rate=0.001,
|
||||||
fee_open=0.1,
|
fee_open=0.1,
|
||||||
fee_close=0.1,
|
fee_close=0.1,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -282,6 +291,8 @@ def test_calc_open_trade_price(limit_buy_order, fee):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
|
open_rate=0.00001099,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -290,10 +301,10 @@ def test_calc_open_trade_price(limit_buy_order, fee):
|
|||||||
trade.update(limit_buy_order) # Buy @ 0.00001099
|
trade.update(limit_buy_order) # Buy @ 0.00001099
|
||||||
|
|
||||||
# Get the open rate price with the standard fee rate
|
# Get the open rate price with the standard fee rate
|
||||||
assert trade.calc_open_trade_price() == 0.0010024999999225068
|
assert trade._calc_open_trade_price() == 0.0010024999999225068
|
||||||
|
trade.fee_open = 0.003
|
||||||
# Get the open rate price with a custom fee rate
|
# Get the open rate price with a custom fee rate
|
||||||
assert trade.calc_open_trade_price(fee=0.003) == 0.001002999999922468
|
assert trade._calc_open_trade_price() == 0.001002999999922468
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("init_persistence")
|
@pytest.mark.usefixtures("init_persistence")
|
||||||
@ -301,6 +312,8 @@ def test_calc_close_trade_price(limit_buy_order, limit_sell_order, fee):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
|
open_rate=0.00001099,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -324,6 +337,8 @@ def test_calc_profit(limit_buy_order, limit_sell_order, fee):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
|
open_rate=0.00001099,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -352,10 +367,12 @@ def test_calc_profit(limit_buy_order, limit_sell_order, fee):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("init_persistence")
|
@pytest.mark.usefixtures("init_persistence")
|
||||||
def test_calc_profit_percent(limit_buy_order, limit_sell_order, fee):
|
def test_calc_profit_ratio(limit_buy_order, limit_sell_order, fee):
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
|
open_rate=0.00001099,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -364,17 +381,17 @@ def test_calc_profit_percent(limit_buy_order, limit_sell_order, fee):
|
|||||||
trade.update(limit_buy_order) # Buy @ 0.00001099
|
trade.update(limit_buy_order) # Buy @ 0.00001099
|
||||||
|
|
||||||
# Get percent of profit with a custom rate (Higher than open rate)
|
# Get percent of profit with a custom rate (Higher than open rate)
|
||||||
assert trade.calc_profit_percent(rate=0.00001234) == 0.11723875
|
assert trade.calc_profit_ratio(rate=0.00001234) == 0.11723875
|
||||||
|
|
||||||
# Get percent of profit with a custom rate (Lower than open rate)
|
# Get percent of profit with a custom rate (Lower than open rate)
|
||||||
assert trade.calc_profit_percent(rate=0.00000123) == -0.88863828
|
assert trade.calc_profit_ratio(rate=0.00000123) == -0.88863828
|
||||||
|
|
||||||
# Test when we apply a Sell order. Sell higher than open rate @ 0.00001173
|
# Test when we apply a Sell order. Sell higher than open rate @ 0.00001173
|
||||||
trade.update(limit_sell_order)
|
trade.update(limit_sell_order)
|
||||||
assert trade.calc_profit_percent() == 0.06201058
|
assert trade.calc_profit_ratio() == 0.06201058
|
||||||
|
|
||||||
# Test with a custom fee rate on the close trade
|
# Test with a custom fee rate on the close trade
|
||||||
assert trade.calc_profit_percent(fee=0.003) == 0.06147824
|
assert trade.calc_profit_ratio(fee=0.003) == 0.06147824
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("init_persistence")
|
@pytest.mark.usefixtures("init_persistence")
|
||||||
@ -481,6 +498,7 @@ def test_migrate_old(mocker, default_conf, fee):
|
|||||||
assert trade.max_rate == 0.0
|
assert trade.max_rate == 0.0
|
||||||
assert trade.stop_loss == 0.0
|
assert trade.stop_loss == 0.0
|
||||||
assert trade.initial_stop_loss == 0.0
|
assert trade.initial_stop_loss == 0.0
|
||||||
|
assert trade.open_trade_price == trade._calc_open_trade_price()
|
||||||
|
|
||||||
|
|
||||||
def test_migrate_new(mocker, default_conf, fee, caplog):
|
def test_migrate_new(mocker, default_conf, fee, caplog):
|
||||||
@ -563,6 +581,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog):
|
|||||||
assert log_has("trying trades_bak1", caplog)
|
assert log_has("trying trades_bak1", caplog)
|
||||||
assert log_has("trying trades_bak2", caplog)
|
assert log_has("trying trades_bak2", caplog)
|
||||||
assert log_has("Running database migration - backup available as trades_bak2", caplog)
|
assert log_has("Running database migration - backup available as trades_bak2", caplog)
|
||||||
|
assert trade.open_trade_price == trade._calc_open_trade_price()
|
||||||
|
|
||||||
|
|
||||||
def test_migrate_mid_state(mocker, default_conf, fee, caplog):
|
def test_migrate_mid_state(mocker, default_conf, fee, caplog):
|
||||||
@ -622,6 +641,7 @@ def test_migrate_mid_state(mocker, default_conf, fee, caplog):
|
|||||||
assert trade.max_rate == 0.0
|
assert trade.max_rate == 0.0
|
||||||
assert trade.stop_loss == 0.0
|
assert trade.stop_loss == 0.0
|
||||||
assert trade.initial_stop_loss == 0.0
|
assert trade.initial_stop_loss == 0.0
|
||||||
|
assert trade.open_trade_price == trade._calc_open_trade_price()
|
||||||
assert log_has("trying trades_bak0", caplog)
|
assert log_has("trying trades_bak0", caplog)
|
||||||
assert log_has("Running database migration - backup available as trades_bak0", caplog)
|
assert log_has("Running database migration - backup available as trades_bak0", caplog)
|
||||||
|
|
||||||
@ -630,6 +650,7 @@ def test_adjust_stop_loss(fee):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
@ -681,6 +702,7 @@ def test_adjust_min_max_rates(fee):
|
|||||||
trade = Trade(
|
trade = Trade(
|
||||||
pair='ETH/BTC',
|
pair='ETH/BTC',
|
||||||
stake_amount=0.001,
|
stake_amount=0.001,
|
||||||
|
amount=5,
|
||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='bittrex',
|
exchange='bittrex',
|
||||||
|
Loading…
Reference in New Issue
Block a user