diff --git a/freqtrade/rpc/__init__.py b/freqtrade/rpc/__init__.py index 62cf11873..4d68b80d0 100644 --- a/freqtrade/rpc/__init__.py +++ b/freqtrade/rpc/__init__.py @@ -5,6 +5,7 @@ from decimal import Decimal from datetime import datetime, timedelta from pandas import DataFrame import sqlalchemy as sql +# from sqlalchemy import and_, func, text from freqtrade.persistence import Trade from freqtrade.misc import State, get_state, update_state @@ -64,6 +65,28 @@ def shorten_date(_date): return new_date +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) + + # # Below follows the RPC backend # it is prefixed with rpc_ @@ -355,3 +378,30 @@ def rpc_stop(): return (False, '`Stopping trader ...`') else: return (True, '*Status:* `already stopped`') + + +def rpc_forcesell(trade_id) -> None: + """ + Handler for forcesell . + Sells the given trade at current price + :return: error or None + """ + if get_state() != State.RUNNING: + return (True, '`trader is not running`') + + if trade_id == 'all': + # Execute sell for all open orders + for trade in Trade.query.filter(Trade.is_open.is_(True)).all(): + _exec_forcesell(trade) + return (False, '') + + # Query for trade + trade = Trade.query.filter(sql.and_( + Trade.id == trade_id, + Trade.is_open.is_(True) + )).first() + if not trade: + logger.warning('/forcesell: Invalid argument received') + return (True, 'Invalid argument. See `/help` to view usage') + + _exec_forcesell(trade) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 123d01d33..130b30d41 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -1,7 +1,7 @@ import logging from typing import Any, Callable -from sqlalchemy import and_, func, text +from sqlalchemy import func, text from tabulate import tabulate from telegram import Bot, ParseMode, ReplyKeyboardMarkup, Update from telegram.error import NetworkError, TelegramError @@ -13,7 +13,8 @@ from freqtrade.rpc.__init__ import (rpc_status_table, rpc_trade_statistics, rpc_balance, rpc_start, - rpc_stop + rpc_stop, + rpc_forcesell, ) from freqtrade import __version__, exchange @@ -296,6 +297,7 @@ def _stop(bot: Bot, update: Update) -> None: send_msg(msg, bot=bot) +# FIX: no test for this!!!! @authorized_only def _forcesell(bot: Bot, update: Update) -> None: """ @@ -305,29 +307,13 @@ def _forcesell(bot: Bot, update: Update) -> None: :param update: message update :return: None """ - if get_state() != State.RUNNING: - send_msg('`trader is not running`', bot=bot) - return trade_id = update.message.text.replace('/forcesell', '').strip() - if trade_id == 'all': - # Execute sell for all open orders - for trade in Trade.query.filter(Trade.is_open.is_(True)).all(): - _exec_forcesell(trade) + (error, message) = rpc_forcesell(trade_id) + if error: + send_msg(message, bot=bot) return - # Query for trade - trade = Trade.query.filter(and_( - Trade.id == trade_id, - Trade.is_open.is_(True) - )).first() - if not trade: - send_msg('Invalid argument. See `/help` to view usage') - logger.warning('/forcesell: Invalid argument received') - return - - _exec_forcesell(trade) - @authorized_only def _performance(bot: Bot, update: Update) -> None: