Merge branch 'develop' of https://github.com/gcarq/freqtrade into pair_blacklist

This commit is contained in:
Jean-Baptiste LE STANG 2017-12-29 16:00:24 +01:00
commit 1adbeb5f06
13 changed files with 375 additions and 151 deletions

View File

@ -179,17 +179,20 @@ def handle_trade(trade: Trade) -> bool:
current_rate = exchange.get_ticker(trade.pair)['bid']
# Check if minimal roi has been reached
if not min_roi_reached(trade, current_rate, datetime.utcnow()):
return False
if min_roi_reached(trade, current_rate, datetime.utcnow()):
logger.debug('Executing sell due to ROI ...')
execute_sell(trade, current_rate)
return True
# Check if sell signal has been enabled and triggered
if _CONF.get('experimental', {}).get('use_sell_signal'):
logger.debug('Checking sell_signal ...')
if not get_signal(trade.pair, SignalType.SELL):
return False
if get_signal(trade.pair, SignalType.SELL):
logger.debug('Executing sell due to sell signal ...')
execute_sell(trade, current_rate)
return True
execute_sell(trade, current_rate)
return True
return False
def get_target_bid(ticker: Dict[str, float]) -> float:

View File

@ -4,11 +4,9 @@ import logging
import json
import os
from typing import Optional, List, Dict
from pandas import DataFrame
from freqtrade.exchange import get_ticker_history
from freqtrade.optimize.hyperopt_conf import hyperopt_optimize_conf
from pandas import DataFrame
from freqtrade.analyze import populate_indicators, parse_ticker_dataframe
logger = logging.getLogger(__name__)
@ -50,10 +48,8 @@ def load_data(ticker_interval: int = 5, pairs: Optional[List[str]] = None,
def preprocess(tickerdata: Dict[str, List]) -> Dict[str, DataFrame]:
"""Creates a dataframe and populates indicators for given ticker data"""
processed = {}
for pair, pair_data in tickerdata.items():
processed[pair] = populate_indicators(parse_ticker_dataframe(pair_data))
return processed
return {pair: populate_indicators(parse_ticker_dataframe(pair_data))
for pair, pair_data in tickerdata.items()}
def testdata_path() -> str:
@ -91,17 +87,17 @@ def download_backtesting_testdata(pair: str, interval: int = 5) -> bool:
))
filepair = pair.replace("-", "_")
filename = os.path.join(path, '{}-{}.json'.format(
filepair,
interval,
filename = os.path.join(path, '{pair}-{interval}.json'.format(
pair=filepair,
interval=interval,
))
filename = filename.replace('USDT_BTC', 'BTC_FAKEBULL')
if os.path.isfile(filename):
with open(filename, "rt") as fp:
data = json.load(fp)
logger.debug("Current Start:", data[1]['T'])
logger.debug("Current End: ", data[-1:][0]['T'])
logger.debug("Current Start: {}".format(data[1]['T']))
logger.debug("Current End: {}".format(data[-1:][0]['T']))
else:
data = []
logger.debug("Current Start: None")
@ -111,8 +107,8 @@ def download_backtesting_testdata(pair: str, interval: int = 5) -> bool:
for row in new_data:
if row not in data:
data.append(row)
logger.debug("New Start:", data[1]['T'])
logger.debug("New End: ", data[-1:][0]['T'])
logger.debug("New Start: {}".format(data[1]['T']))
logger.debug("New End: {}".format(data[-1:][0]['T']))
data = sorted(data, key=lambda data: data['T'])
with open(filename, "wt") as fp:

View File

@ -111,14 +111,14 @@ def backtest(stake_amount: float, processed: Dict[str, DataFrame],
if min_roi_reached(trade, row2.close, row2.date) or row2.sell == 1:
current_profit_percent = trade.calc_profit_percent(rate=row2.close)
current_profit_BTC = trade.calc_profit(rate=row2.close)
current_profit_btc = trade.calc_profit(rate=row2.close)
lock_pair_until = row2.Index
trades.append(
(
pair,
current_profit_percent,
current_profit_BTC,
current_profit_btc,
row2.Index - row.Index
)
)

View File

@ -25,12 +25,10 @@ logging.getLogger('hyperopt.tpe').setLevel(logging.WARNING)
logger = logging.getLogger(__name__)
# set TARGET_TRADES to suit your number concurrent trades so its realistic to 20days of data
TARGET_TRADES = 1100
TOTAL_TRIES = None
_CURRENT_TRIES = 0
CURRENT_BEST_LOSS = 100
# this is expexted avg profit * expected trade count
@ -111,6 +109,13 @@ def log_results(results):
sys.stdout.flush()
def calculate_loss(total_profit: float, trade_count: int):
""" objective function, returns smaller number for more optimal results """
trade_loss = 1 - 0.35 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.2)
profit_loss = max(0, 1 - total_profit / EXPECTED_MAX_PROFIT)
return trade_loss + profit_loss
def optimizer(params):
global _CURRENT_TRIES
@ -118,37 +123,33 @@ def optimizer(params):
backtesting.populate_buy_trend = buy_strategy_generator(params)
results = backtest(OPTIMIZE_CONFIG['stake_amount'], PROCESSED)
result = format_results(results)
result_explanation = format_results(results)
total_profit = results.profit_percent.sum()
trade_count = len(results.index)
if trade_count == 0:
print('.', end='')
return {
'status': STATUS_FAIL,
'loss': float('inf')
}
trade_loss = 1 - 0.35 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.2)
profit_loss = max(0, 1 - total_profit / EXPECTED_MAX_PROFIT)
loss = trade_loss + profit_loss
loss = calculate_loss(total_profit, trade_count)
_CURRENT_TRIES += 1
result_data = {
log_results({
'loss': loss,
'current_tries': _CURRENT_TRIES,
'total_tries': TOTAL_TRIES,
'result': result,
}
log_results(result_data)
'result': result_explanation,
})
return {
'loss': loss,
'status': STATUS_OK,
'result': result,
'total_profit': total_profit,
'avg_profit': results.profit_percent.mean() * 100.0,
'result': result_explanation,
}

View File

@ -1,12 +1,12 @@
import logging
import re
from decimal import Decimal
from datetime import timedelta, date, datetime
from datetime import timedelta, datetime
from typing import Callable, Any
import arrow
from pandas import DataFrame
from sqlalchemy import and_, func, text, between
from sqlalchemy import and_, func, text
from tabulate import tabulate
from telegram import ParseMode, Bot, Update, ReplyKeyboardMarkup
from telegram.error import NetworkError, TelegramError
@ -220,29 +220,28 @@ def _daily(bot: Bot, update: Update) -> None:
:param update: message update
:return: None
"""
today = datetime.utcnow().toordinal()
today = datetime.utcnow().date()
profit_days = {}
try:
timescale = int(update.message.text.replace('/daily', '').strip())
except (TypeError, ValueError):
timescale = 5
timescale = 7
if not (isinstance(timescale, int) and timescale > 0):
send_msg('*Daily [n]:* `must be an integer greater than 0`', bot=bot)
return
for day in range(0, timescale):
# need to query between day+1 and day-1
nextdate = date.fromordinal(today - day + 1)
prevdate = date.fromordinal(today - day - 1)
profitday = today - timedelta(days=day)
trades = Trade.query \
.filter(Trade.is_open.is_(False)) \
.filter(between(Trade.close_date, prevdate, nextdate)) \
.filter(Trade.close_date >= profitday)\
.filter(Trade.close_date < (profitday + timedelta(days=1)))\
.order_by(Trade.close_date)\
.all()
curdayprofit = sum(trade.calc_profit() for trade in trades)
profit_days[date.fromordinal(today - day)] = format(curdayprofit, '.8f')
profit_days[profitday] = format(curdayprofit, '.8f')
stats = [
[

View File

@ -0,0 +1,48 @@
# pragma pylint: disable=missing-docstring,W0212
import pandas as pd
from freqtrade import exchange, optimize
from freqtrade.exchange import Bittrex
from freqtrade.optimize.backtesting import backtest, generate_text_table, get_timeframe
def test_generate_text_table():
results = pd.DataFrame(
{
'currency': ['BTC_ETH', 'BTC_ETH'],
'profit_percent': [0.1, 0.2],
'profit_BTC': [0.2, 0.4],
'duration': [10, 30]
}
)
assert generate_text_table({'BTC_ETH': {}}, results, 'BTC', 5) == (
'pair buy count avg profit total profit avg duration\n'
'------- ----------- ------------ -------------- --------------\n'
'BTC_ETH 2 15.00% 0.60000000 BTC 100\n'
'TOTAL 2 15.00% 0.60000000 BTC 100')
def test_get_timeframe():
data = optimize.load_data(ticker_interval=1, pairs=['BTC_UNITEST'])
min_date, max_date = get_timeframe(data)
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
assert max_date.isoformat() == '2017-11-14T22:59:00+00:00'
def test_backtest(default_conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
data = optimize.load_data(ticker_interval=5, pairs=['BTC_ETH'])
results = backtest(default_conf['stake_amount'], optimize.preprocess(data), 10, True)
assert not results.empty
def test_backtest_1min_ticker_interval(default_conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
# Run a backtesting for an exiting 5min ticker_interval
data = optimize.load_data(ticker_interval=1, pairs=['BTC_UNITEST'])
results = backtest(default_conf['stake_amount'], optimize.preprocess(data), 1, True)
assert not results.empty

View File

@ -0,0 +1,79 @@
# pragma pylint: disable=missing-docstring,W0212,C0103
from freqtrade.optimize.hyperopt import calculate_loss, TARGET_TRADES, EXPECTED_MAX_PROFIT, start, \
log_results
def test_loss_calculation_prefer_correct_trade_count():
correct = calculate_loss(1, TARGET_TRADES)
over = calculate_loss(1, TARGET_TRADES + 100)
under = calculate_loss(1, TARGET_TRADES - 100)
assert over > correct
assert under > correct
def test_loss_calculation_has_limited_profit():
correct = calculate_loss(EXPECTED_MAX_PROFIT, TARGET_TRADES)
over = calculate_loss(EXPECTED_MAX_PROFIT * 2, TARGET_TRADES)
under = calculate_loss(EXPECTED_MAX_PROFIT / 2, TARGET_TRADES)
assert over == correct
assert under > correct
def create_trials(mocker):
return mocker.Mock(
results=[{
'loss': 1,
'result': 'foo'
}]
)
def test_start_calls_fmin(mocker):
mocker.patch('freqtrade.optimize.hyperopt.Trials', return_value=create_trials(mocker))
mocker.patch('freqtrade.optimize.preprocess')
mocker.patch('freqtrade.optimize.load_data')
mock_fmin = mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={})
args = mocker.Mock(epochs=1, config='config.json.example', mongodb=False)
start(args)
mock_fmin.assert_called_once()
def test_start_uses_mongotrials(mocker):
mock_mongotrials = mocker.patch('freqtrade.optimize.hyperopt.MongoTrials',
return_value=create_trials(mocker))
mocker.patch('freqtrade.optimize.preprocess')
mocker.patch('freqtrade.optimize.load_data')
mocker.patch('freqtrade.optimize.hyperopt.fmin', return_value={})
args = mocker.Mock(epochs=1, config='config.json.example', mongodb=True)
start(args)
mock_mongotrials.assert_called_once()
def test_log_results_if_loss_improves(mocker):
logger = mocker.patch('freqtrade.optimize.hyperopt.logger.info')
global CURRENT_BEST_LOSS
CURRENT_BEST_LOSS = 2
log_results({
'loss': 1,
'current_tries': 1,
'total_tries': 2,
'result': 'foo'
})
logger.assert_called_once()
def test_no_log_if_loss_does_not_improve(mocker):
logger = mocker.patch('freqtrade.optimize.hyperopt.logger.info')
global CURRENT_BEST_LOSS
CURRENT_BEST_LOSS = 2
log_results({
'loss': 3,
})
assert not logger.called

View File

@ -0,0 +1,166 @@
# pragma pylint: disable=missing-docstring,W0212
import os
import logging
from shutil import copyfile
from freqtrade import exchange, optimize
from freqtrade.exchange import Bittrex
from freqtrade.optimize.__init__ import testdata_path, download_pairs, download_backtesting_testdata
def _backup_file(file: str, copy_file: bool = False) -> None:
"""
Backup existing file to avoid deleting the user file
:param file: complete path to the file
:param touch_file: create an empty file in replacement
:return: None
"""
file_swp = file + '.swp'
if os.path.isfile(file):
os.rename(file, file_swp)
if copy_file:
copyfile(file_swp, file)
def _clean_test_file(file: str) -> None:
"""
Backup existing file to avoid deleting the user file
:param file: complete path to the file
:return: None
"""
file_swp = file + '.swp'
# 1. Delete file from the test
if os.path.isfile(file):
os.remove(file)
# 2. Rollback to the initial file
if os.path.isfile(file_swp):
os.rename(file_swp, file)
def test_load_data_5min_ticker(default_conf, ticker_history, mocker, caplog):
mocker.patch('freqtrade.optimize.get_ticker_history', return_value=ticker_history)
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
file = 'freqtrade/tests/testdata/BTC_ETH-5.json'
_backup_file(file, copy_file=True)
optimize.load_data(pairs=['BTC_ETH'])
assert os.path.isfile(file) is True
assert ('freqtrade.optimize',
logging.INFO,
'Download the pair: "BTC_ETH", Interval: 5 min'
) not in caplog.record_tuples
_clean_test_file(file)
def test_load_data_1min_ticker(default_conf, ticker_history, mocker, caplog):
mocker.patch('freqtrade.optimize.get_ticker_history', return_value=ticker_history)
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
file = 'freqtrade/tests/testdata/BTC_ETH-1.json'
_backup_file(file, copy_file=True)
optimize.load_data(ticker_interval=1, pairs=['BTC_ETH'])
assert os.path.isfile(file) is True
assert ('freqtrade.optimize',
logging.INFO,
'Download the pair: "BTC_ETH", Interval: 1 min'
) not in caplog.record_tuples
_clean_test_file(file)
def test_load_data_with_new_pair_1min(default_conf, ticker_history, mocker, caplog):
mocker.patch('freqtrade.optimize.get_ticker_history', return_value=ticker_history)
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
file = 'freqtrade/tests/testdata/BTC_MEME-1.json'
_backup_file(file)
optimize.load_data(ticker_interval=1, pairs=['BTC_MEME'])
assert os.path.isfile(file) is True
assert ('freqtrade.optimize',
logging.INFO,
'Download the pair: "BTC_MEME", Interval: 1 min'
) in caplog.record_tuples
_clean_test_file(file)
def test_testdata_path():
assert os.path.join('freqtrade', 'tests', 'testdata') in testdata_path()
def test_download_pairs(default_conf, ticker_history, mocker):
mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history)
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
file1_1 = 'freqtrade/tests/testdata/BTC_MEME-1.json'
file1_5 = 'freqtrade/tests/testdata/BTC_MEME-5.json'
file2_1 = 'freqtrade/tests/testdata/BTC_CFI-1.json'
file2_5 = 'freqtrade/tests/testdata/BTC_CFI-5.json'
_backup_file(file1_1)
_backup_file(file1_5)
_backup_file(file2_1)
_backup_file(file2_5)
assert download_pairs(pairs=['BTC-MEME', 'BTC-CFI']) is True
assert os.path.isfile(file1_1) is True
assert os.path.isfile(file1_5) is True
assert os.path.isfile(file2_1) is True
assert os.path.isfile(file2_5) is True
# clean files freshly downloaded
_clean_test_file(file1_1)
_clean_test_file(file1_5)
_clean_test_file(file2_1)
_clean_test_file(file2_5)
def test_download_pairs_exception(default_conf, ticker_history, mocker, caplog):
mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history)
mocker.patch('freqtrade.optimize.__init__.download_backtesting_testdata',
side_effect=BaseException('File Error'))
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
file1_1 = 'freqtrade/tests/testdata/BTC_MEME-1.json'
file1_5 = 'freqtrade/tests/testdata/BTC_MEME-5.json'
_backup_file(file1_1)
_backup_file(file1_5)
download_pairs(pairs=['BTC-MEME'])
# clean files freshly downloaded
_clean_test_file(file1_1)
_clean_test_file(file1_5)
assert ('freqtrade.optimize.__init__',
logging.INFO,
'Failed to download the pair: "BTC-MEME", Interval: 1 min'
) in caplog.record_tuples
def test_download_backtesting_testdata(default_conf, ticker_history, mocker):
mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history)
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
# Download a 1 min ticker file
file1 = 'freqtrade/tests/testdata/BTC_XEL-1.json'
_backup_file(file1)
download_backtesting_testdata(pair="BTC-XEL", interval=1)
assert os.path.isfile(file1) is True
_clean_test_file(file1)
# Download a 5 min ticker file
file2 = 'freqtrade/tests/testdata/BTC_STORJ-5.json'
_backup_file(file2)
download_backtesting_testdata(pair="BTC-STORJ", interval=5)
assert os.path.isfile(file2) is True
_clean_test_file(file2)

View File

@ -217,7 +217,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, mocker):
assert trade.close_date is not None
def test_handle_trade_experimental(default_conf, ticker, limit_buy_order, mocker, caplog):
def test_handle_trade_roi(default_conf, ticker, limit_buy_order, mocker, caplog):
default_conf.update({'experimental': {'use_sell_signal': True}})
mocker.patch.dict('freqtrade.main._CONF', default_conf)
@ -235,10 +235,46 @@ def test_handle_trade_experimental(default_conf, ticker, limit_buy_order, mocker
trade = Trade.query.first()
trade.is_open = True
# FIX: sniffing logs, suggest handle_trade should not execute_sell
# instead that responsibility should be moved out of handle_trade(),
# we might just want to check if we are in a sell condition without
# executing
# if ROI is reached we must sell
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: False)
assert handle_trade(trade)
assert ('freqtrade', logging.DEBUG, 'Executing sell due to ROI ...') in caplog.record_tuples
# if ROI is reached we must sell even if sell-signal is not signalled
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True)
assert handle_trade(trade)
assert ('freqtrade', logging.DEBUG, 'Executing sell due to ROI ...') in caplog.record_tuples
def test_handle_trade_experimental(default_conf, ticker, limit_buy_order, mocker, caplog):
default_conf.update({'experimental': {'use_sell_signal': True}})
mocker.patch.dict('freqtrade.main._CONF', default_conf)
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True)
mocker.patch.multiple('freqtrade.rpc', init=MagicMock(), send_msg=MagicMock())
mocker.patch.multiple('freqtrade.main.exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
buy=MagicMock(return_value='mocked_limit_buy'))
mocker.patch('freqtrade.main.min_roi_reached', return_value=False)
init(default_conf, create_engine('sqlite://'))
create_trade(0.001)
trade = Trade.query.first()
trade.is_open = True
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: False)
value_returned = handle_trade(trade)
assert ('freqtrade', logging.DEBUG, 'Checking sell_signal ...') in caplog.record_tuples
assert value_returned is False
mocker.patch('freqtrade.main.get_signal', side_effect=lambda s, t: True)
assert handle_trade(trade)
s = 'Executing sell due to sell signal ...'
assert ('freqtrade', logging.DEBUG, s) in caplog.record_tuples
def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, mocker):

View File

@ -1,98 +0,0 @@
# pragma pylint: disable=missing-docstring,W0212
import os
from freqtrade import exchange, optimize
from freqtrade.exchange import Bittrex
from freqtrade.optimize.backtesting import backtest
from freqtrade.optimize.__init__ import testdata_path, download_pairs, download_backtesting_testdata
def test_backtest(default_conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
data = optimize.load_data(ticker_interval=5, pairs=['BTC_ETH'])
results = backtest(default_conf['stake_amount'], optimize.preprocess(data), 10, True)
assert not results.empty
def test_1min_ticker_interval(default_conf, mocker):
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
# Run a backtesting for an exiting 5min ticker_interval
data = optimize.load_data(ticker_interval=1, pairs=['BTC_UNITEST'])
results = backtest(default_conf['stake_amount'], optimize.preprocess(data), 1, True)
assert not results.empty
def test_backtest_with_new_pair(default_conf, ticker_history, mocker):
mocker.patch('freqtrade.optimize.get_ticker_history', return_value=ticker_history)
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
optimize.load_data(ticker_interval=1, pairs=['BTC_MEME'])
file = 'freqtrade/tests/testdata/BTC_MEME-1.json'
assert os.path.isfile(file) is True
# delete file freshly downloaded
if os.path.isfile(file):
os.remove(file)
def test_testdata_path():
assert os.path.join('freqtrade', 'tests', 'testdata') in testdata_path()
def test_download_pairs(default_conf, ticker_history, mocker):
mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history)
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
file1_1 = 'freqtrade/tests/testdata/BTC_MEME-1.json'
file1_5 = 'freqtrade/tests/testdata/BTC_MEME-5.json'
file2_1 = 'freqtrade/tests/testdata/BTC_CFI-1.json'
file2_5 = 'freqtrade/tests/testdata/BTC_CFI-5.json'
assert download_pairs(pairs=['BTC-MEME', 'BTC-CFI']) is True
assert os.path.isfile(file1_1) is True
assert os.path.isfile(file1_5) is True
assert os.path.isfile(file2_1) is True
assert os.path.isfile(file2_5) is True
# delete files freshly downloaded
if os.path.isfile(file1_1):
os.remove(file1_1)
if os.path.isfile(file1_5):
os.remove(file1_5)
if os.path.isfile(file2_1):
os.remove(file2_1)
if os.path.isfile(file2_5):
os.remove(file2_5)
def test_download_backtesting_testdata(default_conf, ticker_history, mocker):
mocker.patch('freqtrade.optimize.__init__.get_ticker_history', return_value=ticker_history)
mocker.patch.dict('freqtrade.main._CONF', default_conf)
exchange._API = Bittrex({'key': '', 'secret': ''})
# Download a 1 min ticker file
file1 = 'freqtrade/tests/testdata/BTC_XEL-1.json'
download_backtesting_testdata(pair="BTC-XEL", interval=1)
assert os.path.isfile(file1) is True
if os.path.isfile(file1):
os.remove(file1)
# Download a 5 min ticker file
file2 = 'freqtrade/tests/testdata/BTC_STORJ-5.json'
download_backtesting_testdata(pair="BTC-STORJ", interval=5)
assert os.path.isfile(file2) is True
if os.path.isfile(file2):
os.remove(file2)

View File

@ -1,6 +0,0 @@
# pragma pylint: disable=missing-docstring,W0212
def test_optimizer(default_conf, mocker):
# TODO: implement test
pass

View File

@ -1,5 +1,5 @@
python-bittrex==0.2.2
SQLAlchemy==1.1.15
SQLAlchemy==1.2.0
python-telegram-bot==9.0.0
arrow==0.12.0
cachetools==2.0.1