From 36f91fcdf564ad700534e06e46526b8b0beffb31 Mon Sep 17 00:00:00 2001 From: creslin Date: Wed, 1 Aug 2018 06:03:34 +0000 Subject: [PATCH 01/84] XBT missing as a market symbol for BTC in constants --- freqtrade/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 87e354455..b30add71b 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -36,7 +36,7 @@ SUPPORTED_FIAT = [ "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", "RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR", "USD", - "BTC", "ETH", "XRP", "LTC", "BCH", "USDT" + "BTC", "XBT", "ETH", "XRP", "LTC", "BCH", "USDT" ] # Required json-schema for user specified config @@ -45,7 +45,7 @@ CONF_SCHEMA = { 'properties': { 'max_open_trades': {'type': 'integer', 'minimum': 0}, 'ticker_interval': {'type': 'string', 'enum': list(TICKER_INTERVAL_MINUTES.keys())}, - 'stake_currency': {'type': 'string', 'enum': ['BTC', 'ETH', 'USDT', 'EUR', 'USD']}, + 'stake_currency': {'type': 'string', 'enum': ['BTC', 'XBT', 'ETH', 'USDT', 'EUR', 'USD']}, 'stake_amount': { "type": ["number", "string"], "minimum": 0.0005, From 145008421f9fd62e964366873239b0d83635b874 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 2 Aug 2018 14:26:07 +0200 Subject: [PATCH 02/84] Update ccxt from 1.17.60 to 1.17.63 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5ff5d3694..ff6457a8c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.60 +ccxt==1.17.63 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 85c73ea8507d012353bb9744b4371d978bf07af6 Mon Sep 17 00:00:00 2001 From: Gert Date: Thu, 2 Aug 2018 16:39:13 -0700 Subject: [PATCH 03/84] added index --- freqtrade/persistence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 8fb01d074..c21b902bc 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -157,8 +157,8 @@ class Trade(_DECL_BASE): id = Column(Integer, primary_key=True) exchange = Column(String, nullable=False) - pair = Column(String, nullable=False) - is_open = Column(Boolean, nullable=False, default=True) + pair = Column(String, nullable=False,index=True) + is_open = Column(Boolean, nullable=False, default=True, index=True) fee_open = Column(Float, nullable=False, default=0.0) fee_close = Column(Float, nullable=False, default=0.0) open_rate = Column(Float) From 2cfa3b7607874879584484c7c99d47c969517fb5 Mon Sep 17 00:00:00 2001 From: Gert Wohlgemuth Date: Thu, 2 Aug 2018 17:08:14 -0700 Subject: [PATCH 04/84] updated dockerfile and requirements --- Dockerfile | 7 ++++++- requirements.txt | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 309763d2a..10cd14bfe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM python:3.6.6-slim-stretch # Install TA-lib -RUN apt-get update && apt-get -y install curl build-essential && apt-get clean +RUN apt-get update && apt-get -y install curl build-essential git && apt-get clean RUN curl -L http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz | \ tar xzvf - && \ cd ta-lib && \ @@ -13,6 +13,11 @@ ENV LD_LIBRARY_PATH /usr/local/lib RUN mkdir /freqtrade WORKDIR /freqtrade +# Update PIP +RUN python -m pip install --upgrade pip +RUN pip install future +RUN pip install numpy + # Install dependencies COPY requirements.txt /freqtrade/ RUN pip install numpy \ diff --git a/requirements.txt b/requirements.txt index ff6457a8c..183d79cdf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,3 +23,13 @@ scikit-optimize==0.5.2 # Required for plotting data #plotly==3.0.0 + +# Required for plotting data +plotly==3.0.0 + +# find first, C search in arrays +py_find_1st==1.1.1 + +#Load ticker files 30% faster +ujson==1.35 +git+git://github.com/berlinguyinca/technical.git@master From 3037d85529fc0504506a902a46fb27ca2ae20091 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Fri, 3 Aug 2018 14:26:06 +0200 Subject: [PATCH 05/84] Update ccxt from 1.17.63 to 1.17.66 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ff6457a8c..0c523ddec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.63 +ccxt==1.17.66 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From b963b95ee9909d2c03f5ef244c49ac6bc6d78130 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Fri, 3 Aug 2018 14:26:07 +0200 Subject: [PATCH 06/84] Update pytest from 3.7.0 to 3.7.1 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0c523ddec..8670b4074 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ scipy==1.1.0 jsonschema==2.6.0 numpy==1.15.0 TA-Lib==0.4.17 -pytest==3.7.0 +pytest==3.7.1 pytest-mock==1.10.0 pytest-cov==2.5.1 tabulate==0.8.2 From 721341e4128a422a33ef6a059db4e7e97a164a9a Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 4 Aug 2018 14:26:05 +0200 Subject: [PATCH 07/84] Update ccxt from 1.17.66 to 1.17.73 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8670b4074..221bdf968 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.66 +ccxt==1.17.73 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From ea506b05c67c4da1b66e328bdf5d8b79bf33ed4a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 4 Aug 2018 20:22:16 +0200 Subject: [PATCH 08/84] Add test for failing database migration --- freqtrade/tests/test_persistence.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index 26932136a..e52500071 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -404,6 +404,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): Test Database migration (starting with new pairformat) """ amount = 103.223 + # Always create all columns apart from the last! create_table_old = """CREATE TABLE IF NOT EXISTS "trades" ( id INTEGER NOT NULL, exchange VARCHAR NOT NULL, @@ -418,14 +419,21 @@ def test_migrate_new(mocker, default_conf, fee, caplog): open_date DATETIME NOT NULL, close_date DATETIME, open_order_id VARCHAR, + stop_loss FLOAT, + initial_stop_loss FLOAT, + max_rate FLOAT, + sell_reason VARCHAR, + strategy VARCHAR, PRIMARY KEY (id), CHECK (is_open IN (0, 1)) );""" insert_table_old = """INSERT INTO trades (exchange, pair, is_open, fee, - open_rate, stake_amount, amount, open_date) + open_rate, stake_amount, amount, open_date, + stop_loss, initial_stop_loss, max_rate) VALUES ('binance', 'ETC/BTC', 1, {fee}, 0.00258580, {stake}, {amount}, - '2019-11-28 12:44:24.000000') + '2019-11-28 12:44:24.000000', + 0.0, 0.0, 0.0) """.format(fee=fee.return_value, stake=default_conf.get("stake_amount"), amount=amount From d73d0a5253016b65fadb97578a5eb5b1c80180c8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 4 Aug 2018 20:22:45 +0200 Subject: [PATCH 09/84] Fix database migration --- freqtrade/persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 8fb01d074..6eaa5008a 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -82,7 +82,7 @@ def check_migrate(engine) -> None: logger.info(f'trying {table_back_name}') # Check for latest column - if not has_column(cols, 'max_rate'): + if not has_column(cols, 'ticker_interval'): fee_open = get_column_def(cols, 'fee_open', 'fee') fee_close = get_column_def(cols, 'fee_close', 'fee') open_rate_requested = get_column_def(cols, 'open_rate_requested', 'null') From 4a9bf78770624357d91de4675a10c541fc488a74 Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Sun, 5 Aug 2018 12:41:06 +0800 Subject: [PATCH 10/84] Order Book with tests --- config.json.example | 16 +++- config_full.json.example | 16 +++- docs/configuration.md | 7 ++ freqtrade/constants.py | 25 ++++- freqtrade/exchange/__init__.py | 23 +++++ freqtrade/exchange/exchange_helpers.py | 24 +++++ freqtrade/freqtradebot.py | 111 ++++++++++++++++++++-- freqtrade/tests/conftest.py | 16 ++++ freqtrade/tests/exchange/test_exchange.py | 10 ++ freqtrade/tests/test_freqtradebot.py | 39 +++++++- 10 files changed, 271 insertions(+), 16 deletions(-) diff --git a/config.json.example b/config.json.example index 8bd3942e6..c3dc6b5b6 100644 --- a/config.json.example +++ b/config.json.example @@ -37,7 +37,21 @@ "experimental": { "use_sell_signal": false, "sell_profit_only": false, - "ignore_roi_if_buy_signal": false + "ignore_roi_if_buy_signal": false, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + }, + "bid_strategy": { + "use_order_book": false, + "order_book_top": 2, + "percent_from_top": 0 + }, + "ask_strategy":{ + "use_order_book": false, + "order_book_min": 1, + "order_book_max": 9 + } }, "telegram": { "enabled": true, diff --git a/config_full.json.example b/config_full.json.example index cc3b3d630..5a364a93b 100644 --- a/config_full.json.example +++ b/config_full.json.example @@ -46,7 +46,21 @@ "experimental": { "use_sell_signal": false, "sell_profit_only": false, - "ignore_roi_if_buy_signal": false + "ignore_roi_if_buy_signal": false, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + }, + "bid_strategy": { + "use_order_book": false, + "order_book_top": 2, + "percent_from_top": 0 + }, + "ask_strategy":{ + "use_order_book": false, + "order_book_min": 1, + "order_book_max": 9 + }s }, "telegram": { "enabled": true, diff --git a/docs/configuration.md b/docs/configuration.md index ff5ce118c..5ffe24556 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -39,6 +39,13 @@ The table below will list all configuration parameters. | `experimental.use_sell_signal` | false | No | Use your sell strategy in addition of the `minimal_roi`. | `experimental.sell_profit_only` | false | No | waits until you have made a positive profit before taking a sell decision. | `experimental.ignore_roi_if_buy_signal` | false | No | Does not sell if the buy-signal is still active. Takes preference over `minimal_roi` and `use_sell_signal` +| `experimental.check_depth_of_market` | false | No | Does not sell if the % difference of buy orders and sell orders is met in Order Book. +| `experimental.bids_to_ask_delta` | 0 | No | The % difference of buy orders and sell orders found in Order Book. A value lesser than 1 means sell orders is greater, while value greater than 1 means buy orders is higher. +| `experimental.bid_strategy.use_order_book` | false | No | Allows buying of pair using the rates in Order Book Bids. +| `experimental.bid_strategy.order_book_top` | 0 | No | Bot will use the top N rate in Order Book Bids. Ie. a value of 2 will allow the bot to pick the 2nd bid rate in Order Book Bids. +| `experimental.ask_strategy.use_order_book` | false | No | Allows selling of open traded pair using the rates in Order Book Asks. +| `experimental.ask_strategy.order_book_min` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. +| `experimental.ask_strategy.order_book_max` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `telegram.enabled` | true | Yes | Enable or not the usage of Telegram. | `telegram.token` | token | No | Your Telegram bot token. Only required if `telegram.enabled` is `true`. | `telegram.chat_id` | chat_id | No | Your personal Telegram account id. Only required if `telegram.enabled` is `true`. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 87e354455..b7431af3c 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -89,7 +89,30 @@ CONF_SCHEMA = { 'properties': { 'use_sell_signal': {'type': 'boolean'}, 'sell_profit_only': {'type': 'boolean'}, - "ignore_roi_if_buy_signal_true": {'type': 'boolean'} + 'ignore_roi_if_buy_signal_true': {'type': 'boolean'}, + 'check_depth_of_market': { + 'type': 'object', + 'properties': { + 'enabled': {'type': 'boolean'}, + 'bids_to_ask_delta': {'type': 'number', 'minimum': 0}, + } + }, + 'bid_strategy': { + 'type': 'object', + 'properties': { + 'percent_from_top': {'type': 'number', 'minimum': 0}, + 'use_order_book': {'type': 'boolean'}, + 'order_book_top': {'type': 'number', 'maximum': 20, 'minimum': 1} + } + }, + 'ask_strategy': { + 'type': 'object', + 'properties': { + 'use_order_book': {'type': 'boolean'}, + 'order_book_min': {'type': 'number', 'minimum': 1}, + 'order_book_max': {'type': 'number', 'minimum': 1, 'maximum': 50} + } + } } }, 'telegram': { diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 810957902..18b95b604 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -409,6 +409,29 @@ class Exchange(object): except ccxt.BaseError as e: raise OperationalException(e) + @retrier + def get_order_book(self, pair: str, limit: int = 100) -> dict: + try: + # 20180619: bittrex doesnt support limits -.- + # 20180619: binance support limits but only on specific range + if self._api.name == 'Binance': + limit_range = [5, 10, 20, 50, 100, 500, 1000] + for limitx in limit_range: + if limit <= limitx: + limit = limitx + break + + return self._api.fetch_l2_order_book(pair, limit) + except ccxt.NotSupported as e: + raise OperationalException( + f'Exchange {self._api.name} does not support fetching order book.' + f'Message: {e}') + except (ccxt.NetworkError, ccxt.ExchangeError) as e: + raise TemporaryError( + f'Could not get order book due to {e.__class__.__name__}. Message: {e}') + except ccxt.BaseError as e: + raise OperationalException(e) + @retrier def get_trades_for_order(self, order_id: str, pair: str, since: datetime) -> List: if self._conf['dry_run']: diff --git a/freqtrade/exchange/exchange_helpers.py b/freqtrade/exchange/exchange_helpers.py index 254c16309..6574f5a53 100644 --- a/freqtrade/exchange/exchange_helpers.py +++ b/freqtrade/exchange/exchange_helpers.py @@ -2,6 +2,7 @@ Functions to analyze ticker data with indicators and produce buy and sell signals """ import logging +import pandas as pd from pandas import DataFrame, to_datetime logger = logging.getLogger(__name__) @@ -31,3 +32,26 @@ def parse_ticker_dataframe(ticker: list) -> DataFrame: }) frame.drop(frame.tail(1).index, inplace=True) # eliminate partial candle return frame + + +def order_book_to_dataframe(data: list) -> DataFrame: + """ + Gets order book list, returns dataframe with below format per suggested by creslin + ------------------------------------------------------------------- + b_sum b_size bids asks a_size a_sum + ------------------------------------------------------------------- + """ + cols = ['bids', 'b_size'] + bids_frame = DataFrame(data['bids'], columns=cols) + # add cumulative sum column + bids_frame['b_sum'] = bids_frame['b_size'].cumsum() + cols2 = ['asks', 'a_size'] + asks_frame = DataFrame(data['asks'], columns=cols2) + # add cumulative sum column + asks_frame['a_sum'] = asks_frame['a_size'].cumsum() + + frame = pd.concat([bids_frame['b_sum'], bids_frame['b_size'], bids_frame['bids'], + asks_frame['asks'], asks_frame['a_size'], asks_frame['a_sum']], axis=1, + keys=['b_sum', 'b_size', 'bids', 'asks', 'a_size', 'a_sum']) + # logger.info('order book %s', frame ) + return frame diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 46fbb3a38..0c4670971 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -21,6 +21,7 @@ from freqtrade.rpc import RPCManager, RPCMessageType from freqtrade.state import State from freqtrade.strategy.interface import SellType from freqtrade.strategy.resolver import IStrategy, StrategyResolver +from freqtrade.exchange.exchange_helpers import order_book_to_dataframe logger = logging.getLogger(__name__) @@ -233,16 +234,47 @@ class FreqtradeBot(object): return final_list - def get_target_bid(self, ticker: Dict[str, float]) -> float: + def get_target_bid(self, pair: str, ticker: Dict[str, float]) -> float: """ Calculates bid target between current ask price and last price :param ticker: Ticker to use for getting Ask and Last Price :return: float: Price """ if ticker['ask'] < ticker['last']: - return ticker['ask'] - balance = self.config['bid_strategy']['ask_last_balance'] - return ticker['ask'] + balance * (ticker['last'] - ticker['ask']) + ticker_rate = ticker['ask'] + else: + balance = self.config['bid_strategy']['ask_last_balance'] + ticker_rate = ticker['ask'] + balance * (ticker['last'] - ticker['ask']) + + used_rate = ticker_rate + experimental_bid_strategy = self.config.get('experimental', {}).get('bid_strategy', {}) + if 'use_order_book' in experimental_bid_strategy and\ + experimental_bid_strategy.get('use_order_book', False): + logger.info('Getting price from order book') + order_book_top = experimental_bid_strategy.get('order_book_top', 1) + order_book = self.exchange.get_order_book(pair, order_book_top) + # top 1 = index 0 + order_book_rate = order_book['bids'][order_book_top - 1][0] + # if ticker has lower rate, then use ticker ( usefull if down trending ) + logger.info('...top %s order book buy rate %0.8f', order_book_top, order_book_rate) + if ticker_rate < order_book_rate: + logger.info('...using ticker rate instead %0.8f', ticker_rate) + used_rate = ticker_rate + used_rate = order_book_rate + else: + logger.info('Using Last Ask / Last Price') + used_rate = ticker_rate + percent_from_top = self.config.get('bid_strategy', {}).get('percent_from_top', 0) + if percent_from_top > 0: + used_rate = used_rate - (used_rate * percent_from_top) + used_rate = self._trunc_num(used_rate, 8) + logger.info('...percent_from_top enabled, new buy rate %0.8f', used_rate) + + return used_rate + + def _trunc_num(self, f, n): + import math + return math.floor(f * 10 ** n) / 10 ** n def _get_trade_stake_amount(self) -> Optional[float]: """ @@ -334,9 +366,37 @@ class FreqtradeBot(object): (buy, sell) = self.strategy.get_signal(_pair, interval, thistory) if buy and not sell: + experimental_check_depth_of_market = self.config.get('experimental', {}).\ + get('check_depth_of_market', {}) + if (experimental_check_depth_of_market.get('enabled', False)) and\ + (experimental_check_depth_of_market.get('bids_to_ask_delta', 0) > 0): + if self._check_depth_of_market_buy(_pair): + return self.execute_buy(_pair, stake_amount) + else: + return False return self.execute_buy(_pair, stake_amount) return False + def _check_depth_of_market_buy(self, pair: str, ) -> bool: + """ + Checks depth of market before executing a buy + """ + experimental_check_depth_of_market = self.config.get('experimental', {}).\ + get('check_depth_of_market', {}) + conf_bids_to_ask_delta = experimental_check_depth_of_market.get('bids_to_ask_delta', 0) + logger.info('checking depth of market for %s', pair) + order_book = self.exchange.get_order_book(pair, 1000) + order_book_data_frame = order_book_to_dataframe(order_book) + order_book_bids = order_book_data_frame['b_size'].sum() + order_book_asks = order_book_data_frame['a_size'].sum() + bids_ask_delta = order_book_bids / order_book_asks + logger.info('bids: %s, asks: %s, delta: %s', order_book_bids, + order_book_asks, + order_book_bids / order_book_asks) + if bids_ask_delta >= conf_bids_to_ask_delta: + return True + return False + def execute_buy(self, pair: str, stake_amount: float) -> bool: """ Executes a limit buy for the given pair @@ -349,7 +409,7 @@ class FreqtradeBot(object): fiat_currency = self.config.get('fiat_display_currency', None) # Calculate amount - buy_limit = self.get_target_bid(self.exchange.get_ticker(pair)) + buy_limit = self.get_target_bid(pair, self.exchange.get_ticker(pair)) min_stake_amount = self._get_min_pair_stake_amount(pair_s, buy_limit) if min_stake_amount is not None and min_stake_amount > stake_amount: @@ -492,7 +552,7 @@ class FreqtradeBot(object): raise ValueError(f'attempt to handle closed trade: {trade}') logger.debug('Handling %s ...', trade) - current_rate = self.exchange.get_ticker(trade.pair)['bid'] + sell_rate = self.exchange.get_ticker(trade.pair)['bid'] (buy, sell) = (False, False) experimental = self.config.get('experimental', {}) @@ -501,13 +561,44 @@ class FreqtradeBot(object): (buy, sell) = self.strategy.get_signal(trade.pair, self.strategy.ticker_interval, ticker) - should_sell = self.strategy.should_sell(trade, current_rate, datetime.utcnow(), buy, sell) - if should_sell.sell_flag: - self.execute_sell(trade, current_rate, should_sell.sell_type) - return True + experimental_ask_strategy = self.config.get('experimental', {}).get('ask_strategy', {}) + if 'use_order_book' in experimental_ask_strategy and\ + experimental_ask_strategy.get('use_order_book', False): + logger.info('Using order book for selling...') + # logger.debug('Order book %s',orderBook) + order_book_min = experimental_ask_strategy.get('order_book_min', 1) + order_book_max = experimental_ask_strategy.get('order_book_max', 1) + + order_book = self.exchange.get_order_book(trade.pair, order_book_max) + + for i in range(order_book_min, order_book_max + 1): + order_book_rate = order_book['asks'][i - 1][0] + + # if orderbook has higher rate (high profit), + # use orderbook, otherwise just use bids rate + logger.info(' order book asks top %s: %0.8f', i, order_book_rate) + if sell_rate < order_book_rate: + sell_rate = order_book_rate + + if self.check_sell(trade, sell_rate, buy, sell): + return True + break + else: + logger.info('checking sell') + if self.check_sell(trade, sell_rate, buy, sell): + return True + logger.info('Found no sell signals for whitelisted currencies. Trying again..') return False + def check_sell(self, trade: Trade, sell_rate: float, buy: bool, sell: bool) -> bool: + should_sell = self.strategy.should_sell(trade, sell_rate, datetime.utcnow(), buy, sell) + if should_sell.sell_flag: + self.execute_sell(trade, sell_rate, should_sell.sell_type) + logger.info('excuted sell') + return True + return False + def check_handle_timedout(self) -> None: """ Check if any orders are timed out and cancel if neccessary diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index d18016e16..d7f7e96d9 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -116,6 +116,22 @@ def default_conf(): "NEO/BTC" ] }, + "experimental": { + "check_depth_of_market": { + "enabled": False, + "bids_to_ask_delta": 1 + }, + "bid_strategy": { + "percent_from_top": 0, + "use_order_book": False, + "order_book_top": 1 + }, + "ask_strategy": { + "use_order_book": False, + "order_book_min": 1, + "order_book_max": 1 + } + }, "telegram": { "enabled": True, "token": "token", diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index d327b97c7..d0917bda2 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -515,6 +515,16 @@ def test_get_ticker(default_conf, mocker): exchange.get_ticker(pair='ETH/BTC', refresh=True) +def test_get_order_book(default_conf, mocker): + default_conf['exchange']['name'] = 'binance' + exchange = Exchange(default_conf) + order_book = exchange.get_order_book(pair='ETH/BTC', limit=50) + assert 'bids' in order_book + assert 'asks' in order_book + assert len(order_book['bids']) == 50 + assert len(order_book['asks']) == 50 + + def make_fetch_ohlcv_mock(data): def fetch_ohlcv_mock(pair, timeframe, since): if since: diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 69f349107..4718ab0fa 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -664,21 +664,21 @@ def test_balance_fully_ask_side(mocker, default_conf) -> None: default_conf['bid_strategy']['ask_last_balance'] = 0.0 freqtrade = get_patched_freqtradebot(mocker, default_conf) - assert freqtrade.get_target_bid({'ask': 20, 'last': 10}) == 20 + assert freqtrade.get_target_bid('ETH/BTC', {'ask': 20, 'last': 10}) == 20 def test_balance_fully_last_side(mocker, default_conf) -> None: default_conf['bid_strategy']['ask_last_balance'] = 1.0 freqtrade = get_patched_freqtradebot(mocker, default_conf) - assert freqtrade.get_target_bid({'ask': 20, 'last': 10}) == 10 + assert freqtrade.get_target_bid('ETH/BTC', {'ask': 20, 'last': 10}) == 10 def test_balance_bigger_last_ask(mocker, default_conf) -> None: default_conf['bid_strategy']['ask_last_balance'] = 1.0 freqtrade = get_patched_freqtradebot(mocker, default_conf) - assert freqtrade.get_target_bid({'ask': 5, 'last': 10}) == 5 + assert freqtrade.get_target_bid('ETH/BTC', {'ask': 5, 'last': 10}) == 5 def test_process_maybe_execute_buy(mocker, default_conf) -> None: @@ -1876,3 +1876,36 @@ def test_get_real_amount_open_trade(default_conf, mocker): freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) assert freqtrade.get_real_amount(trade, order) == amount + + +def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, markets, mocker): + default_conf['experimental']['check_depth_of_market']['enabled'] = True + default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 0.1 + patch_RPCManager(mocker) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + validate_pairs=MagicMock(), + get_ticker=ticker, + buy=MagicMock(return_value={'id': limit_buy_order['id']}), + get_fee=fee, + get_markets=markets + ) + + # Save state of current whitelist + whitelist = deepcopy(default_conf['exchange']['pair_whitelist']) + freqtrade = FreqtradeBot(default_conf) + patch_get_signal(freqtrade) + freqtrade.create_trade() + + trade = Trade.query.first() + assert trade is not None + assert trade.stake_amount == 0.001 + assert trade.is_open + assert trade.open_date is not None + assert trade.exchange == 'bittrex' + + # Simulate fulfilled LIMIT_BUY order for trade + trade.update(limit_buy_order) + + assert trade.open_rate == 0.00001099 + assert whitelist == default_conf['exchange']['pair_whitelist'] From be9436b2a6d7e50bd61c90cc51a832e0cd13ceb8 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 5 Aug 2018 14:26:07 +0200 Subject: [PATCH 11/84] Update ccxt from 1.17.73 to 1.17.78 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 221bdf968..3c2b10847 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.73 +ccxt==1.17.78 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From ba4de4137e033319ed34ce8ffca155f56b100480 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 5 Aug 2018 14:26:08 +0200 Subject: [PATCH 12/84] Update pandas from 0.23.3 to 0.23.4 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3c2b10847..edeb07527 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ cachetools==2.1.0 requests==2.19.1 urllib3==1.22 wrapt==1.10.11 -pandas==0.23.3 +pandas==0.23.4 scikit-learn==0.19.2 scipy==1.1.0 jsonschema==2.6.0 From 26d591ea43dfc8a9799ab80bbc0e7bdbdd51f724 Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Sun, 5 Aug 2018 21:08:07 +0800 Subject: [PATCH 13/84] mypy fix --- freqtrade/exchange/__init__.py | 2 +- freqtrade/exchange/exchange_helpers.py | 7 ++++--- freqtrade/freqtradebot.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 18b95b604..d5be25ba0 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -116,7 +116,7 @@ class Exchange(object): api.urls['api'] = api.urls['test'] logger.info("Enabled Sandbox API on %s", name) else: - logger.warning(self, "No Sandbox URL in CCXT, exiting. " + logger.warning(name, "No Sandbox URL in CCXT, exiting. " "Please check your config.json") raise OperationalException(f'Exchange {name} does not provide a sandbox api') diff --git a/freqtrade/exchange/exchange_helpers.py b/freqtrade/exchange/exchange_helpers.py index 6574f5a53..ac729190a 100644 --- a/freqtrade/exchange/exchange_helpers.py +++ b/freqtrade/exchange/exchange_helpers.py @@ -34,7 +34,7 @@ def parse_ticker_dataframe(ticker: list) -> DataFrame: return frame -def order_book_to_dataframe(data: list) -> DataFrame: +def order_book_to_dataframe(bids: list, asks: list) -> DataFrame: """ Gets order book list, returns dataframe with below format per suggested by creslin ------------------------------------------------------------------- @@ -42,11 +42,12 @@ def order_book_to_dataframe(data: list) -> DataFrame: ------------------------------------------------------------------- """ cols = ['bids', 'b_size'] - bids_frame = DataFrame(data['bids'], columns=cols) + + bids_frame = DataFrame(bids, columns=cols) # add cumulative sum column bids_frame['b_sum'] = bids_frame['b_size'].cumsum() cols2 = ['asks', 'a_size'] - asks_frame = DataFrame(data['asks'], columns=cols2) + asks_frame = DataFrame(asks, columns=cols2) # add cumulative sum column asks_frame['a_sum'] = asks_frame['a_size'].cumsum() diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 0c4670971..b91cb1bd2 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -386,7 +386,7 @@ class FreqtradeBot(object): conf_bids_to_ask_delta = experimental_check_depth_of_market.get('bids_to_ask_delta', 0) logger.info('checking depth of market for %s', pair) order_book = self.exchange.get_order_book(pair, 1000) - order_book_data_frame = order_book_to_dataframe(order_book) + order_book_data_frame = order_book_to_dataframe(order_book['bids'], order_book['asks']) order_book_bids = order_book_data_frame['b_size'].sum() order_book_asks = order_book_data_frame['a_size'].sum() bids_ask_delta = order_book_bids / order_book_asks From 7143b64fb73411744686381770a3adbf1897da6c Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Sun, 5 Aug 2018 22:41:58 +0800 Subject: [PATCH 14/84] tests for coverage --- freqtrade/freqtradebot.py | 7 +- freqtrade/tests/exchange/test_exchange.py | 16 +++++ freqtrade/tests/test_freqtradebot.py | 81 +++++++++++++++++++++++ 3 files changed, 98 insertions(+), 6 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index b91cb1bd2..f1955a9d7 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -264,11 +264,6 @@ class FreqtradeBot(object): else: logger.info('Using Last Ask / Last Price') used_rate = ticker_rate - percent_from_top = self.config.get('bid_strategy', {}).get('percent_from_top', 0) - if percent_from_top > 0: - used_rate = used_rate - (used_rate * percent_from_top) - used_rate = self._trunc_num(used_rate, 8) - logger.info('...percent_from_top enabled, new buy rate %0.8f', used_rate) return used_rate @@ -377,7 +372,7 @@ class FreqtradeBot(object): return self.execute_buy(_pair, stake_amount) return False - def _check_depth_of_market_buy(self, pair: str, ) -> bool: + def _check_depth_of_market_buy(self, pair: str) -> bool: """ Checks depth of market before executing a buy """ diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index d0917bda2..60f51553a 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -525,6 +525,22 @@ def test_get_order_book(default_conf, mocker): assert len(order_book['asks']) == 50 +def test_get_order_book_exception(default_conf, mocker): + api_mock = MagicMock() + with pytest.raises(OperationalException): + api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NotSupported) + exchange = get_patched_exchange(mocker, default_conf, api_mock) + exchange.get_order_book(pair='ETH/BTC', limit=50) + with pytest.raises(TemporaryError): + api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.NetworkError) + exchange = get_patched_exchange(mocker, default_conf, api_mock) + exchange.get_order_book(pair='ETH/BTC', limit=50) + with pytest.raises(OperationalException): + api_mock.fetch_l2_order_book = MagicMock(side_effect=ccxt.BaseError) + exchange = get_patched_exchange(mocker, default_conf, api_mock) + exchange.get_order_book(pair='ETH/BTC', limit=50) + + def make_fetch_ohlcv_mock(data): def fetch_ohlcv_mock(pair, timeframe, since): if since: diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 4718ab0fa..563f9961b 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1909,3 +1909,84 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, assert trade.open_rate == 0.00001099 assert whitelist == default_conf['exchange']['pair_whitelist'] + + +def test_order_book_depth_of_market_high_delta(default_conf, ticker, + limit_buy_order, fee, markets, mocker): + default_conf['experimental']['check_depth_of_market']['enabled'] = True + default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 100 + patch_RPCManager(mocker) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + validate_pairs=MagicMock(), + get_ticker=ticker, + buy=MagicMock(return_value={'id': limit_buy_order['id']}), + get_fee=fee, + get_markets=markets + ) + + # Save state of current whitelist + freqtrade = FreqtradeBot(default_conf) + patch_get_signal(freqtrade) + freqtrade.create_trade() + + trade = Trade.query.first() + assert trade is None + + +def test_order_book_bid_strategy(default_conf) -> None: + default_conf['exchange']['name'] = 'binance' + default_conf['experimental']['bid_strategy']['use_order_book'] = True + default_conf['experimental']['bid_strategy']['order_book_top'] = 2 + default_conf['telegram']['enabled'] = False + + freqtrade = FreqtradeBot(default_conf) + + assert freqtrade.get_target_bid('ETH/BTC', {'ask': 20, 'last': 10}) != 20 + + +def test_trunc_num(default_conf) -> None: + default_conf['telegram']['enabled'] = False + freqtrade = FreqtradeBot(default_conf) + + assert freqtrade._trunc_num(10.1111, 2) == 10.11 + + +def test_check_depth_of_market_buy(default_conf) -> None: + default_conf['telegram']['enabled'] = False + default_conf['exchange']['name'] = 'binance' + default_conf['experimental']['check_depth_of_market']['enabled'] = True + default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 100 + freqtrade = FreqtradeBot(default_conf) + + assert freqtrade._check_depth_of_market_buy('ETH/BTC') is False + + +def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order, + fee, markets, mocker) -> None: + default_conf['exchange']['name'] = 'binance' + default_conf['experimental']['ask_strategy']['use_order_book'] = True + default_conf['experimental']['ask_strategy']['order_book_min'] = 1 + default_conf['experimental']['ask_strategy']['order_book_max'] = 2 + default_conf['telegram']['enabled'] = False + patch_RPCManager(mocker) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + validate_pairs=MagicMock(), + get_ticker=MagicMock(return_value={ + 'bid': 0.00001172, + 'ask': 0.00001173, + 'last': 0.00001172 + }), + buy=MagicMock(return_value={'id': limit_buy_order['id']}), + sell=MagicMock(return_value={'id': limit_sell_order['id']}), + get_fee=fee, + get_markets=markets + ) + freqtrade = FreqtradeBot(default_conf) + patch_get_signal(freqtrade) + + freqtrade.create_trade() + + trade = Trade.query.first() + assert trade From 1309c2b14f50c55acdbdeaaf217aba34dfd7656b Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Sun, 5 Aug 2018 22:56:14 +0800 Subject: [PATCH 15/84] tests update --- freqtrade/freqtradebot.py | 6 +++--- freqtrade/tests/test_freqtradebot.py | 10 +++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index f1955a9d7..496ef1168 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -260,7 +260,8 @@ class FreqtradeBot(object): if ticker_rate < order_book_rate: logger.info('...using ticker rate instead %0.8f', ticker_rate) used_rate = ticker_rate - used_rate = order_book_rate + else: + used_rate = order_book_rate else: logger.info('Using Last Ask / Last Price') used_rate = ticker_rate @@ -557,8 +558,7 @@ class FreqtradeBot(object): ticker) experimental_ask_strategy = self.config.get('experimental', {}).get('ask_strategy', {}) - if 'use_order_book' in experimental_ask_strategy and\ - experimental_ask_strategy.get('use_order_book', False): + if experimental_ask_strategy.get('use_order_book', False): logger.info('Using order book for selling...') # logger.debug('Order book %s',orderBook) order_book_min = experimental_ask_strategy.get('order_book_min', 1) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 563f9961b..6282720d6 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1938,11 +1938,12 @@ def test_order_book_bid_strategy(default_conf) -> None: default_conf['exchange']['name'] = 'binance' default_conf['experimental']['bid_strategy']['use_order_book'] = True default_conf['experimental']['bid_strategy']['order_book_top'] = 2 + default_conf['bid_strategy']['ask_last_balance'] = 0 default_conf['telegram']['enabled'] = False freqtrade = FreqtradeBot(default_conf) - assert freqtrade.get_target_bid('ETH/BTC', {'ask': 20, 'last': 10}) != 20 + assert freqtrade.get_target_bid('BTC/USDT', {'ask': 2, 'last': 2}) == 2 def test_trunc_num(default_conf) -> None: @@ -1990,3 +1991,10 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order trade = Trade.query.first() assert trade + + time.sleep(0.01) # Race condition fix + trade.update(limit_buy_order) + assert trade.is_open is True + + patch_get_signal(freqtrade, value=(False, True)) + assert freqtrade.handle_trade(trade) is True From 0b825e96aac2bf5e93606309ccc12a209cdf6582 Mon Sep 17 00:00:00 2001 From: Axel Cherubin Date: Sun, 5 Aug 2018 16:08:49 -0400 Subject: [PATCH 16/84] fix talib bug on bollinger bands and other indicators when working on small assets, rise talib prescision and add test associated --- Dockerfile | 1 + freqtrade/tests/test_talib.py | 15 +++++++++++++++ install_ta-lib.sh | 8 ++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 freqtrade/tests/test_talib.py diff --git a/Dockerfile b/Dockerfile index 309763d2a..e959b9296 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,7 @@ RUN apt-get update && apt-get -y install curl build-essential && apt-get clean RUN curl -L http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz | \ tar xzvf - && \ cd ta-lib && \ + sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && \ ./configure && make && make install && \ cd .. && rm -rf ta-lib ENV LD_LIBRARY_PATH /usr/local/lib diff --git a/freqtrade/tests/test_talib.py b/freqtrade/tests/test_talib.py new file mode 100644 index 000000000..f5e51c553 --- /dev/null +++ b/freqtrade/tests/test_talib.py @@ -0,0 +1,15 @@ + + +import talib.abstract as ta +import pandas as pd + +def test_talib_bollingerbands_near_zero_values(): + inputs = pd.DataFrame([ + {'close': 0.00000010}, + {'close': 0.00000011}, + {'close': 0.00000012}, + {'close': 0.00000013}, + {'close': 0.00000014} + ]) + bollinger = ta.BBANDS(inputs, matype=0, timeperiod=2) + assert (bollinger['upperband'][3] != bollinger['middleband'][3]) \ No newline at end of file diff --git a/install_ta-lib.sh b/install_ta-lib.sh index 21e69cbba..d5d7cf03e 100755 --- a/install_ta-lib.sh +++ b/install_ta-lib.sh @@ -1,7 +1,11 @@ if [ ! -f "ta-lib/CHANGELOG.TXT" ]; then tar zxvf ta-lib-0.4.0-src.tar.gz - cd ta-lib && ./configure && make && sudo make install && cd .. + cd ta-lib && \ + sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && \ + ./configure && make && sudo make install && cd .. else echo "TA-lib already installed, skipping download and build." - cd ta-lib && sudo make install && cd .. + cd ta-lib && \ + sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && \ + sudo make install && cd .. fi From a5554604e0e3a9a01582d5221f13e754766d7e87 Mon Sep 17 00:00:00 2001 From: Axel Cherubin Date: Sun, 5 Aug 2018 16:59:18 -0400 Subject: [PATCH 17/84] add sed command in doc, fix travis error --- docs/installation.md | 1 + install_ta-lib.sh | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 7a7719fc0..4de05c121 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -267,6 +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 tar xvzf 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 --prefix=/usr make make install diff --git a/install_ta-lib.sh b/install_ta-lib.sh index d5d7cf03e..1639bd3a2 100755 --- a/install_ta-lib.sh +++ b/install_ta-lib.sh @@ -1,11 +1,7 @@ if [ ! -f "ta-lib/CHANGELOG.TXT" ]; then 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 "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && ./configure && make && sudo make install && cd .. else echo "TA-lib already installed, skipping download and build." - cd ta-lib && \ - sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && \ - sudo make install && cd .. + cd ta-lib && sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && sudo make install && cd .. fi From 848ecb91bbb537e834cc38221d2360fd4a0118a0 Mon Sep 17 00:00:00 2001 From: Axel Cherubin Date: Sun, 5 Aug 2018 17:28:53 -0400 Subject: [PATCH 18/84] remove unnecessary seb command --- install_ta-lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install_ta-lib.sh b/install_ta-lib.sh index 1639bd3a2..18e7b8bbb 100755 --- a/install_ta-lib.sh +++ b/install_ta-lib.sh @@ -3,5 +3,5 @@ if [ ! -f "ta-lib/CHANGELOG.TXT" ]; then cd ta-lib && sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && ./configure && make && sudo make install && cd .. else echo "TA-lib already installed, skipping download and build." - cd ta-lib && sed -i "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h && sudo make install && cd .. + cd ta-lib && sudo make install && cd .. fi From 65f7b75c343693ed560a15addaac6413865fd865 Mon Sep 17 00:00:00 2001 From: Axel Cherubin Date: Sun, 5 Aug 2018 17:52:06 -0400 Subject: [PATCH 19/84] fix flake8 issue --- freqtrade/tests/test_talib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/tests/test_talib.py b/freqtrade/tests/test_talib.py index f5e51c553..093c3023c 100644 --- a/freqtrade/tests/test_talib.py +++ b/freqtrade/tests/test_talib.py @@ -3,6 +3,7 @@ import talib.abstract as ta import pandas as pd + def test_talib_bollingerbands_near_zero_values(): inputs = pd.DataFrame([ {'close': 0.00000010}, @@ -12,4 +13,4 @@ def test_talib_bollingerbands_near_zero_values(): {'close': 0.00000014} ]) bollinger = ta.BBANDS(inputs, matype=0, timeperiod=2) - assert (bollinger['upperband'][3] != bollinger['middleband'][3]) \ No newline at end of file + assert (bollinger['upperband'][3] != bollinger['middleband'][3]) From bc62f626c529ed7478f7876bf52b7c6dd2fb42a3 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 6 Aug 2018 14:26:06 +0200 Subject: [PATCH 20/84] Update ccxt from 1.17.78 to 1.17.81 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index edeb07527..f3135f9bb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.78 +ccxt==1.17.81 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 131d268721f7a9499961db619d337261ee7b4f62 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Aug 2018 19:15:30 +0200 Subject: [PATCH 21/84] Fix failing tests when metadata in `analyze_ticker` is actually used --- freqtrade/tests/test_dataframe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/tests/test_dataframe.py b/freqtrade/tests/test_dataframe.py index ce144e118..dc030d630 100644 --- a/freqtrade/tests/test_dataframe.py +++ b/freqtrade/tests/test_dataframe.py @@ -14,7 +14,7 @@ def load_dataframe_pair(pairs, strategy): assert isinstance(pairs[0], str) dataframe = ld[pairs[0]] - dataframe = strategy.analyze_ticker(dataframe, pairs[0]) + dataframe = strategy.analyze_ticker(dataframe, {'pair': pairs[0]}) return dataframe From c9580b31d0b2e7cd4e80a7b91f12d6fbc76f8ef8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 7 Aug 2018 09:25:21 +0200 Subject: [PATCH 22/84] parametrize outdated_offset to simplify sandbox usage --- config_full.json.example | 3 +- docs/sandbox-testing.md | 120 +++++++++++++++----------------- freqtrade/constants.py | 3 +- freqtrade/strategy/interface.py | 3 +- 4 files changed, 61 insertions(+), 68 deletions(-) diff --git a/config_full.json.example b/config_full.json.example index cc3b3d630..a06eeb7e6 100644 --- a/config_full.json.example +++ b/config_full.json.example @@ -41,7 +41,8 @@ ], "pair_blacklist": [ "DOGE/BTC" - ] + ], + "outdated_offset": 5 }, "experimental": { "use_sell_signal": false, diff --git a/docs/sandbox-testing.md b/docs/sandbox-testing.md index 572fbccef..7f3457d15 100644 --- a/docs/sandbox-testing.md +++ b/docs/sandbox-testing.md @@ -1,4 +1,5 @@ # Sandbox API testing + Where an exchange provides a sandbox for risk-free integration, or end-to-end, testing CCXT provides access to these. This document is a *light overview of configuring Freqtrade and GDAX sandbox. @@ -11,8 +12,11 @@ https://public.sandbox.gdax.com https://api-public.sandbox.gdax.com --- + # Configure a Sandbox account on Gdax + Aim of this document section + - An sanbox account - create 2FA (needed to create an API) - Add test 50BTC to account @@ -30,122 +34,108 @@ After registration and Email confimation you wil be redirected into your sanbox > https://public.sandbox.pro.coinbase.com/ ## Enable 2Fa (a prerequisite to creating sandbox API Keys) + From within sand box site select your profile, top right. >Or as a direct link: https://public.sandbox.pro.coinbase.com/profile -From the menu panel to the left of the screen select +From the menu panel to the left of the screen select + > Security: "*View or Update*" -In the new site select "enable authenticator" as typical google Authenticator. -- open Google Authenticator on your phone -- scan barcode -- enter your generated 2fa +In the new site select "enable authenticator" as typical google Authenticator. + +- open Google Authenticator on your phone +- scan barcode +- enter your generated 2fa + +## Enable API Access -## Enable API Access From within sandbox select profile>api>create api-keys >or as a direct link: https://public.sandbox.pro.coinbase.com/profile/api -Click on "create one" and ensure **view** and **trade** are "checked" and sumbit your 2Fa +Click on "create one" and ensure **view** and **trade** are "checked" and sumbit your 2FA + - **Copy and paste the Passphase** into a notepade this will be needed later - **Copy and paste the API Secret** popup into a notepad this will needed later - **Copy and paste the API Key** into a notepad this will needed later ## Add 50 BTC test funds -To add funds, use the web interface deposit and withdraw buttons. +To add funds, use the web interface deposit and withdraw buttons. To begin select 'Wallets' from the top menu. > Or as a direct link: https://public.sandbox.pro.coinbase.com/wallets - Deposits (bottom left of screen) -- - Deposit Funds Bitcoin -- - - Coinbase BTC Wallet -- - - - Max (50 BTC) +- - Deposit Funds Bitcoin +- - - Coinbase BTC Wallet +- - - - Max (50 BTC) - - - - - Deposit *This process may be repeated for other currencies, ETH as example* + --- + # Configure Freqtrade to use Gax Sandbox The aim of this document section - - Enable sandbox URLs in Freqtrade - - Configure API - - - secret - - - key - - - passphrase + +- Enable sandbox URLs in Freqtrade +- Configure API +- - secret +- - key +- - passphrase ## Sandbox URLs -Freqtrade makes use of CCXT which in turn provides a list of URLs to Freqtrade. -These include `['test']` and `['api']`. + +Freqtrade makes use of CCXT which in turn provides a list of URLs to Freqtrade. +These include `['test']` and `['api']`. + - `[Test]` if available will point to an Exchanges sandbox. - `[Api]` normally used, and resolves to live API target on the exchange To make use of sandbox / test add "sandbox": true, to your config.json -``` + +```json "exchange": { "name": "gdax", "sandbox": true, "key": "5wowfxemogxeowo;heiohgmd", "secret": "/ZMH1P62rCVmwefewrgcewX8nh4gob+lywxfwfxwwfxwfNsH1ySgvWCUR/w==", "password": "1bkjfkhfhfu6sr", + "outdated_offset": 5 "pair_whitelist": [ "BTC/USD" ``` + Also insert your + - api-key (noted earlier) - api-secret (noted earlier) - password (the passphrase - noted earlier) --- -## You should now be ready to test your sandbox! + +## You should now be ready to test your sandbox + Ensure Freqtrade logs show the sandbox URL, and trades made are shown in sandbox. -** Typically the BTC/USD has the most activity in sandbox to test against. +** Typically the BTC/USD has the most activity in sandbox to test against. ## GDAX - Old Candles problem -It is my experience that GDAX sandbox candles may be 20+- minutes out of date. This can cause trades to fail as one of Freqtrades safety checks -To disable this check, edit: ->strategy/interface.py -Look for the following section: -``` - # Check if dataframe is out of date - signal_date = arrow.get(latest['date']) - interval_minutes = constants.TICKER_INTERVAL_MINUTES[interval] - if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + 5))): - logger.warning( - 'Outdated history for pair %s. Last tick is %s minutes old', - pair, - (arrow.utcnow() - signal_date).seconds // 60 - ) - return False, False -``` +It is my experience that GDAX sandbox candles may be 20+- minutes out of date. This can cause trades to fail as one of Freqtrades safety checks. -You could Hash out the entire check as follows: +To disable this check, add / change the `"outdated_offset"` parameter in the exchange section of your configuration to adjust for this delay. +Example based on the above configuration: + +```json + "exchange": { + "name": "gdax", + "sandbox": true, + "key": "5wowfxemogxeowo;heiohgmd", + "secret": "/ZMH1P62rCVmwefewrgcewX8nh4gob+lywxfwfxwwfxwfNsH1ySgvWCUR/w==", + "password": "1bkjfkhfhfu6sr", + "outdated_offset": 30 + "pair_whitelist": [ + "BTC/USD" ``` - # # Check if dataframe is out of date - # signal_date = arrow.get(latest['date']) - # interval_minutes = constants.TICKER_INTERVAL_MINUTES[interval] - # if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + 5))): - # logger.warning( - # 'Outdated history for pair %s. Last tick is %s minutes old', - # pair, - # (arrow.utcnow() - signal_date).seconds // 60 - # ) - # return False, False - ``` - - Or inrease the timeout to offer a level of protection/alignment of this test to freqtrade in live. - - As example, to allow an additional 30 minutes. "(interval_minutes * 2 + 5 + 30)" - ``` - # Check if dataframe is out of date - signal_date = arrow.get(latest['date']) - interval_minutes = constants.TICKER_INTERVAL_MINUTES[interval] - if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + 5 + 30))): - logger.warning( - 'Outdated history for pair %s. Last tick is %s minutes old', - pair, - (arrow.utcnow() - signal_date).seconds // 60 - ) - return False, False -``` \ No newline at end of file diff --git a/freqtrade/constants.py b/freqtrade/constants.py index b30add71b..175d09405 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -145,7 +145,8 @@ CONF_SCHEMA = { 'pattern': '^[0-9A-Z]+/[0-9A-Z]+$' }, 'uniqueItems': True - } + }, + 'outdated_offset': {'type': 'integer', 'minimum': 1} }, 'required': ['name', 'key', 'secret', 'pair_whitelist'] } diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index dfd624393..aa1e903de 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -155,7 +155,8 @@ class IStrategy(ABC): # Check if dataframe is out of date signal_date = arrow.get(latest['date']) interval_minutes = constants.TICKER_INTERVAL_MINUTES[interval] - if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + 5))): + offset = self.config.get('outdated_offset', 5) + if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): logger.warning( 'Outdated history for pair %s. Last tick is %s minutes old', pair, From c9c0e108ab249df607699c4b8ea066517e664e24 Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Tue, 7 Aug 2018 18:29:37 +0800 Subject: [PATCH 23/84] refactor --- freqtrade/exchange/__init__.py | 20 +++++++++---- freqtrade/freqtradebot.py | 15 +++------- freqtrade/tests/test_freqtradebot.py | 43 +++++++++++++++++++++------- 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index d5be25ba0..4b78283ea 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -411,15 +411,23 @@ class Exchange(object): @retrier def get_order_book(self, pair: str, limit: int = 100) -> dict: + """ + get order book level 2 from exchange + + Notes: + 20180619: bittrex doesnt support limits -.- + 20180619: binance support limits but only on specific range + """ try: - # 20180619: bittrex doesnt support limits -.- - # 20180619: binance support limits but only on specific range if self._api.name == 'Binance': limit_range = [5, 10, 20, 50, 100, 500, 1000] - for limitx in limit_range: - if limit <= limitx: - limit = limitx - break + # get next-higher step in the limit_range list + limit = min(list(filter(lambda x: limit <= x, limit_range))) + # above script works like loop below (but with slightly better performance): + # for limitx in limit_range: + # if limit <= limitx: + # limit = limitx + # break return self._api.fetch_l2_order_book(pair, limit) except ccxt.NotSupported as e: diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 496ef1168..55b9c577f 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -268,10 +268,6 @@ class FreqtradeBot(object): return used_rate - def _trunc_num(self, f, n): - import math - return math.floor(f * 10 ** n) / 10 ** n - def _get_trade_stake_amount(self) -> Optional[float]: """ Check if stake amount can be fulfilled with the available balance @@ -366,20 +362,18 @@ class FreqtradeBot(object): get('check_depth_of_market', {}) if (experimental_check_depth_of_market.get('enabled', False)) and\ (experimental_check_depth_of_market.get('bids_to_ask_delta', 0) > 0): - if self._check_depth_of_market_buy(_pair): + if self._check_depth_of_market_buy(_pair, experimental_check_depth_of_market): return self.execute_buy(_pair, stake_amount) else: return False return self.execute_buy(_pair, stake_amount) return False - def _check_depth_of_market_buy(self, pair: str) -> bool: + def _check_depth_of_market_buy(self, pair: str, conf: Dict) -> bool: """ Checks depth of market before executing a buy """ - experimental_check_depth_of_market = self.config.get('experimental', {}).\ - get('check_depth_of_market', {}) - conf_bids_to_ask_delta = experimental_check_depth_of_market.get('bids_to_ask_delta', 0) + conf_bids_to_ask_delta = conf.get('bids_to_ask_delta', 0) logger.info('checking depth of market for %s', pair) order_book = self.exchange.get_order_book(pair, 1000) order_book_data_frame = order_book_to_dataframe(order_book['bids'], order_book['asks']) @@ -387,8 +381,7 @@ class FreqtradeBot(object): order_book_asks = order_book_data_frame['a_size'].sum() bids_ask_delta = order_book_bids / order_book_asks logger.info('bids: %s, asks: %s, delta: %s', order_book_bids, - order_book_asks, - order_book_bids / order_book_asks) + order_book_asks, bids_ask_delta) if bids_ask_delta >= conf_bids_to_ask_delta: return True return False diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 6282720d6..4357b573a 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -159,6 +159,15 @@ def test_gen_pair_whitelist(mocker, default_conf, tickers) -> None: assert whitelist == [] +def test_gen_pair_whitelist_not_supported(mocker, default_conf, tickers) -> None: + freqtrade = get_patched_freqtradebot(mocker, default_conf) + mocker.patch('freqtrade.exchange.Exchange.get_tickers', tickers) + mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=False)) + + with pytest.raises(OperationalException): + freqtrade._gen_pair_whitelist(base_currency='BTC') + + @pytest.mark.skip(reason="Test not implemented") def test_refresh_whitelist() -> None: pass @@ -1914,6 +1923,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_order, fee, markets, mocker): default_conf['experimental']['check_depth_of_market']['enabled'] = True + # delta is 100 which is impossible to reach. hence check_depth_of_market will return false default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 100 patch_RPCManager(mocker) mocker.patch.multiple( @@ -1924,7 +1934,6 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, get_fee=fee, get_markets=markets ) - # Save state of current whitelist freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) @@ -1934,33 +1943,47 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, assert trade is None -def test_order_book_bid_strategy(default_conf) -> None: +def test_order_book_bid_strategy1(default_conf) -> None: + """ + test if function get_target_bid will return the order book price + instead of the ask rate + """ default_conf['exchange']['name'] = 'binance' default_conf['experimental']['bid_strategy']['use_order_book'] = True default_conf['experimental']['bid_strategy']['order_book_top'] = 2 default_conf['bid_strategy']['ask_last_balance'] = 0 default_conf['telegram']['enabled'] = False + freqtrade = FreqtradeBot(default_conf) + assert freqtrade.get_target_bid('BTC/USDT', {'ask': 200000, 'last': 200000}) != 200000 + + +def test_order_book_bid_strategy2(default_conf) -> None: + """ + test if function get_target_bid will return ask rate instead + of the order book rate + """ + default_conf['exchange']['name'] = 'binance' + default_conf['experimental']['bid_strategy']['use_order_book'] = True + default_conf['experimental']['bid_strategy']['order_book_top'] = 1 + default_conf['bid_strategy']['ask_last_balance'] = 0 + default_conf['telegram']['enabled'] = False + freqtrade = FreqtradeBot(default_conf) assert freqtrade.get_target_bid('BTC/USDT', {'ask': 2, 'last': 2}) == 2 -def test_trunc_num(default_conf) -> None: - default_conf['telegram']['enabled'] = False - freqtrade = FreqtradeBot(default_conf) - - assert freqtrade._trunc_num(10.1111, 2) == 10.11 - - def test_check_depth_of_market_buy(default_conf) -> None: default_conf['telegram']['enabled'] = False default_conf['exchange']['name'] = 'binance' default_conf['experimental']['check_depth_of_market']['enabled'] = True + # delta is 100 which is impossible to reach. hence function will return false default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 100 freqtrade = FreqtradeBot(default_conf) - assert freqtrade._check_depth_of_market_buy('ETH/BTC') is False + conf = default_conf['experimental']['check_depth_of_market'] + assert freqtrade._check_depth_of_market_buy('ETH/BTC', conf) is False def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order, From 3d94720be98953f658f0c96d867d055a0c6d5f91 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 7 Aug 2018 14:26:07 +0200 Subject: [PATCH 24/84] Update ccxt from 1.17.81 to 1.17.84 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f3135f9bb..2db78bd2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.81 +ccxt==1.17.84 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 4d03fc213f51acbe5a23a5f7e13e94c5ad02b428 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 8 Aug 2018 14:26:07 +0200 Subject: [PATCH 25/84] Update ccxt from 1.17.84 to 1.17.86 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2db78bd2c..82c739a70 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.84 +ccxt==1.17.86 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 3c451e067716f65c656729dcc4a95333836d0c55 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 8 Aug 2018 21:54:52 +0200 Subject: [PATCH 26/84] Add test for bugreport #1111 --- freqtrade/tests/rpc/test_rpc.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index 70b7dcfd9..01130fccf 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -6,6 +6,7 @@ from unittest.mock import MagicMock, ANY import pytest +from freqtrade import TemporaryError from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade @@ -320,6 +321,32 @@ def test_rpc_balance_handle(default_conf, mocker): 'pending': 2.0, 'est_btc': 12.0, }] + assert result['total'] == 12.0 + + mock_balance = { + 'ETH': { + 'free': 10.0, + 'total': 12.0, + 'used': 2.0, + } + } + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + validate_pairs=MagicMock(), + get_balances=MagicMock(return_value=mock_balance), + get_ticker=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx')) + ) + result = rpc._rpc_balance(default_conf['fiat_display_currency']) + assert prec_satoshi(result['total'], 12) + assert prec_satoshi(result['value'], 180000) + assert 'USD' == result['symbol'] + assert result['currencies'] == [{ + 'currency': 'ETH', + 'available': 10.0, + 'balance': 12.0, + 'pending': 2.0, + 'est_btc': 12.0, + }] def test_rpc_start(mocker, default_conf) -> None: From e1921c88490b29735da7d959068bace13ee26c30 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 8 Aug 2018 21:55:48 +0200 Subject: [PATCH 27/84] Fix bug causing /balance to fail --- freqtrade/exchange/__init__.py | 2 +- freqtrade/rpc/rpc.py | 12 +++++++---- freqtrade/tests/rpc/test_rpc.py | 35 ++++++--------------------------- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index a6ec70636..485599c2c 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -322,7 +322,7 @@ class Exchange(object): return data except (ccxt.NetworkError, ccxt.ExchangeError) as e: raise TemporaryError( - f'Could not load ticker history due to {e.__class__.__name__}. Message: {e}') + f'Could not load ticker due to {e.__class__.__name__}. Message: {e}') except ccxt.BaseError as e: raise OperationalException(e) else: diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index f58fbae9a..a39469d07 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -13,6 +13,7 @@ import sqlalchemy as sql from numpy import mean, nan_to_num from pandas import DataFrame +from freqtrade import TemporaryError from freqtrade.fiat_convert import CryptoToFiatConverter from freqtrade.misc import shorten_date from freqtrade.persistence import Trade @@ -271,10 +272,13 @@ class RPC(object): if coin == 'BTC': rate = 1.0 else: - if coin == 'USDT': - rate = 1.0 / self._freqtrade.exchange.get_ticker('BTC/USDT', False)['bid'] - else: - rate = self._freqtrade.exchange.get_ticker(coin + '/BTC', False)['bid'] + try: + if coin == 'USDT': + rate = 1.0 / self._freqtrade.exchange.get_ticker('BTC/USDT', False)['bid'] + else: + rate = self._freqtrade.exchange.get_ticker(coin + '/BTC', False)['bid'] + except TemporaryError: + continue est_btc: float = rate * balance['total'] total = total + est_btc output.append({ diff --git a/freqtrade/tests/rpc/test_rpc.py b/freqtrade/tests/rpc/test_rpc.py index 01130fccf..c17ab6b2f 100644 --- a/freqtrade/tests/rpc/test_rpc.py +++ b/freqtrade/tests/rpc/test_rpc.py @@ -286,11 +286,12 @@ def test_rpc_balance_handle(default_conf, mocker): 'used': 2.0, }, 'ETH': { - 'free': 0.0, - 'total': 0.0, - 'used': 0.0, + 'free': 1.0, + 'total': 5.0, + 'used': 4.0, } } + # ETH will be skipped due to mocked Error below mocker.patch.multiple( 'freqtrade.fiat_convert.Market', @@ -302,7 +303,8 @@ def test_rpc_balance_handle(default_conf, mocker): mocker.patch.multiple( 'freqtrade.exchange.Exchange', validate_pairs=MagicMock(), - get_balances=MagicMock(return_value=mock_balance) + get_balances=MagicMock(return_value=mock_balance), + get_ticker=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx')) ) freqtradebot = FreqtradeBot(default_conf) @@ -323,31 +325,6 @@ def test_rpc_balance_handle(default_conf, mocker): }] assert result['total'] == 12.0 - mock_balance = { - 'ETH': { - 'free': 10.0, - 'total': 12.0, - 'used': 2.0, - } - } - mocker.patch.multiple( - 'freqtrade.exchange.Exchange', - validate_pairs=MagicMock(), - get_balances=MagicMock(return_value=mock_balance), - get_ticker=MagicMock(side_effect=TemporaryError('Could not load ticker due to xxx')) - ) - result = rpc._rpc_balance(default_conf['fiat_display_currency']) - assert prec_satoshi(result['total'], 12) - assert prec_satoshi(result['value'], 180000) - assert 'USD' == result['symbol'] - assert result['currencies'] == [{ - 'currency': 'ETH', - 'available': 10.0, - 'balance': 12.0, - 'pending': 2.0, - 'est_btc': 12.0, - }] - def test_rpc_start(mocker, default_conf) -> None: patch_coinmarketcap(mocker) From 1bcd4333fc3ffef27e978f33c3d8b47e554414f4 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 9 Aug 2018 14:26:06 +0200 Subject: [PATCH 28/84] Update ccxt from 1.17.86 to 1.17.94 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 82c739a70..91ecf71c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.86 +ccxt==1.17.94 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 5bec389e853ec6ab9c6fd48a0b2866af4e1fd069 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 11 Aug 2018 14:26:06 +0200 Subject: [PATCH 29/84] Update ccxt from 1.17.94 to 1.17.106 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 91ecf71c9..d3ff4e6d7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.94 +ccxt==1.17.106 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 5f8ec82319f63630db3f58f15b0ab6d6c3c17284 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Aug 2018 09:18:30 +0200 Subject: [PATCH 30/84] Revert "updated dockerfile and requirements" This reverts commit 2cfa3b7607874879584484c7c99d47c969517fb5. --- Dockerfile | 7 +------ requirements.txt | 10 ---------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/Dockerfile b/Dockerfile index 10cd14bfe..309763d2a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM python:3.6.6-slim-stretch # Install TA-lib -RUN apt-get update && apt-get -y install curl build-essential git && apt-get clean +RUN apt-get update && apt-get -y install curl build-essential && apt-get clean RUN curl -L http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz | \ tar xzvf - && \ cd ta-lib && \ @@ -13,11 +13,6 @@ ENV LD_LIBRARY_PATH /usr/local/lib RUN mkdir /freqtrade WORKDIR /freqtrade -# Update PIP -RUN python -m pip install --upgrade pip -RUN pip install future -RUN pip install numpy - # Install dependencies COPY requirements.txt /freqtrade/ RUN pip install numpy \ diff --git a/requirements.txt b/requirements.txt index 183d79cdf..ff6457a8c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,13 +23,3 @@ scikit-optimize==0.5.2 # Required for plotting data #plotly==3.0.0 - -# Required for plotting data -plotly==3.0.0 - -# find first, C search in arrays -py_find_1st==1.1.1 - -#Load ticker files 30% faster -ujson==1.35 -git+git://github.com/berlinguyinca/technical.git@master From ffa47151ee50ece9b00dece77e6fe3f0e6edfabf Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Aug 2018 09:30:12 +0200 Subject: [PATCH 31/84] Flake8 fix --- freqtrade/persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index c21b902bc..a169bc042 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -157,7 +157,7 @@ class Trade(_DECL_BASE): id = Column(Integer, primary_key=True) exchange = Column(String, nullable=False) - pair = Column(String, nullable=False,index=True) + pair = Column(String, nullable=False, index=True) is_open = Column(Boolean, nullable=False, default=True, index=True) fee_open = Column(Float, nullable=False, default=0.0) fee_close = Column(Float, nullable=False, default=0.0) From e3e79a55fa6fc1baedac19d8ff1b28af78391a97 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Aug 2018 10:16:51 +0200 Subject: [PATCH 32/84] Fix _abc_data pickle error in 3.7 --- freqtrade/strategy/__init__.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/freqtrade/strategy/__init__.py b/freqtrade/strategy/__init__.py index 283426dfa..49b0c45c0 100644 --- a/freqtrade/strategy/__init__.py +++ b/freqtrade/strategy/__init__.py @@ -12,8 +12,18 @@ def import_strategy(strategy: IStrategy, config: dict) -> IStrategy: Imports given Strategy instance to global scope of freqtrade.strategy and returns an instance of it """ + # Copy all attributes from base class and class - attr = deepcopy({**strategy.__class__.__dict__, **strategy.__dict__}) + + comb = {**strategy.__class__.__dict__, **strategy.__dict__} + + # Delete '_abc_impl' from dict as deepcopy fails on 3.7 with + # `TypeError: can't pickle _abc_data objects`` + # This will only apply to python 3.7 + if '_abc_impl' in comb: + del comb['_abc_impl'] + + attr = deepcopy(comb) # Adjust module name attr['__module__'] = 'freqtrade.strategy' From 7f6f5791ea0d56bd7ff6d029e40dd0287a335cc6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Aug 2018 10:25:19 +0200 Subject: [PATCH 33/84] update plotly dependency --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d3ff4e6d7..c13cd4fa8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,4 +22,4 @@ coinmarketcap==5.0.3 scikit-optimize==0.5.2 # Required for plotting data -#plotly==3.0.0 +#plotly==3.1.1 From f7afd9a5ffc354cc0559d9019b66a8bceaee1d6c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Aug 2018 10:37:10 +0200 Subject: [PATCH 34/84] update setup.sh to support 3.7 --- setup.sh | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/setup.sh b/setup.sh index a825ca41f..557bcdd12 100755 --- a/setup.sh +++ b/setup.sh @@ -1,13 +1,31 @@ #!/usr/bin/env bash #encoding=utf8 +# Check which python version is installed +function check_installed_python() { + which python3.7 + if [ $? -eq 0 ]; then + echo "using Python 3.7" + PYTHON=python3.7 + return + fi + + which python3.6 + if [ $? -eq 0 ]; then + echo "using Python 3.6" + PYTHON=python3.6 + return + fi + +} + function updateenv () { echo "-------------------------" echo "Update your virtual env" echo "-------------------------" source .env/bin/activate echo "pip3 install in-progress. Please wait..." - pip3.6 install --quiet --upgrade pip + pip3 install --quiet --upgrade pip pip3 install --quiet -r requirements.txt --upgrade pip3 install --quiet -r requirements.txt pip3 install --quiet -e . @@ -79,7 +97,7 @@ function reset () { fi echo - python3.6 -m venv .env + ${PYTHON} -m venv .env updateenv } @@ -183,7 +201,7 @@ function install () { install_debian else echo "This script does not support your OS." - echo "If you have Python3.6, pip, virtualenv, ta-lib you can continue." + echo "If you have Python3.6 or Python3.7, pip, virtualenv, ta-lib you can continue." echo "Wait 10 seconds to continue the next install steps or use ctrl+c to interrupt this shell." sleep 10 fi @@ -193,7 +211,7 @@ function install () { echo "-------------------------" echo "Run the bot" echo "-------------------------" - echo "You can now use the bot by executing 'source .env/bin/activate; python3.6 freqtrade/main.py'." + echo "You can now use the bot by executing 'source .env/bin/activate; ${PYTHON} freqtrade/main.py'." } function plot () { @@ -214,6 +232,9 @@ function help () { echo " -p,--plot Install dependencies for Plotting scripts." } +# Verify if 3.6 or 3.7 is installed +check_installed_python + case $* in --install|-i) install From 7d72e364aaa066e4e34387db4906611f39ea01c1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Aug 2018 13:08:10 +0200 Subject: [PATCH 35/84] Remove broken ujson loading - replace with variable-based fix --- freqtrade/optimize/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/__init__.py b/freqtrade/optimize/__init__.py index 5c1bd06ab..a2259e19c 100644 --- a/freqtrade/optimize/__init__.py +++ b/freqtrade/optimize/__init__.py @@ -3,10 +3,11 @@ import gzip try: import ujson as json + _UJSON = True except ImportError: # see mypy/issues/1153 import json # type: ignore -import inspect + _UJSON = False import logging import os from typing import Optional, List, Dict, Tuple, Any @@ -21,7 +22,7 @@ logger = logging.getLogger(__name__) def json_load(data): """Try to load data with ujson""" - if inspect.getfullargspec(json.load)[5].get('precise_float'): + if _UJSON: return json.load(data, precise_float=True) else: return json.load(data) From a0bc17d1ef25effd20c70130ecc4407d03d4fc2d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Aug 2018 13:59:50 +0200 Subject: [PATCH 36/84] Update dockerfile to 3.7.0 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e959b9296..5d1b44f8c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.6.6-slim-stretch +FROM python:3.7.0-slim-stretch # Install TA-lib RUN apt-get update && apt-get -y install curl build-essential && apt-get clean From 2e7837976da309dfcdc7d85186a5268766e21ae2 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 12 Aug 2018 14:26:06 +0200 Subject: [PATCH 37/84] Update ccxt from 1.17.106 to 1.17.113 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d3ff4e6d7..c1bd768c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.106 +ccxt==1.17.113 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From eca8682528d525885149693a1b6a1946ff08838a Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 13 Aug 2018 14:26:06 +0200 Subject: [PATCH 38/84] Update ccxt from 1.17.113 to 1.17.118 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c1bd768c5..d373f8c73 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.113 +ccxt==1.17.118 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 78610bb47f84007718b8dd6dfe1a7672bb1adb8c Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Tue, 14 Aug 2018 18:12:44 +0800 Subject: [PATCH 39/84] mock order_book and additional test --- freqtrade/freqtradebot.py | 1 + freqtrade/tests/conftest.py | 33 +++++++++++++++++++ freqtrade/tests/test_freqtradebot.py | 47 ++++++++++++++++++++++------ 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 55b9c577f..715cbce80 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -253,6 +253,7 @@ class FreqtradeBot(object): logger.info('Getting price from order book') order_book_top = experimental_bid_strategy.get('order_book_top', 1) order_book = self.exchange.get_order_book(pair, order_book_top) + logger.debug('order_book %s', order_book) # top 1 = index 0 order_book_rate = order_book['bids'][order_book_top - 1][0] # if ticker has lower rate, then use ticker ( usefull if down trending ) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index d7f7e96d9..8a40397f3 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -419,6 +419,39 @@ def limit_sell_order(): } +@pytest.fixture +def order_book_l2(): + return MagicMock(return_value={ + 'bids': [ + [0.043936, 10.442], + [0.043935, 31.865], + [0.043933, 11.212], + [0.043928, 0.088], + [0.043925, 10.0], + [0.043921, 10.0], + [0.04392, 37.64], + [0.043899, 0.066], + [0.043885, 0.676], + [0.04387, 22.758] + ], + 'asks': [ + [0.043949, 0.346], + [0.04395, 0.608], + [0.043951, 3.948], + [0.043954, 0.288], + [0.043958, 9.277], + [0.043995, 1.566], + [0.044, 0.588], + [0.044002, 0.992], + [0.044003, 0.095], + [0.04402, 37.64] + ], + 'timestamp': None, + 'datetime': None, + 'nonce': 288004540 + }) + + @pytest.fixture def ticker_history(): return [ diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 4357b573a..85f393b9d 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1887,10 +1887,12 @@ def test_get_real_amount_open_trade(default_conf, mocker): assert freqtrade.get_real_amount(trade, order) == amount -def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, markets, mocker): +def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, markets, mocker, + order_book_l2): default_conf['experimental']['check_depth_of_market']['enabled'] = True default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 0.1 patch_RPCManager(mocker) + mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) mocker.patch.multiple( 'freqtrade.exchange.Exchange', validate_pairs=MagicMock(), @@ -1920,12 +1922,13 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, assert whitelist == default_conf['exchange']['pair_whitelist'] -def test_order_book_depth_of_market_high_delta(default_conf, ticker, - limit_buy_order, fee, markets, mocker): +def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_order, + fee, markets, mocker, order_book_l2): default_conf['experimental']['check_depth_of_market']['enabled'] = True # delta is 100 which is impossible to reach. hence check_depth_of_market will return false default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 100 patch_RPCManager(mocker) + mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) mocker.patch.multiple( 'freqtrade.exchange.Exchange', validate_pairs=MagicMock(), @@ -1943,11 +1946,12 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, assert trade is None -def test_order_book_bid_strategy1(default_conf) -> None: +def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None: """ test if function get_target_bid will return the order book price instead of the ask rate """ + mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) default_conf['exchange']['name'] = 'binance' default_conf['experimental']['bid_strategy']['use_order_book'] = True default_conf['experimental']['bid_strategy']['order_book_top'] = 2 @@ -1955,14 +1959,31 @@ def test_order_book_bid_strategy1(default_conf) -> None: default_conf['telegram']['enabled'] = False freqtrade = FreqtradeBot(default_conf) - assert freqtrade.get_target_bid('BTC/USDT', {'ask': 200000, 'last': 200000}) != 200000 + assert freqtrade.get_target_bid('ETH/BTC', {'ask': 0.045, 'last': 0.046}) == 0.043935 -def test_order_book_bid_strategy2(default_conf) -> None: +def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2) -> None: + """ + test if function get_target_bid will return the ask rate (since its value is lower) + instead of the order book rate (even if enabled) + """ + mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) + default_conf['exchange']['name'] = 'binance' + default_conf['experimental']['bid_strategy']['use_order_book'] = True + default_conf['experimental']['bid_strategy']['order_book_top'] = 2 + default_conf['bid_strategy']['ask_last_balance'] = 0 + default_conf['telegram']['enabled'] = False + + freqtrade = FreqtradeBot(default_conf) + assert freqtrade.get_target_bid('ETH/BTC', {'ask': 0.042, 'last': 0.046}) == 0.042 + + +def test_order_book_bid_strategy3(default_conf, mocker, order_book_l2) -> None: """ test if function get_target_bid will return ask rate instead of the order book rate """ + mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) default_conf['exchange']['name'] = 'binance' default_conf['experimental']['bid_strategy']['use_order_book'] = True default_conf['experimental']['bid_strategy']['order_book_top'] = 1 @@ -1971,10 +1992,14 @@ def test_order_book_bid_strategy2(default_conf) -> None: freqtrade = FreqtradeBot(default_conf) - assert freqtrade.get_target_bid('BTC/USDT', {'ask': 2, 'last': 2}) == 2 + assert freqtrade.get_target_bid('ETH/BTC', {'ask': 0.03, 'last': 0.029}) == 0.03 -def test_check_depth_of_market_buy(default_conf) -> None: +def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None: + """ + test check depth of market + """ + mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) default_conf['telegram']['enabled'] = False default_conf['exchange']['name'] = 'binance' default_conf['experimental']['check_depth_of_market']['enabled'] = True @@ -1987,7 +2012,11 @@ def test_check_depth_of_market_buy(default_conf) -> None: def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order, - fee, markets, mocker) -> None: + fee, markets, mocker, order_book_l2) -> None: + """ + test order book ask strategy + """ + mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) default_conf['exchange']['name'] = 'binance' default_conf['experimental']['ask_strategy']['use_order_book'] = True default_conf['experimental']['ask_strategy']['order_book_min'] = 1 From 04878da66b47d522004aa45f1b6175f746651d36 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 14 Aug 2018 14:27:07 +0200 Subject: [PATCH 40/84] Update ccxt from 1.17.118 to 1.17.122 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d373f8c73..67fda790f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.118 +ccxt==1.17.122 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 2bc7a668a3282d346dae13a900ad62e195c07e07 Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Wed, 15 Aug 2018 10:39:32 +0800 Subject: [PATCH 41/84] informative startup --- freqtrade/exchange/__init__.py | 4 ++-- freqtrade/freqtradebot.py | 34 ++++++++++++++++++++++++++++++++++ freqtrade/rpc/rpc.py | 2 ++ freqtrade/rpc/telegram.py | 6 ++++++ freqtrade/tests/test_talib.py | 2 +- 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index a6ec70636..cd75a7229 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -116,8 +116,8 @@ class Exchange(object): api.urls['api'] = api.urls['test'] logger.info("Enabled Sandbox API on %s", name) else: - logger.warning(self, "No Sandbox URL in CCXT, exiting. " - "Please check your config.json") + logger.warning(self._api.name, "No Sandbox URL in CCXT, exiting. " + "Please check your config.json") raise OperationalException(f'Exchange {name} does not provide a sandbox api') def validate_pairs(self, pairs: List[str]) -> None: diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 706435017..ba081d960 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -94,6 +94,8 @@ class FreqtradeBot(object): 'status': f'{state.name.lower()}' }) logger.info('Changing state to: %s', state.name) + if state == State.RUNNING: + self._startup_messages() if state == State.STOPPED: time.sleep(1) @@ -110,6 +112,38 @@ class FreqtradeBot(object): nb_assets=nb_assets) return state + def _startup_messages(self) -> None: + if self.config.get('dry_run', False): + self.rpc.send_msg({ + 'type': RPCMessageType.WARNING_NOTIFICATION, + 'status': 'Dry run is enabled. All trades are simulated.' + }) + stake_currency = self.config['stake_currency'] + stake_amount = self.config['stake_amount'] + minimal_roi = self.config['minimal_roi'] + ticker_interval = self.config['ticker_interval'] + exchange_name = self.config['exchange']['name'] + strategy_name = self.config.get('strategy', '') + self.rpc.send_msg({ + 'type': RPCMessageType.CUSTOM_NOTIFICATION, + 'status': f'*Exchange:* `{exchange_name}`\n' + f'*Stake per trade:* `{stake_amount} {stake_currency}`\n' + f'*Minimum ROI:* `{minimal_roi}`\n' + f'*Ticker Interval:* `{ticker_interval}`\n' + f'*Strategy:* `{strategy_name}`' + }) + if self.config.get('dynamic_whitelist', False): + top_pairs = 'top ' + str(self.config.get('dynamic_whitelist', False)) + specific_pairs = '' + else: + top_pairs = 'whitelisted' + specific_pairs = '\n' + ', '.join(self.config['exchange'].get('pair_whitelist', '')) + self.rpc.send_msg({ + 'type': RPCMessageType.STATUS_NOTIFICATION, + 'status': f'Searching for {top_pairs} {stake_currency} pairs to buy and sell...\ + {specific_pairs}' + }) + def _throttle(self, func: Callable[..., Any], min_secs: float, *args, **kwargs) -> Any: """ Throttles the given callable that it diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index f58fbae9a..80bac0dd4 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -24,6 +24,8 @@ logger = logging.getLogger(__name__) class RPCMessageType(Enum): STATUS_NOTIFICATION = 'status' + WARNING_NOTIFICATION = 'warning' + CUSTOM_NOTIFICATION = 'custom' BUY_NOTIFICATION = 'buy' SELL_NOTIFICATION = 'sell' diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 3b5ce3f74..64708ef74 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -154,6 +154,12 @@ class Telegram(RPC): elif msg['type'] == RPCMessageType.STATUS_NOTIFICATION: message = '*Status:* `{status}`'.format(**msg) + elif msg['type'] == RPCMessageType.WARNING_NOTIFICATION: + message = '*Warning:* `{status}`'.format(**msg) + + elif msg['type'] == RPCMessageType.CUSTOM_NOTIFICATION: + message = '{status}'.format(**msg) + else: raise NotImplementedError('Unknown message type: {}'.format(msg['type'])) diff --git a/freqtrade/tests/test_talib.py b/freqtrade/tests/test_talib.py index 093c3023c..0fefbccb3 100644 --- a/freqtrade/tests/test_talib.py +++ b/freqtrade/tests/test_talib.py @@ -13,4 +13,4 @@ def test_talib_bollingerbands_near_zero_values(): {'close': 0.00000014} ]) bollinger = ta.BBANDS(inputs, matype=0, timeperiod=2) - assert (bollinger['upperband'][3] != bollinger['middleband'][3]) + assert (bollinger['upperband'][3] == bollinger['middleband'][3]) From 48e218d6c08fb5380b12eab07e0e7613ffdd1259 Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Wed, 15 Aug 2018 11:01:59 +0800 Subject: [PATCH 42/84] test_talib fix --- freqtrade/tests/test_talib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/tests/test_talib.py b/freqtrade/tests/test_talib.py index 0fefbccb3..093c3023c 100644 --- a/freqtrade/tests/test_talib.py +++ b/freqtrade/tests/test_talib.py @@ -13,4 +13,4 @@ def test_talib_bollingerbands_near_zero_values(): {'close': 0.00000014} ]) bollinger = ta.BBANDS(inputs, matype=0, timeperiod=2) - assert (bollinger['upperband'][3] == bollinger['middleband'][3]) + assert (bollinger['upperband'][3] != bollinger['middleband'][3]) From b34aa461811c341d926bf9737d2cc799f52612eb Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Wed, 15 Aug 2018 12:05:56 +0800 Subject: [PATCH 43/84] additional tests --- freqtrade/freqtradebot.py | 2 +- freqtrade/tests/rpc/test_rpc_telegram.py | 32 ++++++++++++++++++++++++ freqtrade/tests/test_freqtradebot.py | 6 +++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index ba081d960..2ff999fdb 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -133,7 +133,7 @@ class FreqtradeBot(object): f'*Strategy:* `{strategy_name}`' }) if self.config.get('dynamic_whitelist', False): - top_pairs = 'top ' + str(self.config.get('dynamic_whitelist', False)) + top_pairs = 'top ' + str(self.config.get('dynamic_whitelist', 20)) specific_pairs = '' else: top_pairs = 'whitelisted' diff --git a/freqtrade/tests/rpc/test_rpc_telegram.py b/freqtrade/tests/rpc/test_rpc_telegram.py index 4b2fe4cf5..4d2b9cda2 100644 --- a/freqtrade/tests/rpc/test_rpc_telegram.py +++ b/freqtrade/tests/rpc/test_rpc_telegram.py @@ -1095,6 +1095,38 @@ def test_send_msg_status_notification(default_conf, mocker) -> None: assert msg_mock.call_args[0][0] == '*Status:* `running`' +def test_warning_notification(default_conf, mocker) -> None: + msg_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + telegram = Telegram(freqtradebot) + telegram.send_msg({ + 'type': RPCMessageType.WARNING_NOTIFICATION, + 'status': 'message' + }) + assert msg_mock.call_args[0][0] == '*Warning:* `message`' + + +def test_custom_notification(default_conf, mocker) -> None: + msg_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + telegram = Telegram(freqtradebot) + telegram.send_msg({ + 'type': RPCMessageType.CUSTOM_NOTIFICATION, + 'status': '*Custom:* `Hello World`' + }) + assert msg_mock.call_args[0][0] == '*Custom:* `Hello World`' + + def test_send_msg_unknown_type(default_conf, mocker) -> None: msg_mock = MagicMock() mocker.patch.multiple( diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 89adae6ab..fa6bc7c2a 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1876,3 +1876,9 @@ def test_get_real_amount_open_trade(default_conf, mocker): freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) assert freqtrade.get_real_amount(trade, order) == amount + + +def test_startup_messages(default_conf, mocker): + default_conf['dynamic_whitelist'] = 20 + freqtrade = get_patched_freqtradebot(mocker, default_conf) + assert freqtrade.state is State.RUNNING From 1edbc494ee91b5303090fe6d46b92ed093b11ed4 Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Wed, 15 Aug 2018 12:37:30 +0800 Subject: [PATCH 44/84] refactor --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 2ff999fdb..a2090d267 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -140,8 +140,8 @@ class FreqtradeBot(object): specific_pairs = '\n' + ', '.join(self.config['exchange'].get('pair_whitelist', '')) self.rpc.send_msg({ 'type': RPCMessageType.STATUS_NOTIFICATION, - 'status': f'Searching for {top_pairs} {stake_currency} pairs to buy and sell...\ - {specific_pairs}' + 'status': f'Searching for {top_pairs} {stake_currency} pairs to buy and sell...' + f'{specific_pairs}' }) def _throttle(self, func: Callable[..., Any], min_secs: float, *args, **kwargs) -> Any: From dd7f540e5add2f75a023d98c1f63f6aa19eb01bb Mon Sep 17 00:00:00 2001 From: Samuel Husso Date: Wed, 15 Aug 2018 08:25:04 +0300 Subject: [PATCH 45/84] Push develop as 0.17.2 --- freqtrade/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index ac00264f0..46825f548 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -1,5 +1,5 @@ """ FreqTrade bot """ -__version__ = '0.17.1' +__version__ = '0.17.2' class DependencyException(BaseException): From d007ac4b96b3bf34f7e55a07ee53b0f3680e0b19 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Aug 2018 08:37:20 +0200 Subject: [PATCH 46/84] check version explicitly, use "python" in venv --- freqtrade/strategy/__init__.py | 3 ++- setup.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/strategy/__init__.py b/freqtrade/strategy/__init__.py index 49b0c45c0..38a110bd7 100644 --- a/freqtrade/strategy/__init__.py +++ b/freqtrade/strategy/__init__.py @@ -1,4 +1,5 @@ import logging +import sys from copy import deepcopy from freqtrade.strategy.interface import IStrategy @@ -20,7 +21,7 @@ def import_strategy(strategy: IStrategy, config: dict) -> IStrategy: # Delete '_abc_impl' from dict as deepcopy fails on 3.7 with # `TypeError: can't pickle _abc_data objects`` # This will only apply to python 3.7 - if '_abc_impl' in comb: + if sys.version_info.major == 3 and sys.version_info.minor == 7 and '_abc_impl' in comb: del comb['_abc_impl'] attr = deepcopy(comb) diff --git a/setup.sh b/setup.sh index 557bcdd12..bd58edbee 100755 --- a/setup.sh +++ b/setup.sh @@ -211,7 +211,7 @@ function install () { echo "-------------------------" echo "Run the bot" echo "-------------------------" - echo "You can now use the bot by executing 'source .env/bin/activate; ${PYTHON} freqtrade/main.py'." + echo "You can now use the bot by executing 'source .env/bin/activate; python freqtrade/main.py'." } function plot () { From be373e7563154bedb1e8abe44cee4b18780ebd95 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 15 Aug 2018 14:27:06 +0200 Subject: [PATCH 47/84] Update ccxt from 1.17.122 to 1.17.126 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f44085505..c2b90fff7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.122 +ccxt==1.17.126 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 4a8c1209262d48387ec255b27ac1e8de1ea76aa3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 16 Aug 2018 11:35:01 +0200 Subject: [PATCH 48/84] Output min-roi setting when overwriting from config --- freqtrade/strategy/resolver.py | 7 ++++--- freqtrade/tests/strategy/test_strategy.py | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/freqtrade/strategy/resolver.py b/freqtrade/strategy/resolver.py index 7aeec300e..5a44a2c57 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -44,14 +44,15 @@ class StrategyResolver(object): # Check if we need to override configuration if 'minimal_roi' in config: self.strategy.minimal_roi = config['minimal_roi'] - logger.info("Override strategy \'minimal_roi\' with value in config file.") + logger.info("Override strategy 'minimal_roi' with value in config file: %s.", + config['minimal_roi']) else: config['minimal_roi'] = self.strategy.minimal_roi if 'stoploss' in config: self.strategy.stoploss = config['stoploss'] logger.info( - "Override strategy \'stoploss\' with value in config file: %s.", config['stoploss'] + "Override strategy 'stoploss' with value in config file: %s.", config['stoploss'] ) else: config['stoploss'] = self.strategy.stoploss @@ -59,7 +60,7 @@ class StrategyResolver(object): if 'ticker_interval' in config: self.strategy.ticker_interval = config['ticker_interval'] logger.info( - "Override strategy \'ticker_interval\' with value in config file: %s.", + "Override strategy 'ticker_interval' with value in config file: %s.", config['ticker_interval'] ) else: diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index 0cbd9f22c..ca41d1d39 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -130,7 +130,7 @@ def test_strategy_override_minimal_roi(caplog): assert resolver.strategy.minimal_roi[0] == 0.5 assert ('freqtrade.strategy.resolver', logging.INFO, - 'Override strategy \'minimal_roi\' with value in config file.' + "Override strategy 'minimal_roi' with value in config file: {'0': 0.5}." ) in caplog.record_tuples @@ -145,7 +145,7 @@ def test_strategy_override_stoploss(caplog): assert resolver.strategy.stoploss == -0.5 assert ('freqtrade.strategy.resolver', logging.INFO, - 'Override strategy \'stoploss\' with value in config file: -0.5.' + "Override strategy 'stoploss' with value in config file: -0.5." ) in caplog.record_tuples @@ -161,7 +161,7 @@ def test_strategy_override_ticker_interval(caplog): assert resolver.strategy.ticker_interval == 60 assert ('freqtrade.strategy.resolver', logging.INFO, - 'Override strategy \'ticker_interval\' with value in config file: 60.' + "Override strategy 'ticker_interval' with value in config file: 60." ) in caplog.record_tuples From 16fa877b67259cfc5096ee6a625f6138135cde0f Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 16 Aug 2018 13:15:46 +0200 Subject: [PATCH 49/84] Remove verbosity of trying backup tables - properly log if databasemigration happened --- freqtrade/persistence.py | 4 +++- freqtrade/tests/test_persistence.py | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 80d49b895..c26d74015 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -79,10 +79,12 @@ def check_migrate(engine) -> None: table_back_name = 'trades_bak' for i, table_back_name in enumerate(tabs): table_back_name = f'trades_bak{i}' - logger.info(f'trying {table_back_name}') + logger.debug(f'trying {table_back_name}') # Check for latest column if not has_column(cols, 'ticker_interval'): + logger.info(f'Running database migration - backup available as {table_back_name}') + fee_open = get_column_def(cols, 'fee_open', 'fee') fee_close = get_column_def(cols, 'fee_close', 'fee') open_rate_requested = get_column_def(cols, 'open_rate_requested', 'null') diff --git a/freqtrade/tests/test_persistence.py b/freqtrade/tests/test_persistence.py index e52500071..7584537e2 100644 --- a/freqtrade/tests/test_persistence.py +++ b/freqtrade/tests/test_persistence.py @@ -1,5 +1,6 @@ # pragma pylint: disable=missing-docstring, C0103 from unittest.mock import MagicMock +import logging import pytest from sqlalchemy import create_engine @@ -403,6 +404,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): """ Test Database migration (starting with new pairformat) """ + caplog.set_level(logging.DEBUG) amount = 103.223 # Always create all columns apart from the last! create_table_old = """CREATE TABLE IF NOT EXISTS "trades" ( @@ -471,12 +473,15 @@ def test_migrate_new(mocker, default_conf, fee, caplog): assert trade.ticker_interval is None assert log_has("trying trades_bak1", caplog.record_tuples) assert log_has("trying trades_bak2", caplog.record_tuples) + assert log_has("Running database migration - backup available as trades_bak2", + caplog.record_tuples) def test_migrate_mid_state(mocker, default_conf, fee, caplog): """ Test Database migration (starting with new pairformat) """ + caplog.set_level(logging.DEBUG) amount = 103.223 create_table_old = """CREATE TABLE IF NOT EXISTS "trades" ( id INTEGER NOT NULL, @@ -530,6 +535,8 @@ def test_migrate_mid_state(mocker, default_conf, fee, caplog): assert trade.stop_loss == 0.0 assert trade.initial_stop_loss == 0.0 assert log_has("trying trades_bak0", caplog.record_tuples) + assert log_has("Running database migration - backup available as trades_bak0", + caplog.record_tuples) def test_adjust_stop_loss(limit_buy_order, limit_sell_order, fee): From dc41a19f995d4c3f6af58aa26f198d9090652156 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 16 Aug 2018 14:27:06 +0200 Subject: [PATCH 50/84] Update ccxt from 1.17.126 to 1.17.132 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c2b90fff7..4fad3a77b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.126 +ccxt==1.17.132 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From d1c5eebff2b95f7443b43505f3fd18297fbd4eee Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 17 Aug 2018 06:50:36 +0200 Subject: [PATCH 51/84] Add explicit test on handling min_roi_reached --- freqtrade/tests/strategy/test_interface.py | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/freqtrade/tests/strategy/test_interface.py b/freqtrade/tests/strategy/test_interface.py index ec4ab0fd4..2c54e492a 100644 --- a/freqtrade/tests/strategy/test_interface.py +++ b/freqtrade/tests/strategy/test_interface.py @@ -8,6 +8,7 @@ from pandas import DataFrame from freqtrade.arguments import TimeRange from freqtrade.optimize.__init__ import load_tickerdata_file +from freqtrade.persistence import Trade from freqtrade.tests.conftest import get_patched_exchange, log_has from freqtrade.strategy.default_strategy import DefaultStrategy @@ -105,3 +106,26 @@ def test_tickerdata_to_dataframe(default_conf) -> None: tickerlist = {'UNITTEST/BTC': tick} data = strategy.tickerdata_to_dataframe(tickerlist) assert len(data['UNITTEST/BTC']) == 99 # partial candle was removed + + +def test_min_roi_reached(default_conf, fee) -> None: + strategy = DefaultStrategy(default_conf) + strategy.minimal_roi = {0: 0.1, 20: 0.05, 55: 0.01} + trade = Trade( + pair='ETH/BTC', + stake_amount=0.001, + open_date=arrow.utcnow().shift(hours=-1).datetime, + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='bittrex', + open_rate=1, + ) + + assert not strategy.min_roi_reached(trade, 0.01, arrow.utcnow().shift(minutes=-55).datetime) + assert strategy.min_roi_reached(trade, 0.12, arrow.utcnow().shift(minutes=-55).datetime) + + assert not strategy.min_roi_reached(trade, 0.04, arrow.utcnow().shift(minutes=-39).datetime) + assert strategy.min_roi_reached(trade, 0.06, arrow.utcnow().shift(minutes=-39).datetime) + + assert not strategy.min_roi_reached(trade, -0.01, arrow.utcnow().shift(minutes=-1).datetime) + assert strategy.min_roi_reached(trade, 0.02, arrow.utcnow().shift(minutes=-1).datetime) From 56188f2f679aaaa2d1f699f783c31dadef434dd1 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Fri, 17 Aug 2018 14:27:07 +0200 Subject: [PATCH 52/84] Update ccxt from 1.17.132 to 1.17.134 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4fad3a77b..ede96a535 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.132 +ccxt==1.17.134 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From bc22320f776f524c9d7b39189c8e4fef09168eca Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 18 Aug 2018 14:27:07 +0200 Subject: [PATCH 53/84] Update ccxt from 1.17.134 to 1.17.139 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index ede96a535..4a5f1ff33 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.134 +ccxt==1.17.139 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 97e9a44fd2a4a7557922544b65646f6f7a7c7216 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 19 Aug 2018 14:28:06 +0200 Subject: [PATCH 54/84] Update ccxt from 1.17.139 to 1.17.146 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4a5f1ff33..c00e4fba0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.139 +ccxt==1.17.146 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 5a0876704a5a124441140c9b98026fc852a3afb7 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 19 Aug 2018 14:28:07 +0200 Subject: [PATCH 55/84] Update pytest from 3.7.1 to 3.7.2 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c00e4fba0..d6a8dfca1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ scipy==1.1.0 jsonschema==2.6.0 numpy==1.15.0 TA-Lib==0.4.17 -pytest==3.7.1 +pytest==3.7.2 pytest-mock==1.10.0 pytest-cov==2.5.1 tabulate==0.8.2 From a077955efacf6362006007301d535212b458db51 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 19 Aug 2018 19:58:07 +0200 Subject: [PATCH 56/84] update json.load to json_load - followup to #1142 --- freqtrade/optimize/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/__init__.py b/freqtrade/optimize/__init__.py index 5591898fa..0478dbda6 100644 --- a/freqtrade/optimize/__init__.py +++ b/freqtrade/optimize/__init__.py @@ -177,7 +177,7 @@ def load_cached_data_for_updating(filename: str, # read the cached file if os.path.isfile(filename): with open(filename, "rt") as file: - data = json.load(file) + data = json_load(file) # remove the last item, because we are not sure if it is correct # it could be fetched when the candle was incompleted if data: From 43f73c5aecf048888d3b69fe9c6b5d60125f213f Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 20 Aug 2018 14:28:06 +0200 Subject: [PATCH 57/84] Update ccxt from 1.17.146 to 1.17.152 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d6a8dfca1..7610f43d6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.146 +ccxt==1.17.152 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 8f41e0e190e057b961af2e855093d0ca3ad8fb82 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Aug 2018 20:01:57 +0200 Subject: [PATCH 58/84] Use setting in 'exchange' dict --- freqtrade/strategy/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index aa1e903de..1a2b88c9a 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -155,7 +155,7 @@ class IStrategy(ABC): # Check if dataframe is out of date signal_date = arrow.get(latest['date']) interval_minutes = constants.TICKER_INTERVAL_MINUTES[interval] - offset = self.config.get('outdated_offset', 5) + offset = self.config.get('exchange', {}).get('outdated_offset', 5) if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): logger.warning( 'Outdated history for pair %s. Last tick is %s minutes old', From e5707b8a2cd5fea5164d33904903aa2ab364ca79 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 21 Aug 2018 14:28:06 +0200 Subject: [PATCH 59/84] Update ccxt from 1.17.152 to 1.17.157 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7610f43d6..9a6784cf0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.152 +ccxt==1.17.157 SQLAlchemy==1.2.10 python-telegram-bot==10.1.0 arrow==0.12.1 From 8a844488d465334973936ba9ea947e2398995ec0 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 21 Aug 2018 14:28:08 +0200 Subject: [PATCH 60/84] Update sqlalchemy from 1.2.10 to 1.2.11 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 9a6784cf0..4181d0d1b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ ccxt==1.17.157 -SQLAlchemy==1.2.10 +SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 cachetools==2.1.0 From 6e90d482eff02d84cb285493f81f387b16ed1924 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 21 Aug 2018 19:08:21 +0200 Subject: [PATCH 61/84] remove amount_to_lots (deprecated / removed) was removed from ccxt in https://github.com/ccxt/ccxt/commit/527f082e59e1cd3698cb7ae95bdcaae4459ea218 --- freqtrade/exchange/__init__.py | 9 --------- freqtrade/tests/exchange/test_exchange.py | 12 ------------ 2 files changed, 21 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index cd75a7229..60756d84c 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -462,12 +462,3 @@ class Exchange(object): f'Could not get fee info due to {e.__class__.__name__}. Message: {e}') except ccxt.BaseError as e: raise OperationalException(e) - - def get_amount_lots(self, pair: str, amount: float) -> float: - """ - get buyable amount rounding, .. - """ - # validate that markets are loaded before trying to get fee - if not self._api.markets: - self._api.load_markets() - return self._api.amount_to_lots(pair, amount) diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 6918e9da1..5ee21c9e4 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -823,15 +823,3 @@ def test_get_fee(default_conf, mocker): ccxt_exceptionhandlers(mocker, default_conf, api_mock, 'get_fee', 'calculate_fee') - - -def test_get_amount_lots(default_conf, mocker): - api_mock = MagicMock() - api_mock.amount_to_lots = MagicMock(return_value=1.0) - api_mock.markets = None - marketmock = MagicMock() - api_mock.load_markets = marketmock - exchange = get_patched_exchange(mocker, default_conf, api_mock) - - assert exchange.get_amount_lots('LTC/BTC', 1.54) == 1 - assert marketmock.call_count == 1 From 4508349d07819f469d6d1c134ea77da5af7778f0 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 22 Aug 2018 14:28:07 +0200 Subject: [PATCH 62/84] Update ccxt from 1.17.157 to 1.17.163 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4181d0d1b..467ff4408 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.157 +ccxt==1.17.163 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From ebc072396b1e451b26132216749a573e5033e98f Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 22 Aug 2018 14:28:09 +0200 Subject: [PATCH 63/84] Update numpy from 1.15.0 to 1.15.1 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 467ff4408..85d2f6b89 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ pandas==0.23.4 scikit-learn==0.19.2 scipy==1.1.0 jsonschema==2.6.0 -numpy==1.15.0 +numpy==1.15.1 TA-Lib==0.4.17 pytest==3.7.2 pytest-mock==1.10.0 From 8c0e33753e39116d1140d89e9942ba9fb4dd9291 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 23 Aug 2018 14:28:07 +0200 Subject: [PATCH 64/84] Update ccxt from 1.17.163 to 1.17.170 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 85d2f6b89..e10f88b43 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.163 +ccxt==1.17.170 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From ab628c1381e65486fffa22a226fd4e08a98755ad Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Fri, 24 Aug 2018 14:28:06 +0200 Subject: [PATCH 65/84] Update ccxt from 1.17.170 to 1.17.176 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e10f88b43..bda14b36b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.170 +ccxt==1.17.176 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From a489a044adca228a68e2d856d2a4af30b909be1e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Aug 2018 13:17:07 +0200 Subject: [PATCH 66/84] Mock Exchange results to avoid random test-failures --- freqtrade/tests/exchange/test_exchange.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py index 60f51553a..4686176c4 100644 --- a/freqtrade/tests/exchange/test_exchange.py +++ b/freqtrade/tests/exchange/test_exchange.py @@ -515,14 +515,17 @@ def test_get_ticker(default_conf, mocker): exchange.get_ticker(pair='ETH/BTC', refresh=True) -def test_get_order_book(default_conf, mocker): +def test_get_order_book(default_conf, mocker, order_book_l2): default_conf['exchange']['name'] = 'binance' - exchange = Exchange(default_conf) - order_book = exchange.get_order_book(pair='ETH/BTC', limit=50) + api_mock = MagicMock() + + api_mock.fetch_l2_order_book = order_book_l2 + exchange = get_patched_exchange(mocker, default_conf, api_mock) + order_book = exchange.get_order_book(pair='ETH/BTC', limit=10) assert 'bids' in order_book assert 'asks' in order_book - assert len(order_book['bids']) == 50 - assert len(order_book['asks']) == 50 + assert len(order_book['bids']) == 10 + assert len(order_book['asks']) == 10 def test_get_order_book_exception(default_conf, mocker): From 42587741dd0b6b91d4e837ca546ca3fde256d6d0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Aug 2018 13:21:10 +0200 Subject: [PATCH 67/84] mock exchange to avoid random failures --- freqtrade/tests/test_freqtradebot.py | 36 +++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 85f393b9d..43ab587ec 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1946,12 +1946,17 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o assert trade is None -def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None: +def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets) -> None: """ test if function get_target_bid will return the order book price instead of the ask rate """ - mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + validate_pairs=MagicMock(), + get_markets=markets, + get_order_book=order_book_l2 + ) default_conf['exchange']['name'] = 'binance' default_conf['experimental']['bid_strategy']['use_order_book'] = True default_conf['experimental']['bid_strategy']['order_book_top'] = 2 @@ -1962,12 +1967,17 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None: assert freqtrade.get_target_bid('ETH/BTC', {'ask': 0.045, 'last': 0.046}) == 0.043935 -def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2) -> None: +def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets) -> None: """ test if function get_target_bid will return the ask rate (since its value is lower) instead of the order book rate (even if enabled) """ - mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + validate_pairs=MagicMock(), + get_markets=markets, + get_order_book=order_book_l2 + ) default_conf['exchange']['name'] = 'binance' default_conf['experimental']['bid_strategy']['use_order_book'] = True default_conf['experimental']['bid_strategy']['order_book_top'] = 2 @@ -1978,12 +1988,17 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2) -> None: assert freqtrade.get_target_bid('ETH/BTC', {'ask': 0.042, 'last': 0.046}) == 0.042 -def test_order_book_bid_strategy3(default_conf, mocker, order_book_l2) -> None: +def test_order_book_bid_strategy3(default_conf, mocker, order_book_l2, markets) -> None: """ test if function get_target_bid will return ask rate instead of the order book rate """ - mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + validate_pairs=MagicMock(), + get_markets=markets, + get_order_book=order_book_l2 + ) default_conf['exchange']['name'] = 'binance' default_conf['experimental']['bid_strategy']['use_order_book'] = True default_conf['experimental']['bid_strategy']['order_book_top'] = 1 @@ -1995,11 +2010,16 @@ def test_order_book_bid_strategy3(default_conf, mocker, order_book_l2) -> None: assert freqtrade.get_target_bid('ETH/BTC', {'ask': 0.03, 'last': 0.029}) == 0.03 -def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None: +def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2, markets) -> None: """ test check depth of market """ - mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + validate_pairs=MagicMock(), + get_markets=markets, + get_order_book=order_book_l2 + ) default_conf['telegram']['enabled'] = False default_conf['exchange']['name'] = 'binance' default_conf['experimental']['check_depth_of_market']['enabled'] = True From 2ee1a2d851fab49b82469df38ebbfc9787270208 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 25 Aug 2018 14:28:06 +0200 Subject: [PATCH 68/84] Update ccxt from 1.17.176 to 1.17.184 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index bda14b36b..92957cf94 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.176 +ccxt==1.17.184 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From c5efcace4747999c72c02f6218e86e263c7bca20 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Aug 2018 12:49:39 +0200 Subject: [PATCH 69/84] change pip3.6 to pip3 --- docs/installation.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 4de05c121..7d0076673 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -335,11 +335,11 @@ cp config.json.example config.json #### 2. Setup your Python virtual environment (virtualenv) ```bash -python3.6 -m venv .env +python3 -m venv .env source .env/bin/activate -pip3.6 install --upgrade pip -pip3.6 install -r requirements.txt -pip3.6 install -e . +pip3 install --upgrade pip +pip3 install -r requirements.txt +pip3 install -e . ``` #### 3. Run the Bot From fe169483eddb81fe585a13e49c764a193995a476 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 26 Aug 2018 14:28:07 +0200 Subject: [PATCH 70/84] Update ccxt from 1.17.184 to 1.17.188 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 92957cf94..cfee7c5f5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.184 +ccxt==1.17.188 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From 1a9c085f10793ccb21ca676f80bce9b161bb0181 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Aug 2018 20:09:12 +0200 Subject: [PATCH 71/84] Restructure install documentation --- docs/installation.md | 151 ++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 87 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 7d0076673..525c6f187 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -8,7 +8,6 @@ To understand how to set up the bot please read the [Bot Configuration](https:// * [Table of Contents](#table-of-contents) * [Easy Installation - Linux Script](#easy-installation---linux-script) -* [Manual installation](#manual-installation) * [Automatic Installation - Docker](#automatic-installation---docker) * [Custom Linux MacOS Installation](#custom-installation) - [Requirements](#requirements) @@ -56,34 +55,6 @@ 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 - -```bash -git clone git@github.com:freqtrade/freqtrade.git -git checkout develop -cd freqtrade -``` - -### 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 - -```bash -docker build -t freqtrade . -docker run --rm -v /etc/localtime:/etc/localtime:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade -``` - ------ ## Automatic Installation - Docker @@ -196,7 +167,7 @@ docker run -d \ freqtrade --db-url sqlite:///tradesv3.sqlite ``` -NOTE: db-url defaults to `sqlite:///tradesv3.sqlite` but it defaults to `sqlite://` if `dry_run=True` is being used. +*Note*: db-url defaults to `sqlite:///tradesv3.sqlite` but it defaults to `sqlite://` if `dry_run=True` is being used. To override this behaviour use a custom db-url value: i.e.: `--db-url sqlite:///tradesv3.dryrun.sqlite` ### 6. Monitor your Docker instance @@ -211,14 +182,15 @@ docker stop freqtrade docker start freqtrade ``` -You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. +For more information on how to operate Docker, please refer to the [official Docker documentation](https://docs.docker.com/). + +*Note*: You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. ### 7. Backtest with docker The following assumes that the above steps (1-4) have been completed successfully. Also, backtest-data should be available at `~/.freqtrade/user_data/`. - ``` bash docker run -d \ --name freqtrade \ @@ -238,12 +210,13 @@ Head over to the [Backtesting Documentation](https://github.com/freqtrade/freqtr ## Custom Installation We've included/collected install instructions for Ubuntu 16.04, MacOS, and Windows. These are guidelines and your success may vary with other distros. +OS Specific steps are listed first, the [common](#common) section below is necessary for all systems. ### Requirements Click each one for install guide: -* [Python 3.6.x](http://docs.python-guide.org/en/latest/starting/installation/), note the bot was not tested on Python >= 3.7.x +* [Python >= 3.6.x](http://docs.python-guide.org/en/latest/starting/installation/) * [pip](https://pip.pypa.io/en/stable/installing/) * [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) * [virtualenv](https://virtualenv.pypa.io/en/stable/installation/) (Recommended) @@ -251,7 +224,7 @@ Click each one for install guide: ### Linux - Ubuntu 16.04 -#### 1. Install Python 3.6, Git, and wget +#### Install Python 3.6, Git, and wget ```bash sudo add-apt-repository ppa:jonathonf/python-3.6 @@ -259,7 +232,17 @@ sudo apt-get update sudo apt-get install python3.6 python3.6-venv python3.6-dev build-essential autoconf libtool pkg-config make wget git ``` -#### 2. Install TA-Lib +### MacOS + +#### Install Python 3.6, git, wget and ta-lib + +```bash +brew install python3 git wget +``` + +### common + +#### 1. Install TA-Lib Official webpage: https://mrjbq7.github.io/ta-lib/install.html @@ -275,15 +258,60 @@ cd .. rm -rf ./ta-lib* ``` +*Note*: An already downloaded version of ta-lib is included in the repository, as the sourceforge.net source seems to have problems frequently. + +#### 2. Setup your Python virtual environment (virtualenv) + +*Note*: This step is optional but strongly recommended to keep your system organized + +```bash +python3 -m venv .env +source .env/bin/activate +``` + #### 3. Install FreqTrade Clone the git repository: ```bash git clone https://github.com/freqtrade/freqtrade.git + ``` -#### 4. Configure `freqtrade` as a `systemd` service +Optionally checkout the stable/master branch: + +```bash +git checkout master +``` + +#### 4. Initialize the configuration + +```bash +cd freqtrade +cp config.json.example config.json +``` + +> *To edit the config please refer to [Bot Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md).* + +#### 5. Install python dependencies + +``` bash +pip3 install --upgrade pip +pip3 install -r requirements.txt +pip3 install -e . +``` + +#### 6. Run the Bot + +If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins. + +```bash +python3.6 ./freqtrade/main.py -c config.json +``` + +*Note*: If you run the bot on a server, you should consider using [Docker](#automatic-installation---docker) a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout. + +#### 7. [Optional] Configure `freqtrade` as a `systemd` service From the freqtrade repo... copy `freqtrade.service` to your systemd user directory (usually `~/.config/systemd/user`) and update `WorkingDirectory` and `ExecStart` to match your setup. @@ -299,57 +327,6 @@ For this to be persistent (run when user is logged out) you'll need to enable `l sudo loginctl enable-linger "$USER" ``` -### MacOS - -#### 1. Install Python 3.6, git, wget and ta-lib - -```bash -brew install python3 git wget ta-lib -``` - -#### 2. Install FreqTrade - -Clone the git repository: - -```bash -git clone https://github.com/freqtrade/freqtrade.git -``` - -Optionally checkout the develop branch: - -```bash -git checkout develop -``` - -### Setup Config and virtual env - -#### 1. Initialize the configuration - -```bash -cd freqtrade -cp config.json.example config.json -``` - -> *To edit the config please refer to [Bot Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md).* - -#### 2. Setup your Python virtual environment (virtualenv) - -```bash -python3 -m venv .env -source .env/bin/activate -pip3 install --upgrade pip -pip3 install -r requirements.txt -pip3 install -e . -``` - -#### 3. Run the Bot - -If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins. - -```bash -python3.6 ./freqtrade/main.py -c config.json -``` - ------ ## Windows From 188cfc435d8fac9ba1fc47e39abcb69402cdffb8 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 27 Aug 2018 14:28:05 +0200 Subject: [PATCH 72/84] Update ccxt from 1.17.188 to 1.17.194 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index cfee7c5f5..007a26323 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.188 +ccxt==1.17.194 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From c99ff78f2f131d2fec272d5393a79a413e8c1d50 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 27 Aug 2018 14:28:07 +0200 Subject: [PATCH 73/84] Update pytest from 3.7.2 to 3.7.3 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 007a26323..7203d362b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ scipy==1.1.0 jsonschema==2.6.0 numpy==1.15.1 TA-Lib==0.4.17 -pytest==3.7.2 +pytest==3.7.3 pytest-mock==1.10.0 pytest-cov==2.5.1 tabulate==0.8.2 From 19628d317a92e4b66380b344ea938e343d9538cb Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 28 Aug 2018 14:28:06 +0200 Subject: [PATCH 74/84] Update ccxt from 1.17.194 to 1.17.199 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7203d362b..b2f1e3a25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.194 +ccxt==1.17.199 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From 9bce6c5f4837c2651ccb06d28fdb78de87b7b11b Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Aug 2018 19:30:26 +0200 Subject: [PATCH 75/84] Add error-section for windows --- docs/installation.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 525c6f187..820383ff6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -346,7 +346,7 @@ git clone https://github.com/freqtrade/freqtrade.git copy paste `config.json` to ``\path\freqtrade-develop\freqtrade` -#### install ta-lib +#### Install ta-lib Install ta-lib according to the [ta-lib documentation](https://github.com/mrjbq7/ta-lib#windows). @@ -367,5 +367,17 @@ REM >pip install TA_Lib‑0.4.17‑cp36‑cp36m‑win32.whl > Thanks [Owdr](https://github.com/Owdr) for the commands. Source: [Issue #222](https://github.com/freqtrade/freqtrade/issues/222) +#### Error during installation under Windows + +``` bash +error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools +``` + +Unfortunately, many packages requiring compilation don't provide a pre-build wheel. It is therefore mandatory to have a C/C++ compiler installed and available for your python environment to use. + +The easiest way is to download install Microsoft Visual Studio Community [here](https://visualstudio.microsoft.com/downloads/) and make sure to install "Common Tools for Visual C++" to enable building c code on Windows. Unfortunately, this is a heavy download / dependency (~4Gb) so you might want to consider WSL or docker first. + +--- + Now you have an environment ready, the next step is [Bot Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md)... From c9ee528050cd5d964e50021ad9592d0f74cc2b88 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Aug 2018 22:06:46 +0200 Subject: [PATCH 76/84] Add section about raspberry / conda to install.md --- docs/installation.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/installation.md b/docs/installation.md index 820383ff6..0fecfcf78 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -232,6 +232,23 @@ sudo apt-get update sudo apt-get install python3.6 python3.6-venv python3.6-dev build-essential autoconf libtool pkg-config make wget git ``` +#### Raspberry Pi / Raspbian + +Before installing FreqTrade on a Raspberry Pi running the official Raspbian Image, make sure you have at least Python 3.6 installed. The default image only provides Python 3.5. Probably the easiest way to get a recent version of python is [miniconda](https://repo.continuum.io/miniconda/). + +The following assumes that miniconda3 is installed and available in your environment, and is installed. +It's recommended to use (mini)conda for this as installation/compilation of `scipy` and `pandas` takes a long time. + +``` bash +conda config --add channels rpi +conda install python=3.6 +conda create -n freqtrade python=3.6 +conda install scipy pandas + +pip install -r requirements.txt +pip install -e . +``` + ### MacOS #### Install Python 3.6, git, wget and ta-lib From b6b89a464fd388b3955990a59f54a5100665bb77 Mon Sep 17 00:00:00 2001 From: Nullart2 Date: Wed, 29 Aug 2018 17:38:43 +0800 Subject: [PATCH 77/84] move order_book config out of experimental --- config.json.example | 29 ++++++++---------- config_full.json.example | 29 ++++++++---------- docs/configuration.md | 14 ++++----- freqtrade/constants.py | 44 ++++++++++++---------------- freqtrade/freqtradebot.py | 24 +++++++-------- freqtrade/tests/conftest.py | 29 ++++++++---------- freqtrade/tests/test_freqtradebot.py | 32 ++++++++++---------- 7 files changed, 92 insertions(+), 109 deletions(-) diff --git a/config.json.example b/config.json.example index c3dc6b5b6..7a0bb6b9b 100644 --- a/config.json.example +++ b/config.json.example @@ -11,7 +11,18 @@ "sell": 30 }, "bid_strategy": { - "ask_last_balance": 0.0 + "ask_last_balance": 0.0, + "use_order_book": false, + "order_book_top": 1, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + } + }, + "ask_strategy":{ + "use_order_book": false, + "order_book_min": 1, + "order_book_max": 9 }, "exchange": { "name": "bittrex", @@ -37,21 +48,7 @@ "experimental": { "use_sell_signal": false, "sell_profit_only": false, - "ignore_roi_if_buy_signal": false, - "check_depth_of_market": { - "enabled": false, - "bids_to_ask_delta": 1 - }, - "bid_strategy": { - "use_order_book": false, - "order_book_top": 2, - "percent_from_top": 0 - }, - "ask_strategy":{ - "use_order_book": false, - "order_book_min": 1, - "order_book_max": 9 - } + "ignore_roi_if_buy_signal": false }, "telegram": { "enabled": true, diff --git a/config_full.json.example b/config_full.json.example index 5a364a93b..717f3c7df 100644 --- a/config_full.json.example +++ b/config_full.json.example @@ -20,7 +20,18 @@ "sell": 30 }, "bid_strategy": { - "ask_last_balance": 0.0 + "ask_last_balance": 0.0, + "use_order_book": false, + "order_book_top": 1, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + } + }, + "ask_strategy":{ + "use_order_book": false, + "order_book_min": 1, + "order_book_max": 9 }, "exchange": { "name": "bittrex", @@ -46,21 +57,7 @@ "experimental": { "use_sell_signal": false, "sell_profit_only": false, - "ignore_roi_if_buy_signal": false, - "check_depth_of_market": { - "enabled": false, - "bids_to_ask_delta": 1 - }, - "bid_strategy": { - "use_order_book": false, - "order_book_top": 2, - "percent_from_top": 0 - }, - "ask_strategy":{ - "use_order_book": false, - "order_book_min": 1, - "order_book_max": 9 - }s + "ignore_roi_if_buy_signal": false }, "telegram": { "enabled": true, diff --git a/docs/configuration.md b/docs/configuration.md index 5ffe24556..edc376f90 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -31,6 +31,13 @@ The table below will list all configuration parameters. | `unfilledtimeout.buy` | 10 | Yes | How long (in minutes) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled. | `unfilledtimeout.sell` | 10 | Yes | How long (in minutes) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled. | `bid_strategy.ask_last_balance` | 0.0 | Yes | Set the bidding price. More information below. +| `bid_strategy.use_order_book` | false | No | Allows buying of pair using the rates in Order Book Bids. +| `bid_strategy.order_book_top` | 0 | No | Bot will use the top N rate in Order Book Bids. Ie. a value of 2 will allow the bot to pick the 2nd bid rate in Order Book Bids. +| `bid_strategy.check_depth_of_market.enabled` | false | No | Does not buy if the % difference of buy orders and sell orders is met in Order Book. +| `experimental.check_depth_of_market.bids_to_ask_delta` | 0 | No | The % difference of buy orders and sell orders found in Order Book. A value lesser than 1 means sell orders is greater, while value greater than 1 means buy orders is higher. +| `ask_strategy.use_order_book` | false | No | Allows selling of open traded pair using the rates in Order Book Asks. +| `ask_strategy.order_book_min` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. +| `ask_strategy.order_book_max` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `exchange.name` | bittrex | Yes | Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). | `exchange.key` | key | No | API key to use for the exchange. Only required when you are in production mode. | `exchange.secret` | secret | No | API secret to use for the exchange. Only required when you are in production mode. @@ -39,13 +46,6 @@ The table below will list all configuration parameters. | `experimental.use_sell_signal` | false | No | Use your sell strategy in addition of the `minimal_roi`. | `experimental.sell_profit_only` | false | No | waits until you have made a positive profit before taking a sell decision. | `experimental.ignore_roi_if_buy_signal` | false | No | Does not sell if the buy-signal is still active. Takes preference over `minimal_roi` and `use_sell_signal` -| `experimental.check_depth_of_market` | false | No | Does not sell if the % difference of buy orders and sell orders is met in Order Book. -| `experimental.bids_to_ask_delta` | 0 | No | The % difference of buy orders and sell orders found in Order Book. A value lesser than 1 means sell orders is greater, while value greater than 1 means buy orders is higher. -| `experimental.bid_strategy.use_order_book` | false | No | Allows buying of pair using the rates in Order Book Bids. -| `experimental.bid_strategy.order_book_top` | 0 | No | Bot will use the top N rate in Order Book Bids. Ie. a value of 2 will allow the bot to pick the 2nd bid rate in Order Book Bids. -| `experimental.ask_strategy.use_order_book` | false | No | Allows selling of open traded pair using the rates in Order Book Asks. -| `experimental.ask_strategy.order_book_min` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. -| `experimental.ask_strategy.order_book_max` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `telegram.enabled` | true | Yes | Enable or not the usage of Telegram. | `telegram.token` | token | No | Your Telegram bot token. Only required if `telegram.enabled` is `true`. | `telegram.chat_id` | chat_id | No | Your personal Telegram account id. Only required if `telegram.enabled` is `true`. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index b7431af3c..59b1c3ccf 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -78,41 +78,35 @@ CONF_SCHEMA = { 'type': 'number', 'minimum': 0, 'maximum': 1, - 'exclusiveMaximum': False + 'exclusiveMaximum': False, + 'use_order_book': {'type': 'boolean'}, + 'order_book_top': {'type': 'number', 'maximum': 20, 'minimum': 1}, + 'check_depth_of_market': { + 'type': 'object', + 'properties': { + 'enabled': {'type': 'boolean'}, + 'bids_to_ask_delta': {'type': 'number', 'minimum': 0}, + } + }, }, }, 'required': ['ask_last_balance'] }, + 'ask_strategy': { + 'type': 'object', + 'properties': { + 'use_order_book': {'type': 'boolean'}, + 'order_book_min': {'type': 'number', 'minimum': 1}, + 'order_book_max': {'type': 'number', 'minimum': 1, 'maximum': 50} + } + }, 'exchange': {'$ref': '#/definitions/exchange'}, 'experimental': { 'type': 'object', 'properties': { 'use_sell_signal': {'type': 'boolean'}, 'sell_profit_only': {'type': 'boolean'}, - 'ignore_roi_if_buy_signal_true': {'type': 'boolean'}, - 'check_depth_of_market': { - 'type': 'object', - 'properties': { - 'enabled': {'type': 'boolean'}, - 'bids_to_ask_delta': {'type': 'number', 'minimum': 0}, - } - }, - 'bid_strategy': { - 'type': 'object', - 'properties': { - 'percent_from_top': {'type': 'number', 'minimum': 0}, - 'use_order_book': {'type': 'boolean'}, - 'order_book_top': {'type': 'number', 'maximum': 20, 'minimum': 1} - } - }, - 'ask_strategy': { - 'type': 'object', - 'properties': { - 'use_order_book': {'type': 'boolean'}, - 'order_book_min': {'type': 'number', 'minimum': 1}, - 'order_book_max': {'type': 'number', 'minimum': 1, 'maximum': 50} - } - } + 'ignore_roi_if_buy_signal_true': {'type': 'boolean'} } }, 'telegram': { diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 715cbce80..1f25fb0e4 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -247,11 +247,11 @@ class FreqtradeBot(object): ticker_rate = ticker['ask'] + balance * (ticker['last'] - ticker['ask']) used_rate = ticker_rate - experimental_bid_strategy = self.config.get('experimental', {}).get('bid_strategy', {}) - if 'use_order_book' in experimental_bid_strategy and\ - experimental_bid_strategy.get('use_order_book', False): + config_bid_strategy = self.config.get('bid_strategy', {}) + if 'use_order_book' in config_bid_strategy and\ + config_bid_strategy.get('use_order_book', False): logger.info('Getting price from order book') - order_book_top = experimental_bid_strategy.get('order_book_top', 1) + order_book_top = config_bid_strategy.get('order_book_top', 1) order_book = self.exchange.get_order_book(pair, order_book_top) logger.debug('order_book %s', order_book) # top 1 = index 0 @@ -359,11 +359,11 @@ class FreqtradeBot(object): (buy, sell) = self.strategy.get_signal(_pair, interval, thistory) if buy and not sell: - experimental_check_depth_of_market = self.config.get('experimental', {}).\ + bidstrat_check_depth_of_market = self.config.get('bid_strategy', {}).\ get('check_depth_of_market', {}) - if (experimental_check_depth_of_market.get('enabled', False)) and\ - (experimental_check_depth_of_market.get('bids_to_ask_delta', 0) > 0): - if self._check_depth_of_market_buy(_pair, experimental_check_depth_of_market): + if (bidstrat_check_depth_of_market.get('enabled', False)) and\ + (bidstrat_check_depth_of_market.get('bids_to_ask_delta', 0) > 0): + if self._check_depth_of_market_buy(_pair, bidstrat_check_depth_of_market): return self.execute_buy(_pair, stake_amount) else: return False @@ -551,12 +551,12 @@ class FreqtradeBot(object): (buy, sell) = self.strategy.get_signal(trade.pair, self.strategy.ticker_interval, ticker) - experimental_ask_strategy = self.config.get('experimental', {}).get('ask_strategy', {}) - if experimental_ask_strategy.get('use_order_book', False): + config_ask_strategy = self.config.get('ask_strategy', {}) + if config_ask_strategy.get('use_order_book', False): logger.info('Using order book for selling...') # logger.debug('Order book %s',orderBook) - order_book_min = experimental_ask_strategy.get('order_book_min', 1) - order_book_max = experimental_ask_strategy.get('order_book_max', 1) + order_book_min = config_ask_strategy.get('order_book_min', 1) + order_book_max = config_ask_strategy.get('order_book_max', 1) order_book = self.exchange.get_order_book(trade.pair, order_book_max) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index 8a40397f3..af9062cab 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -102,7 +102,18 @@ def default_conf(): "sell": 30 }, "bid_strategy": { - "ask_last_balance": 0.0 + "ask_last_balance": 0.0, + "use_order_book": False, + "order_book_top": 1, + "check_depth_of_market": { + "enabled": False, + "bids_to_ask_delta": 1 + } + }, + "ask_strategy": { + "use_order_book": False, + "order_book_min": 1, + "order_book_max": 1 }, "exchange": { "name": "bittrex", @@ -116,22 +127,6 @@ def default_conf(): "NEO/BTC" ] }, - "experimental": { - "check_depth_of_market": { - "enabled": False, - "bids_to_ask_delta": 1 - }, - "bid_strategy": { - "percent_from_top": 0, - "use_order_book": False, - "order_book_top": 1 - }, - "ask_strategy": { - "use_order_book": False, - "order_book_min": 1, - "order_book_max": 1 - } - }, "telegram": { "enabled": True, "token": "token", diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 43ab587ec..389215f6f 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -1889,8 +1889,8 @@ def test_get_real_amount_open_trade(default_conf, mocker): def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, markets, mocker, order_book_l2): - default_conf['experimental']['check_depth_of_market']['enabled'] = True - default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 0.1 + default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True + default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1 patch_RPCManager(mocker) mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) mocker.patch.multiple( @@ -1924,9 +1924,9 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee, def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_order, fee, markets, mocker, order_book_l2): - default_conf['experimental']['check_depth_of_market']['enabled'] = True + default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True # delta is 100 which is impossible to reach. hence check_depth_of_market will return false - default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 100 + default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100 patch_RPCManager(mocker) mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) mocker.patch.multiple( @@ -1958,8 +1958,8 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets) get_order_book=order_book_l2 ) default_conf['exchange']['name'] = 'binance' - default_conf['experimental']['bid_strategy']['use_order_book'] = True - default_conf['experimental']['bid_strategy']['order_book_top'] = 2 + default_conf['bid_strategy']['use_order_book'] = True + default_conf['bid_strategy']['order_book_top'] = 2 default_conf['bid_strategy']['ask_last_balance'] = 0 default_conf['telegram']['enabled'] = False @@ -1979,8 +1979,8 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets) get_order_book=order_book_l2 ) default_conf['exchange']['name'] = 'binance' - default_conf['experimental']['bid_strategy']['use_order_book'] = True - default_conf['experimental']['bid_strategy']['order_book_top'] = 2 + default_conf['bid_strategy']['use_order_book'] = True + default_conf['bid_strategy']['order_book_top'] = 2 default_conf['bid_strategy']['ask_last_balance'] = 0 default_conf['telegram']['enabled'] = False @@ -2000,8 +2000,8 @@ def test_order_book_bid_strategy3(default_conf, mocker, order_book_l2, markets) get_order_book=order_book_l2 ) default_conf['exchange']['name'] = 'binance' - default_conf['experimental']['bid_strategy']['use_order_book'] = True - default_conf['experimental']['bid_strategy']['order_book_top'] = 1 + default_conf['bid_strategy']['use_order_book'] = True + default_conf['bid_strategy']['order_book_top'] = 1 default_conf['bid_strategy']['ask_last_balance'] = 0 default_conf['telegram']['enabled'] = False @@ -2022,12 +2022,12 @@ def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2, markets) ) default_conf['telegram']['enabled'] = False default_conf['exchange']['name'] = 'binance' - default_conf['experimental']['check_depth_of_market']['enabled'] = True + default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True # delta is 100 which is impossible to reach. hence function will return false - default_conf['experimental']['check_depth_of_market']['bids_to_ask_delta'] = 100 + default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 100 freqtrade = FreqtradeBot(default_conf) - conf = default_conf['experimental']['check_depth_of_market'] + conf = default_conf['bid_strategy']['check_depth_of_market'] assert freqtrade._check_depth_of_market_buy('ETH/BTC', conf) is False @@ -2038,9 +2038,9 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order """ mocker.patch('freqtrade.exchange.Exchange.get_order_book', order_book_l2) default_conf['exchange']['name'] = 'binance' - default_conf['experimental']['ask_strategy']['use_order_book'] = True - default_conf['experimental']['ask_strategy']['order_book_min'] = 1 - default_conf['experimental']['ask_strategy']['order_book_max'] = 2 + default_conf['ask_strategy']['use_order_book'] = True + default_conf['ask_strategy']['order_book_min'] = 1 + default_conf['ask_strategy']['order_book_max'] = 2 default_conf['telegram']['enabled'] = False patch_RPCManager(mocker) mocker.patch.multiple( From b659ec00ee495e59f1c055d019abd7e7c57c8282 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 29 Aug 2018 14:28:07 +0200 Subject: [PATCH 78/84] Update ccxt from 1.17.199 to 1.17.205 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b2f1e3a25..fe64ea684 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.199 +ccxt==1.17.205 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From f7b67cec5b50a93bf0bad4e30656b408caf8a47b Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Aug 2018 19:16:41 +0200 Subject: [PATCH 79/84] Fix missing docstring --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index edc376f90..757310957 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -34,7 +34,7 @@ The table below will list all configuration parameters. | `bid_strategy.use_order_book` | false | No | Allows buying of pair using the rates in Order Book Bids. | `bid_strategy.order_book_top` | 0 | No | Bot will use the top N rate in Order Book Bids. Ie. a value of 2 will allow the bot to pick the 2nd bid rate in Order Book Bids. | `bid_strategy.check_depth_of_market.enabled` | false | No | Does not buy if the % difference of buy orders and sell orders is met in Order Book. -| `experimental.check_depth_of_market.bids_to_ask_delta` | 0 | No | The % difference of buy orders and sell orders found in Order Book. A value lesser than 1 means sell orders is greater, while value greater than 1 means buy orders is higher. +| `bid_strategy.check_depth_of_market.bids_to_ask_delta` | 0 | No | The % difference of buy orders and sell orders found in Order Book. A value lesser than 1 means sell orders is greater, while value greater than 1 means buy orders is higher. | `ask_strategy.use_order_book` | false | No | Allows selling of open traded pair using the rates in Order Book Asks. | `ask_strategy.order_book_min` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `ask_strategy.order_book_max` | 0 | No | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. From a1bd30aa605228510349c2ec97671eb28af282de Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Aug 2018 19:59:25 +0200 Subject: [PATCH 80/84] Fix documentation string --- docs/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 757310957..3866effd2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -25,9 +25,9 @@ The table below will list all configuration parameters. | `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. | `minimal_roi` | See below | No | Set the threshold in percent the bot will use to sell a trade. More information below. If set, this parameter will override `minimal_roi` from your strategy file. | `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. If set, this parameter will override `stoploss` from your strategy file. -| `trailing_stoploss` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). -| `trailing_stoploss_positve` | 0 | No | Changes stop-loss once profit has been reached. -| `trailing_stoploss_positve_offset` | 0 | No | Offset on when to apply `trailing_stoploss_positive`. Percentage value which should be positive. +| `trailing_stop` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). +| `trailing_stop_positve` | 0 | No | Changes stop-loss once profit has been reached. +| `trailing_stop_positve_offset` | 0 | No | Offset on when to apply `trailing_stop_positive`. Percentage value which should be positive. | `unfilledtimeout.buy` | 10 | Yes | How long (in minutes) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled. | `unfilledtimeout.sell` | 10 | Yes | How long (in minutes) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled. | `bid_strategy.ask_last_balance` | 0.0 | Yes | Set the bidding price. More information below. From 35c5d4f5804b211b97889301e93cd872c35b1fba Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 30 Aug 2018 14:28:07 +0200 Subject: [PATCH 81/84] Update ccxt from 1.17.205 to 1.17.210 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fe64ea684..fcffbf887 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.205 +ccxt==1.17.210 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From 3ed97fe5e880dd0cb3ffcad238a9e0fa9f340b20 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 30 Aug 2018 14:28:08 +0200 Subject: [PATCH 82/84] Update python-telegram-bot from 10.1.0 to 11.0.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fcffbf887..0e0685487 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ ccxt==1.17.210 SQLAlchemy==1.2.11 -python-telegram-bot==10.1.0 +python-telegram-bot==11.0.0 arrow==0.12.1 cachetools==2.1.0 requests==2.19.1 From 9560cb80566efb3414ed0bbbc7da5a93318f345f Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 30 Aug 2018 14:28:10 +0200 Subject: [PATCH 83/84] Update pytest from 3.7.3 to 3.7.4 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0e0685487..3a605a663 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ scipy==1.1.0 jsonschema==2.6.0 numpy==1.15.1 TA-Lib==0.4.17 -pytest==3.7.3 +pytest==3.7.4 pytest-mock==1.10.0 pytest-cov==2.5.1 tabulate==0.8.2 From fa5c8e4bb11519ec3302beed5324b7c85ba19635 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 1 Sep 2018 14:28:06 +0200 Subject: [PATCH 84/84] Update ccxt from 1.17.210 to 1.17.216 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3a605a663..5cb061855 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.210 +ccxt==1.17.216 SQLAlchemy==1.2.11 python-telegram-bot==11.0.0 arrow==0.12.1