Beispiel #1
0
def handle_trade(trade: Trade) -> None:
    """
    Sells the current pair if the threshold is reached and updates the trade record.
    :return: None
    """
    try:
        if not trade.is_open:
            raise ValueError('attempt to handle closed trade: {}'.format(trade))

        logger.debug('Handling open trade %s ...', trade)
        # Get current rate
        current_rate = exchange.get_ticker(trade.pair)['bid']
        current_profit = 100.0 * ((current_rate - trade.open_rate) / trade.open_rate)

        if 'stoploss' in _CONF and current_profit < float(_CONF['stoploss']) * 100.0:
            logger.debug('Stop loss hit.')
            execute_sell(trade, current_rate)
            return

        for duration, threshold in sorted(_CONF['minimal_roi'].items()):
            duration, threshold = float(duration), float(threshold)
            # 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(trade, current_rate)
                return

        logger.debug('Threshold not reached. (cur_profit: %1.2f%%)', current_profit)
    except ValueError:
        logger.exception('Unable to handle open order')
Beispiel #2
0
def _profit(bot: Bot, update: Update) -> None:
    """
    Handler for /profit.
    Returns a cumulative profit statistics.
    :param bot: telegram bot
    :param update: message update
    :return: None
    """
    trades = Trade.query.order_by(Trade.id).all()

    profit_amounts = []
    profits = []
    durations = []
    for trade in trades:
        if trade.close_date:
            durations.append(
                (trade.close_date - trade.open_date).total_seconds())
        if trade.close_profit:
            profit = trade.close_profit
        else:
            # Get current rate
            current_rate = exchange.get_ticker(trade.pair)['bid']
            profit = 100 * ((current_rate - trade.open_rate) / trade.open_rate)

        profit_amounts.append((profit / 100) * trade.btc_amount)
        profits.append(profit)

    best_pair = Trade.session.query(Trade.pair, func.sum(Trade.close_profit).label('profit_sum')) \
        .filter(Trade.is_open.is_(False)) \
        .group_by(Trade.pair) \
        .order_by(text('profit_sum DESC')) \
        .first()

    if not best_pair:
        send_msg('*Status:* `no closed trade`', bot=bot)
        return

    bp_pair, bp_rate = best_pair
    markdown_msg = """
*ROI:* `{profit_btc:.2f} ({profit:.2f}%)`
*Trade Count:* `{trade_count}`
*First Trade opened:* `{first_trade_date}`
*Latest Trade opened:* `{latest_trade_date}`
*Avg. Duration:* `{avg_duration}`
*Best Performing:* `{best_pair}: {best_rate:.2f}%`
    """.format(
        profit_btc=round(sum(profit_amounts), 8),
        profit=round(sum(profits), 2),
        trade_count=len(trades),
        first_trade_date=arrow.get(trades[0].open_date).humanize(),
        latest_trade_date=arrow.get(trades[-1].open_date).humanize(),
        avg_duration=str(
            timedelta(seconds=sum(durations) /
                      float(len(durations)))).split('.')[0],
        best_pair=bp_pair,
        best_rate=round(bp_rate, 2),
    )
    send_msg(markdown_msg, bot=bot)
Beispiel #3
0
def create_trade(stake_amount: float, _exchange: exchange.Exchange) -> Optional[Trade]:
    """
    Checks the implemented trading indicator(s) for a randomly picked pair,
    if one pair triggers the buy_signal a new trade record gets created
    :param stake_amount: amount of btc to spend
    :param _exchange: exchange to use
    """
    logger.info('Creating new trade with stake_amount: %f ...', stake_amount)
    whitelist = _CONF[_exchange.name.lower()]['pair_whitelist']
    # Check if btc_amount is fulfilled
    if exchange.get_balance(_CONF['stake_currency']) < stake_amount:
        raise ValueError(
            'stake amount is not fulfilled (currency={}'.format(_CONF['stake_currency'])
        )

    # Remove currently opened and latest pairs from whitelist
    trades = Trade.query.filter(Trade.is_open.is_(True)).all()
    latest_trade = Trade.query.filter(Trade.is_open.is_(False)).order_by(Trade.id.desc()).first()
    if latest_trade:
        trades.append(latest_trade)
    for trade in trades:
        if trade.pair in whitelist:
            whitelist.remove(trade.pair)
            logger.debug('Ignoring %s in pair whitelist', trade.pair)
    if not whitelist:
        raise ValueError('No pair in whitelist')

    # Pick pair based on StochRSI buy signals
    for _pair in whitelist:
        if get_buy_signal(_pair):
            pair = _pair
            break
    else:
        return None

    open_rate = exchange.get_ticker(pair)['ask']
    amount = stake_amount / open_rate
    order_id = exchange.buy(pair, open_rate, amount)

    # Create trade entity and return
    message = '*{}:* Buying [{}]({}) at rate `{:f}`'.format(
        _exchange.name,
        pair.replace('_', '/'),
        exchange.get_pair_detail_url(pair),
        open_rate
    )
    logger.info(message)
    telegram.send_msg(message)
    return Trade(pair=pair,
                 btc_amount=stake_amount,
                 open_rate=open_rate,
                 open_date=datetime.utcnow(),
                 amount=amount,
                 exchange=_exchange,
                 open_order_id=order_id,
                 is_open=True)
