Merge branch 'develop' into align_userdata
This commit is contained in:
commit
bcccdda7c0
@ -12,8 +12,8 @@ Special fields for the documentation (like Note boxes, ...) can be found [here](
|
|||||||
|
|
||||||
## Developer setup
|
## Developer setup
|
||||||
|
|
||||||
To configure a development environment, use best use the `setup.sh` script and answer "y" when asked "Do you want to install dependencies for dev [y/N]? ".
|
To configure a development environment, best use the `setup.sh` script and answer "y" when asked "Do you want to install dependencies for dev [y/N]? ".
|
||||||
Alternatively (if your system is not supported by the setup.sh script), follow the manual installation process and run `pip3 install -r requirements-dev.txt`.
|
Alternatively (if your system is not supported by the setup.sh script), follow the manual installation process and run `pip3 install -e .[all]`.
|
||||||
|
|
||||||
This will install all required tools for development, including `pytest`, `flake8`, `mypy`, and `coveralls`.
|
This will install all required tools for development, including `pytest`, `flake8`, `mypy`, and `coveralls`.
|
||||||
|
|
||||||
@ -156,6 +156,8 @@ git log --oneline --no-decorate --no-merges master..develop
|
|||||||
|
|
||||||
### Create github release / tag
|
### Create github release / tag
|
||||||
|
|
||||||
|
Once the PR against master is merged (best right after merging):
|
||||||
|
|
||||||
* Use the button "Draft a new release" in the Github UI (subsection releases)
|
* Use the button "Draft a new release" in the Github UI (subsection releases)
|
||||||
* Use the version-number specified as tag.
|
* Use the version-number specified as tag.
|
||||||
* Use "master" as reference (this step comes after the above PR is merged).
|
* Use "master" as reference (this step comes after the above PR is merged).
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
""" FreqTrade bot """
|
""" FreqTrade bot """
|
||||||
__version__ = '2019.6-dev'
|
__version__ = '2019.7-dev'
|
||||||
|
|
||||||
|
|
||||||
class DependencyException(Exception):
|
class DependencyException(Exception):
|
||||||
|
@ -67,7 +67,6 @@ def evaluate_result_multi(results: pd.DataFrame, freq: str, max_open_trades: int
|
|||||||
dates = pd.Series(pd.concat(dates).values, name='date')
|
dates = pd.Series(pd.concat(dates).values, name='date')
|
||||||
df2 = pd.DataFrame(np.repeat(results.values, deltas, axis=0), columns=results.columns)
|
df2 = pd.DataFrame(np.repeat(results.values, deltas, axis=0), columns=results.columns)
|
||||||
|
|
||||||
df2 = df2.astype(dtype={"open_time": "datetime64", "close_time": "datetime64"})
|
|
||||||
df2 = pd.concat([dates, df2], axis=1)
|
df2 = pd.concat([dates, df2], axis=1)
|
||||||
df2 = df2.set_index('date')
|
df2 = df2.set_index('date')
|
||||||
df_final = df2.resample(freq)[['pair']].count()
|
df_final = df2.resample(freq)[['pair']].count()
|
||||||
|
@ -51,7 +51,8 @@ class Hyperopt(Backtesting):
|
|||||||
'hyperopt_results' / 'hyperopt_results.pickle')
|
'hyperopt_results' / 'hyperopt_results.pickle')
|
||||||
self.tickerdata_pickle = (self.config['user_data_dir'] /
|
self.tickerdata_pickle = (self.config['user_data_dir'] /
|
||||||
'hyperopt_results' / 'hyperopt_tickerdata.pkl')
|
'hyperopt_results' / 'hyperopt_tickerdata.pkl')
|
||||||
self.total_tries = config.get('epochs', 0)
|
self.total_epochs = config.get('epochs', 0)
|
||||||
|
|
||||||
self.current_best_loss = 100
|
self.current_best_loss = 100
|
||||||
|
|
||||||
if not self.config.get('hyperopt_continue'):
|
if not self.config.get('hyperopt_continue'):
|
||||||
@ -128,13 +129,12 @@ class Hyperopt(Backtesting):
|
|||||||
"""
|
"""
|
||||||
results = sorted(self.trials, key=itemgetter('loss'))
|
results = sorted(self.trials, key=itemgetter('loss'))
|
||||||
best_result = results[0]
|
best_result = results[0]
|
||||||
logger.info(
|
|
||||||
'Best result:\n%s\nwith values:\n',
|
log_str = self.format_results_logstring(best_result)
|
||||||
best_result['result']
|
print(f"\nBest result:\n{log_str}\nwith values:")
|
||||||
)
|
|
||||||
pprint(best_result['params'], indent=4)
|
pprint(best_result['params'], indent=4)
|
||||||
if 'roi_t1' in best_result['params']:
|
if 'roi_t1' in best_result['params']:
|
||||||
logger.info('ROI table:')
|
print("ROI table:")
|
||||||
pprint(self.custom_hyperopt.generate_roi_table(best_result['params']), indent=4)
|
pprint(self.custom_hyperopt.generate_roi_table(best_result['params']), indent=4)
|
||||||
|
|
||||||
def log_results(self, results) -> None:
|
def log_results(self, results) -> None:
|
||||||
@ -143,22 +143,26 @@ class Hyperopt(Backtesting):
|
|||||||
"""
|
"""
|
||||||
print_all = self.config.get('print_all', False)
|
print_all = self.config.get('print_all', False)
|
||||||
if print_all or results['loss'] < self.current_best_loss:
|
if print_all or results['loss'] < self.current_best_loss:
|
||||||
# Output human-friendly index here (starting from 1)
|
log_str = self.format_results_logstring(results)
|
||||||
current = results['current_tries'] + 1
|
|
||||||
total = results['total_tries']
|
|
||||||
res = results['result']
|
|
||||||
loss = results['loss']
|
|
||||||
self.current_best_loss = results['loss']
|
|
||||||
log_msg = f'{current:5d}/{total}: {res} Objective: {loss:.5f}'
|
|
||||||
log_msg = f'*{log_msg}' if results['initial_point'] else f' {log_msg}'
|
|
||||||
if print_all:
|
if print_all:
|
||||||
print(log_msg)
|
print(log_str)
|
||||||
else:
|
else:
|
||||||
print('\n' + log_msg)
|
print('\n' + log_str)
|
||||||
else:
|
else:
|
||||||
print('.', end='')
|
print('.', end='')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def format_results_logstring(self, results) -> str:
|
||||||
|
# Output human-friendly index here (starting from 1)
|
||||||
|
current = results['current_epoch'] + 1
|
||||||
|
total = self.total_epochs
|
||||||
|
res = results['results_explanation']
|
||||||
|
loss = results['loss']
|
||||||
|
self.current_best_loss = results['loss']
|
||||||
|
log_str = f'{current:5d}/{total}: {res} Objective: {loss:.5f}'
|
||||||
|
log_str = f'*{log_str}' if results['is_initial_point'] else f' {log_str}'
|
||||||
|
return log_str
|
||||||
|
|
||||||
def has_space(self, space: str) -> bool:
|
def has_space(self, space: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Tell if a space value is contained in the configuration
|
Tell if a space value is contained in the configuration
|
||||||
@ -218,7 +222,7 @@ class Hyperopt(Backtesting):
|
|||||||
'end_date': max_date,
|
'end_date': max_date,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
result_explanation = self.format_results(results)
|
results_explanation = self.format_results(results)
|
||||||
|
|
||||||
trade_count = len(results.index)
|
trade_count = len(results.index)
|
||||||
|
|
||||||
@ -230,7 +234,7 @@ class Hyperopt(Backtesting):
|
|||||||
return {
|
return {
|
||||||
'loss': MAX_LOSS,
|
'loss': MAX_LOSS,
|
||||||
'params': params,
|
'params': params,
|
||||||
'result': result_explanation,
|
'results_explanation': results_explanation,
|
||||||
}
|
}
|
||||||
|
|
||||||
loss = self.calculate_loss(results=results, trade_count=trade_count,
|
loss = self.calculate_loss(results=results, trade_count=trade_count,
|
||||||
@ -239,12 +243,12 @@ class Hyperopt(Backtesting):
|
|||||||
return {
|
return {
|
||||||
'loss': loss,
|
'loss': loss,
|
||||||
'params': params,
|
'params': params,
|
||||||
'result': result_explanation,
|
'results_explanation': results_explanation,
|
||||||
}
|
}
|
||||||
|
|
||||||
def format_results(self, results: DataFrame) -> str:
|
def format_results(self, results: DataFrame) -> str:
|
||||||
"""
|
"""
|
||||||
Return the format result in a string
|
Return the formatted results explanation in a string
|
||||||
"""
|
"""
|
||||||
trades = len(results.index)
|
trades = len(results.index)
|
||||||
avg_profit = results.profit_percent.mean() * 100.0
|
avg_profit = results.profit_percent.mean() * 100.0
|
||||||
@ -327,25 +331,19 @@ class Hyperopt(Backtesting):
|
|||||||
with Parallel(n_jobs=config_jobs) as parallel:
|
with Parallel(n_jobs=config_jobs) as parallel:
|
||||||
jobs = parallel._effective_n_jobs()
|
jobs = parallel._effective_n_jobs()
|
||||||
logger.info(f'Effective number of parallel workers used: {jobs}')
|
logger.info(f'Effective number of parallel workers used: {jobs}')
|
||||||
EVALS = max(self.total_tries // jobs, 1)
|
EVALS = max(self.total_epochs // jobs, 1)
|
||||||
for i in range(EVALS):
|
for i in range(EVALS):
|
||||||
asked = opt.ask(n_points=jobs)
|
asked = opt.ask(n_points=jobs)
|
||||||
f_val = self.run_optimizer_parallel(parallel, asked)
|
f_val = self.run_optimizer_parallel(parallel, asked)
|
||||||
opt.tell(asked, [i['loss'] for i in f_val])
|
opt.tell(asked, [v['loss'] for v in f_val])
|
||||||
|
|
||||||
self.trials += f_val
|
|
||||||
for j in range(jobs):
|
for j in range(jobs):
|
||||||
current = i * jobs + j
|
current = i * jobs + j
|
||||||
self.log_results({
|
val = f_val[j]
|
||||||
'loss': f_val[j]['loss'],
|
val['current_epoch'] = current
|
||||||
'current_tries': current,
|
val['is_initial_point'] = current < INITIAL_POINTS
|
||||||
'initial_point': current < INITIAL_POINTS,
|
self.log_results(val)
|
||||||
'total_tries': self.total_tries,
|
self.trials.append(val)
|
||||||
'result': f_val[j]['result'],
|
logger.debug(f"Optimizer epoch evaluated: {val}")
|
||||||
})
|
|
||||||
logger.debug(f"Optimizer params: {f_val[j]['params']}")
|
|
||||||
for j in range(jobs):
|
|
||||||
logger.debug(f"Optimizer state: Xi: {opt.Xi[-j-1]}, yi: {opt.yi[-j-1]}")
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print('User interrupted..')
|
print('User interrupted..')
|
||||||
|
|
||||||
|
@ -15,9 +15,9 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from plotly import tools
|
from plotly.subplots import make_subplots
|
||||||
from plotly.offline import plot
|
from plotly.offline import plot
|
||||||
import plotly.graph_objs as go
|
import plotly.graph_objects as go
|
||||||
except ImportError:
|
except ImportError:
|
||||||
logger.exception("Module plotly not found \n Please install using `pip install plotly`")
|
logger.exception("Module plotly not found \n Please install using `pip install plotly`")
|
||||||
exit(1)
|
exit(1)
|
||||||
@ -62,7 +62,7 @@ def init_plotscript(config):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def add_indicators(fig, row, indicators: List[str], data: pd.DataFrame) -> tools.make_subplots:
|
def add_indicators(fig, row, indicators: List[str], data: pd.DataFrame) -> make_subplots:
|
||||||
"""
|
"""
|
||||||
Generator all the indicator selected by the user for a specific row
|
Generator all the indicator selected by the user for a specific row
|
||||||
:param fig: Plot figure to append to
|
:param fig: Plot figure to append to
|
||||||
@ -79,7 +79,7 @@ def add_indicators(fig, row, indicators: List[str], data: pd.DataFrame) -> tools
|
|||||||
mode='lines',
|
mode='lines',
|
||||||
name=indicator
|
name=indicator
|
||||||
)
|
)
|
||||||
fig.append_trace(scattergl, row, 1)
|
fig.add_trace(scattergl, row, 1)
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
'Indicator "%s" ignored. Reason: This indicator is not found '
|
'Indicator "%s" ignored. Reason: This indicator is not found '
|
||||||
@ -90,7 +90,7 @@ def add_indicators(fig, row, indicators: List[str], data: pd.DataFrame) -> tools
|
|||||||
return fig
|
return fig
|
||||||
|
|
||||||
|
|
||||||
def add_profit(fig, row, data: pd.DataFrame, column: str, name: str) -> tools.make_subplots:
|
def add_profit(fig, row, data: pd.DataFrame, column: str, name: str) -> make_subplots:
|
||||||
"""
|
"""
|
||||||
Add profit-plot
|
Add profit-plot
|
||||||
:param fig: Plot figure to append to
|
:param fig: Plot figure to append to
|
||||||
@ -105,12 +105,12 @@ def add_profit(fig, row, data: pd.DataFrame, column: str, name: str) -> tools.ma
|
|||||||
y=data[column],
|
y=data[column],
|
||||||
name=name,
|
name=name,
|
||||||
)
|
)
|
||||||
fig.append_trace(profit, row, 1)
|
fig.add_trace(profit, row, 1)
|
||||||
|
|
||||||
return fig
|
return fig
|
||||||
|
|
||||||
|
|
||||||
def plot_trades(fig, trades: pd.DataFrame) -> tools.make_subplots:
|
def plot_trades(fig, trades: pd.DataFrame) -> make_subplots:
|
||||||
"""
|
"""
|
||||||
Add trades to "fig"
|
Add trades to "fig"
|
||||||
"""
|
"""
|
||||||
@ -145,8 +145,8 @@ def plot_trades(fig, trades: pd.DataFrame) -> tools.make_subplots:
|
|||||||
color='red'
|
color='red'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fig.append_trace(trade_buys, 1, 1)
|
fig.add_trace(trade_buys, 1, 1)
|
||||||
fig.append_trace(trade_sells, 1, 1)
|
fig.add_trace(trade_sells, 1, 1)
|
||||||
else:
|
else:
|
||||||
logger.warning("No trades found.")
|
logger.warning("No trades found.")
|
||||||
return fig
|
return fig
|
||||||
@ -167,7 +167,7 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Define the graph
|
# Define the graph
|
||||||
fig = tools.make_subplots(
|
fig = make_subplots(
|
||||||
rows=3,
|
rows=3,
|
||||||
cols=1,
|
cols=1,
|
||||||
shared_xaxes=True,
|
shared_xaxes=True,
|
||||||
@ -189,7 +189,7 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra
|
|||||||
close=data.close,
|
close=data.close,
|
||||||
name='Price'
|
name='Price'
|
||||||
)
|
)
|
||||||
fig.append_trace(candles, 1, 1)
|
fig.add_trace(candles, 1, 1)
|
||||||
|
|
||||||
if 'buy' in data.columns:
|
if 'buy' in data.columns:
|
||||||
df_buy = data[data['buy'] == 1]
|
df_buy = data[data['buy'] == 1]
|
||||||
@ -206,7 +206,7 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra
|
|||||||
color='green',
|
color='green',
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fig.append_trace(buys, 1, 1)
|
fig.add_trace(buys, 1, 1)
|
||||||
else:
|
else:
|
||||||
logger.warning("No buy-signals found.")
|
logger.warning("No buy-signals found.")
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra
|
|||||||
color='red',
|
color='red',
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fig.append_trace(sells, 1, 1)
|
fig.add_trace(sells, 1, 1)
|
||||||
else:
|
else:
|
||||||
logger.warning("No sell-signals found.")
|
logger.warning("No sell-signals found.")
|
||||||
|
|
||||||
@ -244,8 +244,8 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra
|
|||||||
fillcolor="rgba(0,176,246,0.2)",
|
fillcolor="rgba(0,176,246,0.2)",
|
||||||
line={'color': 'rgba(255,255,255,0)'},
|
line={'color': 'rgba(255,255,255,0)'},
|
||||||
)
|
)
|
||||||
fig.append_trace(bb_lower, 1, 1)
|
fig.add_trace(bb_lower, 1, 1)
|
||||||
fig.append_trace(bb_upper, 1, 1)
|
fig.add_trace(bb_upper, 1, 1)
|
||||||
|
|
||||||
# Add indicators to main plot
|
# Add indicators to main plot
|
||||||
fig = add_indicators(fig=fig, row=1, indicators=indicators1, data=data)
|
fig = add_indicators(fig=fig, row=1, indicators=indicators1, data=data)
|
||||||
@ -258,7 +258,7 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra
|
|||||||
y=data['volume'],
|
y=data['volume'],
|
||||||
name='Volume'
|
name='Volume'
|
||||||
)
|
)
|
||||||
fig.append_trace(volume, 2, 1)
|
fig.add_trace(volume, 2, 1)
|
||||||
|
|
||||||
# Add indicators to seperate row
|
# Add indicators to seperate row
|
||||||
fig = add_indicators(fig=fig, row=3, indicators=indicators2, data=data)
|
fig = add_indicators(fig=fig, row=3, indicators=indicators2, data=data)
|
||||||
@ -281,10 +281,10 @@ def generate_profit_graph(pairs: str, tickers: Dict[str, pd.DataFrame],
|
|||||||
name='Avg close price',
|
name='Avg close price',
|
||||||
)
|
)
|
||||||
|
|
||||||
fig = tools.make_subplots(rows=3, cols=1, shared_xaxes=True, row_width=[1, 1, 1])
|
fig = make_subplots(rows=3, cols=1, shared_xaxes=True, row_width=[1, 1, 1])
|
||||||
fig['layout'].update(title="Profit plot")
|
fig['layout'].update(title="Profit plot")
|
||||||
|
|
||||||
fig.append_trace(avgclose, 1, 1)
|
fig.add_trace(avgclose, 1, 1)
|
||||||
fig = add_profit(fig, 2, df_comb, 'cum_profit', 'Profit')
|
fig = add_profit(fig, 2, df_comb, 'cum_profit', 'Profit')
|
||||||
|
|
||||||
for pair in pairs:
|
for pair in pairs:
|
||||||
|
@ -33,13 +33,13 @@ def get_mock_coro(return_value):
|
|||||||
def ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
|
def ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
|
||||||
fun, mock_ccxt_fun, **kwargs):
|
fun, mock_ccxt_fun, **kwargs):
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError)
|
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError("DeaDBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
getattr(exchange, fun)(**kwargs)
|
getattr(exchange, fun)(**kwargs)
|
||||||
assert api_mock.__dict__[mock_ccxt_fun].call_count == API_RETRY_COUNT + 1
|
assert api_mock.__dict__[mock_ccxt_fun].call_count == API_RETRY_COUNT + 1
|
||||||
|
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.BaseError)
|
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
getattr(exchange, fun)(**kwargs)
|
getattr(exchange, fun)(**kwargs)
|
||||||
assert api_mock.__dict__[mock_ccxt_fun].call_count == 1
|
assert api_mock.__dict__[mock_ccxt_fun].call_count == 1
|
||||||
@ -47,13 +47,13 @@ def ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
|
|||||||
|
|
||||||
async def async_ccxt_exception(mocker, default_conf, api_mock, fun, mock_ccxt_fun, **kwargs):
|
async def async_ccxt_exception(mocker, default_conf, api_mock, fun, mock_ccxt_fun, **kwargs):
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError)
|
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||||
await getattr(exchange, fun)(**kwargs)
|
await getattr(exchange, fun)(**kwargs)
|
||||||
assert api_mock.__dict__[mock_ccxt_fun].call_count == API_RETRY_COUNT + 1
|
assert api_mock.__dict__[mock_ccxt_fun].call_count == API_RETRY_COUNT + 1
|
||||||
|
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.BaseError)
|
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||||
await getattr(exchange, fun)(**kwargs)
|
await getattr(exchange, fun)(**kwargs)
|
||||||
assert api_mock.__dict__[mock_ccxt_fun].call_count == 1
|
assert api_mock.__dict__[mock_ccxt_fun].call_count == 1
|
||||||
@ -256,13 +256,13 @@ def test__load_async_markets(default_conf, mocker, caplog):
|
|||||||
def test__load_markets(default_conf, mocker, caplog):
|
def test__load_markets(default_conf, mocker, caplog):
|
||||||
caplog.set_level(logging.INFO)
|
caplog.set_level(logging.INFO)
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
api_mock.load_markets = MagicMock(side_effect=ccxt.BaseError())
|
api_mock.load_markets = MagicMock(side_effect=ccxt.BaseError("SomeError"))
|
||||||
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
|
||||||
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
|
||||||
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
|
||||||
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
|
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
|
||||||
Exchange(default_conf)
|
Exchange(default_conf)
|
||||||
assert log_has('Unable to initialize markets. Reason: ', caplog.record_tuples)
|
assert log_has('Unable to initialize markets. Reason: SomeError', caplog.record_tuples)
|
||||||
|
|
||||||
expected_return = {'ETH/BTC': 'available'}
|
expected_return = {'ETH/BTC': 'available'}
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
@ -305,7 +305,7 @@ def test__reload_markets_exception(default_conf, mocker, caplog):
|
|||||||
caplog.set_level(logging.DEBUG)
|
caplog.set_level(logging.DEBUG)
|
||||||
|
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
api_mock.load_markets = MagicMock(side_effect=ccxt.NetworkError)
|
api_mock.load_markets = MagicMock(side_effect=ccxt.NetworkError("LoadError"))
|
||||||
default_conf['exchange']['markets_refresh_interval'] = 10
|
default_conf['exchange']['markets_refresh_interval'] = 10
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
|
||||||
|
|
||||||
@ -634,25 +634,25 @@ def test_buy_prod(default_conf, mocker, exchange_name):
|
|||||||
|
|
||||||
# test exception handling
|
# test exception handling
|
||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds)
|
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("Not enough funds"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.buy(pair='ETH/BTC', ordertype=order_type,
|
exchange.buy(pair='ETH/BTC', ordertype=order_type,
|
||||||
amount=1, rate=200, time_in_force=time_in_force)
|
amount=1, rate=200, time_in_force=time_in_force)
|
||||||
|
|
||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder)
|
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.buy(pair='ETH/BTC', ordertype=order_type,
|
exchange.buy(pair='ETH/BTC', ordertype=order_type,
|
||||||
amount=1, rate=200, time_in_force=time_in_force)
|
amount=1, rate=200, time_in_force=time_in_force)
|
||||||
|
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError)
|
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("Network disconnect"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.buy(pair='ETH/BTC', ordertype=order_type,
|
exchange.buy(pair='ETH/BTC', ordertype=order_type,
|
||||||
amount=1, rate=200, time_in_force=time_in_force)
|
amount=1, rate=200, time_in_force=time_in_force)
|
||||||
|
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError)
|
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("Unknown error"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.buy(pair='ETH/BTC', ordertype=order_type,
|
exchange.buy(pair='ETH/BTC', ordertype=order_type,
|
||||||
amount=1, rate=200, time_in_force=time_in_force)
|
amount=1, rate=200, time_in_force=time_in_force)
|
||||||
@ -758,22 +758,22 @@ def test_sell_prod(default_conf, mocker, exchange_name):
|
|||||||
|
|
||||||
# test exception handling
|
# test exception handling
|
||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds)
|
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
|
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
|
||||||
|
|
||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder)
|
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
|
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
|
||||||
|
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError)
|
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("No Connection"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
|
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
|
||||||
|
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError)
|
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
|
exchange.sell(pair='ETH/BTC', ordertype=order_type, amount=1, rate=200)
|
||||||
|
|
||||||
@ -846,7 +846,7 @@ def test_get_balance_prod(default_conf, mocker, exchange_name):
|
|||||||
assert exchange.get_balance(currency='BTC') == 123.4
|
assert exchange.get_balance(currency='BTC') == 123.4
|
||||||
|
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.fetch_balance = MagicMock(side_effect=ccxt.BaseError)
|
api_mock.fetch_balance = MagicMock(side_effect=ccxt.BaseError("Unknown error"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
|
|
||||||
exchange.get_balance(currency='BTC')
|
exchange.get_balance(currency='BTC')
|
||||||
@ -919,7 +919,7 @@ def test_get_tickers(default_conf, mocker, exchange_name):
|
|||||||
"get_tickers", "fetch_tickers")
|
"get_tickers", "fetch_tickers")
|
||||||
|
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.fetch_tickers = MagicMock(side_effect=ccxt.NotSupported)
|
api_mock.fetch_tickers = MagicMock(side_effect=ccxt.NotSupported("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.get_tickers()
|
exchange.get_tickers()
|
||||||
|
|
||||||
@ -1101,7 +1101,7 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_
|
|||||||
|
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
with pytest.raises(OperationalException, match=r'Could not fetch ticker data*'):
|
with pytest.raises(OperationalException, match=r'Could not fetch ticker data*'):
|
||||||
api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.BaseError)
|
api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.BaseError("Unknown error"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
await exchange._async_get_candle_history(pair, "5m",
|
await exchange._async_get_candle_history(pair, "5m",
|
||||||
(arrow.utcnow().timestamp - 2000) * 1000)
|
(arrow.utcnow().timestamp - 2000) * 1000)
|
||||||
@ -1173,15 +1173,15 @@ def test_get_order_book(default_conf, mocker, order_book_l2, exchange_name):
|
|||||||
def test_get_order_book_exception(default_conf, mocker, exchange_name):
|
def test_get_order_book_exception(default_conf, mocker, exchange_name):
|
||||||
api_mock = MagicMock()
|
api_mock = MagicMock()
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NotSupported)
|
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NotSupported("Not supported"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NetworkError)
|
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NetworkError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.BaseError)
|
api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
exchange.get_order_book(pair='ETH/BTC', limit=50)
|
||||||
|
|
||||||
@ -1294,7 +1294,7 @@ def test_cancel_order(default_conf, mocker, exchange_name):
|
|||||||
assert exchange.cancel_order(order_id='_', pair='TKN/BTC') == 123
|
assert exchange.cancel_order(order_id='_', pair='TKN/BTC') == 123
|
||||||
|
|
||||||
with pytest.raises(InvalidOrderException):
|
with pytest.raises(InvalidOrderException):
|
||||||
api_mock.cancel_order = MagicMock(side_effect=ccxt.InvalidOrder)
|
api_mock.cancel_order = MagicMock(side_effect=ccxt.InvalidOrder("Did not find order"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.cancel_order(order_id='_', pair='TKN/BTC')
|
exchange.cancel_order(order_id='_', pair='TKN/BTC')
|
||||||
assert api_mock.cancel_order.call_count == 1
|
assert api_mock.cancel_order.call_count == 1
|
||||||
@ -1321,7 +1321,7 @@ def test_get_order(default_conf, mocker, exchange_name):
|
|||||||
assert exchange.get_order('X', 'TKN/BTC') == 456
|
assert exchange.get_order('X', 'TKN/BTC') == 456
|
||||||
|
|
||||||
with pytest.raises(InvalidOrderException):
|
with pytest.raises(InvalidOrderException):
|
||||||
api_mock.fetch_order = MagicMock(side_effect=ccxt.InvalidOrder)
|
api_mock.fetch_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
|
||||||
exchange.get_order(order_id='_', pair='TKN/BTC')
|
exchange.get_order(order_id='_', pair='TKN/BTC')
|
||||||
assert api_mock.fetch_order.call_count == 1
|
assert api_mock.fetch_order.call_count == 1
|
||||||
@ -1437,22 +1437,22 @@ def test_stoploss_limit_order(default_conf, mocker):
|
|||||||
|
|
||||||
# test exception handling
|
# test exception handling
|
||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds)
|
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||||
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
|
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
|
||||||
|
|
||||||
with pytest.raises(DependencyException):
|
with pytest.raises(DependencyException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder)
|
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||||
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
|
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
|
||||||
|
|
||||||
with pytest.raises(TemporaryError):
|
with pytest.raises(TemporaryError):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError)
|
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("No connection"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||||
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
|
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
|
||||||
|
|
||||||
with pytest.raises(OperationalException):
|
with pytest.raises(OperationalException):
|
||||||
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError)
|
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock)
|
||||||
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
|
exchange.stoploss_limit(pair='ETH/BTC', amount=1, stop_price=220, rate=200)
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ from arrow import Arrow
|
|||||||
from filelock import Timeout
|
from filelock import Timeout
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from freqtrade import DependencyException
|
from freqtrade import DependencyException, OperationalException
|
||||||
from freqtrade.data.converter import parse_ticker_dataframe
|
from freqtrade.data.converter import parse_ticker_dataframe
|
||||||
from freqtrade.data.history import load_tickerdata_file
|
from freqtrade.data.history import load_tickerdata_file
|
||||||
from freqtrade.optimize import setup_configuration, start_hyperopt
|
from freqtrade.optimize import setup_configuration, start_hyperopt
|
||||||
@ -189,6 +189,13 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
|||||||
assert hasattr(x, "ticker_interval")
|
assert hasattr(x, "ticker_interval")
|
||||||
|
|
||||||
|
|
||||||
|
def test_hyperoptresolver_wrongname(mocker, default_conf, caplog) -> None:
|
||||||
|
default_conf.update({'hyperopt': "NonExistingHyperoptClass"})
|
||||||
|
|
||||||
|
with pytest.raises(OperationalException, match=r'Impossible to load Hyperopt.*'):
|
||||||
|
HyperOptResolver(default_conf, ).hyperopt
|
||||||
|
|
||||||
|
|
||||||
def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None:
|
def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None:
|
||||||
|
|
||||||
hl = DefaultHyperOptLoss
|
hl = DefaultHyperOptLoss
|
||||||
@ -196,9 +203,15 @@ def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None:
|
|||||||
'freqtrade.resolvers.hyperopt_resolver.HyperOptLossResolver._load_hyperoptloss',
|
'freqtrade.resolvers.hyperopt_resolver.HyperOptLossResolver._load_hyperoptloss',
|
||||||
MagicMock(return_value=hl)
|
MagicMock(return_value=hl)
|
||||||
)
|
)
|
||||||
x = HyperOptResolver(default_conf, ).hyperopt
|
x = HyperOptLossResolver(default_conf, ).hyperoptloss
|
||||||
assert hasattr(x, "populate_indicators")
|
assert hasattr(x, "hyperopt_loss_function")
|
||||||
assert hasattr(x, "ticker_interval")
|
|
||||||
|
|
||||||
|
def test_hyperoptlossresolver_wrongname(mocker, default_conf, caplog) -> None:
|
||||||
|
default_conf.update({'hyperopt_loss': "NonExistingLossClass"})
|
||||||
|
|
||||||
|
with pytest.raises(OperationalException, match=r'Impossible to load HyperoptLoss.*'):
|
||||||
|
HyperOptLossResolver(default_conf, ).hyperopt
|
||||||
|
|
||||||
|
|
||||||
def test_start(mocker, default_conf, caplog) -> None:
|
def test_start(mocker, default_conf, caplog) -> None:
|
||||||
@ -360,13 +373,13 @@ def test_onlyprofit_loss_prefers_higher_profits(default_conf, hyperopt_results)
|
|||||||
|
|
||||||
def test_log_results_if_loss_improves(hyperopt, capsys) -> None:
|
def test_log_results_if_loss_improves(hyperopt, capsys) -> None:
|
||||||
hyperopt.current_best_loss = 2
|
hyperopt.current_best_loss = 2
|
||||||
|
hyperopt.total_epochs = 2
|
||||||
hyperopt.log_results(
|
hyperopt.log_results(
|
||||||
{
|
{
|
||||||
'loss': 1,
|
'loss': 1,
|
||||||
'current_tries': 1,
|
'current_epoch': 1,
|
||||||
'total_tries': 2,
|
'results_explanation': 'foo.',
|
||||||
'result': 'foo.',
|
'is_initial_point': False
|
||||||
'initial_point': False
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
@ -423,7 +436,7 @@ def test_roi_table_generation(hyperopt) -> None:
|
|||||||
assert hyperopt.custom_hyperopt.generate_roi_table(params) == {0: 6, 15: 3, 25: 1, 30: 0}
|
assert hyperopt.custom_hyperopt.generate_roi_table(params) == {0: 6, 15: 3, 25: 1, 30: 0}
|
||||||
|
|
||||||
|
|
||||||
def test_start_calls_optimizer(mocker, default_conf, caplog) -> None:
|
def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None:
|
||||||
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
|
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
|
||||||
mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
|
mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
|
||||||
mocker.patch(
|
mocker.patch(
|
||||||
@ -433,7 +446,7 @@ def test_start_calls_optimizer(mocker, default_conf, caplog) -> None:
|
|||||||
|
|
||||||
parallel = mocker.patch(
|
parallel = mocker.patch(
|
||||||
'freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel',
|
'freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel',
|
||||||
MagicMock(return_value=[{'loss': 1, 'result': 'foo result', 'params': {}}])
|
MagicMock(return_value=[{'loss': 1, 'results_explanation': 'foo result', 'params': {}}])
|
||||||
)
|
)
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
@ -447,8 +460,11 @@ def test_start_calls_optimizer(mocker, default_conf, caplog) -> None:
|
|||||||
hyperopt.strategy.tickerdata_to_dataframe = MagicMock()
|
hyperopt.strategy.tickerdata_to_dataframe = MagicMock()
|
||||||
|
|
||||||
hyperopt.start()
|
hyperopt.start()
|
||||||
|
|
||||||
parallel.assert_called_once()
|
parallel.assert_called_once()
|
||||||
assert log_has('Best result:\nfoo result\nwith values:\n', caplog.record_tuples)
|
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert 'Best result:\n* 1/1: foo result Objective: 1.00000\nwith values:\n' in out
|
||||||
assert dumper.called
|
assert dumper.called
|
||||||
# Should be called twice, once for tickerdata, once to save evaluations
|
# Should be called twice, once for tickerdata, once to save evaluations
|
||||||
assert dumper.call_count == 2
|
assert dumper.call_count == 2
|
||||||
@ -588,7 +604,7 @@ def test_generate_optimizer(mocker, default_conf) -> None:
|
|||||||
}
|
}
|
||||||
response_expected = {
|
response_expected = {
|
||||||
'loss': 1.9840569076926293,
|
'loss': 1.9840569076926293,
|
||||||
'result': ' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC '
|
'results_explanation': ' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC '
|
||||||
'( 2.31Σ%). Avg duration 100.0 mins.',
|
'( 2.31Σ%). Avg duration 100.0 mins.',
|
||||||
'params': optimizer_param
|
'params': optimizer_param
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ from copy import deepcopy
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
import plotly.graph_objs as go
|
import plotly.graph_objects as go
|
||||||
from plotly import tools
|
from plotly.subplots import make_subplots
|
||||||
|
|
||||||
from freqtrade.configuration import Arguments, TimeRange
|
from freqtrade.configuration import Arguments, TimeRange
|
||||||
from freqtrade.data import history
|
from freqtrade.data import history
|
||||||
@ -29,7 +29,7 @@ def find_trace_in_fig_data(data, search_string: str):
|
|||||||
|
|
||||||
|
|
||||||
def generage_empty_figure():
|
def generage_empty_figure():
|
||||||
return tools.make_subplots(
|
return make_subplots(
|
||||||
rows=3,
|
rows=3,
|
||||||
cols=1,
|
cols=1,
|
||||||
shared_xaxes=True,
|
shared_xaxes=True,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# requirements without requirements installable via conda
|
# requirements without requirements installable via conda
|
||||||
# mainly used for Raspberry pi installs
|
# mainly used for Raspberry pi installs
|
||||||
ccxt==1.18.860
|
ccxt==1.18.992
|
||||||
SQLAlchemy==1.3.5
|
SQLAlchemy==1.3.6
|
||||||
python-telegram-bot==11.1.0
|
python-telegram-bot==11.1.0
|
||||||
arrow==0.14.2
|
arrow==0.14.3
|
||||||
cachetools==3.1.1
|
cachetools==3.1.1
|
||||||
requests==2.22.0
|
requests==2.22.0
|
||||||
urllib3==1.24.2 # pyup: ignore
|
urllib3==1.24.2 # pyup: ignore
|
||||||
@ -29,4 +29,4 @@ python-rapidjson==0.7.2
|
|||||||
sdnotify==0.3.2
|
sdnotify==0.3.2
|
||||||
|
|
||||||
# Api server
|
# Api server
|
||||||
flask==1.0.3
|
flask==1.1.1
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
-r requirements.txt
|
-r requirements.txt
|
||||||
-r requirements-plot.txt
|
-r requirements-plot.txt
|
||||||
|
|
||||||
flake8==3.7.7
|
coveralls==1.8.1
|
||||||
|
flake8==3.7.8
|
||||||
flake8-type-annotations==0.1.0
|
flake8-type-annotations==0.1.0
|
||||||
flake8-tidy-imports==2.0.0
|
flake8-tidy-imports==2.0.0
|
||||||
pytest==5.0.0
|
mypy==0.720
|
||||||
pytest-mock==1.10.4
|
pytest==5.0.1
|
||||||
pytest-asyncio==0.10.0
|
pytest-asyncio==0.10.0
|
||||||
pytest-cov==2.7.1
|
pytest-cov==2.7.1
|
||||||
|
pytest-mock==1.10.4
|
||||||
pytest-random-order==1.0.4
|
pytest-random-order==1.0.4
|
||||||
coveralls==1.8.1
|
|
||||||
mypy==0.711
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Include all requirements to run the bot.
|
# Include all requirements to run the bot.
|
||||||
-r requirements.txt
|
-r requirements.txt
|
||||||
|
|
||||||
plotly==3.10.0
|
plotly==4.0.0
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Load common requirements
|
# Load common requirements
|
||||||
-r requirements-common.txt
|
-r requirements-common.txt
|
||||||
|
|
||||||
numpy==1.16.4
|
numpy==1.17.0
|
||||||
pandas==0.24.2
|
pandas==0.25.0
|
||||||
scipy==1.3.0
|
scipy==1.3.0
|
||||||
|
39
setup.py
39
setup.py
@ -8,6 +8,24 @@ if version_info.major == 3 and version_info.minor < 6 or \
|
|||||||
|
|
||||||
from freqtrade import __version__
|
from freqtrade import __version__
|
||||||
|
|
||||||
|
# Requirements used for submodules
|
||||||
|
api = ['flask']
|
||||||
|
plot = ['plotly>=4.0']
|
||||||
|
|
||||||
|
develop = [
|
||||||
|
'coveralls',
|
||||||
|
'flake8',
|
||||||
|
'flake8-type-annotations',
|
||||||
|
'flake8-tidy-imports',
|
||||||
|
'mypy',
|
||||||
|
'pytest',
|
||||||
|
'pytest-asyncio',
|
||||||
|
'pytest-cov',
|
||||||
|
'pytest-mock',
|
||||||
|
'pytest-random-order',
|
||||||
|
]
|
||||||
|
|
||||||
|
all_extra = api + plot + develop
|
||||||
|
|
||||||
setup(name='freqtrade',
|
setup(name='freqtrade',
|
||||||
version=__version__,
|
version=__version__,
|
||||||
@ -20,26 +38,37 @@ setup(name='freqtrade',
|
|||||||
setup_requires=['pytest-runner', 'numpy'],
|
setup_requires=['pytest-runner', 'numpy'],
|
||||||
tests_require=['pytest', 'pytest-mock', 'pytest-cov'],
|
tests_require=['pytest', 'pytest-mock', 'pytest-cov'],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'ccxt',
|
# from requirements-common.txt
|
||||||
|
'ccxt>=1.18',
|
||||||
'SQLAlchemy',
|
'SQLAlchemy',
|
||||||
'python-telegram-bot',
|
'python-telegram-bot',
|
||||||
'arrow',
|
'arrow',
|
||||||
|
'cachetools',
|
||||||
'requests',
|
'requests',
|
||||||
'urllib3',
|
'urllib3',
|
||||||
'wrapt',
|
'wrapt',
|
||||||
'pandas',
|
|
||||||
'scikit-learn',
|
'scikit-learn',
|
||||||
'scipy',
|
|
||||||
'joblib',
|
'joblib',
|
||||||
'jsonschema',
|
'jsonschema',
|
||||||
'TA-Lib',
|
'TA-Lib',
|
||||||
'tabulate',
|
'tabulate',
|
||||||
'cachetools',
|
|
||||||
'coinmarketcap',
|
'coinmarketcap',
|
||||||
'scikit-optimize',
|
'scikit-optimize',
|
||||||
|
'filelock',
|
||||||
|
'py_find_1st',
|
||||||
'python-rapidjson',
|
'python-rapidjson',
|
||||||
'py_find_1st'
|
'sdnotify',
|
||||||
|
# from requirements.txt
|
||||||
|
'numpy',
|
||||||
|
'pandas',
|
||||||
|
'scipy',
|
||||||
],
|
],
|
||||||
|
extras_require={
|
||||||
|
'api': api,
|
||||||
|
'dev': all_extra,
|
||||||
|
'plot': plot,
|
||||||
|
'all': all_extra,
|
||||||
|
},
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
entry_points={
|
entry_points={
|
||||||
|
Loading…
Reference in New Issue
Block a user