Merge branch 'develop_current' into backslap_develop

This commit is contained in:
Gert 2018-07-31 17:07:30 -07:00
commit 3428b6666b
19 changed files with 204 additions and 607 deletions

View File

@ -15,7 +15,8 @@ WORKDIR /freqtrade
# Install dependencies
COPY requirements.txt /freqtrade/
RUN pip install -r requirements.txt
RUN pip install numpy \
&& pip install -r requirements.txt
# Install and execute
COPY . /freqtrade/

View File

@ -17,6 +17,7 @@
"name": "bittrex",
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"ccxt_rate_limit": true,
"pair_whitelist": [
"ETH/BTC",
"LTC/BTC",

View File

@ -26,6 +26,7 @@
"name": "bittrex",
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"ccxt_rate_limit": true,
"pair_whitelist": [
"ETH/BTC",
"LTC/BTC",

View File

@ -56,23 +56,29 @@ Reset parameter will hard reset your branch (only if you are on `master` or `dev
Config parameter is a `config.json` configurator. This script will ask you questions to setup your bot and create your `config.json`.
## Manual installation - Linux/MacOS
The following steps are made for Linux/MacOS environment
**1. Clone the repo**
### 1. Clone the repo
```bash
git clone git@github.com:freqtrade/freqtrade.git
git checkout develop
cd freqtrade
```
**2. Create the config file**
### 2. Create the config file
Switch `"dry_run": true,`
```bash
cp config.json.example config.json
vi config.json
```
**3. Build your docker image and run it**
### 3. Build your docker image and run it
```bash
docker build -t freqtrade .
docker run --rm -v /etc/localtime:/etc/localtime:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade

View File

@ -91,7 +91,7 @@ class Exchange(object):
'secret': exchange_config.get('secret'),
'password': exchange_config.get('password'),
'uid': exchange_config.get('uid', ''),
'enableRateLimit': True,
'enableRateLimit': exchange_config.get('ccxt_rate_limit', True),
})
except (KeyError, AttributeError):
raise OperationalException(f'Exchange {name} is not supported')

View File

@ -8,10 +8,8 @@ from unittest.mock import MagicMock
import arrow
import pytest
from jsonschema import validate
from telegram import Chat, Message, Update
from freqtrade import constants
from freqtrade.exchange.exchange_helpers import parse_ticker_dataframe
from freqtrade.exchange import Exchange
from freqtrade.freqtradebot import FreqtradeBot
@ -127,7 +125,6 @@ def default_conf():
"db_url": "sqlite://",
"loglevel": logging.DEBUG,
}
validate(configuration, constants.CONF_SCHEMA)
return configuration

View File

@ -1,7 +1,6 @@
# pragma pylint: disable=missing-docstring, C0103, bad-continuation, global-statement
# pragma pylint: disable=protected-access
import logging
from copy import deepcopy
from datetime import datetime
from random import randint
from unittest.mock import MagicMock, PropertyMock
@ -15,8 +14,6 @@ from freqtrade.tests.conftest import get_patched_exchange, log_has
def ccxt_exceptionhandlers(mocker, default_conf, api_mock, fun, mock_ccxt_fun, **kwargs):
"""Function to test ccxt exception handling """
with pytest.raises(TemporaryError):
api_mock.__dict__[mock_ccxt_fun] = MagicMock(side_effect=ccxt.NetworkError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
@ -167,12 +164,11 @@ def test_validate_pairs_not_compatible(default_conf, mocker):
api_mock.load_markets = MagicMock(return_value={
'ETH/BTC': '', 'TKN/BTC': '', 'TRST/BTC': '', 'SWT/BTC': '', 'BCC/BTC': ''
})
conf = deepcopy(default_conf)
conf['stake_currency'] = 'ETH'
default_conf['stake_currency'] = 'ETH'
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
with pytest.raises(OperationalException, match=r'not compatible'):
Exchange(conf)
Exchange(default_conf)
def test_validate_pairs_exception(default_conf, mocker, caplog):
@ -197,8 +193,7 @@ def test_validate_pairs_exception(default_conf, mocker, caplog):
def test_validate_pairs_stake_exception(default_conf, mocker, caplog):
caplog.set_level(logging.INFO)
conf = deepcopy(default_conf)
conf['stake_currency'] = 'ETH'
default_conf['stake_currency'] = 'ETH'
api_mock = MagicMock()
api_mock.name = MagicMock(return_value='binance')
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock)
@ -208,7 +203,7 @@ def test_validate_pairs_stake_exception(default_conf, mocker, caplog):
OperationalException,
match=r'Pair ETH/BTC not compatible with stake_currency: ETH'
):
Exchange(conf)
Exchange(default_conf)
def test_validate_timeframes(default_conf, mocker):

