Repository: freqtrade/freqtrade

Issue:
Huobi - Market orders do not work to buy
## Step 1: Have you search for this issue before posting it?

Yes.

## Step 2: Describe your environment

Python Version: python3.7
CCXT version: 1.18.551
Branch: Master | Develop
  
## Step 3: Describe the problem:

*Can't use market orders to buy but exchange does support them*

### Steps to reproduce:

1. Configure huobi
2.run with market orders for buying
3. wait for buy signal
  
### Observed Results:

* There was an error saying something about spread but calling an error on the python function
*I was expecting it to simply market buy the pair when the buy signal came in

### Relevant code exceptions or logs:
```
2019-06-10 15:03:02,906 - freqtrade.freqtradebot - INFO - Buy signal found: about create a new trade with stake_amount: 0.0045 ...
2019-06-10 15:03:02,907 - freqtrade.freqtradebot - INFO - Using Last Ask / Last Price
2019-06-10 15:03:04,833 - freqtrade - ERROR - Fatal exception!
Traceback (most recent call last):
  File "/home/dantefreqtrade/freqtrade/exchange/exchange.py", line 353, in create_order
    amount, rate, params)
  File "/home/dante.local/lib/python3.7/site-packages/ccxt/huobipro.py", line 754, in create_order
    raise InvalidOrder(self.id + " market buy order requires price argument to calculate cost(total amount of quote currency to spend for buying, amount * price). To switch off self warning exception and specify cost in the amount argument, set .options['createMarketBuyOrderRequiresPrice'] = False. Make sure you know what you're doing.")
ccxt.base.errors.InvalidOrder: huobipro market buy order requires price argument to calculate cost(total amount of quote currency to spend for buying, amount * price). To switch off self warning exception and specify cost in the amount argument, set .options['createMarketBuyOrderRequiresPrice'] = False. Make sure you know what you're doing.

During handling of the above exception, another exception occurred:


Traceback (most recent call last):
  File "/home/dantefreqtrade/freqtrade/main.py", line 42, in main
    worker.run()
  File "/home/dantefreqtrade/freqtrade/worker.py", line 72, in run
    state = self._worker(old_state=state)
  File "/home/dantefreqtrade/freqtrade/worker.py", line 110, in _worker
    self._throttle(func=self._process, min_secs=throttle_secs)
  File "/home/dantefreqtrade/freqtrade/worker.py", line 123, in _throttle
    result = func(*args, **kwargs)
  File "/home/dantefreqtrade/freqtrade/worker.py", line 133, in _process
    state_changed = self.freqtrade.process()
  File "/home/dantefreqtrade/freqtrade/freqtradebot.py", line 129, in process
    state_changed = self.process_maybe_execute_buy()
  File "/home/dantefreqtrade/freqtrade/freqtradebot.py", line 423, in process_maybe_execute_buy
    if self.create_trade():
  File "/home/dantefreqtrade/freqtrade/freqtradebot.py", line 290, in create_trade
    return self.execute_buy(_pair, stake_amount)
  File "/home/dantefreqtrade/freqtrade/freqtradebot.py", line 340, in execute_buy
    time_in_force=time_in_force)
 File "/home/dantefreqtrade/freqtrade/exchange/exchange.py", line 382, in buy
    return self.create_order(pair, ordertype, 'buy', amount, rate, params)
  File "/home/dantefreqtrade/freqtrade/exchange/exchange.py", line 362, in create_order
    f'Could not create {ordertype} {side} order on market {pair}.'
TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'

```



Discussion:
Honestly, without logs and for an exchange we don't support officially, i am very tempted to close the issue until we have logs at least, since this will be impossible to even try to analyze.
@xmatthias added the logs
well technically the message is clear - HuobiPro seems to require a price for market orders (which i still need to investigate the reason for) - which does not make sense to me, as a market-order is (by definition) a order which you want filled immediately, at the "best price" available, which will probably not be what you supply as price.

Related ccxt code:
https://github.com/ccxt/ccxt/blob/d5e98352e17694a66a4656d0a4a7ec29b56e99c5/python/ccxt/huobipro.py#L753-L764

@xmatthias should not be this ccxt option (options['createMarketBuyOrderRequiresPrice'] = False) be set in ft_has for Huobi?

