Merge branch 'develop' into money_mgt

This commit is contained in:
misagh 2018-09-27 14:54:18 +02:00
commit d6415f3499
11 changed files with 77 additions and 33 deletions

View File

@ -200,6 +200,10 @@ to understand the requirements before sending your pull-requests.
## Requirements ## Requirements
### Uptodate clock
The clock must be accurate, syncronized to a NTP server very frequently to avoid problems with communication to the exchanges.
### Min hardware required ### Min hardware required
To run this bot we recommend you a cloud instance with a minimum of: To run this bot we recommend you a cloud instance with a minimum of:

View File

@ -267,7 +267,7 @@ Official webpage: https://mrjbq7.github.io/ta-lib/install.html
wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar xvzf ta-lib-0.4.0-src.tar.gz tar xvzf ta-lib-0.4.0-src.tar.gz
cd ta-lib cd ta-lib
sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h
./configure --prefix=/usr ./configure --prefix=/usr
make make
make install make install

View File

@ -119,7 +119,6 @@ class Arguments(object):
help='Override trades database URL, this is useful if dry_run is enabled' help='Override trades database URL, this is useful if dry_run is enabled'
' or in custom deployments (default: %(default)s)', ' or in custom deployments (default: %(default)s)',
dest='db_url', dest='db_url',
default=constants.DEFAULT_DB_PROD_URL,
type=str, type=str,
metavar='PATH', metavar='PATH',
) )

View File

@ -110,9 +110,12 @@ class Configuration(object):
'(not applicable with Backtesting and Hyperopt)' '(not applicable with Backtesting and Hyperopt)'
) )
if self.args.db_url != constants.DEFAULT_DB_PROD_URL: if self.args.db_url and self.args.db_url != constants.DEFAULT_DB_PROD_URL:
config.update({'db_url': self.args.db_url}) config.update({'db_url': self.args.db_url})
logger.info('Parameter --db-url detected ...') logger.info('Parameter --db-url detected ...')
else:
# Set default here
config.update({'db_url': constants.DEFAULT_DB_PROD_URL})
if config.get('dry_run', False): if config.get('dry_run', False):
logger.info('Dry run is enabled') logger.info('Dry run is enabled')

View File

@ -599,7 +599,8 @@ class Exchange(object):
if not self.exchange_has('fetchMyTrades'): if not self.exchange_has('fetchMyTrades'):
return [] return []
try: try:
my_trades = self._api.fetch_my_trades(pair, since.timestamp()) # Allow 5s offset to catch slight time offsets (discovered in #1185)
my_trades = self._api.fetch_my_trades(pair, since.timestamp() - 5)
matched_trades = [trade for trade in my_trades if trade['order'] == order_id] matched_trades = [trade for trade in my_trades if trade['order'] == order_id]
return matched_trades return matched_trades

View File