View File

@ -3,7 +3,6 @@
import json
import math
import random
from copy import deepcopy
from typing import List
from unittest.mock import MagicMock
@ -164,9 +163,6 @@ def _trend_alternate(dataframe=None, metadata=None):
# Unit tests
def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> None:
"""
Test setup_configuration() function
"""
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(default_conf)
))
@ -205,9 +201,6 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> None:
"""
Test setup_configuration() function
"""
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(default_conf)
))
@ -276,15 +269,10 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None:
"""
Test setup_configuration() function
"""
conf = deepcopy(default_conf)
conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(conf)
read_data=json.dumps(default_conf)
))
args = [
@ -298,9 +286,6 @@ def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog
def test_start(mocker, fee, default_conf, caplog) -> None:
"""
Test start() function
"""
start_mock = MagicMock()
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
patch_exchange(mocker)
@ -323,9 +308,6 @@ def test_start(mocker, fee, default_conf, caplog) -> None:
def test_backtesting_init(mocker, default_conf) -> None:
"""
Test Backtesting._init() method
"""
patch_exchange(mocker)
get_fee = mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.5))
backtesting = Backtesting(default_conf)
@ -339,9 +321,6 @@ def test_backtesting_init(mocker, default_conf) -> None:
def test_tickerdata_to_dataframe(default_conf, mocker) -> None:
"""
Test Backtesting.tickerdata_to_dataframe() method
"""
patch_exchange(mocker)
timerange = TimeRange(None, 'line', 0, -100)
tick = optimize.load_tickerdata_file(None, 'UNITTEST/BTC', '1m', timerange=timerange)
@ -358,9 +337,6 @@ def test_tickerdata_to_dataframe(default_conf, mocker) -> None:
def test_get_timeframe(default_conf, mocker) -> None:
"""
Test Backtesting.get_timeframe() method
"""
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
@ -377,9 +353,6 @@ def test_get_timeframe(default_conf, mocker) -> None:
def test_generate_text_table(default_conf, mocker):
"""
Test Backtesting.generate_text_table() method
"""
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
@ -408,9 +381,6 @@ def test_generate_text_table(default_conf, mocker):
def test_generate_text_table_sell_reason(default_conf, mocker):
"""
Test Backtesting.generate_text_table_sell_reason() method
"""
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
@ -437,10 +407,6 @@ def test_generate_text_table_sell_reason(default_conf, mocker):
def test_backtesting_start(default_conf, mocker, caplog) -> None:
"""
Test Backtesting.start() method
"""
def get_timeframe(input1, input2):
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
@ -454,15 +420,14 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
get_timeframe=get_timeframe,
)
conf = deepcopy(default_conf)
conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
conf['ticker_interval'] = 1
conf['live'] = False
conf['datadir'] = None
conf['export'] = None
conf['timerange'] = '-100'
default_conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
default_conf['ticker_interval'] = 1
default_conf['live'] = False
default_conf['datadir'] = None
default_conf['export'] = None
default_conf['timerange'] = '-100'
backtesting = Backtesting(conf)
backtesting = Backtesting(default_conf)
backtesting.start()
# check the logs, that will contain the backtest result
exists = [
@ -477,10 +442,6 @@ def test_backtesting_start(default_conf, mocker, caplog) -> None:
def test_backtesting_start_no_data(default_conf, mocker, caplog) -> None:
"""
Test Backtesting.start() method if no data is found
"""
def get_timeframe(input1, input2):
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)
@ -494,15 +455,14 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog) -> None:
get_timeframe=get_timeframe,
)
conf = deepcopy(default_conf)
conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
conf['ticker_interval'] = "1m"
conf['live'] = False
conf['datadir'] = None
conf['export'] = None
conf['timerange'] = '20180101-20180102'
default_conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
default_conf['ticker_interval'] = "1m"
default_conf['live'] = False
default_conf['datadir'] = None
default_conf['export'] = None
default_conf['timerange'] = '20180101-20180102'
backtesting = Backtesting(conf)
backtesting = Backtesting(default_conf)
backtesting.start()
# check the logs, that will contain the backtest result
@ -510,9 +470,6 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog) -> None:
def test_backtest(default_conf, fee, mocker) -> None:
"""
Test Backtesting.backtest() method
"""
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
@ -560,9 +517,6 @@ def test_backtest(default_conf, fee, mocker) -> None:
def test_backtest_1min_ticker_interval(default_conf, fee, mocker) -> None:
"""
Test Backtesting.backtest() method with 1 min ticker
"""
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
@ -583,9 +537,6 @@ def test_backtest_1min_ticker_interval(default_conf, fee, mocker) -> None:
def test_processed(default_conf, mocker) -> None:
"""
Test Backtesting.backtest() method with offline data
"""
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
@ -725,15 +676,14 @@ def test_backtest_record(default_conf, fee, mocker):
def test_backtest_start_live(default_conf, mocker, caplog):
conf = deepcopy(default_conf)
conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
default_conf['exchange']['pair_whitelist'] = ['UNITTEST/BTC']
mocker.patch('freqtrade.exchange.Exchange.get_ticker_history',
new=lambda s, n, i: _load_pair_as_ticks(n, i))
patch_exchange(mocker)
mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', MagicMock())
mocker.patch('freqtrade.optimize.backtesting.Backtesting._generate_text_table', MagicMock())
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(conf)
read_data=json.dumps(default_conf)
))
args = MagicMock()

