updated requested change in PR #6545

Co-Authored-By: மனோஜ்குமார் பழனிச்சாமி <smartmanoj42857@gmail.com>
This commit is contained in:
Kavinkumar 2022-03-19 12:26:46 +05:30
parent 8a6fe48c2f
commit 13ff413e4f
5 changed files with 73 additions and 46 deletions

View File

@ -452,15 +452,8 @@ class FreqtradeBot(LoggingMixin):
If the strategy triggers the adjustment, a new order gets issued. If the strategy triggers the adjustment, a new order gets issued.
Once that completes, the existing trade is modified to match new data. Once that completes, the existing trade is modified to match new data.
""" """
if self.strategy.max_entry_position_adjustment > -1:
count_of_buys = trade.nr_of_successful_buys
if count_of_buys > self.strategy.max_entry_position_adjustment:
logger.debug(f"Max adjustment entries for {trade.pair} has been reached.")
return
else:
logger.debug("Max adjustment entries is set to unlimited.")
current_entry_rate = self.exchange.get_rate(trade.pair, refresh=True, side="buy") current_entry_rate = self.exchange.get_rate(trade.pair, refresh=True, side="buy")
current_exit_rate = self.exchange.get_rate(trade.pair, refresh=True, side="sell") current_exit_rate = current_entry_rate
current_rate = current_entry_rate # backward compatibilty current_rate = current_entry_rate # backward compatibilty
current_profit = trade.calc_profit_ratio(current_rate) current_profit = trade.calc_profit_ratio(current_rate)
@ -478,11 +471,18 @@ class FreqtradeBot(LoggingMixin):
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
if self.strategy.max_entry_position_adjustment > -1:
count_of_buys = trade.nr_of_successful_buys
if count_of_buys > self.strategy.max_entry_position_adjustment:
logger.debug(f"Max adjustment entries for {trade.pair} has been reached.")
return
else:
logger.debug("Max adjustment entries is set to unlimited.")
self.execute_entry(trade.pair, stake_amount, trade=trade) self.execute_entry(trade.pair, stake_amount, trade=trade)
if stake_amount is not None and stake_amount < 0.0: if stake_amount is not None and stake_amount < 0.0:
# We should decrease our position # We should decrease our position
amount = -stake_amount / current_exit_rate amount = abs(stake_amount) / current_exit_rate
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
@ -1270,6 +1270,8 @@ class FreqtradeBot(LoggingMixin):
current_rate = self.exchange.get_rate( current_rate = self.exchange.get_rate(
trade.pair, refresh=False, side="sell") if not fill else None trade.pair, refresh=False, side="sell") if not fill else None
if sub_trade: if sub_trade:
# for mypy only; order will always be passed during sub trade
assert order is not None assert order is not None
amount = order.safe_filled amount = order.safe_filled
profit_rate = order.safe_price profit_rate = order.safe_price
@ -1279,13 +1281,11 @@ class FreqtradeBot(LoggingMixin):
profit_ratio = trade.close_profit profit_ratio = trade.close_profit
profit = trade.close_profit_abs profit = trade.close_profit_abs
open_rate = trade.get_open_rate(profit, profit_rate, amount)
else: else:
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
profit = trade.calc_profit(rate=profit_rate) profit = trade.calc_profit(rate=profit_rate)
profit_ratio = trade.calc_profit_ratio(profit_rate) profit_ratio = trade.calc_profit_ratio(profit_rate)
amount = trade.amount amount = trade.amount
open_rate = trade.open_rate
gain = "profit" if profit_ratio > 0 else "loss" gain = "profit" if profit_ratio > 0 else "loss"
msg = { msg = {
@ -1298,7 +1298,7 @@ class FreqtradeBot(LoggingMixin):
'limit': profit_rate, 'limit': profit_rate,
'order_type': order_type, 'order_type': order_type,
'amount': amount, 'amount': amount,
'open_rate': open_rate, 'open_rate': trade.open_rate,
'close_rate': profit_rate, 'close_rate': profit_rate,
'current_rate': current_rate, 'current_rate': current_rate,
'profit_amount': profit, 'profit_amount': profit,
@ -1409,6 +1409,7 @@ class FreqtradeBot(LoggingMixin):
self.handle_order_fee(trade, order_obj, order) self.handle_order_fee(trade, order_obj, order)
trade.update_trade(order_obj) trade.update_trade(order_obj)
Trade.commit()
if order['status'] in constants.NON_OPEN_EXCHANGE_STATES: if order['status'] in constants.NON_OPEN_EXCHANGE_STATES:
# If a buy order was closed, force update on stoploss on exchange # If a buy order was closed, force update on stoploss on exchange

View File

@ -816,7 +816,7 @@ class Backtesting:
sub_trade = order.safe_amount_after_fee != trade.amount sub_trade = order.safe_amount_after_fee != trade.amount
if sub_trade: if sub_trade:
order.close_bt_order(current_time) order.close_bt_order(current_time)
trade.process_sell_sub_trade(order, is_non_bt=False) trade.process_sell_sub_trade(order)
trade.recalc_trade_from_orders() trade.recalc_trade_from_orders()
else: else:
trade.close_date = current_time trade.close_date = current_time

View File

@ -127,7 +127,6 @@ class Order(_DECL_BASE):
side = Column(String(25), nullable=True) side = Column(String(25), nullable=True)
price = Column(Float, nullable=True) price = Column(Float, nullable=True)
average = Column(Float, nullable=True) average = Column(Float, nullable=True)
initial_average = Column(Float, nullable=True)
amount = Column(Float, nullable=True) amount = Column(Float, nullable=True)
filled = Column(Float, nullable=True) filled = Column(Float, nullable=True)
remaining = Column(Float, nullable=True) remaining = Column(Float, nullable=True)
@ -500,8 +499,10 @@ class LocalTrade():
# condition to avoid reset value when updating fees # condition to avoid reset value when updating fees
if self.open_order_id == order.order_id: if self.open_order_id == order.order_id:
self.open_order_id = None self.open_order_id = None
self.process_sell_sub_trade(order) if self.amount == order.safe_amount_after_fee:
return self.close(order.safe_price)
else:
self.process_sell_sub_trade(order)
elif order.ft_order_side == 'stoploss': elif order.ft_order_side == 'stoploss':
self.stoploss_order_id = None self.stoploss_order_id = None
self.close_rate_requested = self.stop_loss self.close_rate_requested = self.stop_loss
@ -518,12 +519,6 @@ class LocalTrade():
sell_amount = order.safe_amount_after_fee sell_amount = order.safe_amount_after_fee
sell_rate = order.safe_price sell_rate = order.safe_price
sell_stake_amount = sell_rate * sell_amount * (1 - self.fee_close) sell_stake_amount = sell_rate * sell_amount * (1 - self.fee_close)
if sell_amount == self.amount:
if is_closed:
self.close(sell_rate)
if is_non_bt:
Trade.commit()
return
profit = self.calc_profit2(self.open_rate, sell_rate, sell_amount) profit = self.calc_profit2(self.open_rate, sell_rate, sell_amount)
if is_closed: if is_closed:
self.amount -= sell_amount self.amount -= sell_amount
@ -533,8 +528,6 @@ class LocalTrade():
self.close_profit_abs = profit self.close_profit_abs = profit
self.close_profit = sell_stake_amount / (sell_stake_amount - profit) - 1 self.close_profit = sell_stake_amount / (sell_stake_amount - profit) - 1
self.recalc_open_trade_value() self.recalc_open_trade_value()
if is_non_bt:
Trade.commit()
def calc_profit2(self, open_rate: float, close_rate: float, def calc_profit2(self, open_rate: float, close_rate: float,
amount: float) -> float: amount: float) -> float:
@ -542,12 +535,6 @@ class LocalTrade():
(Decimal(1 - self.fee_close) * Decimal(close_rate) - (Decimal(1 - self.fee_close) * Decimal(close_rate) -
Decimal(1 + self.fee_open) * Decimal(open_rate))) Decimal(1 + self.fee_open) * Decimal(open_rate)))
def get_open_rate(self, profit: float, close_rate: float,
amount: float) -> float:
return float((Decimal(amount) *
(Decimal(1 - self.fee_close) * Decimal(close_rate)) -
Decimal(profit))/(Decimal(amount) * Decimal(1 + self.fee_open)))
def close(self, rate: float, *, show_msg: bool = True) -> None: def close(self, rate: float, *, show_msg: bool = True) -> None:
""" """
Sets close_rate to the given rate, calculates total profit Sets close_rate to the given rate, calculates total profit
@ -685,10 +672,11 @@ class LocalTrade():
tmp_amount = o.safe_amount_after_fee tmp_amount = o.safe_amount_after_fee
tmp_price = o.safe_price tmp_price = o.safe_price
is_sell = o.ft_order_side != 'buy' is_sell = o.ft_order_side != 'buy'
side = [1, -1][is_sell] side = -1 if is_sell else 1
if tmp_amount > 0.0 and tmp_price is not None: if tmp_amount > 0.0 and tmp_price is not None:
total_amount += tmp_amount * side total_amount += tmp_amount * side
total_stake += [tmp_price, avg_price][is_sell] * tmp_amount * side price = avg_price if is_sell else tmp_price
total_stake += price * tmp_amount * side
if total_amount > 0: if total_amount > 0:
avg_price = total_stake / total_amount avg_price = total_stake / total_amount

