Exemple #1
0
def test_exchange_misc(mocker):
    api_mock = MagicMock()
    mocker.patch('freqtrade.exchange._API', api_mock)
    exchange.get_markets()
    assert api_mock.get_markets.call_count == 1
    exchange.get_market_summaries()
    assert api_mock.get_market_summaries.call_count == 1
    api_mock.name = 123
    assert exchange.get_name() == 123
    api_mock.fee = 456
    assert exchange.get_fee() == 456
    exchange.get_wallet_health()
    assert api_mock.get_wallet_health.call_count == 1
Exemple #2
0
    def _refresh_whitelist(self, whitelist: List[str]) -> List[str]:
        """
        Check wallet health and remove pair from whitelist if necessary
        :param whitelist: the sorted list (based on BaseVolume) of pairs the user might want to
        trade
        :return: the list of pairs the user wants to trade without the one unavailable or
        black_listed
        """
        sanitized_whitelist = whitelist
        health = exchange.get_wallet_health()
        known_pairs = set()
        for status in health:
            pair = '{}_{}'.format(self.config['stake_currency'],
                                  status['Currency'])
            # pair is not int the generated dynamic market, or in the blacklist ... ignore it
            if pair not in whitelist or pair in self.config['exchange'].get(
                    'pair_blacklist', []):
                continue
            # else the pair is valid
            known_pairs.add(pair)
            # Market is not active
            if not status['IsActive']:
                sanitized_whitelist.remove(pair)
                logger.info('Ignoring %s from whitelist (reason: %s).', pair,
                            status.get('Notice') or 'wallet is not active')

        # We need to remove pairs that are unknown
        final_list = [x for x in sanitized_whitelist if x in known_pairs]
        return final_list
Exemple #3
0
def refresh_whitelist(whitelist: List[str]) -> List[str]:
    """
    Check wallet health and remove pair from whitelist if necessary
    :param whitelist: the sorted list (based on BaseVolume) of pairs the user might want to trade
    :return: the list of pairs the user wants to trade without the one unavailable or black_listed
    """
    sanitized_whitelist = whitelist
    health = exchange.get_wallet_health()
    known_pairs = set()
    for status in health:
        pair = '{}_{}'.format(_CONF['stake_currency'], status['Currency'])
        # pair is not int the generated dynamic market, or in the blacklist ... ignore it
        if pair not in whitelist or pair in _CONF['exchange'].get('pair_blacklist', []):
            continue
        # else the pair is valid
        known_pairs.add(pair)
        # Market is not active
        if not status['IsActive']:
            sanitized_whitelist.remove(pair)
            logger.info(
                'Ignoring %s from whitelist (reason: %s).',
                pair, status.get('Notice') or 'wallet is not active'
            )

    # We need to remove pairs that are unknown
    final_list = [x for x in sanitized_whitelist if x in known_pairs]
    return final_list
Exemple #4
0
def refresh_whitelist(whitelist: Optional[List[str]] = None) -> None:
    """
    Check wallet health and remove pair from whitelist if necessary
    :param whitelist: a new whitelist (optional)
    :return: None
    """
    whitelist = whitelist or _CONF['exchange']['pair_whitelist']

    sanitized_whitelist = []
    health = exchange.get_wallet_health()
    for status in health:
        if exchange.get_name() == 'HitBTC':
            pair = status['Currency']
        else:
            pair = '{}_{}'.format(_CONF['stake_currency'], status['Currency'])
        if pair not in whitelist:
            continue
        if status['IsActive']:
            sanitized_whitelist.append(pair)
        else:
            logger.info('Ignoring %s from whitelist (reason: %s).', pair,
                        status.get('Notice') or 'wallet is not active')
    if _CONF['exchange']['pair_whitelist'] != sanitized_whitelist:
        logger.debug('Using refreshed pair whitelist: %s ...',
                     sanitized_whitelist)
        _CONF['exchange']['pair_whitelist'] = sanitized_whitelist

        if analyzer.name == 'cryptoml':
            analyzer.whitelist = sanitized_whitelist
            analyzer.reset_buffer()
