added 2nd unit test
This commit is contained in:
parent
988a9f05f2
commit
f67b1b4fcf
@ -460,6 +460,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
else:
|
else:
|
||||||
logger.debug("Max adjustment entries is set to unlimited.")
|
logger.debug("Max adjustment entries is set to unlimited.")
|
||||||
current_rate = self.exchange.get_rate(trade.pair, refresh=True, side="buy")
|
current_rate = self.exchange.get_rate(trade.pair, refresh=True, side="buy")
|
||||||
|
current_rate_sell = self.exchange.get_rate(trade.pair, refresh=True, side="sell")
|
||||||
current_profit = trade.calc_profit_ratio(current_rate)
|
current_profit = trade.calc_profit_ratio(current_rate)
|
||||||
|
|
||||||
min_stake_amount = self.exchange.get_min_pair_stake_amount(trade.pair,
|
min_stake_amount = self.exchange.get_min_pair_stake_amount(trade.pair,
|
||||||
@ -470,7 +471,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position,
|
stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position,
|
||||||
default_retval=None)(
|
default_retval=None)(
|
||||||
trade=trade, current_time=datetime.now(timezone.utc), current_rate=current_rate,
|
trade=trade, current_time=datetime.now(timezone.utc), current_rate=current_rate,
|
||||||
current_profit=current_profit, min_stake=min_stake_amount, max_stake=max_stake_amount)
|
current_profit=current_profit, min_stake=min_stake_amount,
|
||||||
|
max_stake=max_stake_amount, current_rate_sell=current_rate_sell)
|
||||||
|
|
||||||
if stake_amount is not None and stake_amount > 0.0:
|
if stake_amount is not None and stake_amount > 0.0:
|
||||||
# We should increase our position
|
# We should increase our position
|
||||||
@ -487,7 +489,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
}
|
}
|
||||||
self.rpc.send_msg(msg)
|
self.rpc.send_msg(msg)
|
||||||
return
|
return
|
||||||
amount = -stake_amount / current_rate
|
amount = -stake_amount / current_rate_sell
|
||||||
if trade.amount - amount < min_stake_amount:
|
if trade.amount - amount < min_stake_amount:
|
||||||
logger.info('Remaining amount would be too small')
|
logger.info('Remaining amount would be too small')
|
||||||
return
|
return
|
||||||
|
@ -539,14 +539,14 @@ class LocalTrade():
|
|||||||
amount = buy_amount
|
amount = buy_amount
|
||||||
if is_closed:
|
if is_closed:
|
||||||
b_order.filled -= amount
|
b_order.filled -= amount
|
||||||
|
b_order.order_update_date = datetime.now(timezone.utc)
|
||||||
sell_amount -= amount
|
sell_amount -= amount
|
||||||
profit += self.calc_profit2(buy_rate, sell_rate, amount)
|
profit += self.calc_profit2(buy_rate, sell_rate, amount)
|
||||||
if is_closed:
|
if is_closed:
|
||||||
b_order2 = orders[idx]
|
b_order2 = orders[idx]
|
||||||
amount2 = b_order2.filled or b_order2.amount
|
amount2 = b_order2.safe_amount_after_fee
|
||||||
b_order2.average = (b_order2.average * amount2 - profit) / amount2
|
b_order2.average = (b_order2.average * amount2 - profit / (1 + self.fee_open)) / amount2
|
||||||
b_order2.order_update_date = datetime.now(timezone.utc)
|
b_order2.order_update_date = datetime.now(timezone.utc)
|
||||||
self.update_order(b_order2)
|
|
||||||
if is_non_bt: Order.query.session.commit()
|
if is_non_bt: Order.query.session.commit()
|
||||||
self.recalc_trade_from_orders()
|
self.recalc_trade_from_orders()
|
||||||
|
|
||||||
@ -693,8 +693,13 @@ class LocalTrade():
|
|||||||
|
|
||||||
def recalc_trade_from_orders(self):
|
def recalc_trade_from_orders(self):
|
||||||
# mdebug
|
# mdebug
|
||||||
# import json
|
import json
|
||||||
# logger.info(json.dumps(self.to_json(), indent =4))
|
# logger.info(json.dumps(self.to_json(), indent =4))
|
||||||
|
if len(self.select_filled_orders('buy')) < 2 and 0:
|
||||||
|
# Just in case, still recalc open trade value
|
||||||
|
# needs to remove
|
||||||
|
self.recalc_open_trade_value()
|
||||||
|
return
|
||||||
total_amount = 0.0
|
total_amount = 0.0
|
||||||
total_stake = 0.0
|
total_stake = 0.0
|
||||||
for o in self.orders:
|
for o in self.orders:
|
||||||
@ -719,6 +724,7 @@ class LocalTrade():
|
|||||||
if self.stop_loss_pct is not None and self.open_rate is not None:
|
if self.stop_loss_pct is not None and self.open_rate is not None:
|
||||||
self.adjust_stop_loss(self.open_rate, self.stop_loss_pct)
|
self.adjust_stop_loss(self.open_rate, self.stop_loss_pct)
|
||||||
# logger.info(json.dumps(self.to_json(), indent =4))
|
# logger.info(json.dumps(self.to_json(), indent =4))
|
||||||
|
# mdebug
|
||||||
|
|
||||||
def select_order_by_order_id(self, order_id: str) -> Optional[Order]:
|
def select_order_by_order_id(self, order_id: str) -> Optional[Order]:
|
||||||
"""
|
"""
|
||||||
|
@ -279,7 +279,8 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
|
|||||||
|
|
||||||
# Simulate buy & sell
|
# Simulate buy & sell
|
||||||
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
||||||
trade.update_trade(oobj)
|
trade.open_rate = oobj.safe_price
|
||||||
|
trade.amount = oobj.safe_amount_after_fee
|
||||||
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
||||||
trade.update_trade(oobj)
|
trade.update_trade(oobj)
|
||||||
trade.close_date = datetime.utcnow()
|
trade.close_date = datetime.utcnow()
|
||||||
@ -419,7 +420,8 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
|||||||
trade = Trade.query.first()
|
trade = Trade.query.first()
|
||||||
# Simulate fulfilled LIMIT_BUY order for trade
|
# Simulate fulfilled LIMIT_BUY order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
||||||
trade.update_trade(oobj)
|
trade.open_rate = oobj.safe_price
|
||||||
|
trade.amount = oobj.safe_amount_after_fee
|
||||||
|
|
||||||
# Update the ticker with a market going up
|
# Update the ticker with a market going up
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
@ -435,7 +437,8 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
|||||||
trade = Trade.query.first()
|
trade = Trade.query.first()
|
||||||
# Simulate fulfilled LIMIT_BUY order for trade
|
# Simulate fulfilled LIMIT_BUY order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
||||||
trade.update_trade(oobj)
|
trade.open_rate = oobj.safe_price
|
||||||
|
trade.amount = oobj.safe_amount_after_fee
|
||||||
|
|
||||||
# Update the ticker with a market going up
|
# Update the ticker with a market going up
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
@ -503,8 +506,10 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
|
|||||||
trade = Trade.query.first()
|
trade = Trade.query.first()
|
||||||
# Simulate fulfilled LIMIT_BUY order for trade
|
# Simulate fulfilled LIMIT_BUY order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
||||||
trade.update_trade(oobj)
|
trade.open_rate = oobj.safe_price
|
||||||
|
trade.amount = oobj.safe_amount_after_fee
|
||||||
# Update the ticker with a market going up
|
# Update the ticker with a market going up
|
||||||
|
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
fetch_ticker=ticker_sell_up,
|
fetch_ticker=ticker_sell_up,
|
||||||
@ -850,7 +855,8 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
|||||||
|
|
||||||
# Simulate fulfilled LIMIT_BUY order for trade
|
# Simulate fulfilled LIMIT_BUY order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
||||||
trade.update_trade(oobj)
|
trade.open_rate = oobj.safe_price
|
||||||
|
trade.amount = oobj.safe_amount_after_fee
|
||||||
|
|
||||||
# Simulate fulfilled LIMIT_SELL order for trade
|
# Simulate fulfilled LIMIT_SELL order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
||||||
@ -886,7 +892,8 @@ def test_buy_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
|||||||
|
|
||||||
# Simulate fulfilled LIMIT_BUY order for trade
|
# Simulate fulfilled LIMIT_BUY order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
||||||
trade.update_trade(oobj)
|
trade.open_rate = oobj.safe_price
|
||||||
|
trade.amount = oobj.safe_amount_after_fee
|
||||||
|
|
||||||
# Simulate fulfilled LIMIT_SELL order for trade
|
# Simulate fulfilled LIMIT_SELL order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
||||||
@ -960,8 +967,8 @@ def test_sell_reason_performance_handle(default_conf, ticker, limit_buy_order, f
|
|||||||
|
|
||||||
# Simulate fulfilled LIMIT_BUY order for trade
|
# Simulate fulfilled LIMIT_BUY order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
||||||
trade.update_trade(oobj)
|
trade.open_rate = oobj.safe_price
|
||||||
|
trade.amount = oobj.safe_amount_after_fee
|
||||||
# Simulate fulfilled LIMIT_SELL order for trade
|
# Simulate fulfilled LIMIT_SELL order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
||||||
trade.update_trade(oobj)
|
trade.update_trade(oobj)
|
||||||
@ -1034,7 +1041,8 @@ def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
|
|||||||
|
|
||||||
# Simulate fulfilled LIMIT_BUY order for trade
|
# Simulate fulfilled LIMIT_BUY order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
|
||||||
trade.update_trade(oobj)
|
trade.open_rate = oobj.safe_price
|
||||||
|
trade.amount = oobj.safe_amount_after_fee
|
||||||
|
|
||||||
# Simulate fulfilled LIMIT_SELL order for trade
|
# Simulate fulfilled LIMIT_SELL order for trade
|
||||||
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
|
||||||
|
@ -4620,7 +4620,6 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
|
|||||||
assert trade
|
assert trade
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.is_open
|
assert trade.is_open
|
||||||
print(trade.is_open)
|
|
||||||
assert trade.amount == 22
|
assert trade.amount == 22
|
||||||
assert trade.stake_amount == 203.5625
|
assert trade.stake_amount == 203.5625
|
||||||
assert pytest.approx(trade.open_rate) == 9.252840909090908
|
assert pytest.approx(trade.open_rate) == 9.252840909090908
|
||||||
@ -4635,7 +4634,11 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
|
def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
|
||||||
return
|
"""
|
||||||
|
buy 100 @ 11
|
||||||
|
sell 50 @ 8
|
||||||
|
sell 50 @ 16
|
||||||
|
"""
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
patch_wallet(mocker, free=10000)
|
patch_wallet(mocker, free=10000)
|
||||||
@ -4693,8 +4696,8 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
|
|||||||
assert trade
|
assert trade
|
||||||
assert trade.is_open is True
|
assert trade.is_open is True
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.open_rate == 11
|
assert trade.open_rate == bid
|
||||||
assert trade.stake_amount == 1100
|
assert trade.stake_amount == bid * amount
|
||||||
|
|
||||||
# Assume it does nothing since order is closed and trade is open
|
# Assume it does nothing since order is closed and trade is open
|
||||||
freqtrade.update_closed_trades_without_assigned_fees()
|
freqtrade.update_closed_trades_without_assigned_fees()
|
||||||
@ -4703,8 +4706,8 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
|
|||||||
assert trade
|
assert trade
|
||||||
assert trade.is_open is True
|
assert trade.is_open is True
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.open_rate == 11
|
assert trade.open_rate == bid
|
||||||
assert trade.stake_amount == 1100
|
assert trade.stake_amount == bid * amount
|
||||||
assert not trade.fee_updated('buy')
|
assert not trade.fee_updated('buy')
|
||||||
|
|
||||||
freqtrade.check_handle_timedout()
|
freqtrade.check_handle_timedout()
|
||||||
@ -4713,21 +4716,23 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
|
|||||||
assert trade
|
assert trade
|
||||||
assert trade.is_open is True
|
assert trade.is_open is True
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.open_rate == 11
|
assert trade.open_rate == bid
|
||||||
assert trade.stake_amount == 1100
|
assert trade.stake_amount == bid * amount
|
||||||
assert not trade.fee_updated('buy')
|
assert not trade.fee_updated('buy')
|
||||||
|
|
||||||
|
amount = 50
|
||||||
|
ask = 8
|
||||||
closed_sell_dca_order_1 = {
|
closed_sell_dca_order_1 = {
|
||||||
'ft_pair': pair,
|
'ft_pair': pair,
|
||||||
'status': 'closed',
|
'status': 'closed',
|
||||||
'ft_order_side': 'sell',
|
'ft_order_side': 'sell',
|
||||||
'side': 'sell',
|
'side': 'sell',
|
||||||
'type': 'limit',
|
'type': 'limit',
|
||||||
'price': 8,
|
'price': ask,
|
||||||
'average': 8,
|
'average': ask,
|
||||||
'amount': 50,
|
'amount': amount,
|
||||||
'filled': 50,
|
'filled': amount,
|
||||||
'cost': 120,
|
'cost': amount * ask,
|
||||||
'ft_is_open': False,
|
'ft_is_open': False,
|
||||||
'id': '601',
|
'id': '601',
|
||||||
'order_id': '601'
|
'order_id': '601'
|
||||||
@ -4738,18 +4743,16 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
|
|||||||
MagicMock(return_value=closed_sell_dca_order_1))
|
MagicMock(return_value=closed_sell_dca_order_1))
|
||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
|
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
|
||||||
MagicMock(return_value=closed_sell_dca_order_1))
|
MagicMock(return_value=closed_sell_dca_order_1))
|
||||||
assert freqtrade.execute_trade_exit(trade=trade, limit=8,
|
assert freqtrade.execute_trade_exit(trade=trade, limit=ask,
|
||||||
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS),
|
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS),
|
||||||
sub_trade_amt=50)
|
sub_trade_amt=amount)
|
||||||
trades: List[Trade] = trade.get_open_trades_without_assigned_fees()
|
trades: List[Trade] = trade.get_open_trades_without_assigned_fees()
|
||||||
assert len(trades) == 1
|
assert len(trades) == 1
|
||||||
# Assert trade is as expected (averaged dca)
|
# Assert trade is as expected (averaged dca)
|
||||||
|
|
||||||
trade = Trade.query.first()
|
trade = Trade.query.first()
|
||||||
assert trade
|
assert trade
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.amount == 100
|
|
||||||
assert trade.stake_amount == 1100
|
|
||||||
assert pytest.approx(trade.open_rate) == 11.0
|
|
||||||
|
|
||||||
orders = Order.query.all()
|
orders = Order.query.all()
|
||||||
assert orders
|
assert orders
|
||||||
@ -4758,6 +4761,47 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
|
|||||||
order = trade.select_order('sell', False)
|
order = trade.select_order('sell', False)
|
||||||
assert order.order_id == '601'
|
assert order.order_id == '601'
|
||||||
|
|
||||||
|
amount = 50
|
||||||
|
ask = 16
|
||||||
|
closed_sell_dca_order_2 = {
|
||||||
|
'ft_pair': pair,
|
||||||
|
'status': 'closed',
|
||||||
|
'ft_order_side': 'sell',
|
||||||
|
'side': 'sell',
|
||||||
|
'type': 'limit',
|
||||||
|
'price': ask,
|
||||||
|
'average': ask,
|
||||||
|
'amount': amount,
|
||||||
|
'filled': amount,
|
||||||
|
'cost': amount * ask,
|
||||||
|
'ft_is_open': False,
|
||||||
|
'id': '602',
|
||||||
|
'order_id': '602'
|
||||||
|
}
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.create_order',
|
||||||
|
MagicMock(return_value=closed_sell_dca_order_2))
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
|
||||||
|
MagicMock(return_value=closed_sell_dca_order_2))
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
|
||||||
|
MagicMock(return_value=closed_sell_dca_order_2))
|
||||||
|
assert freqtrade.execute_trade_exit(trade=trade, limit=ask,
|
||||||
|
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS),
|
||||||
|
sub_trade_amt=amount)
|
||||||
|
# Assert trade is as expected (averaged dca)
|
||||||
|
|
||||||
|
trade = Trade.query.first()
|
||||||
|
assert trade
|
||||||
|
assert trade.open_order_id is None
|
||||||
|
assert trade.close_profit_abs == 94.25
|
||||||
|
|
||||||
|
orders = Order.query.all()
|
||||||
|
assert orders
|
||||||
|
assert len(orders) == 3
|
||||||
|
|
||||||
|
# Make sure the closed order is found as the second order.
|
||||||
|
order = trade.select_order('sell', False)
|
||||||
|
assert order.order_id == '602'
|
||||||
|
|
||||||
|
|
||||||
def test_process_open_trade_positions_exception(mocker, default_conf_usdt, fee, caplog) -> None:
|
def test_process_open_trade_positions_exception(mocker, default_conf_usdt, fee, caplog) -> None:
|
||||||
default_conf_usdt.update({
|
default_conf_usdt.update({
|
||||||
|
Loading…
Reference in New Issue
Block a user