def should_sell(trade: Trade, current_rate: float, current_time: datetime) -> bool: """ Based an earlier trade and current price and configuration, decides whether bot should sell :return True if bot should sell at current rate """ # todo: query model to see if more gains are possible # get current profit current_profit = trade.calc_profit(current_rate) # check how much is available and determine if above dust trade available = exchange.get_available_balance(get_quote_token(str( trade.pair))) satoshi = 1e-08 dust_trade_sat = 50000 * satoshi trade_amount_btc = available * current_rate if trade_amount_btc < dust_trade_sat: logger.debug('Trade is DUST') logger.debug('Threshold not reached. (cur_profit: %1.2f%%)', current_profit * 100.0) logger.debug('Current rate: {}'.format(current_rate)) return False # determine if stoploss is hit if 'stoploss' in _CONF and current_profit < float(_CONF['stoploss']): logger.debug('Stop loss hit.') return True # check model (before minimal rois) if analyzer.name == 'danml': # check if ema-5 is greater than last minute to continue # todo: also make sure previous is lower than current if get_ema_signal(trade.pair, 1, exchange.get_name()): if get_buy_signal(trade.pair, exchange.get_name(), analyzer): logger.debug('Threshold not reached. (cur_profit: %1.2f%%)', current_profit * 100.0) logger.debug('Current rate: {}'.format(current_rate)) return False # check minimal rois for duration, threshold in sorted(_CONF['minimal_roi'].items()): # Check if time matches and current rate is above threshold time_diff = (current_time - trade.open_date).total_seconds() / 60 if time_diff > float(duration) and current_profit > threshold: return True logger.debug('Threshold not reached. (cur_profit: %1.2f%%)', current_profit * 100.0) logger.debug('Current rate: {}'.format(current_rate)) return False
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( 'Checking buy signals to create a 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 for _pair in whitelist: if get_buy_signal(_pair): pair = _pair break else: 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 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)
def test_get_name(default_conf, mocker): mocker.patch('freqtrade.exchange.validate_pairs', side_effect=lambda s: True) default_conf['exchange']['name'] = 'bittrex' init(default_conf) assert get_name() == 'Bittrex'
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 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 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(self) -> bool: """ 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 interval: Ticker interval used for Analyze :return: True if a trade object has been created and persisted, False otherwise """ stake_amount = self.config['stake_amount'] interval = self.analyze.get_ticker_interval() logger.info( 'Checking buy signals to create a new trade with stake_amount: %f ...', stake_amount) whitelist = copy.deepcopy(self.config['exchange']['pair_whitelist']) # Check if stake_amount is fulfilled if exchange.get_balance(self.config['stake_currency']) < stake_amount: raise DependencyException( 'stake amount is not fulfilled (currency={})'.format( self.config['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 DependencyException('No currency pairs in whitelist') # Pick pair based on StochRSI buy signals for _pair in whitelist: (buy, sell) = self.analyze.get_signal(_pair, interval) if buy and not sell: pair = _pair break else: return False # Calculate amount buy_limit = self.get_target_bid(exchange.get_ticker(pair)) amount = stake_amount / buy_limit order_id = exchange.buy(pair, buy_limit, amount) stake_amount_fiat = self.fiat_converter.convert_amount( stake_amount, self.config['stake_currency'], self.config['fiat_display_currency']) # Create trade entity and return self.rpc.send_msg( '*{}:* Buying [{}]({}) with limit `{:.8f} ({:.6f} {}, {:.3f} {})` ' .format(exchange.get_name().upper(), pair.replace('_', '/'), exchange.get_pair_detail_url(pair), buy_limit, stake_amount, self.config['stake_currency'], stake_amount_fiat, self.config['fiat_display_currency'])) # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL trade = Trade(pair=pair, stake_amount=stake_amount, amount=amount, fee=exchange.get_fee(), open_rate=buy_limit, open_date=datetime.utcnow(), exchange=exchange.get_name().upper(), open_order_id=order_id) Trade.session.add(trade) Trade.session.flush() return True
def create_trade(stake_amount: float) -> bool: """ 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 :return: True if a trade object has been created and persisted, False otherwise """ logger.info( 'Checking buy signals to create a 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 DependencyException( '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 DependencyException('No pair in whitelist') # Pick pair based on StochRSI buy signals for _pair in whitelist: if get_signal(_pair, SignalType.BUY): pair = _pair break else: return False # Calculate amount buy_limit = get_target_bid(exchange.get_ticker(pair)) amount = stake_amount / buy_limit order_id = exchange.buy(pair, buy_limit, amount) fiat_converter = CryptoToFiatConverter() stake_amount_fiat = fiat_converter.convert_amount( stake_amount, _CONF['stake_currency'], _CONF['fiat_display_currency'] ) # Create trade entity and return rpc.send_msg('*{}:* Buying [{}]({}) with limit `{:.8f} ({:.6f} {}, {:.3f} {})` '.format( exchange.get_name().upper(), pair.replace('_', '/'), exchange.get_pair_detail_url(pair), buy_limit, stake_amount, _CONF['stake_currency'], stake_amount_fiat, _CONF['fiat_display_currency'] )) # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL trade = Trade( pair=pair, stake_amount=stake_amount, amount=amount, fee=exchange.get_fee(), open_rate=buy_limit, open_date=datetime.utcnow(), exchange=exchange.get_name().upper(), open_order_id=order_id ) Trade.session.add(trade) Trade.session.flush() return True
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' )
# ensure directory exists base_path = os.path.join(os.path.expanduser('~'), 'freqtrade') # get configuration with open(os.path.join(base_path, 'config.json')) as file: _CONF = json.load(file) # initialize the exchange exchange.init(_CONF) # get ticker data = exchange.get_ticker(pair='ETH_BTC') print(data) # get ticker history df = exchange.get_ticker_history(pair='ETH_BTC', tick_interval=1) print(pd.DataFrame(df)) # get markets data = exchange.get_markets() print(data) # get name print(exchange.get_name()) print(exchange.get_sleep_time()) print(exchange.get_fee())