implement /forcesell command

This commit is contained in:
gcarq 2017-06-08 20:01:01 +02:00
parent 3c0074520c
commit 3d5913d317
3 changed files with 75 additions and 12 deletions

12
main.py
View File

@ -158,20 +158,14 @@ def handle_trade(trade):
# Check if time matches and current rate is above threshold
time_diff = (datetime.utcnow() - trade.open_date).total_seconds() / 60
if time_diff > duration and current_rate > (1 + threshold) * trade.open_rate:
# Execute sell and update trade record
order_id = api_wrapper.sell(trade.pair, current_rate, balance)
trade.close_rate = current_rate
trade.close_profit = current_profit
trade.close_date = datetime.utcnow()
trade.open_order_id = order_id
# Execute sell
profit = trade.exec_sell_order(current_rate, balance)
message = '*{}:* Selling [{}]({}) at rate `{:f} (profit: {}%)`'.format(
trade.exchange.name,
trade.pair.replace('_', '/'),
api_wrapper.get_pair_detail_url(trade.pair),
trade.close_rate,
round(current_profit, 2)
round(profit, 2)
)
logger.info(message)
TelegramHandler.send_msg(message)

View File

@ -5,10 +5,11 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.types import Enum
from exchange import Exchange
from exchange import Exchange, get_exchange_api
from utils import get_conf
if get_conf().get('dry_run', False):
conf = get_conf()
if conf.get('dry_run', False):
db_handle = 'sqlite:///tradesv2.dry_run.sqlite'
else:
db_handle = 'sqlite:///tradesv2.sqlite'
@ -45,4 +46,22 @@ class Trade(Base):
'closed' if not self.is_open else round((datetime.utcnow() - self.open_date).total_seconds() / 60, 2)
)
def exec_sell_order(self, rate, amount):
"""
Executes a sell for the given trade and updated the entity.
:param rate: rate to sell for
:param amount: amount to sell
:return: current profit as percentage
"""
profit = 100 * ((rate - self.open_rate) / self.open_rate)
# Execute sell and update trade record
order_id = get_exchange_api(conf).sell(self.pair, rate, amount)
self.close_rate = rate
self.close_profit = profit
self.close_date = datetime.utcnow()
self.open_order_id = order_id
Session.flush()
return profit
Base.metadata.create_all(engine)

View File

@ -2,6 +2,7 @@ import logging
from datetime import timedelta
import arrow
from sqlalchemy import and_
from telegram.error import NetworkError
from telegram.ext import CommandHandler, Updater
from telegram import ParseMode, Bot, Update
@ -57,7 +58,7 @@ class TelegramHandler(object):
trades = Trade.query.filter(Trade.is_open.is_(True)).all()
from main import get_instance
if not get_instance().is_alive():
TelegramHandler.send_msg('*Status:* `trader stopped`', bot=bot)
TelegramHandler.send_msg('*Status:* `trader is not running`', bot=bot)
elif not trades:
TelegramHandler.send_msg('*Status:* `no active order`', bot=bot)
else:
@ -198,6 +199,54 @@ class TelegramHandler(object):
TelegramHandler.send_msg('*Order cancelled:* `{}`'.format(order_id), bot=bot)
logger.info('Order cancelled: (order_id: {})'.format(order_id))
@staticmethod
@authorized_only
def _forcesell(bot, update):
"""
Handler for /forcesell <id>.
Sells the given trade at current price
:param bot: telegram bot
:param update: message update
:return: None
"""
from main import get_instance
if not get_instance().is_alive():
TelegramHandler.send_msg('`trader is not running`', bot=bot)
return
try:
trade_id = int(update.message.text
.replace('/forcesell', '')
.strip())
# Query for trade
trade = Trade.query.filter(and_(
Trade.id == trade_id,
Trade.is_open.is_(True)
)).first()
if not trade:
TelegramHandler.send_msg('There is no open trade with ID: `{}`'.format(trade_id))
return
# Get current rate
current_rate = api_wrapper.get_ticker(trade.pair)['bid']
# Get available balance
currency = trade.pair.split('_')[1]
balance = api_wrapper.get_balance(currency)
# Execute sell
profit = trade.exec_sell_order(current_rate, balance)
message = '*{}:* Selling [{}]({}) at rate `{:f} (profit: {}%)`'.format(
trade.exchange.name,
trade.pair.replace('_', '/'),
api_wrapper.get_pair_detail_url(trade.pair),
trade.close_rate,
round(profit, 2)
)
logger.info(message)
TelegramHandler.send_msg(message)
except ValueError:
TelegramHandler.send_msg('Invalid argument. Usage: `/forcesell <trade_id>`')
logger.warning('/forcesell: Invalid argument received')
@staticmethod
@synchronized
def get_updater(conf):
@ -224,6 +273,7 @@ class TelegramHandler(object):
CommandHandler('start', TelegramHandler._start),
CommandHandler('stop', TelegramHandler._stop),
CommandHandler('cancel', TelegramHandler._cancel),
CommandHandler('forcesell', TelegramHandler._forcesell),
]
for handle in handles:
TelegramHandler.get_updater(conf).dispatcher.add_handler(handle)