Stake_amount only adjusted on partially filled trades if amount filled makes leverage <= 1. Fulfilled some other TODOs in freqtradebot
This commit is contained in:
parent
6bbe63eb62
commit
7ac73999f6
@ -38,7 +38,8 @@ class Binance(Exchange):
|
|||||||
return order['type'] == 'stop_loss_limit' and stop_loss > float(order['info']['stopPrice'])
|
return order['type'] == 'stop_loss_limit' and stop_loss > float(order['info']['stopPrice'])
|
||||||
|
|
||||||
@retrier(retries=0)
|
@retrier(retries=0)
|
||||||
def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, side: str) -> Dict:
|
def stoploss(self, pair: str, amount: float,
|
||||||
|
stop_price: float, order_types: Dict, side: str) -> Dict:
|
||||||
"""
|
"""
|
||||||
creates a stoploss limit order.
|
creates a stoploss limit order.
|
||||||
this stoploss-limit is binance-specific.
|
this stoploss-limit is binance-specific.
|
||||||
|
@ -777,14 +777,15 @@ class Exchange:
|
|||||||
):
|
):
|
||||||
raise OperationalException(f"Leverage is not available on {self.name} using freqtrade")
|
raise OperationalException(f"Leverage is not available on {self.name} using freqtrade")
|
||||||
|
|
||||||
def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool:
|
def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Verify stop_loss against stoploss-order value (limit or price)
|
Verify stop_loss against stoploss-order value (limit or price)
|
||||||
Returns True if adjustment is necessary.
|
Returns True if adjustment is necessary.
|
||||||
"""
|
"""
|
||||||
raise OperationalException(f"stoploss is not implemented for {self.name}.")
|
raise OperationalException(f"stoploss is not implemented for {self.name}.")
|
||||||
|
|
||||||
def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, side: str) -> Dict:
|
def stoploss(self, pair: str, amount: float,
|
||||||
|
stop_price: float, order_types: Dict, side: str) -> Dict:
|
||||||
"""
|
"""
|
||||||
creates a stoploss order.
|
creates a stoploss order.
|
||||||
The precise ordertype is determined by the order_types dict or exchange default.
|
The precise ordertype is determined by the order_types dict or exchange default.
|
||||||
|
@ -43,7 +43,8 @@ class Ftx(Exchange):
|
|||||||
return order['type'] == 'stop' and stop_loss > float(order['price'])
|
return order['type'] == 'stop' and stop_loss > float(order['price'])
|
||||||
|
|
||||||
@retrier(retries=0)
|
@retrier(retries=0)
|
||||||
def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, side: str) -> Dict:
|
def stoploss(self, pair: str, amount: float,
|
||||||
|
stop_price: float, order_types: Dict, side: str) -> Dict:
|
||||||
"""
|
"""
|
||||||
Creates a stoploss order.
|
Creates a stoploss order.
|
||||||
depending on order_types.stoploss configuration, uses 'market' or limit order.
|
depending on order_types.stoploss configuration, uses 'market' or limit order.
|
||||||
|
@ -81,7 +81,8 @@ class Kraken(Exchange):
|
|||||||
and stop_loss > float(order['price']))
|
and stop_loss > float(order['price']))
|
||||||
|
|
||||||
@retrier(retries=0)
|
@retrier(retries=0)
|
||||||
def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict, side: str) -> Dict:
|
def stoploss(self, pair: str, amount: float,
|
||||||
|
stop_price: float, order_types: Dict, side: str) -> Dict:
|
||||||
"""
|
"""
|
||||||
Creates a stoploss market order.
|
Creates a stoploss market order.
|
||||||
Stoploss market orders is the only stoploss type supported by kraken.
|
Stoploss market orders is the only stoploss type supported by kraken.
|
||||||
|
@ -5,7 +5,7 @@ import copy
|
|||||||
import logging
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from math import isclose
|
from math import ceil, isclose
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ from freqtrade.configuration import validate_config_consistency
|
|||||||
from freqtrade.data.converter import order_book_to_dataframe
|
from freqtrade.data.converter import order_book_to_dataframe
|
||||||
from freqtrade.data.dataprovider import DataProvider
|
from freqtrade.data.dataprovider import DataProvider
|
||||||
from freqtrade.edge import Edge
|
from freqtrade.edge import Edge
|
||||||
from freqtrade.enums import InterestMode, RPCMessageType, SellType, State
|
from freqtrade.enums import RPCMessageType, SellType, State
|
||||||
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
|
from freqtrade.exceptions import (DependencyException, ExchangeError, InsufficientFundsError,
|
||||||
InvalidOrderException, PricingError)
|
InvalidOrderException, PricingError)
|
||||||
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds
|
||||||
@ -101,9 +101,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
initial_state = self.config.get('initial_state')
|
initial_state = self.config.get('initial_state')
|
||||||
self.state = State[initial_state.upper()] if initial_state else State.STOPPED
|
self.state = State[initial_state.upper()] if initial_state else State.STOPPED
|
||||||
|
|
||||||
# Protect sell-logic from forcesell and vice versa
|
# Protect exit-logic from forcesell and vice versa
|
||||||
# TODO-mg: update to _close_lock
|
self._exit_lock = Lock()
|
||||||
self._sell_lock = Lock()
|
|
||||||
LoggingMixin.__init__(self, logger, timeframe_to_seconds(self.strategy.timeframe))
|
LoggingMixin.__init__(self, logger, timeframe_to_seconds(self.strategy.timeframe))
|
||||||
|
|
||||||
# Start calculating maintenance margin if on cross margin
|
# Start calculating maintenance margin if on cross margin
|
||||||
@ -177,16 +176,15 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
|
|
||||||
self.strategy.analyze(self.active_pair_whitelist)
|
self.strategy.analyze(self.active_pair_whitelist)
|
||||||
|
|
||||||
# TODO-mg: update to _close_lock
|
with self._exit_lock:
|
||||||
with self._sell_lock:
|
|
||||||
# Check and handle any timed out open orders
|
# Check and handle any timed out open orders
|
||||||
self.check_handle_timedout()
|
self.check_handle_timedout()
|
||||||
|
|
||||||
# Protect from collisions with forcesell(#TODO-mg: update to forceclose).
|
# Protect from collisions with forcesell(#TODO-mg: update to forceclose).
|
||||||
# Without this, freqtrade my try to recreate stoploss_on_exchange orders
|
# Without this, freqtrade my try to recreate stoploss_on_exchange orders
|
||||||
# while closing is in process, since telegram messages arrive in an different thread.
|
# while closing is in process, since telegram messages arrive in an different thread.
|
||||||
# TODO-mg: update to _close_lock
|
|
||||||
with self._sell_lock:
|
with self._exit_lock:
|
||||||
trades = Trade.get_open_trades()
|
trades = Trade.get_open_trades()
|
||||||
# First process current opened trades (positions)
|
# First process current opened trades (positions)
|
||||||
self.exit_positions(trades)
|
self.exit_positions(trades)
|
||||||
@ -263,7 +261,6 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
logger.info(f"Updating {len(orders)} open orders.")
|
logger.info(f"Updating {len(orders)} open orders.")
|
||||||
for order in orders:
|
for order in orders:
|
||||||
try:
|
try:
|
||||||
# TODO-mg: How to consider borrow orders?
|
|
||||||
fo = self.exchange.fetch_order_or_stoploss_order(order.order_id, order.ft_pair,
|
fo = self.exchange.fetch_order_or_stoploss_order(order.order_id, order.ft_pair,
|
||||||
order.ft_order_side == 'stoploss')
|
order.ft_order_side == 'stoploss')
|
||||||
|
|
||||||
@ -412,8 +409,6 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
|
|
||||||
def create_trade(self, pair: str) -> bool:
|
def create_trade(self, pair: str) -> bool:
|
||||||
"""
|
"""
|
||||||
# TODO-mg: Just make this function work for shorting and leverage, my todo notes in
|
|
||||||
# TODO-mg: it aren't very clear
|
|
||||||
Check the implemented trading strategy for enter signals.
|
Check the implemented trading strategy for enter signals.
|
||||||
|
|
||||||
If the pair triggers the enter signal a new trade record gets created
|
If the pair triggers the enter signal a new trade record gets created
|
||||||
@ -442,8 +437,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
logger.debug(f"Can't open a new trade for {pair}: max number of trades is reached.")
|
logger.debug(f"Can't open a new trade for {pair}: max number of trades is reached.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
long_lev = 1.0 if True else 1.0 # Replace with self.strategy.get_leverage
|
long_lev = 1.0 if True else 1.0 # TODO-mg: Replace with self.strategy.get_leverage
|
||||||
short_lev = 1.0 if True else 1.0 # Replace with self.strategy.get_leverage
|
short_lev = 1.0 if True else 1.0 # TODO-mg: Replace with self.strategy.get_leverage
|
||||||
# running get_signal on historical data fetched
|
# running get_signal on historical data fetched
|
||||||
(buy, sell, buy_tag) = self.strategy.get_signal(
|
(buy, sell, buy_tag) = self.strategy.get_signal(
|
||||||
pair,
|
pair,
|
||||||
@ -540,8 +535,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
:return: True if a buy order is created, false if it fails.
|
:return: True if a buy order is created, false if it fails.
|
||||||
"""
|
"""
|
||||||
time_in_force = self.strategy.order_time_in_force['buy'] # TODO-mg Change to enter
|
time_in_force = self.strategy.order_time_in_force['buy'] # TODO-mg Change to enter
|
||||||
side = 'sell' if is_short else 'buy'
|
[side, name] = ['sell', 'Short'] if is_short else ['buy', 'Buy']
|
||||||
name = 'Short' if is_short else 'Buy'
|
|
||||||
|
|
||||||
if price:
|
if price:
|
||||||
enter_limit_requested = price
|
enter_limit_requested = price
|
||||||
@ -576,7 +570,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
f"{stake_amount} ...")
|
f"{stake_amount} ...")
|
||||||
|
|
||||||
amount = (stake_amount / enter_limit_requested) * leverage
|
amount = (stake_amount / enter_limit_requested) * leverage
|
||||||
order_type = self.strategy.order_types[side] # TODO-mg: Don't knoww what to do here
|
order_type = self.strategy.order_types["buy"] # TODO-mg: Maybe enter? or side?
|
||||||
if forcebuy:
|
if forcebuy:
|
||||||
# Forcebuy can define a different ordertype
|
# Forcebuy can define a different ordertype
|
||||||
# TODO-mg get a forceshort? What is this
|
# TODO-mg get a forceshort? What is this
|
||||||
@ -629,18 +623,9 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
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')
|
||||||
|
|
||||||
interest_rate = 0
|
interest_rate = 0.0
|
||||||
isolated_liq = None
|
isolated_liq = None
|
||||||
|
|
||||||
if leverage > 1.0: # TODO-mg: and margin == isolated:
|
|
||||||
isolated_liq = self.exchange.get_isolated_liq(
|
|
||||||
pair=pair,
|
|
||||||
open_rate=enter_limit_filled_price,
|
|
||||||
amount=amount,
|
|
||||||
leverage=leverage,
|
|
||||||
is_short=is_short
|
|
||||||
)
|
|
||||||
|
|
||||||
if leverage > 1.0:
|
if leverage > 1.0:
|
||||||
interest_rate = self.exchange.get_interest_rate(
|
interest_rate = self.exchange.get_interest_rate(
|
||||||
pair=pair,
|
pair=pair,
|
||||||
@ -648,6 +633,15 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
is_short=is_short
|
is_short=is_short
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO-mg: if margin == isolated
|
||||||
|
isolated_liq = self.exchange.get_isolated_liq(
|
||||||
|
pair=pair,
|
||||||
|
open_rate=enter_limit_filled_price,
|
||||||
|
amount=amount,
|
||||||
|
leverage=leverage,
|
||||||
|
is_short=is_short
|
||||||
|
)
|
||||||
|
|
||||||
# Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
|
# Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
|
||||||
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
|
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
@ -963,10 +957,9 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
buy: bool, sell: bool) -> bool:
|
buy: bool, sell: bool) -> bool:
|
||||||
"""
|
"""
|
||||||
Check and execute sell
|
Check and execute sell
|
||||||
# TODO-mg: Update this for shorts
|
|
||||||
"""
|
"""
|
||||||
exit = getattr(self.strategy, "should_exit_short") if trade.is_short else getattr(
|
exit = getattr(self.strategy, "should_exit_short") if trade.is_short else getattr(
|
||||||
self.strategy, "should_sell")
|
self.strategy, "should_sell") # TODO-mg: implement should_exit_short
|
||||||
|
|
||||||
should_exit = exit(
|
should_exit = exit(
|
||||||
trade, exit_rate, datetime.now(timezone.utc), buy, sell,
|
trade, exit_rate, datetime.now(timezone.utc), buy, sell,
|
||||||
@ -977,7 +970,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
# TODO-mg: Update to exit_type
|
# TODO-mg: Update to exit_type
|
||||||
logger.info(
|
logger.info(
|
||||||
f'Executing {trade.exit_side} for {trade.pair}. Reason: {should_exit.sell_type}')
|
f'Executing {trade.exit_side} for {trade.pair}. Reason: {should_exit.sell_type}')
|
||||||
self.execute_exit(trade, exit_rate, should_exit, side="sell")
|
self.execute_exit(trade, exit_rate, should_exit, side=trade.exit_side)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -1015,22 +1008,25 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
fully_cancelled = self.update_trade_state(trade, trade.open_order_id, order)
|
fully_cancelled = self.update_trade_state(trade, trade.open_order_id, order)
|
||||||
|
|
||||||
if (order['side'] == trade.enter_side and (
|
if (order['side'] == trade.enter_side and (
|
||||||
|
# TODO-mg: maybe change check_buy_timeout to check_enter_timeout
|
||||||
order['status'] == 'open' or fully_cancelled) and (
|
order['status'] == 'open' or fully_cancelled) and (
|
||||||
fully_cancelled
|
fully_cancelled
|
||||||
or self._check_timed_out(trade.enter_side, order)
|
or self._check_timed_out(trade.enter_side, order)
|
||||||
or strategy_safe_wrapper(self.strategy.check_buy_timeout, # TODO-mg: maybe change to check_enter_timeout
|
or strategy_safe_wrapper(self.strategy.check_buy_timeout,
|
||||||
default_retval=False)(pair=trade.pair,
|
default_retval=False)(pair=trade.pair,
|
||||||
trade=trade,
|
trade=trade,
|
||||||
order=order))):
|
order=order))):
|
||||||
self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT'])
|
self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT'])
|
||||||
|
|
||||||
elif (order['side'] == trade.exit_side and (order['status'] == 'open' or fully_cancelled) and (
|
# TODO-mg: maybe change check_sell_timeout to check_exit_timeout
|
||||||
fully_cancelled
|
elif (order['side'] == trade.exit_side and (
|
||||||
or self._check_timed_out(trade.exit_side, order)
|
order['status'] == 'open' or fully_cancelled
|
||||||
or strategy_safe_wrapper(self.strategy.check_sell_timeout, # TODO-mg: maybe change to check_exit_timeout
|
) and (fully_cancelled
|
||||||
default_retval=False)(pair=trade.pair,
|
or self._check_timed_out(trade.exit_side, order)
|
||||||
trade=trade,
|
or strategy_safe_wrapper(self.strategy.check_sell_timeout,
|
||||||
order=order))):
|
default_retval=False)(pair=trade.pair,
|
||||||
|
trade=trade,
|
||||||
|
order=order))):
|
||||||
self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT'])
|
self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT'])
|
||||||
|
|
||||||
def cancel_all_open_orders(self) -> None:
|
def cancel_all_open_orders(self) -> None:
|
||||||
@ -1058,6 +1054,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
Buy cancel - cancel order
|
Buy cancel - cancel order
|
||||||
:return: True if order was fully cancelled
|
:return: True if order was fully cancelled
|
||||||
"""
|
"""
|
||||||
|
# TODO-mg: Pay back borrowed and transfer back on leveraged trades
|
||||||
was_trade_fully_canceled = False
|
was_trade_fully_canceled = False
|
||||||
|
|
||||||
# Cancelled orders may have the status of 'canceled' or 'closed'
|
# Cancelled orders may have the status of 'canceled' or 'closed'
|
||||||
@ -1105,9 +1102,15 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
# cancel_order may not contain the full order dict, so we need to fallback
|
# cancel_order may not contain the full order dict, so we need to fallback
|
||||||
# to the order dict aquired before cancelling.
|
# to the order dict aquired before cancelling.
|
||||||
# we need to fall back to the values from order if corder does not contain these keys.
|
# we need to fall back to the values from order if corder does not contain these keys.
|
||||||
# TODO-mg: Update trade.leverage if the full buy order was not filled
|
|
||||||
trade.amount = filled_amount
|
trade.amount = filled_amount
|
||||||
trade.stake_amount = trade.amount * trade.open_rate
|
# TODO-mg: Check edge cases, we don't want to make leverage > 1.0 if we don't have to
|
||||||
|
|
||||||
|
if trade.amount <= ceil(trade.stake_amount/trade.open_rate):
|
||||||
|
# If amount is less than 1x leverage
|
||||||
|
trade.stake_amount = trade.amount * trade.open_rate
|
||||||
|
else:
|
||||||
|
# TODO: deal with situation of paying back extra amount
|
||||||
|
trade.leverage = trade.amount/trade.stake_amount
|
||||||
self.update_trade_state(trade, trade.open_order_id, corder)
|
self.update_trade_state(trade, trade.open_order_id, corder)
|
||||||
|
|
||||||
trade.open_order_id = None
|
trade.open_order_id = None
|
||||||
@ -1444,7 +1447,6 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
|
|
||||||
def get_real_amount(self, trade: Trade, order: Dict) -> float:
|
def get_real_amount(self, trade: Trade, order: Dict) -> float:
|
||||||
"""
|
"""
|
||||||
TODO-mg: Update this function to account for shorts
|
|
||||||
Detect and update trade fee.
|
Detect and update trade fee.
|
||||||
Calls trade.update_fee() upon correct detection.
|
Calls trade.update_fee() upon correct detection.
|
||||||
Returns modified amount if the fee was taken from the destination currency.
|
Returns modified amount if the fee was taken from the destination currency.
|
||||||
@ -1477,7 +1479,6 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
|
|
||||||
def fee_detection_from_trades(self, trade: Trade, order: Dict, order_amount: float) -> float:
|
def fee_detection_from_trades(self, trade: Trade, order: Dict, order_amount: float) -> float:
|
||||||
"""
|
"""
|
||||||
TODO-mg: Update this function to account for shorts
|
|
||||||
fee-detection fallback to Trades. Parses result of fetch_my_trades to get correct fee.
|
fee-detection fallback to Trades. Parses result of fetch_my_trades to get correct fee.
|
||||||
"""
|
"""
|
||||||
trades = self.exchange.get_trades_for_order(self.exchange.get_order_id_conditional(order),
|
trades = self.exchange.get_trades_for_order(self.exchange.get_order_id_conditional(order),
|
||||||
@ -1509,6 +1510,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
trade.update_fee(fee_cost, fee_currency, fee_rate, order.get('side', ''))
|
trade.update_fee(fee_cost, fee_currency, fee_rate, order.get('side', ''))
|
||||||
|
|
||||||
if not isclose(amount, order_amount, abs_tol=constants.MATH_CLOSE_PREC):
|
if not isclose(amount, order_amount, abs_tol=constants.MATH_CLOSE_PREC):
|
||||||
|
# TODO-mg: leverage?
|
||||||
logger.warning(f"Amount {amount} does not match amount {trade.amount}")
|
logger.warning(f"Amount {amount} does not match amount {trade.amount}")
|
||||||
raise DependencyException("Half bought? Amounts don't match")
|
raise DependencyException("Half bought? Amounts don't match")
|
||||||
|
|
||||||
|
@ -564,7 +564,7 @@ class RPC:
|
|||||||
if self._freqtrade.state != State.RUNNING:
|
if self._freqtrade.state != State.RUNNING:
|
||||||
raise RPCException('trader is not running')
|
raise RPCException('trader is not running')
|
||||||
|
|
||||||
with self._freqtrade._sell_lock:
|
with self._freqtrade._exit_lock:
|
||||||
if trade_id == 'all':
|
if trade_id == 'all':
|
||||||
# Execute sell for all open orders
|
# Execute sell for all open orders
|
||||||
for trade in Trade.get_open_trades():
|
for trade in Trade.get_open_trades():
|
||||||
@ -626,7 +626,7 @@ class RPC:
|
|||||||
Handler for delete <id>.
|
Handler for delete <id>.
|
||||||
Delete the given trade and close eventually existing open orders.
|
Delete the given trade and close eventually existing open orders.
|
||||||
"""
|
"""
|
||||||
with self._freqtrade._sell_lock:
|
with self._freqtrade._exit_lock:
|
||||||
c_count = 0
|
c_count = 0
|
||||||
trade = Trade.get_trades(trade_filter=[Trade.id == trade_id]).first()
|
trade = Trade.get_trades(trade_filter=[Trade.id == trade_id]).first()
|
||||||
if not trade:
|
if not trade:
|
||||||
|
@ -1845,7 +1845,7 @@ def open_trade():
|
|||||||
amount=90.99181073,
|
amount=90.99181073,
|
||||||
fee_open=0.0,
|
fee_open=0.0,
|
||||||
fee_close=0.0,
|
fee_close=0.0,
|
||||||
stake_amount=1,
|
stake_amount=0.001,
|
||||||
open_date=arrow.utcnow().shift(minutes=-601).datetime,
|
open_date=arrow.utcnow().shift(minutes=-601).datetime,
|
||||||
is_open=True
|
is_open=True
|
||||||
)
|
)
|
||||||
|
@ -2533,7 +2533,7 @@ def test_stoploss_order_unsupported_exchange(default_conf, mocker):
|
|||||||
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side="sell")
|
exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={}, side="sell")
|
||||||
|
|
||||||
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
with pytest.raises(OperationalException, match=r"stoploss is not implemented .*"):
|
||||||
exchange.stoploss_adjust(1, {})
|
exchange.stoploss_adjust(1, {}, side="sell")
|
||||||
|
|
||||||
|
|
||||||
def test_merge_ft_has_dict(default_conf, mocker):
|
def test_merge_ft_has_dict(default_conf, mocker):
|
||||||
|
@ -2480,6 +2480,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf, limit_buy_order) -> N
|
|||||||
caplog.clear()
|
caplog.clear()
|
||||||
cancel_order_mock.reset_mock()
|
cancel_order_mock.reset_mock()
|
||||||
limit_buy_order['filled'] = 2
|
limit_buy_order['filled'] = 2
|
||||||
|
trade.stake_amount = 0.090982711548927
|
||||||
assert not freqtrade.handle_cancel_enter(trade, limit_buy_order, reason)
|
assert not freqtrade.handle_cancel_enter(trade, limit_buy_order, reason)
|
||||||
assert cancel_order_mock.call_count == 1
|
assert cancel_order_mock.call_count == 1
|
||||||
|
|
||||||
@ -2534,6 +2535,7 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf, limit_buy_order,
|
|||||||
|
|
||||||
trade = MagicMock()
|
trade = MagicMock()
|
||||||
trade.pair = 'LTC/USDT'
|
trade.pair = 'LTC/USDT'
|
||||||
|
trade.enter_side = "buy"
|
||||||
trade.open_rate = 200
|
trade.open_rate = 200
|
||||||
trade.enter_side = "buy"
|
trade.enter_side = "buy"
|
||||||
limit_buy_order['filled'] = 0.0
|
limit_buy_order['filled'] = 0.0
|
||||||
@ -2544,6 +2546,7 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf, limit_buy_order,
|
|||||||
|
|
||||||
cancel_order_mock.reset_mock()
|
cancel_order_mock.reset_mock()
|
||||||
limit_buy_order['filled'] = 1.0
|
limit_buy_order['filled'] = 1.0
|
||||||
|
trade.stake_amount = 0.090982711548927
|
||||||
assert not freqtrade.handle_cancel_enter(trade, limit_buy_order, reason)
|
assert not freqtrade.handle_cancel_enter(trade, limit_buy_order, reason)
|
||||||
assert cancel_order_mock.call_count == 1
|
assert cancel_order_mock.call_count == 1
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user