def test_returns_latest_buy_signal(mocker): buydf = DataFrame([{'buy': 1, 'date': arrow.utcnow()}]) mocker.patch('freqtrade.analyze.analyze_ticker', return_value=buydf) assert get_buy_signal('BTC-ETH') buydf = DataFrame([{'buy': 0, 'date': arrow.utcnow()}]) mocker.patch('freqtrade.analyze.analyze_ticker', return_value=buydf) assert not get_buy_signal('BTC-ETH')
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 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('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 for _pair in whitelist: if get_buy_signal(_pair): pair = _pair break else: return None open_rate = get_target_bid(exchange.get_ticker(pair)) 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.EXCHANGE.name.upper(), pair.replace('_', '/'), exchange.get_pair_detail_url(pair), open_rate ) logger.info(message) telegram.send_msg(message) return Trade(pair=pair, stake_amount=stake_amount, open_rate=open_rate, open_date=datetime.utcnow(), amount=amount, exchange=exchange.EXCHANGE.name.upper(), open_order_id=order_id, is_open=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' )