@Dante2333 Try to set this option in the config (just an example, not tested):
```
    "exchange": {
        "name": "huobi",
        ...
        "ccxt_config": {
            "enableRateLimit": true,
            "createMarketBuyOrderRequiresPrice": false
        },
```
@hroff-1902 
this solution would assume that ccxt has this requirement for "fun" ... which i strongly doubt. 
It's probably a requirement of the Huobi API to have a price, so with this setting it'll not fail on ccxt, but on the API itself (at least that's my assumption)... 

ps: no need to add it to the async config dict - that's only used for downloading data

Resolving patch:
diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py
--- a/freqtrade/exchange/exchange.py
+++ b/freqtrade/exchange/exchange.py
@@ -387,7 +387,9 @@ def create_order(self, pair: str, ordertype: str, side: str, amount: float,
         try:
             # Set the precision for amount and price(rate) as accepted by the exchange
             amount = self.symbol_amount_prec(pair, amount)
-            rate = self.symbol_price_prec(pair, rate) if ordertype != 'market' else None
+            needs_price = (ordertype != 'market'
+                           or self._api.options.get("createMarketBuyOrderRequiresPrice", False))
+            rate = self.symbol_price_prec(pair, rate) if needs_price else None
 
             return self._api.create_order(pair, ordertype, side,
                                           amount, rate, params)
@@ -395,12 +397,12 @@ def create_order(self, pair: str, ordertype: str, side: str, amount: float,
         except ccxt.InsufficientFunds as e:
             raise DependencyException(
                 f'Insufficient funds to create {ordertype} {side} order on market {pair}.'
-                f'Tried to {side} amount {amount} at rate {rate} (total {rate*amount}).'
+                f'Tried to {side} amount {amount} at rate {rate} (total {rate * amount}).'
                 f'Message: {e}')
         except ccxt.InvalidOrder as e:
             raise DependencyException(
                 f'Could not create {ordertype} {side} order on market {pair}.'
-                f'Tried to {side} amount {amount} at rate {rate} (total {rate*amount}).'
+                f'Tried to {side} amount {amount} at rate {rate} (total {rate * amount}).'
                 f'Message: {e}')
         except (ccxt.NetworkError, ccxt.ExchangeError) as e:
             raise TemporaryError(


Test patch:
diff --git a/freqtrade/tests/exchange/test_exchange.py b/freqtrade/tests/exchange/test_exchange.py
--- a/freqtrade/tests/exchange/test_exchange.py
+++ b/freqtrade/tests/exchange/test_exchange.py
@@ -543,15 +543,17 @@ def test_dry_run_order(default_conf, mocker, side, exchange_name):
     ("buy"),
     ("sell")
 ])
-@pytest.mark.parametrize("ordertype,rate", [
-    ("market", None),
-    ("limit", 200),
-    ("stop_loss_limit", 200)
+@pytest.mark.parametrize("ordertype,rate,marketprice", [
+    ("market", None, None),
+    ("market", 200, True),
+    ("limit", 200, None),
+    ("stop_loss_limit", 200, None)
 ])
 @pytest.mark.parametrize("exchange_name", EXCHANGES)
-def test_create_order(default_conf, mocker, side, ordertype, rate, exchange_name):
+def test_create_order(default_conf, mocker, side, ordertype, rate, marketprice, exchange_name):
     api_mock = MagicMock()
     order_id = 'test_prod_{}_{}'.format(side, randint(0, 10 ** 6))
+    api_mock.options = {} if not marketprice else {"createMarketBuyOrderRequiresPrice": True}
     api_mock.create_order = MagicMock(return_value={
         'id': order_id,
         'info': {
@@ -592,6 +594,7 @@ def test_buy_prod(default_conf, mocker, exchange_name):
     order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6))
     order_type = 'market'
     time_in_force = 'gtc'
+    api_mock.options = {}
     api_mock.create_order = MagicMock(return_value={
         'id': order_id,
         'info': {
@@ -659,6 +662,7 @@ def test_buy_prod(default_conf, mocker, exchange_name):
 def test_buy_considers_time_in_force(default_conf, mocker, exchange_name):
     api_mock = MagicMock()
     order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6))
+    api_mock.options = {}
     api_mock.create_order = MagicMock(return_value={
         'id': order_id,
         'info': {
@@ -719,6 +723,7 @@ def test_sell_prod(default_conf, mocker, exchange_name):
     api_mock = MagicMock()
     order_id = 'test_prod_sell_{}'.format(randint(0, 10 ** 6))
     order_type = 'market'
+    api_mock.options = {}
     api_mock.create_order = MagicMock(return_value={
         'id': order_id,
         'info': {
@@ -783,6 +788,7 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name):
             'foo': 'bar'
         }
     })
+    api_mock.options = {}
     default_conf['dry_run'] = False
     mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y)
     mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y)
diff --git a/freqtrade/tests/exchange/test_kraken.py b/freqtrade/tests/exchange/test_kraken.py
--- a/freqtrade/tests/exchange/test_kraken.py
+++ b/freqtrade/tests/exchange/test_kraken.py
@@ -11,6 +11,7 @@ def test_buy_kraken_trading_agreement(default_conf, mocker):
     order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6))
     order_type = 'limit'
     time_in_force = 'ioc'
+    api_mock.options = {}
     api_mock.create_order = MagicMock(return_value={
         'id': order_id,
         'info': {
@@ -42,6 +43,7 @@ def test_sell_kraken_trading_agreement(default_conf, mocker):
     api_mock = MagicMock()
     order_id = 'test_prod_sell_{}'.format(randint(0, 10 ** 6))
     order_type = 'market'
+    api_mock.options = {}
     api_mock.create_order = MagicMock(return_value={
         'id': order_id,
         'info': {