Exemple #5
0
def handle_trade(trade: Trade) -> bool:
    """
    Sells the current pair if the threshold is reached and updates the trade record.
    :return: True if trade has been sold, False otherwise
    """
    if not trade.is_open:
        raise ValueError('attempt to handle closed trade: {}'.format(trade))

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

    # first determine if buy order that is still open
    if trade.open_order_id:
        order_info = exchange.get_order(trade.open_order_id)
        order_type = order_info['type']
        if order_type == 'LIMIT_BUY':
            max_open_time = 10
            current_time = datetime.utcnow()
            amount_minutes_open = (current_time -
                                   trade.open_date).total_seconds() / 60.
            if amount_minutes_open > max_open_time:
                health = exchange.get_wallet_health()
                if exchange.get_name() == 'HitBTC':
                    token = trade.pair
                else:
                    token = get_quote_token(trade.pair)
                token_healthy = False
                for status in health:
                    if status['Currency'] == token:
                        token_healthy = status['IsActive']
                if token_healthy:
                    logger.debug('Cancelling %s ...', trade)
                    exchange.cancel_order(trade.open_order_id)
                    # trade.is_open = 0
                    # trade.open_order_id = None
                    Trade.session.delete(trade)
                else:
                    logger.debug(
                        'Cancelling could not execute due to wallet heath for %s ...',
                        trade)
                return False

    current_rate = exchange.get_ticker(trade.pair)['bid']  # ask?
    if current_rate is None:
        return False
    if should_sell(trade, current_rate, datetime.utcnow()):
        execute_sell(trade, current_rate)
        return True
    return False
Exemple #6
0
def execute_sell(trade: Trade, limit: float) -> None:
    """
    Executes a limit sell for the given trade and limit
    :param trade: Trade instance
    :param limit: limit rate for the sell order
    :return: None
    """

    # check how much is available
    available = exchange.get_available_balance(get_quote_token(str(
        trade.pair)))

    # Execute sell and update trade record
    order_id = exchange.sell(str(trade.pair), limit, available)  # trade.amount
    trade.open_order_id = order_id

    if available < trade.amount:

        # cancel the rest
        # todo: check if wallet is healthy before cancelling
        health = exchange.get_wallet_health()
        if exchange.get_name() == 'HitBTC':
            token = trade.pair
        else:
            token = get_quote_token(trade.pair)
        token_healthy = False
        for status in health:
            if status['Currency'] == token:
                token_healthy = status['IsActive']
        if token_healthy:
            exchange.cancel_order(trade.id)

    fmt_exp_profit = round(trade.calc_profit(limit) * 100, 2)
    message = '*{}:* Selling [{}]({}) with limit `{:.8f} (profit: ~{:.2f}%)`'.format(
        trade.exchange, trade.pair.replace('_', '/'),
        exchange.get_pair_detail_url(trade.pair), limit, fmt_exp_profit)
    logger.info(message)
    telegram.send_msg(message)
Exemple #7
0
def create_trade(stake_amount: float) -> 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
    """
    logger.info('Creating new trade with stake_amount: %f ...', stake_amount)
    whitelist = copy.deepcopy(_CONF['exchange']['pair_whitelist'])
    # Check if stake_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
    for trade in Trade.query.filter(Trade.is_open.is_(True)).all():
        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
    if analyzer.name == 'danml':
        for _pair in whitelist:
            if get_buy_signal(_pair, exchange.get_name(), analyzer):
                pair = _pair
                break
        else:
            return None
    elif analyzer.name == 'cryptoml':
        update = False
        if datetime.utcnow().minute % 5 == 0:
            update = True
        pair = analyzer.get_buy_signal(whitelist,
                                       update=update,
                                       threshold=0.01,
                                       repeats=3)
        if pair is None:
            return None

    # Calculate amount and subtract fee
    fee = exchange.get_fee()
    buy_limit = get_target_bid(exchange.get_ticker(pair))
    amount = (1 - fee) * stake_amount / buy_limit

    health = exchange.get_wallet_health()
    if exchange.get_name() == 'HitBTC':
        token = pair
    else:
        token = get_quote_token(pair)
    token_healthy = False
    for status in health:
        if status['Currency'] == token:
            token_healthy = status['IsActive']
    if token_healthy:
        order_id = exchange.buy(pair, buy_limit, amount)
        # Create trade entity and return
        message = '*{}:* Buying [{}]({}) with limit `{:.8f}`'.format(
            exchange.get_name().upper(), pair.replace('_', '/'),
            exchange.get_pair_detail_url(pair), buy_limit)
        logger.info(message)
        telegram.send_msg(message)
        # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
        return Trade(
            pair=pair,
            stake_amount=stake_amount,
            amount=amount,
            fee=fee * 2.,
            open_rate=buy_limit,
            open_date=datetime.utcnow(),
            exchange=exchange.get_name().upper(),
            open_order_id=order_id,
            # open_order_type='buy'
        )