Example #1
0
 def test_1_exec_sell_order(self):
     with patch('main.exchange.sell',
                side_effect='mocked_order_id') as api_mock:
         trade = Trade(pair='BTC_ETH',
                       btc_amount=1.00,
                       open_rate=0.50,
                       amount=10.00,
                       exchange=Exchange.BITTREX,
                       open_order_id='mocked')
         profit = trade.exec_sell_order(1.00, 10.00)
         api_mock.assert_called_once_with('BTC_ETH', 1.0, 10.0)
         self.assertEqual(profit, 100.0)
         self.assertEqual(trade.close_rate, 1.0)
         self.assertEqual(trade.close_profit, profit)
         self.assertIsNotNone(trade.close_date)
Example #2
0
    def test_backtest(self):
        trades = []
        with patch.dict('main._CONF', self.conf):
            for pair in self.pairs:
                with open('test/testdata/'+pair+'.json') as data_file:
                    data = json.load(data_file)

                    with patch('analyze.get_ticker', return_value=data):
                        with patch('arrow.utcnow', return_value=arrow.get('2017-08-20T14:50:00')):
                            ticker = analyze_ticker(pair)
                            # for each buy point
                            for index, row in ticker[ticker.buy == 1].iterrows():
                                trade = Trade(
                                    open_rate=row['close'],
                                    open_date=arrow.get(row['date']).datetime,
                                    amount=1,
                                )
                                # calculate win/lose forwards from buy point
                                for index2, row2 in ticker[index:].iterrows():
                                    if should_sell(trade, row2['close'], arrow.get(row2['date']).datetime):
                                        current_profit = (row2['close'] - trade.open_rate) / trade.open_rate

                                        trades.append((pair, current_profit, index2 - index))
                                        break
            
        labels = ['currency', 'profit', 'duration']
        results = DataFrame.from_records(trades, columns=labels)

        print('====================== BACKTESTING REPORT ================================')

        for pair in self.pairs:
            print('For currency {}:'.format(pair))
            print_results(results[results.currency == pair])
        print('TOTAL OVER ALL TRADES:')
        print_results(results)
Example #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)
Example #4
0
def create_trade(stake_amount: float, exchange):
    """
    Creates a new trade record with a random pair
    :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 = CONFIG[exchange.name.lower()]['pair_whitelist']
    # Check if btc_amount is fulfilled
    if api_wrapper.get_balance(CONFIG['stake_currency']) < stake_amount:
        raise ValueError('stake amount is not fulfilled (currency={}'.format(
            CONFIG['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 p in whitelist:
        if get_buy_signal(p):
            pair = p
            break
    else:
        raise ValueError('No buy signal from pairs: {}'.format(
            ', '.join(whitelist)))

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

    # Create trade entity and return
    message = '*{}:* Buying [{}]({}) at rate `{:f}`'.format(
        exchange.name, pair.replace('_', '/'),
        api_wrapper.get_pair_detail_url(pair), open_rate)
    logger.info(message)
    TelegramHandler.send_msg(message)
    return Trade(pair=pair,
                 btc_amount=stake_amount,
                 open_rate=open_rate,
                 amount=amount,
                 exchange=exchange,
                 open_order_id=order_id)
Example #5
0
def close_trade_if_fulfilled(trade: Trade) -> bool:
    """
    Checks if the trade is closable, and if so it is being closed.
    :param trade: Trade
    :return: True if trade has been closed else False
    """
    # If we don't have an open order and the close rate is already set,
    # we can close this trade.
    if trade.close_profit and trade.close_date and trade.close_rate and not trade.open_order_id:
        trade.is_open = False
        Session.flush()
        return True
    return False
Example #6
0
def execute_sell(trade: Trade, current_rate: float) -> None:
    # Get available balance
    currency = trade.pair.split('_')[1]
    balance = api_wrapper.get_balance(currency)

    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)
Example #7
0
def close_trade_if_fulfilled(trade: Trade) -> bool:
    """
    Checks if the trade is closable, and if so it is being closed.
    :param trade: Trade
    :return: True if trade has been closed else False
    """
    # If we don't have an open order and the close rate is already set,
    # we can close this trade.
    if trade.close_profit is not None \
            and trade.close_date is not None \
            and trade.close_rate is not None \
            and trade.open_order_id is None:
        trade.is_open = False
        logger.info('No open orders found and trade is fulfilled. Marking %s as closed ...', trade)
        return True
    return False
Example #8
0
def execute_sell(trade: Trade, current_rate: float) -> None:
    """
    Executes a sell for the given trade and current rate
    :param trade: Trade instance
    :param current_rate: current rate
    :return: None
    """
    # Get available balance
    currency = trade.pair.split('_')[1]
    balance = exchange.get_balance(currency)

    profit = trade.exec_sell_order(current_rate, balance)
    message = '*{}:* Make It Rain!!!! with [{}]({}) for `{: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)
    telegram.send_msg(message)
Example #9
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 = api_wrapper.get_ticker(trade.pair)['bid']
        current_profit = 100 * (
            (current_rate - trade.open_rate) / trade.open_rate)

        # Get available balance
        currency = trade.pair.split('_')[1]
        balance = api_wrapper.get_balance(currency)

        for duration, threshold in sorted(CONFIG['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
                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)
                return
        else:
            logger.debug('Threshold not reached. (cur_profit: %1.2f%%)',
                         current_profit)
    except ValueError:
        logger.exception('Unable to handle open order')
Example #10
0
def execute_sell(trade: Trade, current_rate: float) -> None:
    """
    Executes a sell for the given trade and current rate
    :param trade: Trade instance
    :param current_rate: current rate
    :return: None
    """
    # Get available balance
    currency = trade.pair.split('_')[1]
    balance = exchange.get_balance(currency)
    whitelist = _CONF[trade.exchange.name.lower()]['pair_whitelist']

    profit = trade.exec_sell_order(current_rate, balance)
    whitelist.append(trade.pair)
    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)
    telegram.send_msg(message)