@ -10,7 +10,7 @@ from datetime import datetime
from typing import Any, Callable, Dict, List, Optional from typing import Any, Callable, Dict, List, Optional
import arrow import arrow
import requests from requests.exceptions import RequestException
from cachetools import TTLCache, cached from cachetools import TTLCache, cached
@ -667,7 +667,7 @@ class FreqtradeBot(object):
if not trade.open_order_id: if not trade.open_order_id:
continue continue
order = self.exchange.get_order(trade.open_order_id, trade.pair) order = self.exchange.get_order(trade.open_order_id, trade.pair)
except requests.exceptions.RequestException: except (RequestException, DependencyException):
logger.info( logger.info(
'Cannot query order for %s due to %s', 'Cannot query order for %s due to %s',
trade, trade,

View File

@ -2,38 +2,39 @@
from unittest.mock import MagicMock from unittest.mock import MagicMock
import freqtrade.tests.conftest as tt # test tools from freqtrade.tests.conftest import get_patched_freqtradebot
import pytest
# whitelist, blacklist, filtering, all of that will # whitelist, blacklist, filtering, all of that will
# eventually become some rules to run on a generic ACL engine # eventually become some rules to run on a generic ACL engine
# perhaps try to anticipate that by using some python package # perhaps try to anticipate that by using some python package
def whitelist_conf(): @pytest.fixture(scope="function")
config = tt.default_conf() def whitelist_conf(default_conf):
config['stake_currency'] = 'BTC' default_conf['stake_currency'] = 'BTC'
config['exchange']['pair_whitelist'] = [ default_conf['exchange']['pair_whitelist'] = [
'ETH/BTC', 'ETH/BTC',
'TKN/BTC', 'TKN/BTC',
'TRST/BTC', 'TRST/BTC',
'SWT/BTC', 'SWT/BTC',
'BCC/BTC' 'BCC/BTC'
] ]
config['exchange']['pair_blacklist'] = [ default_conf['exchange']['pair_blacklist'] = [
'BLK/BTC' 'BLK/BTC'
] ]
return config return default_conf
def test_refresh_market_pair_not_in_whitelist(mocker, markets): def test_refresh_market_pair_not_in_whitelist(mocker, markets, whitelist_conf):
conf = whitelist_conf()
freqtradebot = tt.get_patched_freqtradebot(mocker, conf) freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets) mocker.patch('freqtrade.exchange.Exchange.get_markets', markets)
refreshedwhitelist = freqtradebot._refresh_whitelist( refreshedwhitelist = freqtradebot._refresh_whitelist(
conf['exchange']['pair_whitelist'] + ['XXX/BTC'] whitelist_conf['exchange']['pair_whitelist'] + ['XXX/BTC']
) )
# List ordered by BaseVolume # List ordered by BaseVolume
whitelist = ['ETH/BTC', 'TKN/BTC'] whitelist = ['ETH/BTC', 'TKN/BTC']
@ -41,12 +42,12 @@ def test_refresh_market_pair_not_in_whitelist(mocker, markets):
assert whitelist == refreshedwhitelist assert whitelist == refreshedwhitelist
def test_refresh_whitelist(mocker, markets): def test_refresh_whitelist(mocker, markets, whitelist_conf):
conf = whitelist_conf() freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf)
freqtradebot = tt.get_patched_freqtradebot(mocker, conf)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets) mocker.patch('freqtrade.exchange.Exchange.get_markets', markets)
refreshedwhitelist = freqtradebot._refresh_whitelist(conf['exchange']['pair_whitelist']) refreshedwhitelist = freqtradebot._refresh_whitelist(
whitelist_conf['exchange']['pair_whitelist'])
# List ordered by BaseVolume # List ordered by BaseVolume
whitelist = ['ETH/BTC', 'TKN/BTC'] whitelist = ['ETH/BTC', 'TKN/BTC']
@ -54,9 +55,8 @@ def test_refresh_whitelist(mocker, markets):
assert whitelist == refreshedwhitelist assert whitelist == refreshedwhitelist
def test_refresh_whitelist_dynamic(mocker, markets, tickers): def test_refresh_whitelist_dynamic(mocker, markets, tickers, whitelist_conf):
conf = whitelist_conf() freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf)
freqtradebot = tt.get_patched_freqtradebot(mocker, conf)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_markets=markets, get_markets=markets,
@ -68,21 +68,20 @@ def test_refresh_whitelist_dynamic(mocker, markets, tickers):
whitelist = ['ETH/BTC', 'TKN/BTC'] whitelist = ['ETH/BTC', 'TKN/BTC']
refreshedwhitelist = freqtradebot._refresh_whitelist( refreshedwhitelist = freqtradebot._refresh_whitelist(
freqtradebot._gen_pair_whitelist(conf['stake_currency']) freqtradebot._gen_pair_whitelist(whitelist_conf['stake_currency'])
) )
assert whitelist == refreshedwhitelist assert whitelist == refreshedwhitelist
def test_refresh_whitelist_dynamic_empty(mocker, markets_empty): def test_refresh_whitelist_dynamic_empty(mocker, markets_empty, whitelist_conf):
conf = whitelist_conf() freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf)
freqtradebot = tt.get_patched_freqtradebot(mocker, conf)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets_empty) mocker.patch('freqtrade.exchange.Exchange.get_markets', markets_empty)
# argument: use the whitelist dynamically by exchange-volume # argument: use the whitelist dynamically by exchange-volume
whitelist = [] whitelist = []
conf['exchange']['pair_whitelist'] = [] whitelist_conf['exchange']['pair_whitelist'] = []
freqtradebot._refresh_whitelist(whitelist) freqtradebot._refresh_whitelist(whitelist)
pairslist = conf['exchange']['pair_whitelist'] pairslist = whitelist_conf['exchange']['pair_whitelist']
assert set(whitelist) == set(pairslist) assert set(whitelist) == set(pairslist)