View File

@ -4863,7 +4863,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
assert trade.is_open is False assert trade.is_open is False
@pytest.mark.parametrize('orders, res', [ @pytest.mark.parametrize('orders, results', [
( (
( (
# side ampunt, price # side ampunt, price
@ -4901,7 +4901,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
) )
), ),
]) ])
def test_position_adjust3(mocker, default_conf_usdt, fee, orders, res) -> None: def test_position_adjust3(mocker, default_conf_usdt, fee, orders, results) -> None:
default_conf_usdt.update({ default_conf_usdt.update({
"position_adjustment_enable": True, "position_adjustment_enable": True,
"dry_run": False, "dry_run": False,
@ -4914,7 +4914,7 @@ def test_position_adjust3(mocker, default_conf_usdt, fee, orders, res) -> None:
freqtrade = FreqtradeBot(default_conf_usdt) freqtrade = FreqtradeBot(default_conf_usdt)
trade = None trade = None
freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True) freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True)
for idx, order in enumerate(orders): for idx, (order, result) in enumerate(zip(orders, results)):
amount = order[1] amount = order[1]
price = order[2] price = order[2]
price_mock = MagicMock(return_value=price) price_mock = MagicMock(return_value=price)
@ -4968,11 +4968,11 @@ def test_position_adjust3(mocker, default_conf_usdt, fee, orders, res) -> None:
if idx < len(orders) - 1: if idx < len(orders) - 1:
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.amount == res[idx][0] assert trade.amount == result[0]
assert trade.open_rate == res[idx][1] assert trade.open_rate == result[1]
assert trade.stake_amount == res[idx][2] assert trade.stake_amount == result[2]
assert pytest.approx(trade.realized_profit) == res[idx][3] assert pytest.approx(trade.realized_profit) == result[3]
assert pytest.approx(trade.close_profit_abs) == res[idx][4] assert pytest.approx(trade.close_profit_abs) == result[4]
order_obj = trade.select_order(order[0], False) order_obj = trade.select_order(order[0], False)
assert order_obj.order_id == f'60{idx}' assert order_obj.order_id == f'60{idx}'
@ -5004,9 +5004,20 @@ def test_check_and_call_adjust_trade_position(mocker, default_conf_usdt, fee, ca
"max_entry_position_adjustment": 0, "max_entry_position_adjustment": 0,
}) })
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
buy_rate_mock = MagicMock(return_value=10)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_rate=buy_rate_mock,
fetch_ticker=MagicMock(return_value={
'bid': 10,
'ask': 12,
'last': 11
}),
get_min_pair_stake_amount=MagicMock(return_value=1),
get_fee=fee,
)
create_mock_trades(fee) create_mock_trades(fee)
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=10)
freqtrade.process_open_trade_positions() freqtrade.process_open_trade_positions()
assert log_has_re(r"Max adjustment entries for .* has been reached\.", caplog) assert log_has_re(r"Max adjustment entries for .* has been reached\.", caplog)