View File

@ -1,6 +1,5 @@
# pragma pylint: disable=missing-docstring,W0212,C0103
import os
from copy import deepcopy
from unittest.mock import MagicMock
import pandas as pd
@ -12,29 +11,22 @@ from freqtrade.strategy.resolver import StrategyResolver
from freqtrade.tests.conftest import log_has, patch_exchange
from freqtrade.tests.optimize.test_backtesting import get_args
# Avoid to reinit the same object again and again
_HYPEROPT_INITIALIZED = False
_HYPEROPT = None
@pytest.fixture(scope='function')
def init_hyperopt(default_conf, mocker):
global _HYPEROPT_INITIALIZED, _HYPEROPT
if not _HYPEROPT_INITIALIZED:
patch_exchange(mocker)
_HYPEROPT = Hyperopt(default_conf)
_HYPEROPT_INITIALIZED = True
def hyperopt(default_conf, mocker):
patch_exchange(mocker)
return Hyperopt(default_conf)
# Functions for recurrent object patching
def create_trials(mocker) -> None:
def create_trials(mocker, hyperopt) -> None:
"""
When creating trials, mock the hyperopt Trials so that *by default*
- we don't create any pickle'd files in the filesystem
- we might have a pickle'd file so make sure that we return
false when looking for it
"""
_HYPEROPT.trials_file = os.path.join('freqtrade', 'tests', 'optimize', 'ut_trials.pickle')
hyperopt.trials_file = os.path.join('freqtrade', 'tests', 'optimize', 'ut_trials.pickle')
mocker.patch('freqtrade.optimize.hyperopt.os.path.exists', return_value=False)
mocker.patch('freqtrade.optimize.hyperopt.os.path.getsize', return_value=1)
@ -45,9 +37,6 @@ def create_trials(mocker) -> None:
def test_start(mocker, default_conf, caplog) -> None:
"""
Test start() function
"""
start_mock = MagicMock()
mocker.patch(
'freqtrade.configuration.Configuration._load_config_file',
@ -76,8 +65,7 @@ def test_start(mocker, default_conf, caplog) -> None:
assert start_mock.call_count == 1
def test_loss_calculation_prefer_correct_trade_count(init_hyperopt) -> None:
hyperopt = _HYPEROPT
def test_loss_calculation_prefer_correct_trade_count(hyperopt) -> None:
StrategyResolver({'strategy': 'DefaultStrategy'})
correct = hyperopt.calculate_loss(1, hyperopt.target_trades, 20)
@ -87,17 +75,13 @@ def test_loss_calculation_prefer_correct_trade_count(init_hyperopt) -> None:
assert under > correct
def test_loss_calculation_prefer_shorter_trades(init_hyperopt) -> None:
hyperopt = _HYPEROPT
def test_loss_calculation_prefer_shorter_trades(hyperopt) -> None:
shorter = hyperopt.calculate_loss(1, 100, 20)
longer = hyperopt.calculate_loss(1, 100, 30)
assert shorter < longer
def test_loss_calculation_has_limited_profit(init_hyperopt) -> None:
hyperopt = _HYPEROPT
def test_loss_calculation_has_limited_profit(hyperopt) -> None:
correct = hyperopt.calculate_loss(hyperopt.expected_max_profit, hyperopt.target_trades, 20)
over = hyperopt.calculate_loss(hyperopt.expected_max_profit * 2, hyperopt.target_trades, 20)
under = hyperopt.calculate_loss(hyperopt.expected_max_profit / 2, hyperopt.target_trades, 20)
@ -105,8 +89,7 @@ def test_loss_calculation_has_limited_profit(init_hyperopt) -> None:
assert under > correct
def test_log_results_if_loss_improves(init_hyperopt, capsys) -> None:
hyperopt = _HYPEROPT
def test_log_results_if_loss_improves(hyperopt, capsys) -> None:
hyperopt.current_best_loss = 2
hyperopt.log_results(
{
@ -120,8 +103,7 @@ def test_log_results_if_loss_improves(init_hyperopt, capsys) -> None:
assert ' 1/2: foo. Loss 1.00000' in out
def test_no_log_if_loss_does_not_improve(init_hyperopt, caplog) -> None:
hyperopt = _HYPEROPT
def test_no_log_if_loss_does_not_improve(hyperopt, caplog) -> None:
hyperopt.current_best_loss = 2
hyperopt.log_results(
{
@ -131,13 +113,10 @@ def test_no_log_if_loss_does_not_improve(init_hyperopt, caplog) -> None:
assert caplog.record_tuples == []
def test_save_trials_saves_trials(mocker, init_hyperopt, caplog) -> None:
trials = create_trials(mocker)
def test_save_trials_saves_trials(mocker, hyperopt, caplog) -> None:
trials = create_trials(mocker, hyperopt)
mock_dump = mocker.patch('freqtrade.optimize.hyperopt.dump', return_value=None)
hyperopt = _HYPEROPT
_HYPEROPT.trials = trials
hyperopt.trials = trials
hyperopt.save_trials()
trials_file = os.path.join('freqtrade', 'tests', 'optimize', 'ut_trials.pickle')
@ -148,11 +127,9 @@ def test_save_trials_saves_trials(mocker, init_hyperopt, caplog) -> None:
mock_dump.assert_called_once()
def test_read_trials_returns_trials_file(mocker, init_hyperopt, caplog) -> None:
trials = create_trials(mocker)
def test_read_trials_returns_trials_file(mocker, hyperopt, caplog) -> None:
trials = create_trials(mocker, hyperopt)
mock_load = mocker.patch('freqtrade.optimize.hyperopt.load', return_value=trials)
hyperopt = _HYPEROPT
hyperopt_trial = hyperopt.read_trials()
trials_file = os.path.join('freqtrade', 'tests', 'optimize', 'ut_trials.pickle')
assert log_has(
@ -163,7 +140,7 @@ def test_read_trials_returns_trials_file(mocker, init_hyperopt, caplog) -> None:
mock_load.assert_called_once()
def test_roi_table_generation(init_hyperopt) -> None:
def test_roi_table_generation(hyperopt) -> None:
params = {
'roi_t1': 5,
'roi_t2': 10,
@ -173,11 +150,10 @@ def test_roi_table_generation(init_hyperopt) -> None:
'roi_p3': 3,
}
hyperopt = _HYPEROPT
assert hyperopt.generate_roi_table(params) == {0: 6, 15: 3, 25: 1, 30: 0}
def test_start_calls_optimizer(mocker, init_hyperopt, default_conf, caplog) -> None:
def test_start_calls_optimizer(mocker, default_conf, caplog) -> None:
dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock())
mocker.patch('freqtrade.optimize.hyperopt.load_data', MagicMock())
mocker.patch('freqtrade.optimize.hyperopt.multiprocessing.cpu_count', MagicMock(return_value=1))
@ -187,13 +163,12 @@ def test_start_calls_optimizer(mocker, init_hyperopt, default_conf, caplog) -> N
)
patch_exchange(mocker)
conf = deepcopy(default_conf)
conf.update({'config': 'config.json.example'})
conf.update({'epochs': 1})
conf.update({'timerange': None})
conf.update({'spaces': 'all'})
default_conf.update({'config': 'config.json.example'})
default_conf.update({'epochs': 1})
default_conf.update({'timerange': None})
default_conf.update({'spaces': 'all'})
hyperopt = Hyperopt(conf)
hyperopt = Hyperopt(default_conf)
hyperopt.tickerdata_to_dataframe = MagicMock()
hyperopt.start()
@ -203,11 +178,7 @@ def test_start_calls_optimizer(mocker, init_hyperopt, default_conf, caplog) -> N
assert dumper.called
def test_format_results(init_hyperopt):
"""
Test Hyperopt.format_results()
"""
def test_format_results(hyperopt):
# Test with BTC as stake_currency
trades = [
('ETH/BTC', 2, 2, 123),
@ -217,7 +188,7 @@ def test_format_results(init_hyperopt):
labels = ['currency', 'profit_percent', 'profit_abs', 'trade_duration']
df = pd.DataFrame.from_records(trades, columns=labels)
result = _HYPEROPT.format_results(df)
result = hyperopt.format_results(df)
assert result.find(' 66.67%')
assert result.find('Total profit 1.00000000 BTC')
assert result.find('2.0000Σ %')
@ -229,25 +200,25 @@ def test_format_results(init_hyperopt):
('XPR/EUR', -1, -2, -246)
]
df = pd.DataFrame.from_records(trades, columns=labels)
result = _HYPEROPT.format_results(df)
result = hyperopt.format_results(df)
assert result.find('Total profit 1.00000000 EUR')
def test_has_space(init_hyperopt):
_HYPEROPT.config.update({'spaces': ['buy', 'roi']})
assert _HYPEROPT.has_space('roi')
assert _HYPEROPT.has_space('buy')
assert not _HYPEROPT.has_space('stoploss')
def test_has_space(hyperopt):
hyperopt.config.update({'spaces': ['buy', 'roi']})
assert hyperopt.has_space('roi')
assert hyperopt.has_space('buy')
assert not hyperopt.has_space('stoploss')
_HYPEROPT.config.update({'spaces': ['all']})
assert _HYPEROPT.has_space('buy')
hyperopt.config.update({'spaces': ['all']})
assert hyperopt.has_space('buy')
def test_populate_indicators(init_hyperopt) -> None:
def test_populate_indicators(hyperopt) -> None:
tick = load_tickerdata_file(None, 'UNITTEST/BTC', '1m')
tickerlist = {'UNITTEST/BTC': tick}
dataframes = _HYPEROPT.tickerdata_to_dataframe(tickerlist)
dataframe = _HYPEROPT.populate_indicators(dataframes['UNITTEST/BTC'], {'pair': 'UNITTEST/BTC'})
dataframes = hyperopt.tickerdata_to_dataframe(tickerlist)
dataframe = hyperopt.populate_indicators(dataframes['UNITTEST/BTC'], {'pair': 'UNITTEST/BTC'})
# Check if some indicators are generated. We will not test all of them
assert 'adx' in dataframe
@ -255,13 +226,13 @@ def test_populate_indicators(init_hyperopt) -> None:
assert 'rsi' in dataframe
def test_buy_strategy_generator(init_hyperopt) -> None:
def test_buy_strategy_generator(hyperopt) -> None:
tick = load_tickerdata_file(None, 'UNITTEST/BTC', '1m')
tickerlist = {'UNITTEST/BTC': tick}
dataframes = _HYPEROPT.tickerdata_to_dataframe(tickerlist)
dataframe = _HYPEROPT.populate_indicators(dataframes['UNITTEST/BTC'], {'pair': 'UNITTEST/BTC'})
dataframes = hyperopt.tickerdata_to_dataframe(tickerlist)
dataframe = hyperopt.populate_indicators(dataframes['UNITTEST/BTC'], {'pair': 'UNITTEST/BTC'})
populate_buy_trend = _HYPEROPT.buy_strategy_generator(
populate_buy_trend = hyperopt.buy_strategy_generator(
{
'adx-value': 20,
'fastd-value': 20,
@ -280,11 +251,10 @@ def test_buy_strategy_generator(init_hyperopt) -> None:
assert 1 in result['buy']
def test_generate_optimizer(mocker, init_hyperopt, default_conf) -> None:
conf = deepcopy(default_conf)
conf.update({'config': 'config.json.example'})
conf.update({'timerange': None})
conf.update({'spaces': 'all'})
def test_generate_optimizer(mocker, default_conf) -> None:
default_conf.update({'config': 'config.json.example'})
default_conf.update({'timerange': None})
default_conf.update({'spaces': 'all'})
trades = [
('POWR/BTC', 0.023117, 0.000233, 100)
@ -324,6 +294,6 @@ def test_generate_optimizer(mocker, init_hyperopt, default_conf) -> None:
'params': optimizer_param
}
hyperopt = Hyperopt(conf)
hyperopt = Hyperopt(default_conf)
generate_optimizer_value = hyperopt.generate_optimizer(list(optimizer_param.values()))
assert generate_optimizer_value == response_expected

View File

@ -11,8 +11,8 @@ from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.persistence import Trade
from freqtrade.rpc import RPC, RPCException
from freqtrade.state import State
from freqtrade.tests.test_freqtradebot import (patch_coinmarketcap,
patch_get_signal)
from freqtrade.tests.test_freqtradebot import patch_get_signal
from freqtrade.tests.conftest import patch_coinmarketcap
# Functions for recurrent object patching
@ -278,9 +278,6 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, markets,
def test_rpc_balance_handle(default_conf, mocker):
"""
Test rpc_balance() method
"""
mock_balance = {
'BTC': {
'free': 10.0,

View File

@ -1,7 +1,6 @@
# pragma pylint: disable=missing-docstring, C0103
import logging
from copy import deepcopy
from unittest.mock import MagicMock
from freqtrade.rpc import RPCMessageType, RPCManager
@ -9,18 +8,16 @@ from freqtrade.tests.conftest import log_has, get_patched_freqtradebot
def test__init__(mocker, default_conf) -> None:
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
default_conf['telegram']['enabled'] = False
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, conf))
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, default_conf))
assert rpc_manager.registered_modules == []
def test_init_telegram_disabled(mocker, default_conf, caplog) -> None:
caplog.set_level(logging.DEBUG)
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, conf))
default_conf['telegram']['enabled'] = False
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, default_conf))
assert not log_has('Enabling rpc.telegram ...', caplog.record_tuples)
assert rpc_manager.registered_modules == []
@ -40,10 +37,9 @@ def test_init_telegram_enabled(mocker, default_conf, caplog) -> None:
def test_cleanup_telegram_disabled(mocker, default_conf, caplog) -> None:
caplog.set_level(logging.DEBUG)
telegram_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.cleanup', MagicMock())
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
default_conf['telegram']['enabled'] = False
freqtradebot = get_patched_freqtradebot(mocker, conf)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
rpc_manager = RPCManager(freqtradebot)
rpc_manager.cleanup()
@ -70,10 +66,9 @@ def test_cleanup_telegram_enabled(mocker, default_conf, caplog) -> None:
def test_send_msg_telegram_disabled(mocker, default_conf, caplog) -> None:
telegram_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock())
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
default_conf['telegram']['enabled'] = False
freqtradebot = get_patched_freqtradebot(mocker, conf)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
rpc_manager = RPCManager(freqtradebot)
rpc_manager.send_msg({
'type': RPCMessageType.STATUS_NOTIFICATION,
@ -101,10 +96,9 @@ def test_send_msg_telegram_enabled(mocker, default_conf, caplog) -> None:
def test_init_webhook_disabled(mocker, default_conf, caplog) -> None:
caplog.set_level(logging.DEBUG)
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
conf['webhook'] = {'enabled': False}
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, conf))
default_conf['telegram']['enabled'] = False
default_conf['webhook'] = {'enabled': False}
rpc_manager = RPCManager(get_patched_freqtradebot(mocker, default_conf))
assert not log_has('Enabling rpc.webhook ...', caplog.record_tuples)
assert rpc_manager.registered_modules == []

