def handle_timedout_limit_buy(self, trade: Trade, order: Dict) -> bool: """Buy timeout - cancel order :return: True if order was fully cancelled """ exchange.cancel_order(trade.open_order_id) if order['remaining'] == order['amount']: # if trade is not partially completed, just delete the trade Trade.session.delete(trade) # FIX? do we really need to flush, caller of # check_handle_timedout will flush afterwards Trade.session.flush() logger.info('Buy order timeout for %s.', trade) self.rpc.send_msg( '*Timeout:* Unfilled buy order for {} cancelled'.format( trade.pair.replace('_', '/'))) return True # if trade is partially complete, edit the stake details for the trade # and close the order trade.amount = order['amount'] - order['remaining'] trade.stake_amount = trade.amount * trade.open_rate trade.open_order_id = None logger.info('Partial buy order timeout for %s.', trade) self.rpc.send_msg( '*Timeout:* Remaining buy order for {} cancelled'.format( trade.pair.replace('_', '/'))) return False
def handle_trade(trade: Trade) -> bool: """ Sells the current pair if the threshold is reached and updates the trade record. :return: True if trade has been sold, False otherwise """ if not trade.is_open: raise ValueError('attempt to handle closed trade: {}'.format(trade)) logger.debug('Handling %s ...', trade) # first determine if buy order that is still open if trade.open_order_id: order_info = exchange.get_order(trade.open_order_id) order_type = order_info['type'] if order_type == 'LIMIT_BUY': max_open_time = 10 current_time = datetime.utcnow() amount_minutes_open = (current_time - trade.open_date).total_seconds() / 60. if amount_minutes_open > max_open_time: health = exchange.get_wallet_health() if exchange.get_name() == 'HitBTC': token = trade.pair else: token = get_quote_token(trade.pair) token_healthy = False for status in health: if status['Currency'] == token: token_healthy = status['IsActive'] if token_healthy: logger.debug('Cancelling %s ...', trade) exchange.cancel_order(trade.open_order_id) # trade.is_open = 0 # trade.open_order_id = None Trade.session.delete(trade) else: logger.debug( 'Cancelling could not execute due to wallet heath for %s ...', trade) return False current_rate = exchange.get_ticker(trade.pair)['bid'] # ask? if current_rate is None: return False if should_sell(trade, current_rate, datetime.utcnow()): execute_sell(trade, current_rate) return True return False
def test_cancel_order(default_conf, mocker): default_conf['dry_run'] = False mocker.patch.dict('freqtrade.exchange._CONF', default_conf) api_mock = MagicMock() api_mock.cancel_order = MagicMock(return_value=123) mocker.patch('freqtrade.exchange._API', api_mock) assert cancel_order(order_id='_') == 123
def check_handle_timedout(timeoutvalue: int) -> None: """ Check if any orders are timed out and cancel if neccessary :param timeoutvalue: Number of minutes until order is considered timed out :return: None """ timeoutthreashold = arrow.utcnow().shift(minutes=-timeoutvalue).datetime for trade in Trade.query.filter(Trade.open_order_id.isnot(None)).all(): order = exchange.get_order(trade.open_order_id) ordertime = arrow.get(order['opened']) if order['type'] == "LIMIT_BUY" and ordertime < timeoutthreashold: # Buy timeout - cancel order exchange.cancel_order(trade.open_order_id) if order['remaining'] == order['amount']: # if trade is not partially completed, just delete the trade Trade.session.delete(trade) Trade.session.flush() logger.info('Buy order timeout for %s.', trade) else: # if trade is partially complete, edit the stake details for the trade # and close the order trade.amount = order['amount'] - order['remaining'] trade.stake_amount = trade.amount * trade.open_rate trade.open_order_id = None logger.info('Partial buy order timeout for %s.', trade) elif order['type'] == "LIMIT_SELL" and ordertime < timeoutthreashold: # Sell timeout - cancel order and update trade if order['remaining'] == order['amount']: # if trade is not partially completed, just cancel the trade exchange.cancel_order(trade.open_order_id) trade.close_rate = None trade.close_profit = None trade.close_date = None trade.is_open = True trade.open_order_id = None logger.info('Sell order timeout for %s.', trade) return True else: # TODO: figure out how to handle partially complete sell orders pass
def check_handle_timedout(timeoutvalue: int) -> None: """ Check if any orders are timed out and cancel if neccessary :param timeoutvalue: Number of minutes until order is considered timed out :return: None """ timeoutthreashold = arrow.utcnow().shift(minutes=-timeoutvalue).datetime for trade in Trade.query.filter(Trade.open_order_id.isnot(None)).all(): order = exchange.get_order(trade.open_order_id) ordertime = arrow.get(order['opened']) if order['type'] == "LIMIT_BUY" and ordertime < timeoutthreashold: # Buy timeout - cancel order exchange.cancel_order(trade.open_order_id) if order['remaining'] == order['amount']: # if trade is not partially completed, just delete the trade Trade.session.delete(trade) Trade.session.flush() logger.info('Buy order timeout for %s.', trade) else: # if trade is partially complete, edit the stake details for the trade # and close the order trade.amount = order['amount'] - order['remaining'] trade.stake_amount = trade.amount * trade.open_rate trade.open_order_id = None logger.info('Partial buy order timeout for %s.', trade) elif order['type'] == "LIMIT_SELL" and ordertime < timeoutthreashold: # Sell timeout - cancel order and update trade if order['remaining'] == order['amount']: # if trade is not partially completed, just cancel the trade exchange.cancel_order(trade.open_order_id) trade.close_rate = None trade.close_profit = None trade.close_date = None trade.is_open = True trade.open_order_id = None logger.info('Sell order timeout for %s.', trade) return True else: # TODO: figure out how to handle partially complete sell orders pass
def _exec_forcesell(trade: Trade) -> None: # Check if there is there is an open order if trade.open_order_id: order = exchange.get_order(trade.open_order_id) # Cancel open LIMIT_BUY orders and close trade if order and not order['closed'] and order['type'] == 'LIMIT_BUY': exchange.cancel_order(trade.open_order_id) trade.close(order.get('rate') or trade.open_rate) # TODO: sell amount which has been bought already return # Ignore trades with an attached LIMIT_SELL order if order and not order['closed'] and order['type'] == 'LIMIT_SELL': return # Get current rate and execute sell current_rate = exchange.get_ticker(trade.pair, False)['bid'] from freqtrade.main import execute_sell execute_sell(trade, current_rate)
def _exec_forcesell(trade: Trade) -> None: # Check if there is there is an open order if trade.open_order_id: order = exchange.get_order(trade.open_order_id) # Cancel open LIMIT_BUY orders and close trade if order and not order['closed'] and order['type'] == 'LIMIT_BUY': exchange.cancel_order(trade.open_order_id) trade.close(order.get('rate') or trade.open_rate) # TODO: sell amount which has been bought already return # Ignore trades with an attached LIMIT_SELL order if order and not order['closed'] and order['type'] == 'LIMIT_SELL': return # Get current rate and execute sell current_rate = exchange.get_ticker(trade.pair, False)['bid'] from freqtrade.main import execute_sell execute_sell(trade, current_rate)
def handle_timedout_limit_sell(self, trade: Trade, order: Dict) -> bool: """ Sell timeout - cancel order and update trade :return: True if order was fully cancelled """ if order['remaining'] == order['amount']: # if trade is not partially completed, just cancel the trade exchange.cancel_order(trade.open_order_id) trade.close_rate = None trade.close_profit = None trade.close_date = None trade.is_open = True trade.open_order_id = None self.rpc.send_msg( '*Timeout:* Unfilled sell order for {} cancelled'.format( trade.pair.replace('_', '/'))) logger.info('Sell order timeout for %s.', trade) return True # TODO: figure out how to handle partially complete sell orders return False
def execute_sell(trade: Trade, limit: float) -> None: """ Executes a limit sell for the given trade and limit :param trade: Trade instance :param limit: limit rate for the sell order :return: None """ # check how much is available available = exchange.get_available_balance(get_quote_token(str( trade.pair))) # Execute sell and update trade record order_id = exchange.sell(str(trade.pair), limit, available) # trade.amount trade.open_order_id = order_id if available < trade.amount: # cancel the rest # todo: check if wallet is healthy before cancelling health = exchange.get_wallet_health() if exchange.get_name() == 'HitBTC': token = trade.pair else: token = get_quote_token(trade.pair) token_healthy = False for status in health: if status['Currency'] == token: token_healthy = status['IsActive'] if token_healthy: exchange.cancel_order(trade.id) fmt_exp_profit = round(trade.calc_profit(limit) * 100, 2) message = '*{}:* Selling [{}]({}) with limit `{:.8f} (profit: ~{:.2f}%)`'.format( trade.exchange, trade.pair.replace('_', '/'), exchange.get_pair_detail_url(trade.pair), limit, fmt_exp_profit) logger.info(message) telegram.send_msg(message)
def test_cancel_order_dry_run(default_conf, mocker): default_conf['dry_run'] = True mocker.patch.dict('freqtrade.exchange._CONF', default_conf) assert cancel_order(order_id='123') is None
def test_cancel_order_dry_run(default_conf, mocker): default_conf['dry_run'] = True mocker.patch.dict('freqtrade.exchange._CONF', default_conf) assert cancel_order(order_id='123') is None