View File

@ -1642,6 +1642,33 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
assert trade.open_trade_value == 2 * o1_trade_val assert trade.open_trade_value == 2 * o1_trade_val
assert trade.nr_of_successful_buys == 2 assert trade.nr_of_successful_buys == 2
# Just to make sure sell orders are ignored, let's calculate one more time.
sell1 = Order(
ft_order_side='sell',
ft_pair=trade.pair,
ft_is_open=False,
status="closed",
symbol=trade.pair,
order_type="market",
side="sell",
price=4,
average=3,
filled=o1_amount,
remaining=1,
cost=5,
order_date=trade.open_date,
order_filled_date=trade.open_date,
)
trade.orders.append(sell1)
trade.recalc_trade_from_orders()
assert trade.amount == o1_amount
assert trade.stake_amount == o1_amount
assert trade.open_rate == o1_rate
assert trade.fee_open_cost == o1_fee_cost
assert trade.open_trade_value == o1_trade_val
assert trade.nr_of_successful_buys == 2
# Check with 1 order # Check with 1 order
order_noavg = Order( order_noavg = Order(
ft_order_side='buy', ft_order_side='buy',
@ -1663,11 +1690,11 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
trade.recalc_trade_from_orders() trade.recalc_trade_from_orders()
# Calling recalc with single initial order should not change anything # Calling recalc with single initial order should not change anything
assert trade.amount == 3 * o1_amount assert trade.amount == 2 * o1_amount
assert trade.stake_amount == 3 * o1_amount assert trade.stake_amount == 2 * o1_amount
assert trade.open_rate == o1_rate assert trade.open_rate == o1_rate
assert trade.fee_open_cost == 3 * o1_fee_cost assert trade.fee_open_cost == 2 * o1_fee_cost
assert trade.open_trade_value == 3 * o1_trade_val assert trade.open_trade_value == 2 * o1_trade_val
assert trade.nr_of_successful_buys == 3 assert trade.nr_of_successful_buys == 3