Beispiel #4
0
def _status(bot: Bot, update: Update) -> None:
    """
    Handler for /status.
    Returns the current TradeThread status
    :param bot: telegram bot
    :param update: message update
    :return: None
    """
    # Fetch open trade
    trades = Trade.query.filter(Trade.is_open.is_(True)).all()
    if get_state() != State.RUNNING:
        send_msg('*Status:* `trader is not running`', bot=bot)
    elif not trades:
        send_msg('*Status:* `no active order`', bot=bot)
    else:
        for trade in trades:
            # calculate profit and send message to user
            current_rate = exchange.get_ticker(trade.pair)['bid']
            current_profit = 100 * (
                (current_rate - trade.open_rate) / trade.open_rate)
            orders = exchange.get_open_orders(trade.pair)
            orders = [o for o in orders if o['id'] == trade.open_order_id]
            order = orders[0] if orders else None

            fmt_close_profit = '{:.2f}%'.format(round(
                trade.close_profit, 2)) if trade.close_profit else None
            message = """
*Trade ID:* `{trade_id}`
*Current Pair:* [{pair}]({market_url})
*Open Since:* `{date}`
*Amount:* `{amount}`
*Open Rate:* `{open_rate}`
*Close Rate:* `{close_rate}`
*Current Rate:* `{current_rate}`
*Close Profit:* `{close_profit}`
*Current Profit:* `{current_profit:.2f}%`
*Open Order:* `{open_order}`
            """.format(
                trade_id=trade.id,
                pair=trade.pair,
                market_url=exchange.get_pair_detail_url(trade.pair),
                date=arrow.get(trade.open_date).humanize(),
                open_rate=trade.open_rate,
                close_rate=trade.close_rate,
                current_rate=current_rate,
                amount=round(trade.amount, 8),
                close_profit=fmt_close_profit,
                current_profit=round(current_profit, 2),
                open_order='{} ({})'.format(order['remaining'], order['type'])
                if order else None,
            )
            send_msg(message, bot=bot)
Beispiel #5
0
    def get_forcesell(self, trade):

        # Get current rate
        current_rate = exchange.get_ticker(trade.pair)['bid']
        # Get available balance
        currency = trade.pair.split('_')[1]
        balance = exchange.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('_', '/'),
            exchange.get_pair_detail_url(trade.pair), trade.close_rate,
            round(profit, 2))

        return message
Beispiel #6
0
def handle_trade(trade: Trade) -> None:
    """
    Sells the current pair if the threshold is reached and updates the trade record.
    :return: None
    """
    try:
        if not trade.is_open:
            raise ValueError('attempt to handle closed trade: {}'.format(trade))

        logger.debug('Handling open trade %s ...', trade)

        current_rate = exchange.get_ticker(trade.pair)['bid']
        if should_sell(trade, current_rate, datetime.utcnow()):
            execute_sell(trade, current_rate)
            return

    except ValueError:
        logger.exception('Unable to handle open order')
Beispiel #7
0
    def get_status(self, trades):

        messages = []

        for trade in trades:
            # calculate profit and send message to user
            current_rate = exchange.get_ticker(trade.pair)['bid']
            current_profit = 100 * (
                (current_rate - trade.open_rate) / trade.open_rate)
            orders = exchange.get_open_orders(trade.pair)
            orders = [o for o in orders if o['id'] == trade.open_order_id]
            order = orders[0] if orders else None

            fmt_close_profit = '{:.2f}%'.format(round(
                trade.close_profit, 2)) if trade.close_profit else None
            markdown_msg = """
*Trade ID:* `{trade_id}`
*Current Pair:* [{pair}]({market_url})
*Open Since:* `{date}`
*Amount:* `{amount}`
*Open Rate:* `{open_rate}`
*Close Rate:* `{close_rate}`
*Current Rate:* `{current_rate}`
*Close Profit:* `{close_profit}`
*Current Profit:* `{current_profit:.2f}%`
*Open Order:* `{open_order}`
			""".format(
                trade_id=trade.id,
                pair=trade.pair,
                market_url=exchange.get_pair_detail_url(trade.pair),
                date=arrow.get(trade.open_date).humanize(),
                open_rate=trade.open_rate,
                close_rate=trade.close_rate,
                current_rate=current_rate,
                amount=round(trade.amount, 8),
                close_profit=fmt_close_profit,
                current_profit=round(current_profit, 2),
                open_order='{} ({})'.format(order['remaining'], order['type'])
                if order else None,
            )

            messages.append(markdown_msg)

        return messages