View File

@ -3,7 +3,6 @@
# pragma pylint: disable=too-many-lines, too-many-arguments
import re
from copy import deepcopy
from datetime import datetime
from random import randint
from unittest.mock import MagicMock, ANY
@ -21,8 +20,8 @@ from freqtrade.rpc.telegram import Telegram, authorized_only
from freqtrade.state import State
from freqtrade.tests.conftest import (get_patched_freqtradebot, log_has,
patch_exchange)
from freqtrade.tests.test_freqtradebot import (patch_coinmarketcap,
patch_get_signal)
from freqtrade.tests.test_freqtradebot import patch_get_signal
from freqtrade.tests.conftest import patch_coinmarketcap
class DummyCls(Telegram):
@ -96,9 +95,8 @@ def test_authorized_only(default_conf, mocker, caplog) -> None:
update = Update(randint(1, 100))
update.message = Message(randint(1, 100), 0, datetime.utcnow(), chat)
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
bot = FreqtradeBot(conf)
default_conf['telegram']['enabled'] = False
bot = FreqtradeBot(default_conf)
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
dummy.dummy_handler(bot=MagicMock(), update=update)
@ -124,9 +122,8 @@ def test_authorized_only_unauthorized(default_conf, mocker, caplog) -> None:
update = Update(randint(1, 100))
update.message = Message(randint(1, 100), 0, datetime.utcnow(), chat)
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
bot = FreqtradeBot(conf)
default_conf['telegram']['enabled'] = False
bot = FreqtradeBot(default_conf)
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
dummy.dummy_handler(bot=MagicMock(), update=update)
@ -152,10 +149,9 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None:
update = Update(randint(1, 100))
update.message = Message(randint(1, 100), 0, datetime.utcnow(), Chat(0, 0))
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
default_conf['telegram']['enabled'] = False
bot = FreqtradeBot(conf)
bot = FreqtradeBot(default_conf)
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
@ -177,9 +173,8 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None:
def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
update.message.chat.id = 123
conf = deepcopy(default_conf)
conf['telegram']['enabled'] = False
conf['telegram']['chat_id'] = 123
default_conf['telegram']['enabled'] = False
default_conf['telegram']['chat_id'] = 123
patch_coinmarketcap(mocker)
@ -214,7 +209,7 @@ def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
)
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
freqtradebot = FreqtradeBot(conf)
freqtradebot = FreqtradeBot(default_conf)
patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot)
@ -294,9 +289,8 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker)
)
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
conf = deepcopy(default_conf)
conf['stake_amount'] = 15.0
freqtradebot = FreqtradeBot(conf)
default_conf['stake_amount'] = 15.0
freqtradebot = FreqtradeBot(default_conf)
patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot)
@ -1181,9 +1175,8 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None:
def test__send_msg(default_conf, mocker) -> None:
patch_coinmarketcap(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
conf = deepcopy(default_conf)
bot = MagicMock()
freqtradebot = get_patched_freqtradebot(mocker, conf)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
telegram = Telegram(freqtradebot)
telegram._config['telegram']['enabled'] = True
@ -1194,10 +1187,9 @@ def test__send_msg(default_conf, mocker) -> None:
def test__send_msg_network_error(default_conf, mocker, caplog) -> None:
patch_coinmarketcap(mocker)
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
conf = deepcopy(default_conf)
bot = MagicMock()
bot.send_message = MagicMock(side_effect=NetworkError('Oh snap'))
freqtradebot = get_patched_freqtradebot(mocker, conf)
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
telegram = Telegram(freqtradebot)
telegram._config['telegram']['enabled'] = True

View File

@ -98,9 +98,6 @@ def test_get_signal_handles_exceptions(mocker, default_conf):
def test_tickerdata_to_dataframe(default_conf) -> None:
"""
Test Analyze.tickerdata_to_dataframe() method
"""
strategy = DefaultStrategy(default_conf)
timerange = TimeRange(None, 'line', 0, -100)

View File

@ -1,9 +1,5 @@
# pragma pylint: disable=missing-docstring, C0103
"""
Unit test file for arguments.py
"""
import argparse
import pytest

View File

@ -2,13 +2,13 @@
import json
from argparse import Namespace
from copy import deepcopy
import logging
from unittest.mock import MagicMock
import pytest
from jsonschema import ValidationError
from jsonschema import validate, ValidationError
from freqtrade import constants
from freqtrade import OperationalException
from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration, set_loggers
@ -17,30 +17,27 @@ from freqtrade.tests.conftest import log_has
def test_load_config_invalid_pair(default_conf) -> None:
conf = deepcopy(default_conf)
conf['exchange']['pair_whitelist'].append('ETH-BTC')
default_conf['exchange']['pair_whitelist'].append('ETH-BTC')
with pytest.raises(ValidationError, match=r'.*does not match.*'):
configuration = Configuration(Namespace())
configuration._validate_config(conf)
configuration._validate_config(default_conf)
def test_load_config_missing_attributes(default_conf) -> None:
conf = deepcopy(default_conf)
conf.pop('exchange')
default_conf.pop('exchange')
with pytest.raises(ValidationError, match=r'.*\'exchange\' is a required property.*'):
configuration = Configuration(Namespace())
configuration._validate_config(conf)
configuration._validate_config(default_conf)
def test_load_config_incorrect_stake_amount(default_conf) -> None:
conf = deepcopy(default_conf)
conf['stake_amount'] = 'fake'
default_conf['stake_amount'] = 'fake'
with pytest.raises(ValidationError, match=r'.*\'fake\' does not match \'unlimited\'.*'):
configuration = Configuration(Namespace())
configuration._validate_config(conf)
configuration._validate_config(default_conf)
def test_load_config_file(default_conf, mocker, caplog) -> None:
@ -57,10 +54,9 @@ def test_load_config_file(default_conf, mocker, caplog) -> None:
def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None:
conf = deepcopy(default_conf)
conf['max_open_trades'] = 0
default_conf['max_open_trades'] = 0
file_mock = mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(conf)
read_data=json.dumps(default_conf)
))
Configuration(Namespace())._load_config_file('somefile')
@ -151,13 +147,12 @@ def test_load_config_with_params(default_conf, mocker) -> None:
def test_load_custom_strategy(default_conf, mocker) -> None:
custom_conf = deepcopy(default_conf)
custom_conf.update({
default_conf.update({
'strategy': 'CustomStrategy',
'strategy_path': '/tmp/strategies',
})
mocker.patch('freqtrade.configuration.open', mocker.mock_open(
read_data=json.dumps(custom_conf)
read_data=json.dumps(default_conf)
))
args = Arguments([], '').get_parsed_arg()
@ -322,29 +317,25 @@ def test_hyperopt_with_arguments(mocker, default_conf, caplog) -> None:
def test_check_exchange(default_conf) -> None:
"""
Test the configuration validator with a missing attribute
"""
conf = deepcopy(default_conf)
configuration = Configuration(Namespace())
# Test a valid exchange
conf.get('exchange').update({'name': 'BITTREX'})
assert configuration.check_exchange(conf)
default_conf.get('exchange').update({'name': 'BITTREX'})
assert configuration.check_exchange(default_conf)
# Test a valid exchange
conf.get('exchange').update({'name': 'binance'})
assert configuration.check_exchange(conf)
default_conf.get('exchange').update({'name': 'binance'})
assert configuration.check_exchange(default_conf)
# Test a invalid exchange
conf.get('exchange').update({'name': 'unknown_exchange'})
configuration.config = conf
default_conf.get('exchange').update({'name': 'unknown_exchange'})
configuration.config = default_conf
with pytest.raises(
OperationalException,
match=r'.*Exchange "unknown_exchange" not supported.*'
):
configuration.check_exchange(conf)
configuration.check_exchange(default_conf)
def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
@ -398,3 +389,7 @@ def test_set_loggers() -> None:
assert logging.getLogger('requests').level is logging.DEBUG
assert logging.getLogger('ccxt.base.exchange').level is logging.DEBUG
assert logging.getLogger('telegram').level is logging.INFO
def test_validate_default_conf(default_conf) -> None:
validate(default_conf, constants.CONF_SCHEMA)

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
# pragma pylint: disable=missing-docstring, C0103
from copy import deepcopy
from unittest.mock import MagicMock
import pytest
@ -23,46 +22,40 @@ def test_init_create_session(default_conf):
def test_init_custom_db_url(default_conf, mocker):
conf = deepcopy(default_conf)
# Update path to a value other than default, but still in-memory
conf.update({'db_url': 'sqlite:///tmp/freqtrade2_test.sqlite'})
default_conf.update({'db_url': 'sqlite:///tmp/freqtrade2_test.sqlite'})
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
init(conf)
init(default_conf)
assert create_engine_mock.call_count == 1
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:///tmp/freqtrade2_test.sqlite'
def test_init_invalid_db_url(default_conf):
conf = deepcopy(default_conf)
# Update path to a value other than default, but still in-memory
conf.update({'db_url': 'unknown:///some.url'})
default_conf.update({'db_url': 'unknown:///some.url'})
with pytest.raises(OperationalException, match=r'.*no valid database URL*'):
init(conf)
init(default_conf)
def test_init_prod_db(default_conf, mocker):
conf = deepcopy(default_conf)
conf.update({'dry_run': False})
conf.update({'db_url': constants.DEFAULT_DB_PROD_URL})
default_conf.update({'dry_run': False})
default_conf.update({'db_url': constants.DEFAULT_DB_PROD_URL})
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
init(conf)
init(default_conf)
assert create_engine_mock.call_count == 1
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:///tradesv3.sqlite'
def test_init_dryrun_db(default_conf, mocker):
conf = deepcopy(default_conf)
conf.update({'dry_run': True})
conf.update({'db_url': constants.DEFAULT_DB_DRYRUN_URL})
default_conf.update({'dry_run': True})
default_conf.update({'db_url': constants.DEFAULT_DB_DRYRUN_URL})
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
init(conf)
init(default_conf)
assert create_engine_mock.call_count == 1
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite://'

View File

@ -1,4 +1,4 @@
ccxt==1.17.49
ccxt==1.17.56
SQLAlchemy==1.2.10
python-telegram-bot==10.1.0
arrow==0.12.1
@ -12,7 +12,7 @@ scipy==1.1.0
jsonschema==2.6.0
numpy==1.15.0
TA-Lib==0.4.17
pytest==3.6.4
pytest==3.7.0
pytest-mock==1.10.0
pytest-cov==2.5.1
tabulate==0.8.2

View File

@ -18,7 +18,7 @@ setup(name='freqtrade',
license='GPLv3',
packages=['freqtrade'],
scripts=['bin/freqtrade'],
setup_requires=['pytest-runner'],
setup_requires=['pytest-runner', 'numpy'],
tests_require=['pytest', 'pytest-mock', 'pytest-cov'],
install_requires=[
'ccxt',