Merge branch 'develop' into kraken_support
This commit is contained in:
		| @@ -3,6 +3,7 @@ | |||||||
|     "stake_currency": "BTC", |     "stake_currency": "BTC", | ||||||
|     "stake_amount": 0.05, |     "stake_amount": 0.05, | ||||||
|     "fiat_display_currency": "USD", |     "fiat_display_currency": "USD", | ||||||
|  |     "amount_reserve_percent" : 0.05, | ||||||
|     "dry_run": false, |     "dry_run": false, | ||||||
|     "ticker_interval": "5m", |     "ticker_interval": "5m", | ||||||
|     "trailing_stop": false, |     "trailing_stop": false, | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ Mandatory Parameters are marked as **Required**. | |||||||
| | `max_open_trades` | 3 | **Required.** Number of trades open your bot will have. If -1 then it is ignored (i.e. potentially unlimited open trades) | | `max_open_trades` | 3 | **Required.** Number of trades open your bot will have. If -1 then it is ignored (i.e. potentially unlimited open trades) | ||||||
| | `stake_currency` | BTC | **Required.** Crypto-currency used for trading. | | `stake_currency` | BTC | **Required.** Crypto-currency used for trading. | ||||||
| | `stake_amount` | 0.05 | **Required.** Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged. Set it to `"unlimited"` to allow the bot to use all available balance. | | `stake_amount` | 0.05 | **Required.** Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged. Set it to `"unlimited"` to allow the bot to use all available balance. | ||||||
|  | | `amount_reserve_percent` | 0.05 | Reserve some amount in min pair stake amount. Default is 5%. The bot will reserve `amount_reserve_percent` + stop-loss value when calculating min pair stake amount in order to avoid possible trade refusals. | ||||||
| | `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes. [Strategy Override](#parameters-in-strategy). | | `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes. [Strategy Override](#parameters-in-strategy). | ||||||
| | `fiat_display_currency` | USD | **Required.** Fiat currency used to show your profits. More information below. | | `fiat_display_currency` | USD | **Required.** Fiat currency used to show your profits. More information below. | ||||||
| | `dry_run` | true | **Required.** Define if the bot must be in Dry-run or production mode. | | `dry_run` | true | **Required.** Define if the bot must be in Dry-run or production mode. | ||||||
|   | |||||||
| @@ -211,19 +211,11 @@ class FreqtradeBot(object): | |||||||
|             self.state = State.STOPPED |             self.state = State.STOPPED | ||||||
|         return state_changed |         return state_changed | ||||||
|  |  | ||||||
|     def get_target_bid(self, pair: str, ticker: Dict[str, float]) -> float: |     def get_target_bid(self, pair: str) -> float: | ||||||
|         """ |         """ | ||||||
|         Calculates bid target between current ask price and last price |         Calculates bid target between current ask price and last price | ||||||
|         :param ticker: Ticker to use for getting Ask and Last Price |  | ||||||
|         :return: float: Price |         :return: float: Price | ||||||
|         """ |         """ | ||||||
|         if ticker['ask'] < ticker['last']: |  | ||||||
|             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 |  | ||||||
|         config_bid_strategy = self.config.get('bid_strategy', {}) |         config_bid_strategy = self.config.get('bid_strategy', {}) | ||||||
|         if 'use_order_book' in config_bid_strategy and\ |         if 'use_order_book' in config_bid_strategy and\ | ||||||
|                 config_bid_strategy.get('use_order_book', False): |                 config_bid_strategy.get('use_order_book', False): | ||||||
| @@ -233,15 +225,16 @@ class FreqtradeBot(object): | |||||||
|             logger.debug('order_book %s', order_book) |             logger.debug('order_book %s', order_book) | ||||||
|             # top 1 = index 0 |             # top 1 = index 0 | ||||||
|             order_book_rate = order_book['bids'][order_book_top - 1][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) |             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 |  | ||||||
|             else: |  | ||||||
|             used_rate = order_book_rate |             used_rate = order_book_rate | ||||||
|         else: |         else: | ||||||
|             logger.info('Using Last Ask / Last Price') |             logger.info('Using Last Ask / Last Price') | ||||||
|  |             ticker = self.exchange.get_ticker(pair) | ||||||
|  |             if ticker['ask'] < ticker['last']: | ||||||
|  |                 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 |             used_rate = ticker_rate | ||||||
|  |  | ||||||
|         return used_rate |         return used_rate | ||||||
| @@ -304,7 +297,8 @@ class FreqtradeBot(object): | |||||||
|         if not min_stake_amounts: |         if not min_stake_amounts: | ||||||
|             return None |             return None | ||||||
|  |  | ||||||
|         amount_reserve_percent = 1 - 0.05  # reserve 5% + stoploss |         # reserve some percent defined in config (5% default) + stoploss | ||||||
|  |         amount_reserve_percent = 1.0 - self.config.get('amount_reserve_percent', 0.05) | ||||||
|         if self.strategy.stoploss is not None: |         if self.strategy.stoploss is not None: | ||||||
|             amount_reserve_percent += self.strategy.stoploss |             amount_reserve_percent += self.strategy.stoploss | ||||||
|         # it should not be more than 50% |         # it should not be more than 50% | ||||||
| @@ -387,7 +381,7 @@ class FreqtradeBot(object): | |||||||
|             buy_limit_requested = price |             buy_limit_requested = price | ||||||
|         else: |         else: | ||||||
|             # Calculate amount |             # Calculate amount | ||||||
|             buy_limit_requested = self.get_target_bid(pair, self.exchange.get_ticker(pair)) |             buy_limit_requested = self.get_target_bid(pair) | ||||||
|  |  | ||||||
|         min_stake_amount = self._get_min_pair_stake_amount(pair_s, buy_limit_requested) |         min_stake_amount = self._get_min_pair_stake_amount(pair_s, buy_limit_requested) | ||||||
|         if min_stake_amount is not None and min_stake_amount > stake_amount: |         if min_stake_amount is not None and min_stake_amount > stake_amount: | ||||||
| @@ -587,7 +581,6 @@ class FreqtradeBot(object): | |||||||
|             raise ValueError(f'Attempt to handle closed trade: {trade}') |             raise ValueError(f'Attempt to handle closed trade: {trade}') | ||||||
|  |  | ||||||
|         logger.debug('Handling %s ...', trade) |         logger.debug('Handling %s ...', trade) | ||||||
|         sell_rate = self.exchange.get_ticker(trade.pair)['bid'] |  | ||||||
|  |  | ||||||
|         (buy, sell) = (False, False) |         (buy, sell) = (False, False) | ||||||
|         experimental = self.config.get('experimental', {}) |         experimental = self.config.get('experimental', {}) | ||||||
| @@ -607,11 +600,7 @@ class FreqtradeBot(object): | |||||||
|  |  | ||||||
|             for i in range(order_book_min, order_book_max + 1): |             for i in range(order_book_min, order_book_max + 1): | ||||||
|                 order_book_rate = order_book['asks'][i - 1][0] |                 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) |                 logger.info('  order book asks top %s: %0.8f', i, order_book_rate) | ||||||
|                 if sell_rate < order_book_rate: |  | ||||||
|                 sell_rate = order_book_rate |                 sell_rate = order_book_rate | ||||||
|  |  | ||||||
|                 if self.check_sell(trade, sell_rate, buy, sell): |                 if self.check_sell(trade, sell_rate, buy, sell): | ||||||
| @@ -619,6 +608,7 @@ class FreqtradeBot(object): | |||||||
|  |  | ||||||
|         else: |         else: | ||||||
|             logger.debug('checking sell') |             logger.debug('checking sell') | ||||||
|  |             sell_rate = self.exchange.get_ticker(trade.pair)['bid'] | ||||||
|             if self.check_sell(trade, sell_rate, buy, sell): |             if self.check_sell(trade, sell_rate, buy, sell): | ||||||
|                 return True |                 return True | ||||||
|  |  | ||||||
|   | |||||||
| @@ -841,22 +841,27 @@ def test_process_informative_pairs_added(default_conf, ticker, markets, mocker) | |||||||
| def test_balance_fully_ask_side(mocker, default_conf) -> None: | def test_balance_fully_ask_side(mocker, default_conf) -> None: | ||||||
|     default_conf['bid_strategy']['ask_last_balance'] = 0.0 |     default_conf['bid_strategy']['ask_last_balance'] = 0.0 | ||||||
|     freqtrade = get_patched_freqtradebot(mocker, default_conf) |     freqtrade = get_patched_freqtradebot(mocker, default_conf) | ||||||
|  |     mocker.patch('freqtrade.exchange.Exchange.get_ticker', | ||||||
|  |                  MagicMock(return_value={'ask': 20, 'last': 10})) | ||||||
|  |  | ||||||
|     assert freqtrade.get_target_bid('ETH/BTC', {'ask': 20, 'last': 10}) == 20 |     assert freqtrade.get_target_bid('ETH/BTC') == 20 | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_balance_fully_last_side(mocker, default_conf) -> None: | def test_balance_fully_last_side(mocker, default_conf) -> None: | ||||||
|     default_conf['bid_strategy']['ask_last_balance'] = 1.0 |     default_conf['bid_strategy']['ask_last_balance'] = 1.0 | ||||||
|     freqtrade = get_patched_freqtradebot(mocker, default_conf) |     freqtrade = get_patched_freqtradebot(mocker, default_conf) | ||||||
|  |     mocker.patch('freqtrade.exchange.Exchange.get_ticker', | ||||||
|  |                  MagicMock(return_value={'ask': 20, 'last': 10})) | ||||||
|  |  | ||||||
|     assert freqtrade.get_target_bid('ETH/BTC', {'ask': 20, 'last': 10}) == 10 |     assert freqtrade.get_target_bid('ETH/BTC') == 10 | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_balance_bigger_last_ask(mocker, default_conf) -> None: | def test_balance_bigger_last_ask(mocker, default_conf) -> None: | ||||||
|     default_conf['bid_strategy']['ask_last_balance'] = 1.0 |     default_conf['bid_strategy']['ask_last_balance'] = 1.0 | ||||||
|     freqtrade = get_patched_freqtradebot(mocker, default_conf) |     freqtrade = get_patched_freqtradebot(mocker, default_conf) | ||||||
|  |     mocker.patch('freqtrade.exchange.Exchange.get_ticker', | ||||||
|     assert freqtrade.get_target_bid('ETH/BTC', {'ask': 5, 'last': 10}) == 5 |                  MagicMock(return_value={'ask': 5, 'last': 10})) | ||||||
|  |     assert freqtrade.get_target_bid('ETH/BTC') == 5 | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_execute_buy(mocker, default_conf, fee, markets, limit_buy_order) -> None: | def test_execute_buy(mocker, default_conf, fee, markets, limit_buy_order) -> None: | ||||||
| @@ -2813,10 +2818,13 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets) | |||||||
|     instead of the ask rate |     instead of the ask rate | ||||||
|     """ |     """ | ||||||
|     patch_exchange(mocker) |     patch_exchange(mocker) | ||||||
|  |     ticker_mock = MagicMock(return_value={'ask': 0.045, 'last': 0.046}) | ||||||
|     mocker.patch.multiple( |     mocker.patch.multiple( | ||||||
|         'freqtrade.exchange.Exchange', |         'freqtrade.exchange.Exchange', | ||||||
|         get_markets=markets, |         get_markets=markets, | ||||||
|         get_order_book=order_book_l2 |         get_order_book=order_book_l2, | ||||||
|  |         get_ticker=ticker_mock, | ||||||
|  |  | ||||||
|     ) |     ) | ||||||
|     default_conf['exchange']['name'] = 'binance' |     default_conf['exchange']['name'] = 'binance' | ||||||
|     default_conf['bid_strategy']['use_order_book'] = True |     default_conf['bid_strategy']['use_order_book'] = True | ||||||
| @@ -2825,7 +2833,8 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets) | |||||||
|     default_conf['telegram']['enabled'] = False |     default_conf['telegram']['enabled'] = False | ||||||
|  |  | ||||||
|     freqtrade = FreqtradeBot(default_conf) |     freqtrade = FreqtradeBot(default_conf) | ||||||
|     assert freqtrade.get_target_bid('ETH/BTC', {'ask': 0.045, 'last': 0.046}) == 0.043935 |     assert freqtrade.get_target_bid('ETH/BTC') == 0.043935 | ||||||
|  |     assert ticker_mock.call_count == 0 | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets) -> None: | def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets) -> None: | ||||||
| @@ -2834,10 +2843,13 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets) | |||||||
|     instead of the order book rate (even if enabled) |     instead of the order book rate (even if enabled) | ||||||
|     """ |     """ | ||||||
|     patch_exchange(mocker) |     patch_exchange(mocker) | ||||||
|  |     ticker_mock = MagicMock(return_value={'ask': 0.042, 'last': 0.046}) | ||||||
|     mocker.patch.multiple( |     mocker.patch.multiple( | ||||||
|         'freqtrade.exchange.Exchange', |         'freqtrade.exchange.Exchange', | ||||||
|         get_markets=markets, |         get_markets=markets, | ||||||
|         get_order_book=order_book_l2 |         get_order_book=order_book_l2, | ||||||
|  |         get_ticker=ticker_mock, | ||||||
|  |  | ||||||
|     ) |     ) | ||||||
|     default_conf['exchange']['name'] = 'binance' |     default_conf['exchange']['name'] = 'binance' | ||||||
|     default_conf['bid_strategy']['use_order_book'] = True |     default_conf['bid_strategy']['use_order_book'] = True | ||||||
| @@ -2846,29 +2858,9 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets) | |||||||
|     default_conf['telegram']['enabled'] = False |     default_conf['telegram']['enabled'] = False | ||||||
|  |  | ||||||
|     freqtrade = FreqtradeBot(default_conf) |     freqtrade = FreqtradeBot(default_conf) | ||||||
|     assert freqtrade.get_target_bid('ETH/BTC', {'ask': 0.042, 'last': 0.046}) == 0.042 |     # ordrebook shall be used even if tickers would be lower. | ||||||
|  |     assert freqtrade.get_target_bid('ETH/BTC', ) != 0.042 | ||||||
|  |     assert ticker_mock.call_count == 0 | ||||||
| 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 |  | ||||||
|     """ |  | ||||||
|     patch_exchange(mocker) |  | ||||||
|     mocker.patch.multiple( |  | ||||||
|         'freqtrade.exchange.Exchange', |  | ||||||
|         get_markets=markets, |  | ||||||
|         get_order_book=order_book_l2 |  | ||||||
|     ) |  | ||||||
|     default_conf['exchange']['name'] = 'binance' |  | ||||||
|     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 |  | ||||||
|  |  | ||||||
|     freqtrade = FreqtradeBot(default_conf) |  | ||||||
|  |  | ||||||
|     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, markets) -> None: | def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2, markets) -> None: | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| ccxt==1.18.234 | ccxt==1.18.243 | ||||||
| SQLAlchemy==1.2.17 | SQLAlchemy==1.2.18 | ||||||
| python-telegram-bot==11.1.0 | python-telegram-bot==11.1.0 | ||||||
| arrow==0.13.1 | arrow==0.13.1 | ||||||
| cachetools==3.1.0 | cachetools==3.1.0 | ||||||
| @@ -9,7 +9,7 @@ wrapt==1.11.1 | |||||||
| numpy==1.16.1 | numpy==1.16.1 | ||||||
| pandas==0.24.1 | pandas==0.24.1 | ||||||
| scikit-learn==0.20.2 | scikit-learn==0.20.2 | ||||||
| joblib==0.13.1 | joblib==0.13.2 | ||||||
| scipy==1.2.1 | scipy==1.2.1 | ||||||
| jsonschema==2.6.0 | jsonschema==2.6.0 | ||||||
| TA-Lib==0.4.17 | TA-Lib==0.4.17 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user