implement /forcesell command
This commit is contained in:
parent
3c0074520c
commit
3d5913d317
12
main.py
12
main.py
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user