Beispiel #8
0
def _forcesellall(bot: Bot, update: Update) -> None:
    """
    Handler for /forcesellall.
    Sell all trades at current price
    :param bot: telegram bot
    :param update: message update
    :return: None
    """
    if get_state() != State.RUNNING:
        send_msg('`trader is not running`', bot=bot)
        return

    try:
        trades = Trade.query.filter(Trade.is_open.is_(True)).all()

        if len(trades) == 0:
            send_msg('`open trades not found`', bot=bot)
            return

        for trade in trades:
            # Get current rate
            current_rate = exchange.get_ticker(trade.pair)['bid']
            # Get available balance
            currency = trade.pair.split('_')[1]
            balance = exchange.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('_', '/'),
                exchange.get_pair_detail_url(trade.pair), trade.close_rate,
                round(profit, 2))
            logger.info(message)
            send_msg(message)
            time.sleep(25)

    except ValueError:
        send_msg('Failed to sell all trades')
        logger.warning('/forcesellall: Failed to sell all trades')
Beispiel #9
0
def _forcesell(bot: Bot, update: Update) -> None:
    """
    Handler for /forcesell <id>.
    Sells the given trade at current price
    :param bot: telegram bot
    :param update: message update
    :return: None
    """
    if get_state() != State.RUNNING:
        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:
            send_msg('There is no open trade with ID: `{}`'.format(trade_id))
            return
        # Get current rate
        current_rate = exchange.get_ticker(trade.pair)['bid']
        # Get available balance
        currency = trade.pair.split('_')[1]
        balance = exchange.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('_', '/'),
            exchange.get_pair_detail_url(trade.pair), trade.close_rate,
            round(profit, 2))
        logger.info(message)
        send_msg(message)

    except ValueError:
        send_msg('Invalid argument. Usage: `/forcesell <trade_id>`')
        logger.warning('/forcesell: Invalid argument received')
Beispiel #10
0
    def get_log(self, trades, balances):

        profit_amounts = []
        profits = []
        durations = []
        for trade in trades:
            if trade.close_date:
                durations.append(
                    (trade.close_date - trade.open_date).total_seconds())
            if trade.close_profit:
                profit = trade.close_profit
            else:
                # Get current rate
                current_rate = exchange.get_ticker(trade.pair)['bid']
                profit = 100 * (
                    (current_rate - trade.open_rate) / trade.open_rate)

            profit_amounts.append((profit / 100) * trade.stake_amount)
            profits.append(profit)
        if len(durations) == 0:
            durations.append(1.0)

        best_pair = Trade.session.query(Trade.pair, func.sum(Trade.close_profit).label('profit_sum')) \
         .filter(Trade.is_open.is_(False)) \
         .group_by(Trade.pair) \
         .order_by(text('profit_sum DESC')) \
         .first()

        now = datetime.datetime.now()

        btc_wallet_balance = 0.0
        for balance in balances:
            if balance['Currency'] == "BTC":
                btc_wallet_balance = balance['Balance']

        # In USD
        current_btc_price = analyze.get_btc_current_price()

        usd_wallet_balance = btc_wallet_balance * current_btc_price

        bp_pair, bp_rate = 1.0, 1.0
        if best_pair is not None:
            bp_pair, bp_rate = best_pair

        markdown_msg = "{date},{time},{trade_count},{best_pair}: {best_rate:.2f}%,{avg_duration},{profit_btc:.2f} ({profit:.2f}%),{btc_wallet}BTC ({usd_wallet:.2f}USD),{price_btc}".format(
            date=str(now.month) + "/" + str(now.day) + "/" + str(now.year),
            time=str(now.hour) + ":" + str(now.minute) + ":" + str(now.second),
            trade_count=len(trades),
            best_pair=bp_pair,
            best_rate=round(bp_rate, 2),
            avg_duration=str(
                timedelta(seconds=sum(durations) /
                          float(len(durations)))).split('.')[0],
            profit_btc=round(sum(profit_amounts), 8),
            profit=round(sum(profits), 2),
            btc_wallet=btc_wallet_balance,
            usd_wallet=usd_wallet_balance,
            price_btc=current_btc_price,
            #btc_wallet,usd_wallet and price_btc are not implemented yet
        )

        return markdown_msg