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
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
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
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()
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
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)
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' )