Merge pull request #6561 from adrianceding/fix_taker_stake_amount
Unified taker and maker's stake amount calculation logic
This commit is contained in:
commit
35a4053dbe
@ -661,16 +661,11 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
self.exchange.name, order['filled'], order['amount'],
|
self.exchange.name, order['filled'], order['amount'],
|
||||||
order['remaining']
|
order['remaining']
|
||||||
)
|
)
|
||||||
stake_amount = order['cost']
|
|
||||||
amount = safe_value_fallback(order, 'filled', 'amount')
|
amount = safe_value_fallback(order, 'filled', 'amount')
|
||||||
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
|
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
|
||||||
|
|
||||||
# in case of FOK the order may be filled immediately and fully
|
# in case of FOK the order may be filled immediately and fully
|
||||||
elif order_status == 'closed':
|
elif order_status == 'closed':
|
||||||
# TODO-lev: Evaluate this. Why is setting stake_amount here necessary?
|
|
||||||
# it should never change in theory - and in case of leveraged orders,
|
|
||||||
# may be the leveraged amount.
|
|
||||||
stake_amount = order['cost']
|
|
||||||
amount = safe_value_fallback(order, 'filled', 'amount')
|
amount = safe_value_fallback(order, 'filled', 'amount')
|
||||||
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
|
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
|
||||||
|
|
||||||
|
@ -847,7 +847,10 @@ class LocalTrade():
|
|||||||
|
|
||||||
def recalc_trade_from_orders(self):
|
def recalc_trade_from_orders(self):
|
||||||
# We need at least 2 entry orders for averaging amounts and rates.
|
# We need at least 2 entry orders for averaging amounts and rates.
|
||||||
|
# TODO: this condition could probably be removed
|
||||||
if len(self.select_filled_orders(self.enter_side)) < 2:
|
if len(self.select_filled_orders(self.enter_side)) < 2:
|
||||||
|
self.stake_amount = self.amount * self.open_rate / self.leverage
|
||||||
|
|
||||||
# Just in case, still recalc open trade value
|
# Just in case, still recalc open trade value
|
||||||
self.recalc_open_trade_value()
|
self.recalc_open_trade_value()
|
||||||
return
|
return
|
||||||
|
@ -294,7 +294,7 @@ def test_create_trade(default_conf_usdt, ticker_usdt, limit_order,
|
|||||||
trade = Trade.query.first()
|
trade = Trade.query.first()
|
||||||
trade.is_short = is_short
|
trade.is_short = is_short
|
||||||
assert trade is not None
|
assert trade is not None
|
||||||
assert trade.stake_amount == 60.0
|
assert pytest.approx(trade.stake_amount) == 60.0
|
||||||
assert trade.is_open
|
assert trade.is_open
|
||||||
assert trade.open_date is not None
|
assert trade.open_date is not None
|
||||||
assert trade.exchange == 'binance'
|
assert trade.exchange == 'binance'
|
||||||
@ -551,7 +551,7 @@ def test_process_trade_creation(default_conf_usdt, ticker_usdt, limit_order, lim
|
|||||||
assert len(trades) == 1
|
assert len(trades) == 1
|
||||||
trade = trades[0]
|
trade = trades[0]
|
||||||
assert trade is not None
|
assert trade is not None
|
||||||
assert trade.stake_amount == default_conf_usdt['stake_amount']
|
assert pytest.approx(trade.stake_amount) == default_conf_usdt['stake_amount']
|
||||||
assert trade.is_open
|
assert trade.is_open
|
||||||
assert trade.open_date is not None
|
assert trade.open_date is not None
|
||||||
assert trade.exchange == 'binance'
|
assert trade.exchange == 'binance'
|
||||||
@ -842,7 +842,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
|
|||||||
assert trade
|
assert trade
|
||||||
assert trade.open_order_id is None
|
assert trade.open_order_id is None
|
||||||
assert trade.open_rate == 10
|
assert trade.open_rate == 10
|
||||||
assert trade.stake_amount == 100
|
assert trade.stake_amount == round(order['price'] * order['filled'] / leverage, 8)
|
||||||
|
|
||||||
# In case of rejected or expired order and partially filled
|
# In case of rejected or expired order and partially filled
|
||||||
order['status'] = 'expired'
|
order['status'] = 'expired'
|
||||||
@ -860,7 +860,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
|
|||||||
assert trade
|
assert trade
|
||||||
assert trade.open_order_id == '555'
|
assert trade.open_order_id == '555'
|
||||||
assert trade.open_rate == 0.5
|
assert trade.open_rate == 0.5
|
||||||
assert trade.stake_amount == 15.0
|
assert trade.stake_amount == round(order['price'] * order['filled'] / leverage, 8)
|
||||||
|
|
||||||
# Test with custom stake
|
# Test with custom stake
|
||||||
order['status'] = 'open'
|
order['status'] = 'open'
|
||||||
@ -871,7 +871,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
|
|||||||
trade = Trade.query.all()[4]
|
trade = Trade.query.all()[4]
|
||||||
trade.is_short = is_short
|
trade.is_short = is_short
|
||||||
assert trade
|
assert trade
|
||||||
assert trade.stake_amount == 150
|
assert pytest.approx(trade.stake_amount) == 150
|
||||||
|
|
||||||
# Exception case
|
# Exception case
|
||||||
order['id'] = '557'
|
order['id'] = '557'
|
||||||
@ -880,7 +880,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
|
|||||||
trade = Trade.query.all()[5]
|
trade = Trade.query.all()[5]
|
||||||
trade.is_short = is_short
|
trade.is_short = is_short
|
||||||
assert trade
|
assert trade
|
||||||
assert trade.stake_amount == 2.0
|
assert pytest.approx(trade.stake_amount) == 2.0
|
||||||
|
|
||||||
# In case of the order is rejected and not filled at all
|
# In case of the order is rejected and not filled at all
|
||||||
order['status'] = 'rejected'
|
order['status'] = 'rejected'
|
||||||
@ -960,7 +960,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
|
|||||||
assert freqtrade.execute_entry(pair, 2000, is_short=is_short)
|
assert freqtrade.execute_entry(pair, 2000, is_short=is_short)
|
||||||
trade = Trade.query.all()[9]
|
trade = Trade.query.all()[9]
|
||||||
trade.is_short = is_short
|
trade.is_short = is_short
|
||||||
assert trade.stake_amount == 500
|
assert pytest.approx(trade.stake_amount) == 500
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("is_short", [False, True])
|
@pytest.mark.parametrize("is_short", [False, True])
|
||||||
@ -1932,7 +1932,8 @@ def test_update_trade_state(
|
|||||||
open_date=arrow.utcnow().datetime,
|
open_date=arrow.utcnow().datetime,
|
||||||
amount=11,
|
amount=11,
|
||||||
exchange="binance",
|
exchange="binance",
|
||||||
is_short=is_short
|
is_short=is_short,
|
||||||
|
leverage=1,
|
||||||
)
|
)
|
||||||
trade.orders.append(Order(
|
trade.orders.append(Order(
|
||||||
ft_order_side=enter_side(is_short),
|
ft_order_side=enter_side(is_short),
|
||||||
@ -2006,7 +2007,8 @@ def test_update_trade_state_withorderdict(
|
|||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
open_order_id=order_id,
|
open_order_id=order_id,
|
||||||
is_open=True,
|
is_open=True,
|
||||||
is_short=is_short
|
leverage=1,
|
||||||
|
is_short=is_short,
|
||||||
)
|
)
|
||||||
trade.orders.append(
|
trade.orders.append(
|
||||||
Order(
|
Order(
|
||||||
@ -2088,7 +2090,8 @@ def test_update_trade_state_sell(
|
|||||||
open_order_id=open_order['id'],
|
open_order_id=open_order['id'],
|
||||||
is_open=True,
|
is_open=True,
|
||||||
interest_rate=0.0005,
|
interest_rate=0.0005,
|
||||||
is_short=is_short
|
leverage=1,
|
||||||
|
is_short=is_short,
|
||||||
)
|
)
|
||||||
order = Order.parse_from_ccxt_object(open_order, 'LTC/ETH', exit_side(is_short))
|
order = Order.parse_from_ccxt_object(open_order, 'LTC/ETH', exit_side(is_short))
|
||||||
trade.orders.append(order)
|
trade.orders.append(order)
|
||||||
@ -4457,7 +4460,7 @@ def test_order_book_depth_of_market(
|
|||||||
else:
|
else:
|
||||||
trade.is_short = is_short
|
trade.is_short = is_short
|
||||||
assert trade is not None
|
assert trade is not None
|
||||||
assert trade.stake_amount == 60.0
|
assert pytest.approx(trade.stake_amount) == 60.0
|
||||||
assert trade.is_open
|
assert trade.is_open
|
||||||
assert trade.open_date is not None
|
assert trade.open_date is not None
|
||||||
assert trade.exchange == 'binance'
|
assert trade.exchange == 'binance'
|
||||||
|
@ -520,7 +520,8 @@ def test_update_market_order(market_buy_order_usdt, market_sell_order_usdt, fee,
|
|||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
open_date=arrow.utcnow().datetime,
|
open_date=arrow.utcnow().datetime,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
trading_mode=margin
|
trading_mode=margin,
|
||||||
|
leverage=1.0,
|
||||||
)
|
)
|
||||||
|
|
||||||
trade.open_order_id = 'something'
|
trade.open_order_id = 'something'
|
||||||
@ -649,7 +650,8 @@ def test_calc_close_trade_price_exception(limit_buy_order_usdt, fee):
|
|||||||
fee_open=fee.return_value,
|
fee_open=fee.return_value,
|
||||||
fee_close=fee.return_value,
|
fee_close=fee.return_value,
|
||||||
exchange='binance',
|
exchange='binance',
|
||||||
trading_mode=margin
|
trading_mode=margin,
|
||||||
|
leverage=1.0,
|
||||||
)
|
)
|
||||||
|
|
||||||
trade.open_order_id = 'something'
|
trade.open_order_id = 'something'
|
||||||
@ -2231,6 +2233,7 @@ def test_recalc_trade_from_orders(fee):
|
|||||||
exchange='binance',
|
exchange='binance',
|
||||||
open_rate=o1_rate,
|
open_rate=o1_rate,
|
||||||
max_rate=o1_rate,
|
max_rate=o1_rate,
|
||||||
|
leverage=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert fee.return_value == 0.0025
|
assert fee.return_value == 0.0025
|
||||||
@ -2395,6 +2398,7 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
|
|||||||
open_rate=o1_rate,
|
open_rate=o1_rate,
|
||||||
max_rate=o1_rate,
|
max_rate=o1_rate,
|
||||||
is_short=is_short,
|
is_short=is_short,
|
||||||
|
leverage=1.0,
|
||||||
)
|
)
|
||||||
trade.update_fee(o1_fee_cost, 'BNB', fee.return_value, enter_side)
|
trade.update_fee(o1_fee_cost, 'BNB', fee.return_value, enter_side)
|
||||||
# Check with 1 order
|
# Check with 1 order
|
||||||
|
Loading…
Reference in New Issue
Block a user