View File

@ -993,6 +993,44 @@ def test_check_handle_timedout_buy(default_conf, ticker, limit_buy_order_old, fe
assert nb_trades == 0 assert nb_trades == 0
def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_order_old,
fee, mocker) -> None:
rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock()
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(),
get_ticker=ticker,
get_order=MagicMock(side_effect=DependencyException),
cancel_order=cancel_order_mock,
get_fee=fee
)
freqtrade = FreqtradeBot(default_conf)
trade_buy = Trade(
pair='ETH/BTC',
open_rate=0.00001099,
exchange='bittrex',
open_order_id='123456789',
amount=90.99181073,
fee_open=0.0,
fee_close=0.0,
stake_amount=1,
open_date=arrow.utcnow().shift(minutes=-601).datetime,
is_open=True
)
Trade.session.add(trade_buy)
# check it does cancel buy orders over the time limit
freqtrade.check_handle_timedout()
assert cancel_order_mock.call_count == 0
assert rpc_mock.call_count == 0
trades = Trade.query.filter(Trade.open_order_id.is_(trade_buy.open_order_id)).all()
nb_trades = len(trades)
assert nb_trades == 1
def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old, mocker) -> None: def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old, mocker) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock() cancel_order_mock = MagicMock()

View File

@ -1,6 +1,6 @@
if [ ! -f "ta-lib/CHANGELOG.TXT" ]; then if [ ! -f "ta-lib/CHANGELOG.TXT" ]; then
tar zxvf ta-lib-0.4.0-src.tar.gz tar zxvf ta-lib-0.4.0-src.tar.gz
cd ta-lib && sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && ./configure && make && sudo make install && cd .. cd ta-lib && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && ./configure && make && sudo make install && cd ..
else else
echo "TA-lib already installed, skipping download and build." echo "TA-lib already installed, skipping download and build."
cd ta-lib && sudo make install && cd .. cd ta-lib && sudo make install && cd ..

View File

@ -1,4 +1,4 @@
ccxt==1.17.350 ccxt==1.17.351
SQLAlchemy==1.2.12 SQLAlchemy==1.2.12
python-telegram-bot==11.1.0 python-telegram-bot==11.1.0
arrow==0.12.1 arrow==0.12.1

View File

@ -73,7 +73,7 @@ def load_trades(args: Namespace, pair: str, timerange: TimeRange) -> pd.DataFram
file = Path(args.exportfilename) file = Path(args.exportfilename)
# must align with columns in backtest.py # must align with columns in backtest.py
columns = ["pair", "profit", "opents", "closets", "index", "duration", columns = ["pair", "profit", "opents", "closets", "index", "duration",
"open_rate", "close_rate", "open_at_end"] "open_rate", "close_rate", "open_at_end", "sell_reason"]
with file.open() as f: with file.open() as f:
data = json.load(f) data = json.load(f)
trades = pd.DataFrame(data, columns=columns) trades = pd.DataFrame(data, columns=columns)