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 # Check if time matches and current rate is above threshold
time_diff = (datetime.utcnow() - trade.open_date).total_seconds() / 60 time_diff = (datetime.utcnow() - trade.open_date).total_seconds() / 60
if time_diff > duration and current_rate > (1 + threshold) * trade.open_rate: if time_diff > duration and current_rate > (1 + threshold) * trade.open_rate:
# Execute sell
# Execute sell and update trade record profit = trade.exec_sell_order(current_rate, balance)
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
message = '*{}:* Selling [{}]({}) at rate `{:f} (profit: {}%)`'.format( message = '*{}:* Selling [{}]({}) at rate `{:f} (profit: {}%)`'.format(
trade.exchange.name, trade.exchange.name,
trade.pair.replace('_', '/'), trade.pair.replace('_', '/'),
api_wrapper.get_pair_detail_url(trade.pair), api_wrapper.get_pair_detail_url(trade.pair),
trade.close_rate, trade.close_rate,
round(current_profit, 2) round(profit, 2)
) )
logger.info(message) logger.info(message)
TelegramHandler.send_msg(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.orm import scoped_session, sessionmaker
from sqlalchemy.types import Enum from sqlalchemy.types import Enum
from exchange import Exchange from exchange import Exchange, get_exchange_api
from utils import get_conf 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' db_handle = 'sqlite:///tradesv2.dry_run.sqlite'
else: else:
db_handle = 'sqlite:///tradesv2.sqlite' 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) '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) Base.metadata.create_all(engine)

View File

@ -2,6 +2,7 @@ import logging
from datetime import timedelta from datetime import timedelta
import arrow import arrow
from sqlalchemy import and_
from telegram.error import NetworkError from telegram.error import NetworkError
from telegram.ext import CommandHandler, Updater from telegram.ext import CommandHandler, Updater
from telegram import ParseMode, Bot, Update from telegram import ParseMode, Bot, Update
@ -57,7 +58,7 @@ class TelegramHandler(object):
trades = Trade.query.filter(Trade.is_open.is_(True)).all() trades = Trade.query.filter(Trade.is_open.is_(True)).all()
from main import get_instance from main import get_instance
if not get_instance().is_alive(): 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: elif not trades:
TelegramHandler.send_msg('*Status:* `no active order`', bot=bot) TelegramHandler.send_msg('*Status:* `no active order`', bot=bot)
else: else:
@ -198,6 +199,54 @@ class TelegramHandler(object):
TelegramHandler.send_msg('*Order cancelled:* `{}`'.format(order_id), bot=bot) TelegramHandler.send_msg('*Order cancelled:* `{}`'.format(order_id), bot=bot)
logger.info('Order cancelled: (order_id: {})'.format(order_id)) 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 @staticmethod
@synchronized @synchronized
def get_updater(conf): def get_updater(conf):
@ -224,6 +273,7 @@ class TelegramHandler(object):
CommandHandler('start', TelegramHandler._start), CommandHandler('start', TelegramHandler._start),
CommandHandler('stop', TelegramHandler._stop), CommandHandler('stop', TelegramHandler._stop),
CommandHandler('cancel', TelegramHandler._cancel), CommandHandler('cancel', TelegramHandler._cancel),
CommandHandler('forcesell', TelegramHandler._forcesell),
] ]
for handle in handles: for handle in handles:
TelegramHandler.get_updater(conf).dispatcher.add_handler(handle) TelegramHandler.get_updater(conf).dispatcher.add_handler(handle)