Merge commit '4dca84817eb1b62047a9e4d282254392ea978e44' into feature/objectify
This commit is contained in:
commit
25d0e5f942
@ -128,8 +128,12 @@ class Analyze(object):
|
|||||||
|
|
||||||
# Check if dataframe is out of date
|
# Check if dataframe is out of date
|
||||||
signal_date = arrow.get(latest['date'])
|
signal_date = arrow.get(latest['date'])
|
||||||
if signal_date < arrow.now() - timedelta(minutes=(interval + 5)):
|
if signal_date < arrow.utcnow() - timedelta(minutes=(interval + 5)):
|
||||||
self.logger.warning('Too old dataframe for pair %s', pair)
|
self.logger.warning(
|
||||||
|
'Outdated history for pair %s. Last tick is %s minutes old',
|
||||||
|
pair,
|
||||||
|
(arrow.utcnow() - signal_date).seconds // 60
|
||||||
|
)
|
||||||
return (False, False) # return False ?
|
return (False, False) # return False ?
|
||||||
|
|
||||||
(buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1
|
(buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1
|
||||||
@ -150,17 +154,17 @@ class Analyze(object):
|
|||||||
"""
|
"""
|
||||||
# Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee)
|
# Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee)
|
||||||
if self.min_roi_reached(trade=trade, current_rate=rate, current_time=date):
|
if self.min_roi_reached(trade=trade, current_rate=rate, current_time=date):
|
||||||
self.logger.debug('Executing sell due to ROI ...')
|
self.logger.debug('Required profit reached. Selling..')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Experimental: Check if the trade is profitable before selling it (avoid selling at loss)
|
# Experimental: Check if the trade is profitable before selling it (avoid selling at loss)
|
||||||
if self.config.get('experimental', {}).get('sell_profit_only', False):
|
if self.config.get('experimental', {}).get('sell_profit_only', False):
|
||||||
self.logger.debug('Checking if trade is profitable ...')
|
self.logger.debug('Checking if trade is profitable..')
|
||||||
if trade.calc_profit(rate=rate) <= 0:
|
if trade.calc_profit(rate=rate) <= 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if sell and not buy and self.config.get('experimental', {}).get('use_sell_signal', False):
|
if sell and not buy and self.config.get('experimental', {}).get('use_sell_signal', False):
|
||||||
self.logger.debug('Executing sell due to sell signal ...')
|
self.logger.debug('Sell signal received. Selling..')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -52,7 +52,7 @@ class Bittrex(Exchange):
|
|||||||
'MIN_TRADE_REQUIREMENT_NOT_MET',
|
'MIN_TRADE_REQUIREMENT_NOT_MET',
|
||||||
]
|
]
|
||||||
if response['message'] in temp_error_messages:
|
if response['message'] in temp_error_messages:
|
||||||
raise ContentDecodingError('Got {}'.format(response['message']))
|
raise ContentDecodingError(response['message'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fee(self) -> float:
|
def fee(self) -> float:
|
||||||
@ -109,8 +109,7 @@ class Bittrex(Exchange):
|
|||||||
if not data.get('result') or\
|
if not data.get('result') or\
|
||||||
not all(key in data.get('result', {}) for key in keys) or\
|
not all(key in data.get('result', {}) for key in keys) or\
|
||||||
not all(data.get('result', {})[key] is not None for key in keys):
|
not all(data.get('result', {})[key] is not None for key in keys):
|
||||||
raise ContentDecodingError('{message} params=({pair})'.format(
|
raise ContentDecodingError('Invalid response from Bittrex params=({pair})'.format(
|
||||||
message='Got invalid response from bittrex',
|
|
||||||
pair=pair))
|
pair=pair))
|
||||||
# Update the pair
|
# Update the pair
|
||||||
self.cached_ticker[pair] = {
|
self.cached_ticker[pair] = {
|
||||||
@ -132,22 +131,20 @@ class Bittrex(Exchange):
|
|||||||
elif tick_interval == 1440:
|
elif tick_interval == 1440:
|
||||||
interval = 'Day'
|
interval = 'Day'
|
||||||
else:
|
else:
|
||||||
raise ValueError('Cannot parse tick_interval: {}'.format(tick_interval))
|
raise ValueError('Unknown tick_interval: {}'.format(tick_interval))
|
||||||
|
|
||||||
data = _API_V2.get_candles(pair.replace('_', '-'), interval)
|
data = _API_V2.get_candles(pair.replace('_', '-'), interval)
|
||||||
|
|
||||||
# These sanity check are necessary because bittrex cannot keep their API stable.
|
# These sanity check are necessary because bittrex cannot keep their API stable.
|
||||||
if not data.get('result'):
|
if not data.get('result'):
|
||||||
raise ContentDecodingError('{message} params=({pair})'.format(
|
raise ContentDecodingError('Invalid response from Bittrex params=({pair})'.format(
|
||||||
message='Got invalid response from bittrex',
|
|
||||||
pair=pair))
|
pair=pair))
|
||||||
|
|
||||||
for prop in ['C', 'V', 'O', 'H', 'L', 'T']:
|
for prop in ['C', 'V', 'O', 'H', 'L', 'T']:
|
||||||
for tick in data['result']:
|
for tick in data['result']:
|
||||||
if prop not in tick.keys():
|
if prop not in tick.keys():
|
||||||
raise ContentDecodingError('{message} params=({pair})'.format(
|
raise ContentDecodingError('Required property {} not present '
|
||||||
message='Required property {} not present in response'.format(prop),
|
'in response params=({})'.format(prop, pair))
|
||||||
pair=pair))
|
|
||||||
|
|
||||||
if not data['success']:
|
if not data['success']:
|
||||||
Bittrex._validate_response(data)
|
Bittrex._validate_response(data)
|
||||||
@ -191,21 +188,21 @@ class Bittrex(Exchange):
|
|||||||
data = _API.get_markets()
|
data = _API.get_markets()
|
||||||
if not data['success']:
|
if not data['success']:
|
||||||
Bittrex._validate_response(data)
|
Bittrex._validate_response(data)
|
||||||
raise OperationalException('{message}'.format(message=data['message']))
|
raise OperationalException(data['message'])
|
||||||
return [m['MarketName'].replace('-', '_') for m in data['result']]
|
return [m['MarketName'].replace('-', '_') for m in data['result']]
|
||||||
|
|
||||||
def get_market_summaries(self) -> List[Dict]:
|
def get_market_summaries(self) -> List[Dict]:
|
||||||
data = _API.get_market_summaries()
|
data = _API.get_market_summaries()
|
||||||
if not data['success']:
|
if not data['success']:
|
||||||
Bittrex._validate_response(data)
|
Bittrex._validate_response(data)
|
||||||
raise OperationalException('{message}'.format(message=data['message']))
|
raise OperationalException(data['message'])
|
||||||
return data['result']
|
return data['result']
|
||||||
|
|
||||||
def get_wallet_health(self) -> List[Dict]:
|
def get_wallet_health(self) -> List[Dict]:
|
||||||
data = _API_V2.get_wallet_health()
|
data = _API_V2.get_wallet_health()
|
||||||
if not data['success']:
|
if not data['success']:
|
||||||
Bittrex._validate_response(data)
|
Bittrex._validate_response(data)
|
||||||
raise OperationalException('{message}'.format(message=data['message']))
|
raise OperationalException(data['message'])
|
||||||
return [{
|
return [{
|
||||||
'Currency': entry['Health']['Currency'],
|
'Currency': entry['Health']['Currency'],
|
||||||
'IsActive': entry['Health']['IsActive'],
|
'IsActive': entry['Health']['IsActive'],
|
||||||
|
@ -191,20 +191,17 @@ class FreqtradeBot(object):
|
|||||||
Trade.session.flush()
|
Trade.session.flush()
|
||||||
|
|
||||||
except (requests.exceptions.RequestException, json.JSONDecodeError) as error:
|
except (requests.exceptions.RequestException, json.JSONDecodeError) as error:
|
||||||
self.logger.warning(
|
self.logger.warning('%s, retrying in 30 seconds...', error)
|
||||||
'Got %s in _process(), retrying in 30 seconds...',
|
|
||||||
error
|
|
||||||
)
|
|
||||||
time.sleep(Constants.RETRY_TIMEOUT)
|
time.sleep(Constants.RETRY_TIMEOUT)
|
||||||
except OperationalException:
|
except OperationalException:
|
||||||
self.rpc.send_msg(
|
self.rpc.send_msg(
|
||||||
'*Status:* Got OperationalException:\n```\n{traceback}```{hint}'
|
'*Status:* OperationalException:\n```\n{traceback}```{hint}'
|
||||||
.format(
|
.format(
|
||||||
traceback=traceback.format_exc(),
|
traceback=traceback.format_exc(),
|
||||||
hint='Issue `/start` if you think it is safe to restart.'
|
hint='Issue `/start` if you think it is safe to restart.'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.logger.exception('Got OperationalException. Stopping trader ...')
|
self.logger.exception('OperationalException. Stopping trader ...')
|
||||||
self.update_state(State.STOPPED)
|
self.update_state(State.STOPPED)
|
||||||
return state_changed
|
return state_changed
|
||||||
|
|
||||||
@ -294,7 +291,7 @@ class FreqtradeBot(object):
|
|||||||
self.logger.debug('Ignoring %s in pair whitelist', trade.pair)
|
self.logger.debug('Ignoring %s in pair whitelist', trade.pair)
|
||||||
|
|
||||||
if not whitelist:
|
if not whitelist:
|
||||||
raise DependencyException('No pair in whitelist')
|
raise DependencyException('No currency pairs in whitelist')
|
||||||
|
|
||||||
# Pick pair based on StochRSI buy signals
|
# Pick pair based on StochRSI buy signals
|
||||||
for _pair in whitelist:
|
for _pair in whitelist:
|
||||||
@ -356,10 +353,7 @@ class FreqtradeBot(object):
|
|||||||
if self.create_trade(float(self.config['stake_amount']), interval):
|
if self.create_trade(float(self.config['stake_amount']), interval):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info('Found no buy signals for whitelisted currencies. Trying again..')
|
||||||
'Checked all whitelisted currencies. '
|
|
||||||
'Found no suitable entry positions for buying. Will keep looking ...'
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
except DependencyException as exception:
|
except DependencyException as exception:
|
||||||
self.logger.warning('Unable to create trade: %s', exception)
|
self.logger.warning('Unable to create trade: %s', exception)
|
||||||
@ -373,7 +367,7 @@ class FreqtradeBot(object):
|
|||||||
# Get order details for actual price per unit
|
# Get order details for actual price per unit
|
||||||
if trade.open_order_id:
|
if trade.open_order_id:
|
||||||
# Update trade with order values
|
# Update trade with order values
|
||||||
self.logger.info('Got open order for %s', trade)
|
self.logger.info('Found open order for %s', trade)
|
||||||
trade.update(exchange.get_order(trade.open_order_id))
|
trade.update(exchange.get_order(trade.open_order_id))
|
||||||
|
|
||||||
if trade.is_open and trade.open_order_id is None:
|
if trade.is_open and trade.open_order_id is None:
|
||||||
|
@ -51,9 +51,9 @@ def main(sysargv: Dict) -> None:
|
|||||||
state = freqtrade.worker(old_state=state)
|
state = freqtrade.worker(old_state=state)
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
logger.info('Got SIGINT, aborting ...')
|
logger.info('SIGINT received, aborting ...')
|
||||||
except BaseException:
|
except BaseException:
|
||||||
logger.exception('Got fatal exception!')
|
logger.exception('Fatal exception!')
|
||||||
finally:
|
finally:
|
||||||
freqtrade.clean()
|
freqtrade.clean()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
@ -427,7 +427,7 @@ class Telegram(RPC):
|
|||||||
# Sometimes the telegram server resets the current connection,
|
# Sometimes the telegram server resets the current connection,
|
||||||
# if this is the case we send the message again.
|
# if this is the case we send the message again.
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'Got Telegram NetworkError: %s! Trying one more time.',
|
'Telegram NetworkError: %s! Trying one more time.',
|
||||||
network_err.message
|
network_err.message
|
||||||
)
|
)
|
||||||
bot.send_message(
|
bot.send_message(
|
||||||
@ -438,6 +438,6 @@ class Telegram(RPC):
|
|||||||
)
|
)
|
||||||
except TelegramError as telegram_err:
|
except TelegramError as telegram_err:
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'Got TelegramError: %s! Giving up on that message.',
|
'TelegramError: %s! Giving up on that message.',
|
||||||
telegram_err.message
|
telegram_err.message
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,7 @@ from freqtrade import OperationalException
|
|||||||
from freqtrade.exchange import init, validate_pairs, buy, sell, get_balance, get_balances, \
|
from freqtrade.exchange import init, validate_pairs, buy, sell, get_balance, get_balances, \
|
||||||
get_ticker, get_ticker_history, cancel_order, get_name, get_fee
|
get_ticker, get_ticker_history, cancel_order, get_name, get_fee
|
||||||
import freqtrade.exchange as exchange
|
import freqtrade.exchange as exchange
|
||||||
|
from freqtrade.tests.conftest import log_has
|
||||||
|
|
||||||
API_INIT = False
|
API_INIT = False
|
||||||
|
|
||||||
@ -26,10 +27,7 @@ def maybe_init_api(conf, mocker):
|
|||||||
def test_init(default_conf, mocker, caplog):
|
def test_init(default_conf, mocker, caplog):
|
||||||
caplog.set_level(logging.INFO)
|
caplog.set_level(logging.INFO)
|
||||||
maybe_init_api(default_conf, mocker)
|
maybe_init_api(default_conf, mocker)
|
||||||
assert ('freqtrade.exchange',
|
assert log_has('Instance is running with dry_run enabled', caplog.record_tuples)
|
||||||
logging.INFO,
|
|
||||||
'Instance is running with dry_run enabled'
|
|
||||||
) in caplog.record_tuples
|
|
||||||
|
|
||||||
|
|
||||||
def test_init_exception(default_conf):
|
def test_init_exception(default_conf):
|
||||||
@ -79,10 +77,8 @@ def test_validate_pairs_exception(default_conf, mocker, caplog):
|
|||||||
|
|
||||||
# with pytest.raises(RequestException, match=r'Unable to validate pairs'):
|
# with pytest.raises(RequestException, match=r'Unable to validate pairs'):
|
||||||
validate_pairs(default_conf['exchange']['pair_whitelist'])
|
validate_pairs(default_conf['exchange']['pair_whitelist'])
|
||||||
assert ('freqtrade.exchange',
|
assert log_has('Unable to validate pairs (assuming they are correct). Reason: ',
|
||||||
logging.WARNING,
|
caplog.record_tuples)
|
||||||
'Unable to validate pairs (assuming they are correct). Reason: '
|
|
||||||
) in caplog.record_tuples
|
|
||||||
|
|
||||||
|
|
||||||
def test_buy_dry_run(default_conf, mocker):
|
def test_buy_dry_run(default_conf, mocker):
|
||||||
|
@ -211,14 +211,14 @@ def test_exchange_bittrex_get_ticker_bad():
|
|||||||
fb = FakeBittrex()
|
fb = FakeBittrex()
|
||||||
fb.result = {'success': True, 'result': {'Bid': 1, 'Ask': 0}} # incomplete result
|
fb.result = {'success': True, 'result': {'Bid': 1, 'Ask': 0}} # incomplete result
|
||||||
|
|
||||||
with pytest.raises(ContentDecodingError, match=r'.*Got invalid response from bittrex params.*'):
|
with pytest.raises(ContentDecodingError, match=r'.*Invalid response from Bittrex params.*'):
|
||||||
wb.get_ticker('BTC_ETH')
|
wb.get_ticker('BTC_ETH')
|
||||||
fb.result = {'success': False, 'message': 'gone bad'}
|
fb.result = {'success': False, 'message': 'gone bad'}
|
||||||
with pytest.raises(btx.OperationalException, match=r'.*gone bad.*'):
|
with pytest.raises(btx.OperationalException, match=r'.*gone bad.*'):
|
||||||
wb.get_ticker('BTC_ETH')
|
wb.get_ticker('BTC_ETH')
|
||||||
|
|
||||||
fb.result = {'success': True, 'result': {}} # incomplete result
|
fb.result = {'success': True, 'result': {}} # incomplete result
|
||||||
with pytest.raises(ContentDecodingError, match=r'.*Got invalid response from bittrex params.*'):
|
with pytest.raises(ContentDecodingError, match=r'.*Invalid response from Bittrex params.*'):
|
||||||
wb.get_ticker('BTC_ETH')
|
wb.get_ticker('BTC_ETH')
|
||||||
fb.result = {'success': False, 'message': 'gone bad'}
|
fb.result = {'success': False, 'message': 'gone bad'}
|
||||||
with pytest.raises(btx.OperationalException, match=r'.*gone bad.*'):
|
with pytest.raises(btx.OperationalException, match=r'.*gone bad.*'):
|
||||||
@ -226,7 +226,7 @@ def test_exchange_bittrex_get_ticker_bad():
|
|||||||
|
|
||||||
fb.result = {'success': True,
|
fb.result = {'success': True,
|
||||||
'result': {'Bid': 1, 'Ask': 0, 'Last': None}} # incomplete result
|
'result': {'Bid': 1, 'Ask': 0, 'Last': None}} # incomplete result
|
||||||
with pytest.raises(ContentDecodingError, match=r'.*Got invalid response from bittrex params.*'):
|
with pytest.raises(ContentDecodingError, match=r'.*Invalid response from Bittrex params.*'):
|
||||||
wb.get_ticker('BTC_ETH')
|
wb.get_ticker('BTC_ETH')
|
||||||
|
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ def test_exchange_bittrex_get_ticker_history():
|
|||||||
wb = make_wrap_bittrex()
|
wb = make_wrap_bittrex()
|
||||||
fb = FakeBittrex()
|
fb = FakeBittrex()
|
||||||
assert wb.get_ticker_history('BTC_ETH', 5)
|
assert wb.get_ticker_history('BTC_ETH', 5)
|
||||||
with pytest.raises(ValueError, match=r'.*Cannot parse tick_interval.*'):
|
with pytest.raises(ValueError, match=r'.*Unknown tick_interval.*'):
|
||||||
wb.get_ticker_history('BTC_ETH', 2)
|
wb.get_ticker_history('BTC_ETH', 2)
|
||||||
|
|
||||||
fb.success = False
|
fb.success = False
|
||||||
@ -250,7 +250,7 @@ def test_exchange_bittrex_get_ticker_history():
|
|||||||
wb.get_ticker_history('BTC_ETH', 5)
|
wb.get_ticker_history('BTC_ETH', 5)
|
||||||
|
|
||||||
fb.success = True
|
fb.success = True
|
||||||
with pytest.raises(ContentDecodingError, match=r'.*Got invalid response from bittrex.*'):
|
with pytest.raises(ContentDecodingError, match=r'.*Invalid response from Bittrex.*'):
|
||||||
fb.result = {'bad': 0}
|
fb.result = {'bad': 0}
|
||||||
wb.get_ticker_history('BTC_ETH', 5)
|
wb.get_ticker_history('BTC_ETH', 5)
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ from freqtrade import optimize
|
|||||||
from freqtrade.optimize.backtesting import Backtesting, start, setup_configuration
|
from freqtrade.optimize.backtesting import Backtesting, start, setup_configuration
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.analyze import Analyze
|
from freqtrade.analyze import Analyze
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
from freqtrade.tests.conftest import default_conf, log_has
|
||||||
|
|
||||||
|
|
||||||
# Avoid to reinit the same object again and again
|
# Avoid to reinit the same object again and again
|
||||||
_BACKTESTING = Backtesting(tt.default_conf())
|
_BACKTESTING = Backtesting(default_conf())
|
||||||
|
|
||||||
|
|
||||||
def get_args(args) -> List[str]:
|
def get_args(args) -> List[str]:
|
||||||
@ -184,21 +184,21 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
assert 'exchange' in config
|
assert 'exchange' in config
|
||||||
assert 'pair_whitelist' in config['exchange']
|
assert 'pair_whitelist' in config['exchange']
|
||||||
assert 'datadir' in config
|
assert 'datadir' in config
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --datadir detected: {} ...'.format(config['datadir']),
|
'Parameter --datadir detected: {} ...'.format(config['datadir']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert not tt.log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'live' not in config
|
assert 'live' not in config
|
||||||
assert not tt.log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'realistic_simulation' not in config
|
assert 'realistic_simulation' not in config
|
||||||
assert not tt.log_has('Parameter --realistic-simulation detected ...', caplog.record_tuples)
|
assert not log_has('Parameter --realistic-simulation detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'refresh_pairs' not in config
|
assert 'refresh_pairs' not in config
|
||||||
assert not tt.log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'timerange' not in config
|
assert 'timerange' not in config
|
||||||
assert 'export' not in config
|
assert 'export' not in config
|
||||||
@ -232,34 +232,34 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
|||||||
assert 'exchange' in config
|
assert 'exchange' in config
|
||||||
assert 'pair_whitelist' in config['exchange']
|
assert 'pair_whitelist' in config['exchange']
|
||||||
assert 'datadir' in config
|
assert 'datadir' in config
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --datadir detected: {} ...'.format(config['datadir']),
|
'Parameter --datadir detected: {} ...'.format(config['datadir']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert tt.log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Using ticker_interval: 1 ...',
|
'Using ticker_interval: 1 ...',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 'live' in config
|
assert 'live' in config
|
||||||
assert tt.log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
assert log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'realistic_simulation'in config
|
assert 'realistic_simulation'in config
|
||||||
assert tt.log_has('Parameter --realistic-simulation detected ...', caplog.record_tuples)
|
assert log_has('Parameter --realistic-simulation detected ...', caplog.record_tuples)
|
||||||
assert tt.log_has('Using max_open_trades: 1 ...', caplog.record_tuples)
|
assert log_has('Using max_open_trades: 1 ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'refresh_pairs'in config
|
assert 'refresh_pairs'in config
|
||||||
assert tt.log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
assert log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
||||||
assert 'timerange' in config
|
assert 'timerange' in config
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --timerange detected: {} ...'.format(config['timerange']),
|
'Parameter --timerange detected: {} ...'.format(config['timerange']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 'export' in config
|
assert 'export' in config
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --export detected: {} ...'.format(config['export']),
|
'Parameter --export detected: {} ...'.format(config['export']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -281,7 +281,7 @@ def test_start(mocker, default_conf, caplog) -> None:
|
|||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start(args)
|
start(args)
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Starting freqtrade in Backtesting mode',
|
'Starting freqtrade in Backtesting mode',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -422,7 +422,7 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
|
|||||||
'up to 2017-11-14T22:59:00+00:00 (0 days)..'
|
'up to 2017-11-14T22:59:00+00:00 (0 days)..'
|
||||||
]
|
]
|
||||||
for line in exists:
|
for line in exists:
|
||||||
assert tt.log_has(line, caplog.record_tuples)
|
assert log_has(line, caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_backtest(default_conf) -> None:
|
def test_backtest(default_conf) -> None:
|
||||||
@ -605,4 +605,4 @@ def test_backtest_start_live(default_conf, mocker, caplog):
|
|||||||
]
|
]
|
||||||
|
|
||||||
for line in exists:
|
for line in exists:
|
||||||
tt.log_has(line, caplog.record_tuples)
|
log_has(line, caplog.record_tuples)
|
||||||
|
@ -4,11 +4,11 @@ from copy import deepcopy
|
|||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from freqtrade.optimize.hyperopt import Hyperopt
|
from freqtrade.optimize.hyperopt import Hyperopt
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
from freqtrade.tests.conftest import default_conf, log_has
|
||||||
|
|
||||||
|
|
||||||
# Avoid to reinit the same object again and again
|
# Avoid to reinit the same object again and again
|
||||||
_HYPEROPT = Hyperopt(tt.default_conf())
|
_HYPEROPT = Hyperopt(default_conf())
|
||||||
|
|
||||||
|
|
||||||
# Functions for recurrent object patching
|
# Functions for recurrent object patching
|
||||||
@ -83,7 +83,7 @@ def test_log_results_if_loss_improves(caplog) -> None:
|
|||||||
'result': 'foo'
|
'result': 'foo'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert tt.log_has(' 1/2: foo. Loss 1.00000', caplog.record_tuples)
|
assert log_has(' 1/2: foo. Loss 1.00000', caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_no_log_if_loss_does_not_improve(caplog) -> None:
|
def test_no_log_if_loss_does_not_improve(caplog) -> None:
|
||||||
@ -245,7 +245,7 @@ def test_save_trials_saves_trials(mocker, caplog) -> None:
|
|||||||
|
|
||||||
hyperopt.save_trials()
|
hyperopt.save_trials()
|
||||||
|
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Saving Trials to \'freqtrade/tests/optimize/ut_trials.pickle\'',
|
'Saving Trials to \'freqtrade/tests/optimize/ut_trials.pickle\'',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -259,7 +259,7 @@ def test_read_trials_returns_trials_file(mocker, default_conf, caplog) -> None:
|
|||||||
|
|
||||||
hyperopt = _HYPEROPT
|
hyperopt = _HYPEROPT
|
||||||
hyperopt_trial = hyperopt.read_trials()
|
hyperopt_trial = hyperopt.read_trials()
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Reading Trials from \'freqtrade/tests/optimize/ut_trials.pickle\'',
|
'Reading Trials from \'freqtrade/tests/optimize/ut_trials.pickle\'',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
import uuid
|
import uuid
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from freqtrade import optimize
|
from freqtrade import optimize
|
||||||
from freqtrade.optimize.__init__ import make_testdata_path, download_pairs,\
|
from freqtrade.optimize.__init__ import make_testdata_path, download_pairs,\
|
||||||
download_backtesting_testdata, load_tickerdata_file, trim_tickerlist
|
download_backtesting_testdata, load_tickerdata_file, trim_tickerlist
|
||||||
from freqtrade.misc import file_dump_json
|
from freqtrade.misc import file_dump_json
|
||||||
|
from freqtrade.tests.conftest import log_has
|
||||||
|
|
||||||
# Change this if modifying BTC_UNITEST testdatafile
|
# Change this if modifying BTC_UNITEST testdatafile
|
||||||
_BTC_UNITTEST_LENGTH = 13681
|
_BTC_UNITTEST_LENGTH = 13681
|
||||||
@ -55,9 +55,7 @@ def test_load_data_30min_ticker(ticker_history, mocker, caplog) -> None:
|
|||||||
_backup_file(file, copy_file=True)
|
_backup_file(file, copy_file=True)
|
||||||
optimize.load_data(None, pairs=['BTC_UNITTEST'], ticker_interval=30)
|
optimize.load_data(None, pairs=['BTC_UNITTEST'], ticker_interval=30)
|
||||||
assert os.path.isfile(file) is True
|
assert os.path.isfile(file) is True
|
||||||
assert ('freqtrade.optimize',
|
assert not log_has('Download the pair: "BTC_ETH", Interval: 30 min', caplog.record_tuples)
|
||||||
logging.INFO,
|
|
||||||
'Download the pair: "BTC_ETH", Interval: 30 min') not in caplog.record_tuples
|
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
@ -71,9 +69,7 @@ def test_load_data_5min_ticker(ticker_history, mocker, caplog) -> None:
|
|||||||
_backup_file(file, copy_file=True)
|
_backup_file(file, copy_file=True)
|
||||||
optimize.load_data(None, pairs=['BTC_ETH'], ticker_interval=5)
|
optimize.load_data(None, pairs=['BTC_ETH'], ticker_interval=5)
|
||||||
assert os.path.isfile(file) is True
|
assert os.path.isfile(file) is True
|
||||||
assert ('freqtrade.optimize',
|
assert not log_has('Download the pair: "BTC_ETH", Interval: 5 min', caplog.record_tuples)
|
||||||
logging.INFO,
|
|
||||||
'Download the pair: "BTC_ETH", Interval: 5 min') not in caplog.record_tuples
|
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
@ -87,9 +83,7 @@ def test_load_data_1min_ticker(ticker_history, mocker, caplog) -> None:
|
|||||||
_backup_file(file, copy_file=True)
|
_backup_file(file, copy_file=True)
|
||||||
optimize.load_data(None, ticker_interval=1, pairs=['BTC_ETH'])
|
optimize.load_data(None, ticker_interval=1, pairs=['BTC_ETH'])
|
||||||
assert os.path.isfile(file) is True
|
assert os.path.isfile(file) is True
|
||||||
assert ('freqtrade.optimize',
|
assert not log_has('Download the pair: "BTC_ETH", Interval: 1 min', caplog.record_tuples)
|
||||||
logging.INFO,
|
|
||||||
'Download the pair: "BTC_ETH", Interval: 1 min') not in caplog.record_tuples
|
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
@ -103,9 +97,7 @@ def test_load_data_with_new_pair_1min(ticker_history, mocker, caplog) -> None:
|
|||||||
_backup_file(file)
|
_backup_file(file)
|
||||||
optimize.load_data(None, ticker_interval=1, pairs=['BTC_MEME'])
|
optimize.load_data(None, ticker_interval=1, pairs=['BTC_MEME'])
|
||||||
assert os.path.isfile(file) is True
|
assert os.path.isfile(file) is True
|
||||||
assert ('freqtrade.optimize',
|
assert log_has('Download the pair: "BTC_MEME", Interval: 1 min', caplog.record_tuples)
|
||||||
logging.INFO,
|
|
||||||
'Download the pair: "BTC_MEME", Interval: 1 min') in caplog.record_tuples
|
|
||||||
_clean_test_file(file)
|
_clean_test_file(file)
|
||||||
|
|
||||||
|
|
||||||
@ -165,9 +157,7 @@ def test_download_pairs_exception(ticker_history, mocker, caplog) -> None:
|
|||||||
# clean files freshly downloaded
|
# clean files freshly downloaded
|
||||||
_clean_test_file(file1_1)
|
_clean_test_file(file1_1)
|
||||||
_clean_test_file(file1_5)
|
_clean_test_file(file1_5)
|
||||||
assert ('freqtrade.optimize.__init__',
|
assert log_has('Failed to download the pair: "BTC-MEME", Interval: 1 min', caplog.record_tuples)
|
||||||
logging.INFO,
|
|
||||||
'Failed to download the pair: "BTC-MEME", Interval: 1 min') in caplog.record_tuples
|
|
||||||
|
|
||||||
|
|
||||||
def test_download_backtesting_testdata(ticker_history, mocker) -> None:
|
def test_download_backtesting_testdata(ticker_history, mocker) -> None:
|
||||||
|
@ -8,7 +8,7 @@ from unittest.mock import MagicMock
|
|||||||
|
|
||||||
from freqtrade.rpc.rpc_manager import RPCManager
|
from freqtrade.rpc.rpc_manager import RPCManager
|
||||||
from freqtrade.rpc.telegram import Telegram
|
from freqtrade.rpc.telegram import Telegram
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
from freqtrade.tests.conftest import log_has, get_patched_freqtradebot
|
||||||
|
|
||||||
|
|
||||||
def test_rpc_manager_object() -> None:
|
def test_rpc_manager_object() -> None:
|
||||||
@ -26,7 +26,7 @@ def test__init__(mocker, default_conf) -> None:
|
|||||||
Test __init__() method
|
Test __init__() method
|
||||||
"""
|
"""
|
||||||
init_mock = mocker.patch('freqtrade.rpc.rpc_manager.RPCManager._init', MagicMock())
|
init_mock = mocker.patch('freqtrade.rpc.rpc_manager.RPCManager._init', MagicMock())
|
||||||
freqtradebot = tt.get_patched_freqtradebot(mocker, default_conf)
|
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||||
|
|
||||||
rpc_manager = RPCManager(freqtradebot)
|
rpc_manager = RPCManager(freqtradebot)
|
||||||
assert rpc_manager.freqtrade == freqtradebot
|
assert rpc_manager.freqtrade == freqtradebot
|
||||||
@ -44,10 +44,10 @@ def test_init_telegram_disabled(mocker, default_conf, caplog) -> None:
|
|||||||
conf = deepcopy(default_conf)
|
conf = deepcopy(default_conf)
|
||||||
conf['telegram']['enabled'] = False
|
conf['telegram']['enabled'] = False
|
||||||
|
|
||||||
freqtradebot = tt.get_patched_freqtradebot(mocker, conf)
|
freqtradebot = get_patched_freqtradebot(mocker, conf)
|
||||||
rpc_manager = RPCManager(freqtradebot)
|
rpc_manager = RPCManager(freqtradebot)
|
||||||
|
|
||||||
assert not tt.log_has('Enabling rpc.telegram ...', caplog.record_tuples)
|
assert not log_has('Enabling rpc.telegram ...', caplog.record_tuples)
|
||||||
assert rpc_manager.registered_modules == []
|
assert rpc_manager.registered_modules == []
|
||||||
assert rpc_manager.telegram is None
|
assert rpc_manager.telegram is None
|
||||||
|
|
||||||
@ -59,10 +59,10 @@ def test_init_telegram_enabled(mocker, default_conf, caplog) -> None:
|
|||||||
caplog.set_level(logging.DEBUG)
|
caplog.set_level(logging.DEBUG)
|
||||||
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
||||||
|
|
||||||
freqtradebot = tt.get_patched_freqtradebot(mocker, default_conf)
|
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||||
rpc_manager = RPCManager(freqtradebot)
|
rpc_manager = RPCManager(freqtradebot)
|
||||||
|
|
||||||
assert tt.log_has('Enabling rpc.telegram ...', caplog.record_tuples)
|
assert log_has('Enabling rpc.telegram ...', caplog.record_tuples)
|
||||||
len_modules = len(rpc_manager.registered_modules)
|
len_modules = len(rpc_manager.registered_modules)
|
||||||
assert len_modules == 1
|
assert len_modules == 1
|
||||||
assert 'telegram' in rpc_manager.registered_modules
|
assert 'telegram' in rpc_manager.registered_modules
|
||||||
@ -79,11 +79,11 @@ def test_cleanup_telegram_disabled(mocker, default_conf, caplog) -> None:
|
|||||||
conf = deepcopy(default_conf)
|
conf = deepcopy(default_conf)
|
||||||
conf['telegram']['enabled'] = False
|
conf['telegram']['enabled'] = False
|
||||||
|
|
||||||
freqtradebot = tt.get_patched_freqtradebot(mocker, conf)
|
freqtradebot = get_patched_freqtradebot(mocker, conf)
|
||||||
rpc_manager = RPCManager(freqtradebot)
|
rpc_manager = RPCManager(freqtradebot)
|
||||||
rpc_manager.cleanup()
|
rpc_manager.cleanup()
|
||||||
|
|
||||||
assert not tt.log_has('Cleaning up rpc.telegram ...', caplog.record_tuples)
|
assert not log_has('Cleaning up rpc.telegram ...', caplog.record_tuples)
|
||||||
assert telegram_mock.call_count == 0
|
assert telegram_mock.call_count == 0
|
||||||
|
|
||||||
|
|
||||||
@ -95,14 +95,14 @@ def test_cleanup_telegram_enabled(mocker, default_conf, caplog) -> None:
|
|||||||
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
||||||
telegram_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.cleanup', MagicMock())
|
telegram_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.cleanup', MagicMock())
|
||||||
|
|
||||||
freqtradebot = tt.get_patched_freqtradebot(mocker, default_conf)
|
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||||
rpc_manager = RPCManager(freqtradebot)
|
rpc_manager = RPCManager(freqtradebot)
|
||||||
|
|
||||||
# Check we have Telegram as a registered modules
|
# Check we have Telegram as a registered modules
|
||||||
assert 'telegram' in rpc_manager.registered_modules
|
assert 'telegram' in rpc_manager.registered_modules
|
||||||
|
|
||||||
rpc_manager.cleanup()
|
rpc_manager.cleanup()
|
||||||
assert tt.log_has('Cleaning up rpc.telegram ...', caplog.record_tuples)
|
assert log_has('Cleaning up rpc.telegram ...', caplog.record_tuples)
|
||||||
assert 'telegram' not in rpc_manager.registered_modules
|
assert 'telegram' not in rpc_manager.registered_modules
|
||||||
assert telegram_mock.call_count == 1
|
assert telegram_mock.call_count == 1
|
||||||
|
|
||||||
@ -116,11 +116,11 @@ def test_send_msg_telegram_disabled(mocker, default_conf, caplog) -> None:
|
|||||||
conf = deepcopy(default_conf)
|
conf = deepcopy(default_conf)
|
||||||
conf['telegram']['enabled'] = False
|
conf['telegram']['enabled'] = False
|
||||||
|
|
||||||
freqtradebot = tt.get_patched_freqtradebot(mocker, conf)
|
freqtradebot = get_patched_freqtradebot(mocker, conf)
|
||||||
rpc_manager = RPCManager(freqtradebot)
|
rpc_manager = RPCManager(freqtradebot)
|
||||||
rpc_manager.send_msg('test')
|
rpc_manager.send_msg('test')
|
||||||
|
|
||||||
assert tt.log_has('test', caplog.record_tuples)
|
assert log_has('test', caplog.record_tuples)
|
||||||
assert telegram_mock.call_count == 0
|
assert telegram_mock.call_count == 0
|
||||||
|
|
||||||
|
|
||||||
@ -131,9 +131,9 @@ def test_send_msg_telegram_enabled(mocker, default_conf, caplog) -> None:
|
|||||||
telegram_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
|
telegram_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
|
||||||
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
||||||
|
|
||||||
freqtradebot = tt.get_patched_freqtradebot(mocker, default_conf)
|
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
|
||||||
rpc_manager = RPCManager(freqtradebot)
|
rpc_manager = RPCManager(freqtradebot)
|
||||||
rpc_manager.send_msg('test')
|
rpc_manager.send_msg('test')
|
||||||
|
|
||||||
assert tt.log_has('test', caplog.record_tuples)
|
assert log_has('test', caplog.record_tuples)
|
||||||
assert telegram_mock.call_count == 1
|
assert telegram_mock.call_count == 1
|
||||||
|
@ -23,7 +23,6 @@ from freqtrade.persistence import Trade
|
|||||||
from freqtrade.state import State
|
from freqtrade.state import State
|
||||||
from freqtrade.tests.test_freqtradebot import patch_get_signal, patch_pymarketcap
|
from freqtrade.tests.test_freqtradebot import patch_get_signal, patch_pymarketcap
|
||||||
from freqtrade.tests.conftest import get_patched_freqtradebot, log_has
|
from freqtrade.tests.conftest import get_patched_freqtradebot, log_has
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
|
||||||
|
|
||||||
|
|
||||||
class DummyCls(Telegram):
|
class DummyCls(Telegram):
|
||||||
@ -160,15 +159,15 @@ def test_authorized_only(default_conf, mocker, caplog) -> None:
|
|||||||
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
||||||
dummy.dummy_handler(bot=MagicMock(), update=update)
|
dummy.dummy_handler(bot=MagicMock(), update=update)
|
||||||
assert dummy.state['called'] is True
|
assert dummy.state['called'] is True
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Executing handler: dummy_handler for chat_id: 0',
|
'Executing handler: dummy_handler for chat_id: 0',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert not tt.log_has(
|
assert not log_has(
|
||||||
'Rejected unauthorized message from: 0',
|
'Rejected unauthorized message from: 0',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert not tt.log_has(
|
assert not log_has(
|
||||||
'Exception occurred within Telegram module',
|
'Exception occurred within Telegram module',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -191,15 +190,15 @@ def test_authorized_only_unauthorized(default_conf, mocker, caplog) -> None:
|
|||||||
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
||||||
dummy.dummy_handler(bot=MagicMock(), update=update)
|
dummy.dummy_handler(bot=MagicMock(), update=update)
|
||||||
assert dummy.state['called'] is False
|
assert dummy.state['called'] is False
|
||||||
assert not tt.log_has(
|
assert not log_has(
|
||||||
'Executing handler: dummy_handler for chat_id: 3735928559',
|
'Executing handler: dummy_handler for chat_id: 3735928559',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Rejected unauthorized message from: 3735928559',
|
'Rejected unauthorized message from: 3735928559',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert not tt.log_has(
|
assert not log_has(
|
||||||
'Exception occurred within Telegram module',
|
'Exception occurred within Telegram module',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -221,15 +220,15 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None:
|
|||||||
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
dummy = DummyCls(FreqtradeBot(conf, create_engine('sqlite://')))
|
||||||
dummy.dummy_exception(bot=MagicMock(), update=update)
|
dummy.dummy_exception(bot=MagicMock(), update=update)
|
||||||
assert dummy.state['called'] is False
|
assert dummy.state['called'] is False
|
||||||
assert not tt.log_has(
|
assert not log_has(
|
||||||
'Executing handler: dummy_handler for chat_id: 0',
|
'Executing handler: dummy_handler for chat_id: 0',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert not tt.log_has(
|
assert not log_has(
|
||||||
'Rejected unauthorized message from: 0',
|
'Rejected unauthorized message from: 0',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Exception occurred within Telegram module',
|
'Exception occurred within Telegram module',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -1086,7 +1085,7 @@ def test_send_msg_network_error(default_conf, mocker, caplog) -> None:
|
|||||||
|
|
||||||
# Bot should've tried to send it twice
|
# Bot should've tried to send it twice
|
||||||
assert len(bot.method_calls) == 2
|
assert len(bot.method_calls) == 2
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Got TelegramError: Oh snap! Giving up on that message.',
|
'Telegram NetworkError: Oh snap! Trying one more time.',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
@ -12,7 +12,7 @@ from pandas import DataFrame
|
|||||||
|
|
||||||
from freqtrade.analyze import Analyze, SignalType
|
from freqtrade.analyze import Analyze, SignalType
|
||||||
from freqtrade.optimize.__init__ import load_tickerdata_file
|
from freqtrade.optimize.__init__ import load_tickerdata_file
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
from freqtrade.tests.conftest import log_has
|
||||||
|
|
||||||
|
|
||||||
# Avoid to reinit the same object again and again
|
# Avoid to reinit the same object again and again
|
||||||
@ -109,7 +109,7 @@ def test_get_signal_empty(default_conf, mocker, caplog):
|
|||||||
caplog.set_level(logging.INFO)
|
caplog.set_level(logging.INFO)
|
||||||
mocker.patch('freqtrade.analyze.get_ticker_history', return_value=None)
|
mocker.patch('freqtrade.analyze.get_ticker_history', return_value=None)
|
||||||
assert (False, False) == _ANALYZE.get_signal('foo', int(default_conf['ticker_interval']))
|
assert (False, False) == _ANALYZE.get_signal('foo', int(default_conf['ticker_interval']))
|
||||||
assert tt.log_has('Empty ticker history for pair foo', caplog.record_tuples)
|
assert log_has('Empty ticker history for pair foo', caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_get_signal_exception_valueerror(default_conf, mocker, caplog):
|
def test_get_signal_exception_valueerror(default_conf, mocker, caplog):
|
||||||
@ -122,8 +122,7 @@ def test_get_signal_exception_valueerror(default_conf, mocker, caplog):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert (False, False) == _ANALYZE.get_signal('foo', int(default_conf['ticker_interval']))
|
assert (False, False) == _ANALYZE.get_signal('foo', int(default_conf['ticker_interval']))
|
||||||
assert tt.log_has('Unable to analyze ticker for pair foo: xyz',
|
assert log_has('Unable to analyze ticker for pair foo: xyz', caplog.record_tuples)
|
||||||
caplog.record_tuples)
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_signal_empty_dataframe(default_conf, mocker, caplog):
|
def test_get_signal_empty_dataframe(default_conf, mocker, caplog):
|
||||||
@ -136,8 +135,7 @@ def test_get_signal_empty_dataframe(default_conf, mocker, caplog):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert (False, False) == _ANALYZE.get_signal('xyz', int(default_conf['ticker_interval']))
|
assert (False, False) == _ANALYZE.get_signal('xyz', int(default_conf['ticker_interval']))
|
||||||
assert tt.log_has('Empty dataframe for pair xyz',
|
assert log_has('Empty dataframe for pair xyz', caplog.record_tuples)
|
||||||
caplog.record_tuples)
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_signal_old_dataframe(default_conf, mocker, caplog):
|
def test_get_signal_old_dataframe(default_conf, mocker, caplog):
|
||||||
@ -153,8 +151,10 @@ def test_get_signal_old_dataframe(default_conf, mocker, caplog):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert (False, False) == _ANALYZE.get_signal('xyz', int(default_conf['ticker_interval']))
|
assert (False, False) == _ANALYZE.get_signal('xyz', int(default_conf['ticker_interval']))
|
||||||
assert tt.log_has('Too old dataframe for pair xyz',
|
assert log_has(
|
||||||
caplog.record_tuples)
|
'Outdated history for pair xyz. Last tick is 11 minutes old',
|
||||||
|
caplog.record_tuples
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_get_signal_handles_exceptions(mocker):
|
def test_get_signal_handles_exceptions(mocker):
|
||||||
|
@ -11,7 +11,7 @@ from jsonschema import ValidationError
|
|||||||
|
|
||||||
from freqtrade.arguments import Arguments
|
from freqtrade.arguments import Arguments
|
||||||
from freqtrade.configuration import Configuration
|
from freqtrade.configuration import Configuration
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
from freqtrade.tests.conftest import log_has
|
||||||
|
|
||||||
|
|
||||||
def test_configuration_object() -> None:
|
def test_configuration_object() -> None:
|
||||||
@ -64,7 +64,7 @@ def test_load_config_file(default_conf, mocker, caplog) -> None:
|
|||||||
assert file_mock.call_count == 1
|
assert file_mock.call_count == 1
|
||||||
assert validated_conf.items() >= default_conf.items()
|
assert validated_conf.items() >= default_conf.items()
|
||||||
assert 'internals' in validated_conf
|
assert 'internals' in validated_conf
|
||||||
assert tt.log_has('Validating configuration ...', caplog.record_tuples)
|
assert log_has('Validating configuration ...', caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_load_config(default_conf, mocker) -> None:
|
def test_load_config(default_conf, mocker) -> None:
|
||||||
@ -129,19 +129,19 @@ def test_show_info(default_conf, mocker, caplog) -> None:
|
|||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
configuration.get_config()
|
configuration.get_config()
|
||||||
|
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --dynamic-whitelist detected. '
|
'Parameter --dynamic-whitelist detected. '
|
||||||
'Using dynamically generated whitelist. '
|
'Using dynamically generated whitelist. '
|
||||||
'(not applicable with Backtesting and Hyperopt)',
|
'(not applicable with Backtesting and Hyperopt)',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --dry-run-db detected ...',
|
'Parameter --dry-run-db detected ...',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Dry_run will use the DB file: "tradesv3.dry_run.sqlite"',
|
'Dry_run will use the DB file: "tradesv3.dry_run.sqlite"',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -149,7 +149,7 @@ def test_show_info(default_conf, mocker, caplog) -> None:
|
|||||||
# Test the Dry run condition
|
# Test the Dry run condition
|
||||||
configuration.config.update({'dry_run': False})
|
configuration.config.update({'dry_run': False})
|
||||||
configuration._load_common_config(configuration.config)
|
configuration._load_common_config(configuration.config)
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Dry run is disabled. (--dry_run_db ignored)',
|
'Dry run is disabled. (--dry_run_db ignored)',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -179,21 +179,21 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
assert 'exchange' in config
|
assert 'exchange' in config
|
||||||
assert 'pair_whitelist' in config['exchange']
|
assert 'pair_whitelist' in config['exchange']
|
||||||
assert 'datadir' in config
|
assert 'datadir' in config
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --datadir detected: {} ...'.format(config['datadir']),
|
'Parameter --datadir detected: {} ...'.format(config['datadir']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert not tt.log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'live' not in config
|
assert 'live' not in config
|
||||||
assert not tt.log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'realistic_simulation' not in config
|
assert 'realistic_simulation' not in config
|
||||||
assert not tt.log_has('Parameter --realistic-simulation detected ...', caplog.record_tuples)
|
assert not log_has('Parameter --realistic-simulation detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'refresh_pairs' not in config
|
assert 'refresh_pairs' not in config
|
||||||
assert not tt.log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
assert not log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'timerange' not in config
|
assert 'timerange' not in config
|
||||||
assert 'export' not in config
|
assert 'export' not in config
|
||||||
@ -230,34 +230,34 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
|||||||
assert 'exchange' in config
|
assert 'exchange' in config
|
||||||
assert 'pair_whitelist' in config['exchange']
|
assert 'pair_whitelist' in config['exchange']
|
||||||
assert 'datadir' in config
|
assert 'datadir' in config
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --datadir detected: {} ...'.format(config['datadir']),
|
'Parameter --datadir detected: {} ...'.format(config['datadir']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
assert 'ticker_interval' in config
|
assert 'ticker_interval' in config
|
||||||
assert tt.log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
assert log_has('Parameter -i/--ticker-interval detected ...', caplog.record_tuples)
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Using ticker_interval: 1 ...',
|
'Using ticker_interval: 1 ...',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 'live' in config
|
assert 'live' in config
|
||||||
assert tt.log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
assert log_has('Parameter -l/--live detected ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'realistic_simulation'in config
|
assert 'realistic_simulation'in config
|
||||||
assert tt.log_has('Parameter --realistic-simulation detected ...', caplog.record_tuples)
|
assert log_has('Parameter --realistic-simulation detected ...', caplog.record_tuples)
|
||||||
assert tt.log_has('Using max_open_trades: 1 ...', caplog.record_tuples)
|
assert log_has('Using max_open_trades: 1 ...', caplog.record_tuples)
|
||||||
|
|
||||||
assert 'refresh_pairs'in config
|
assert 'refresh_pairs'in config
|
||||||
assert tt.log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
assert log_has('Parameter -r/--refresh-pairs-cached detected ...', caplog.record_tuples)
|
||||||
assert 'timerange' in config
|
assert 'timerange' in config
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --timerange detected: {} ...'.format(config['timerange']),
|
'Parameter --timerange detected: {} ...'.format(config['timerange']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
|
|
||||||
assert 'export' in config
|
assert 'export' in config
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Parameter --export detected: {} ...'.format(config['export']),
|
'Parameter --export detected: {} ...'.format(config['export']),
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -282,4 +282,4 @@ def test_hyperopt_space_argument(mocker, default_conf, caplog) -> None:
|
|||||||
config = configuration.get_config()
|
config = configuration.get_config()
|
||||||
assert 'spaces' in config
|
assert 'spaces' in config
|
||||||
assert config['spaces'] == ['all']
|
assert config['spaces'] == ['all']
|
||||||
assert tt.log_has('Parameter -s/--spaces detected: [\'all\']', caplog.record_tuples)
|
assert log_has('Parameter -s/--spaces detected: [\'all\']', caplog.record_tuples)
|
||||||
|
@ -14,7 +14,7 @@ import pytest
|
|||||||
import requests
|
import requests
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
|
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
from freqtrade.tests.conftest import log_has
|
||||||
from freqtrade import DependencyException, OperationalException
|
from freqtrade import DependencyException, OperationalException
|
||||||
from freqtrade.exchange import Exchanges
|
from freqtrade.exchange import Exchanges
|
||||||
from freqtrade.freqtradebot import FreqtradeBot
|
from freqtrade.freqtradebot import FreqtradeBot
|
||||||
@ -145,7 +145,7 @@ def test_throttle(mocker, default_conf, caplog) -> None:
|
|||||||
|
|
||||||
assert result == 42
|
assert result == 42
|
||||||
assert end - start > 0.1
|
assert end - start > 0.1
|
||||||
assert tt.log_has('Throttling func for 0.10 seconds', caplog.record_tuples)
|
assert log_has('Throttling func for 0.10 seconds', caplog.record_tuples)
|
||||||
|
|
||||||
result = freqtrade._throttle(func, min_secs=-1)
|
result = freqtrade._throttle(func, min_secs=-1)
|
||||||
assert result == 42
|
assert result == 42
|
||||||
@ -311,7 +311,7 @@ def test_create_trade_no_pairs(default_conf, ticker, mocker) -> None:
|
|||||||
|
|
||||||
freqtrade.create_trade(0.001, int(default_conf['ticker_interval']))
|
freqtrade.create_trade(0.001, int(default_conf['ticker_interval']))
|
||||||
|
|
||||||
with pytest.raises(DependencyException, match=r'.*No pair in whitelist.*'):
|
with pytest.raises(DependencyException, match=r'.*No currency pairs in whitelist.*'):
|
||||||
freqtrade.create_trade(default_conf['stake_amount'], int(default_conf['ticker_interval']))
|
freqtrade.create_trade(default_conf['stake_amount'], int(default_conf['ticker_interval']))
|
||||||
|
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ def test_create_trade_no_pairs_after_blacklist(default_conf, ticker, mocker) ->
|
|||||||
|
|
||||||
freqtrade.create_trade(0.001, int(default_conf['ticker_interval']))
|
freqtrade.create_trade(0.001, int(default_conf['ticker_interval']))
|
||||||
|
|
||||||
with pytest.raises(DependencyException, match=r'.*No pair in whitelist.*'):
|
with pytest.raises(DependencyException, match=r'.*No currency pairs in whitelist.*'):
|
||||||
freqtrade.create_trade(conf['stake_amount'], int(conf['ticker_interval']))
|
freqtrade.create_trade(conf['stake_amount'], int(conf['ticker_interval']))
|
||||||
|
|
||||||
|
|
||||||
@ -399,7 +399,7 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order,
|
|||||||
assert trade.open_rate == 0.00001099
|
assert trade.open_rate == 0.00001099
|
||||||
assert trade.amount == 90.99181073703367
|
assert trade.amount == 90.99181073703367
|
||||||
|
|
||||||
assert tt.log_has(
|
assert log_has(
|
||||||
'Checking buy signals to create a new trade with stake_amount: 0.001000 ...',
|
'Checking buy signals to create a new trade with stake_amount: 0.001000 ...',
|
||||||
caplog.record_tuples
|
caplog.record_tuples
|
||||||
)
|
)
|
||||||
@ -537,7 +537,7 @@ def test_process_maybe_execute_buy_exception(mocker, default_conf, caplog) -> No
|
|||||||
MagicMock(side_effect=DependencyException)
|
MagicMock(side_effect=DependencyException)
|
||||||
)
|
)
|
||||||
freqtrade.process_maybe_execute_buy(int(default_conf['ticker_interval']))
|
freqtrade.process_maybe_execute_buy(int(default_conf['ticker_interval']))
|
||||||
tt.log_has('Unable to create trade:', caplog.record_tuples)
|
log_has('Unable to create trade:', caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_process_maybe_execute_sell(mocker, default_conf) -> None:
|
def test_process_maybe_execute_sell(mocker, default_conf) -> None:
|
||||||
@ -690,7 +690,7 @@ def test_handle_trade_roi(default_conf, ticker, mocker, caplog) -> None:
|
|||||||
# if ROI is reached we must sell
|
# if ROI is reached we must sell
|
||||||
patch_get_signal(mocker, value=(False, True))
|
patch_get_signal(mocker, value=(False, True))
|
||||||
assert freqtrade.handle_trade(trade, interval=int(default_conf['ticker_interval']))
|
assert freqtrade.handle_trade(trade, interval=int(default_conf['ticker_interval']))
|
||||||
assert tt.log_has('Executing sell due to ROI ...', caplog.record_tuples)
|
assert log_has('Required profit reached. Selling..', caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_handle_trade_experimental(default_conf, ticker, mocker, caplog) -> None:
|
def test_handle_trade_experimental(default_conf, ticker, mocker, caplog) -> None:
|
||||||
@ -723,7 +723,7 @@ def test_handle_trade_experimental(default_conf, ticker, mocker, caplog) -> None
|
|||||||
|
|
||||||
patch_get_signal(mocker, value=(False, True))
|
patch_get_signal(mocker, value=(False, True))
|
||||||
assert freqtrade.handle_trade(trade, int(default_conf['ticker_interval']))
|
assert freqtrade.handle_trade(trade, int(default_conf['ticker_interval']))
|
||||||
assert tt.log_has('Executing sell due to sell signal ...', caplog.record_tuples)
|
assert log_has('Sell signal received. Selling..', caplog.record_tuples)
|
||||||
|
|
||||||
|
|
||||||
def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, mocker) -> None:
|
def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, mocker) -> None:
|
||||||
|
@ -7,7 +7,7 @@ from unittest.mock import MagicMock
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from freqtrade.main import main, set_loggers
|
from freqtrade.main import main, set_loggers
|
||||||
import freqtrade.tests.conftest as tt # test tools
|
from freqtrade.tests.conftest import log_has
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_backtesting(mocker) -> None:
|
def test_parse_args_backtesting(mocker) -> None:
|
||||||
@ -78,8 +78,8 @@ def test_main(mocker, caplog) -> None:
|
|||||||
# Test Main + the KeyboardInterrupt exception
|
# Test Main + the KeyboardInterrupt exception
|
||||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||||
main(args)
|
main(args)
|
||||||
tt.log_has('Starting freqtrade', caplog.record_tuples)
|
log_has('Starting freqtrade', caplog.record_tuples)
|
||||||
tt.log_has('Got SIGINT, aborting ...', caplog.record_tuples)
|
log_has('Got SIGINT, aborting ...', caplog.record_tuples)
|
||||||
assert pytest_wrapped_e.type == SystemExit
|
assert pytest_wrapped_e.type == SystemExit
|
||||||
assert pytest_wrapped_e.value.code == 42
|
assert pytest_wrapped_e.value.code == 42
|
||||||
|
|
||||||
@ -90,4 +90,4 @@ def test_main(mocker, caplog) -> None:
|
|||||||
)
|
)
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
main(args)
|
main(args)
|
||||||
tt.log_has('Got fatal exception!', caplog.record_tuples)
|
log_has('Got fatal exception!', caplog.record_tuples)
|
||||||
|
Loading…
Reference in New Issue
Block a user